From 885ef4ae3c52a1b07cd45f372a34463274efdf75 Mon Sep 17 00:00:00 2001
From: silverweed <silverweed14@proton.me>
Date: Tue, 19 Nov 2024 15:27:11 +0100
Subject: [PATCH] read any other ROOT obj as a blob, rather than just TBaskets

---
 src/argparse.cpp  |  8 ++++----
 src/hover.cpp     |  8 +++++---
 src/render.cpp    | 40 ++++++++++++++++++++--------------------
 src/render.h      |  4 ++--
 src/rntuple.cpp   |  6 +++---
 src/rntuple.h     | 14 ++++++++------
 src/rntviewer.cpp |  6 +++---
 src/tfile.cpp     | 24 ++++++++++++++----------
 8 files changed, 59 insertions(+), 51 deletions(-)

diff --git a/src/argparse.cpp b/src/argparse.cpp
index d8339ce..f17106f 100644
--- a/src/argparse.cpp
+++ b/src/argparse.cpp
@@ -5,7 +5,7 @@ void print_help(const char *argv0)
     "rntviewer v" V_MAJOR "." V_MINOR " by silverweed"
     "\n"
     "\nUsage: %s [-Behkntv] [-s START] [-l LEN] [-w WIDTH] <ntuple_file.root> [ntuple_name]"
-    "\n\t-B: disable highlighting of TBaskets"
+    "\n\t-R: disable highlighting of non-RNTuple ROOT objects"
     "\n\t-e: display some extended info(*) (may slow down the startup)"
     "\n\t-h: display this help and exit"
     "\n\t-l: display LEN bytes (only in terminal mode)"
@@ -76,7 +76,7 @@ struct Cmdline_Args {
   b8 extended_info;
   b8 only_print_rntuple_names;
   b8 print_keys_info;
-  b8 disable_tbaskets;
+  b8 dont_collect_other_root_objs;
 
   String8 ntpl_name;
   String8 file_name;
@@ -169,8 +169,8 @@ Cmdline_Args parse_args(i32 argc, char **argv)
           args.show_version_and_exit = true;
         else if (arg[1] == 'k')
           args.print_keys_info = true;
-        else if (arg[1] == 'B')
-          args.disable_tbaskets = true;
+        else if (arg[1] == 'R')
+          args.dont_collect_other_root_objs = true;
         else if (arg[1] == 'w') {
           u64 n_cols = 0;
           parse_int_arg(i, argc, argv, n_cols);
diff --git a/src/hover.cpp b/src/hover.cpp
index 3e7fdb1..8a4acf2 100644
--- a/src/hover.cpp
+++ b/src/hover.cpp
@@ -1060,9 +1060,11 @@ struct Sec_Hover_Fn {
     });
   }
 
-  void basket()
+  void other_root_obj()
   {
-    titled_section("TBasket", [this] {
+    Other_Root_Obj_Info *info = (Other_Root_Obj_Info *)section.info;
+    String8 name = info ? info->class_name : str8("(Unknown)");
+    titled_section(name.c(), [this] {
       tkey();
       range("Payload", section.range.len - section.post_size); 
     });
@@ -1104,7 +1106,7 @@ Sec_Hover_Info get_section_hover_info(Arena *arena, Section section, u64 off, co
   case Sec_TFile_Info:      hover.tfile_info();     break;
   case Sec_TFile_FreeList:  hover.tfile_freelist(); break;
   case Sec_TKey_List:       hover.tkey_list();      break;
-  case Sec_Basket:          hover.basket();         break;
+  case Sec_Other:           hover.other_root_obj(); break;
   default:
     info.desc = push_str8_node(arena, nullptr, "%s", sec_name.c());
   }
diff --git a/src/render.cpp b/src/render.cpp
index f5a56e9..f5568e7 100644
--- a/src/render.cpp
+++ b/src/render.cpp
@@ -115,8 +115,8 @@ u32 mem_edit_bg_color_fn(const u8 *data, u64 off, void *user_data)
     return imcol(app->viewer.col_highlight, brighten);
   if (section.id == Sec_Page && off == section.range.start) 
     return imcol(app->viewer.col_page_start, brighten);
-  if (section.id == Sec_Basket && off == section.range.start)
-    return imcol(app->viewer.col_basket_start, brighten);
+  if (section.id == Sec_Other && off == section.range.start)
+    return imcol(app->viewer.col_other_root_obj_start, brighten);
   if (off < section.range.start) 
     return imcol(app->viewer.col_key, brighten);
   if (section.range.end() - section.post_size <= off && off < section.range.end()) 
@@ -145,7 +145,7 @@ void init_viewer(App_State &app, u16 n_cols)
 #define COL(c, r, g, b) viewer.c[0] = r/255.0, viewer.c[1] = g/255.0, viewer.c[2] = b/255.0
   COL(col_key,    0, 100, 50);
   COL(col_page_start, 200, 0, 200);
-  COL(col_basket_start, 200, 200, 150);
+  COL(col_other_root_obj_start, 200, 200, 150);
   COL(col_checksum, 134, 65, 25);
   COL(col_highlight, 190, 190, 190);
 #define COL_S(c, r, g, b) viewer.col_section[c][0] = r/255.0, viewer.col_section[c][1] = g/255.0, viewer.col_section[c][2] = b/255.0
@@ -159,7 +159,7 @@ void init_viewer(App_State &app, u16 n_cols)
   COL_S(Sec_Page,   125, 0, 125);
   COL_S(Sec_Page_List, 60, 110, 120);
   COL_S(Sec_TKey_List, 100, 140, 100);
-  COL_S(Sec_Basket, 140, 140, 100);
+  COL_S(Sec_Other, 140, 140, 100);
 #undef COL
 #undef COL_S
 }
@@ -204,20 +204,20 @@ void viewer_jump_to_page_list(App_State &app, u64 page_list_idx)
 }
 
 internal
-void viewer_jump_to_basket(App_State &app, u64 basket_idx)
+void viewer_jump_to_other_root_obj(App_State &app, u64 obj_idx)
 {
-  u64 n_baskets = app.tfile_data.tkeys_data.n_baskets;
-  if (n_baskets == 0)
+  u64 n_other_root_objs = app.tfile_data.tkeys_data.n_other_root_obj;
+  if (n_other_root_objs == 0)
     return;
   
-  basket_idx = (basket_idx + n_baskets) % n_baskets;
+  obj_idx = (obj_idx + n_other_root_objs) % n_other_root_objs;
   
-  Basket_Info *binfo = app.tfile_data.tkeys_data.baskets;
-  for (u64 i = 0; i < basket_idx; ++i)
-    binfo = binfo->next;
+  Other_Root_Obj_Info *info = app.tfile_data.tkeys_data.other_root_obj;
+  for (u64 i = 0; i < obj_idx; ++i)
+    info = info->next;
 
-  app.viewer.latest_basket_gone_to = basket_idx;
-  viewer_jump_to(app, binfo->section.range.start);
+  app.viewer.latest_root_obj_gone_to = obj_idx;
+  viewer_jump_to(app, info->section.range.start);
 }
 
 internal
@@ -409,20 +409,20 @@ void update_and_render(Arena *arena, App_State &app, f32 delta_time_ms)
       ImGui::SameLine(); 
       ImGui::Text("%s", to_pretty_size(scratch.arena, app.rndata.tot_page_list_size).c());
 
-      if (app.tfile_data.tkeys_data.n_baskets > 0) {
-        ImGui::ColorEdit3("_TTree Basket", app.viewer.col_section[Sec_Basket], edit_flags);
+      if (app.tfile_data.tkeys_data.n_other_root_obj > 0) {
+        ImGui::ColorEdit3("_Other", app.viewer.col_section[Sec_Other], edit_flags);
         ImGui::SameLine(); 
-        if (ImGui::Button("TTree Basket"))
-          viewer_jump_to_basket(app, app.viewer.latest_basket_gone_to);
+        if (ImGui::Button("Other"))
+          viewer_jump_to_other_root_obj(app, app.viewer.latest_root_obj_gone_to);
 
         ImGui::SameLine(); 
         {
-          i64 basket_to_go_to = app.viewer.latest_basket_gone_to;
+          i64 other_root_obj_to_go_to = app.viewer.latest_root_obj_gone_to;
           ImGui::PushItemWidth(80.f);
-          if (ImGui::InputScalar("##basket_viewed", ImGuiDataType_S64, &basket_to_go_to, &step_i64, nullptr, "%u") 
+          if (ImGui::InputScalar("##other_root_objviewed", ImGuiDataType_S64, &other_root_obj_to_go_to, &step_i64, nullptr, "%u") 
               && ImGui::IsItemDeactivatedAfterEdit())
           {
-            viewer_jump_to_basket(app, basket_to_go_to);
+            viewer_jump_to_other_root_obj(app, other_root_obj_to_go_to);
           }
           ImGui::PopItemWidth();
         }
diff --git a/src/render.h b/src/render.h
index b7e400f..59e3916 100644
--- a/src/render.h
+++ b/src/render.h
@@ -5,7 +5,7 @@ struct Viewer {
   f32 col_checksum[3];
   f32 col_highlight[3];
   f32 col_page_start[3];
-  f32 col_basket_start[3];
+  f32 col_other_root_obj_start[3];
 
 #ifndef RNT_NO_GFX
   MemoryEditor mem_edit;
@@ -22,7 +22,7 @@ struct Viewer {
   u64 latest_key_gone_to;
   u64 latest_checksum_gone_to;
   u64 latest_page_list_gone_to;
-  u64 latest_basket_gone_to;
+  u64 latest_root_obj_gone_to;
 
   Byte_Range hovered_range;
 
diff --git a/src/rntuple.cpp b/src/rntuple.cpp
index 8fa260a..47787d7 100644
--- a/src/rntuple.cpp
+++ b/src/rntuple.cpp
@@ -539,9 +539,9 @@ Section find_section(App_State &app, u64 off, i64 hilite_cluster = -1)
   }
 
   // @Speed
-  for (Basket_Info *basket = tdata.baskets; basket; basket = basket->next) {
-    if (basket->section.range.start - basket->section.pre_size <= off && off < basket->section.range.end()) {
-      return basket->section;
+  for (Other_Root_Obj_Info *other = tdata.other_root_obj; other; other = other->next) {
+    if (other->section.range.start - other->section.pre_size <= off && off < other->section.range.end()) {
+      return other->section;
     }
   }
 
diff --git a/src/rntuple.h b/src/rntuple.h
index 50674b4..297e43e 100644
--- a/src/rntuple.h
+++ b/src/rntuple.h
@@ -68,7 +68,8 @@ enum Section_Id {
 
   Sec_First_Non_Unique,
   Sec_Page = Sec_First_Non_Unique, 
-  Sec_Basket,
+  // any other object stored in a TKey
+  Sec_Other,
 
   Sec_COUNT
 };
@@ -97,7 +98,7 @@ internal const String8 section_names[Sec_COUNT] = {
   str8("RNTuple Footer"),
   str8("Page List"),
   str8("Page"),
-  str8("Basket"),
+  str8("Other"),
 };
 
 struct Byte_Range_Node {
@@ -111,8 +112,9 @@ struct RNTuple_Anchor_Info {
   u64 offset_in_file;
 };
 
-struct Basket_Info {
-  Basket_Info *next;
+struct Other_Root_Obj_Info {
+  Other_Root_Obj_Info *next;
+  String8 class_name;
   Section section;
 };
 
@@ -122,8 +124,8 @@ struct TKeys_Data {
   RNTuple_Anchor_Info *rntuples;
   Byte_Range_Node *rblob_keys;
 
-  Basket_Info *baskets;
-  u64 n_baskets;
+  Other_Root_Obj_Info *other_root_obj;
+  u64 n_other_root_obj;
 };
 
 struct TFile_Data {
diff --git a/src/rntviewer.cpp b/src/rntviewer.cpp
index fb85a9e..45b87f3 100644
--- a/src/rntviewer.cpp
+++ b/src/rntviewer.cpp
@@ -82,7 +82,7 @@ using ROOT::Experimental::Internal::RNTupleSerializer;
 #endif
 
 #define V_MAJOR "0"
-#define V_MINOR "8"
+#define V_MINOR "9"
 
 // Internal sources
 // --------------------------------------------------
@@ -161,8 +161,8 @@ int main(int argc, char **argv)
   u32 walk_tkeys_flags = WTK_NONE;
   if (args.print_keys_info)
     walk_tkeys_flags |= WTK_PRINT_KEYS_INFO;
-  if (!args.disable_tbaskets)
-    walk_tkeys_flags |= WTK_COLLECT_BASKETS;
+  if (!args.dont_collect_other_root_objs)
+    walk_tkeys_flags |= WTK_COLLECT_OTHER_ROOT_OBJS;
   b8 success = get_tfile_data(arena, app.inspected_file, walk_tkeys_flags, app.ntpl_name, app.tfile_data);
   if (args.only_print_rntuple_names) {
     for (RNTuple_Anchor_Info *info = app.tfile_data.tkeys_data.rntuples; info; info = info->next)
diff --git a/src/tfile.cpp b/src/tfile.cpp
index 299fa0b..dff4fdf 100644
--- a/src/tfile.cpp
+++ b/src/tfile.cpp
@@ -58,7 +58,7 @@ T read_be(const void *data)
 enum {
   WTK_NONE = 0,
   WTK_PRINT_KEYS_INFO = 1,
-  WTK_COLLECT_BASKETS = 2,
+  WTK_COLLECT_OTHER_ROOT_OBJS = 2,
 };
 
 // Examines the innards of a TFile to get byte range info about the TKeys.
@@ -170,7 +170,7 @@ b8 walk_tkeys(Arena *arena, const u8 *data, u64 data_len, u32 flags, TFile_Data
   cur = pre + tfile_obj_nbytes;
 
   RNTuple_Anchor_Info *rntuple_info_tail = nullptr;
-  Basket_Info *baskets_tail = nullptr;
+  Other_Root_Obj_Info *other_root_obj_tail = nullptr;
 
   u32 n_keys = 0;
   // Walk through all the TKeys in the file and do two things:
@@ -271,19 +271,23 @@ b8 walk_tkeys(Arena *arena, const u8 *data, u64 data_len, u32 flags, TFile_Data
         rblob_key->next = tkeys_data.rblob_keys;
         tkeys_data.rblob_keys = rblob_key;
 
-      } else if ((flags & WTK_COLLECT_BASKETS) && key_has_class_name("TBasket")) {
-        Basket_Info *binfo = arena_push<Basket_Info>(arena);
-        binfo->section.id = Sec_Basket;
+      } else if ((flags & WTK_COLLECT_OTHER_ROOT_OBJS)) {
+        Other_Root_Obj_Info *binfo = arena_push<Other_Root_Obj_Info>(arena);
+        if (cname_len) {
+          binfo->class_name = str8_from_buf(arena, data + cname_off + 1, cname_len);
+        }
+        binfo->section.id = Sec_Other;
+        binfo->section.info = binfo;
         binfo->section.range.start = cur + keylen;
         binfo->section.range.len = n_bytes - keylen;
         binfo->section.pre_size = keylen;
-        if (tkeys_data.baskets) {
-          baskets_tail->next = binfo;
+        if (tkeys_data.other_root_obj) {
+          other_root_obj_tail->next = binfo;
         } else {
-          tkeys_data.baskets = binfo;
+          tkeys_data.other_root_obj = binfo;
         }
-        baskets_tail = binfo;
-        tkeys_data.n_baskets++;
+        other_root_obj_tail = binfo;
+        tkeys_data.n_other_root_obj++;
       }
     }
     cur += n_bytes;