From 67d2af596b6974f16fcfa5f2a0a1b3ba3babc503 Mon Sep 17 00:00:00 2001
From: silverweed <silverweed14@proton.me>
Date: Tue, 5 Nov 2024 09:52:00 +0100
Subject: [PATCH] allow reading RC3

---
 src/hover.cpp        |  44 ++++++++++++++++++++++++++++++-------------
 src/render.cpp       |  11 ++++++++---
 src/rntuple.cpp      |  12 ++++++++++--
 test_old.root        | Bin 1387 -> 0 bytes
 test_uncomp_old.root | Bin 2537 -> 0 bytes
 5 files changed, 49 insertions(+), 18 deletions(-)
 delete mode 100644 test_old.root
 delete mode 100644 test_uncomp_old.root

diff --git a/src/hover.cpp b/src/hover.cpp
index f1fcd4e..fc6bc71 100644
--- a/src/hover.cpp
+++ b/src/hover.cpp
@@ -135,6 +135,7 @@ struct Sec_Hover_Fn {
   u64 &cur_field_off; // current field offset relative to the start of `data`
   // settings
   b8 display_grouped;
+  b8 old_version; // if true, treat the RNTuple as 0.x rather than 1.x
   // internals
   u8 cur_section_nesting = 0;
   u8 innermost_section_highlighted = 0;
@@ -440,17 +441,28 @@ struct Sec_Hover_Fn {
       if (!field<u16>("Flags: 0b%b", hover_display_val_le, &flags))
         return;
 
-      if (flags & RNTupleSerializer::kFlagRepetitiveField)
-        field_le<u64>("N Repetitions: %" PRIu64);
-      if (flags & RNTupleSerializer::kFlagProjectedField)
-        field_le<u32>("On disk proj.src id: %u");
-      if (flags & RNTupleSerializer::kFlagHasTypeChecksum)
-        field_le<u32>("Checksum: %u");
+      if (old_version) {
+        if (flags & RNTupleSerializer::kFlagRepetitiveField)
+          field_le<u64>("N Repetitions: %" PRIu64);
+        if (flags & RNTupleSerializer::kFlagProjectedField)
+          field_le<u32>("On disk proj.src id: %u");
+        if (flags & RNTupleSerializer::kFlagHasTypeChecksum)
+          field_le<u32>("Checksum: %u");
+      }
 
       field_str8<u32>("Name: %s");
       field_str8<u32>("Type Name: %s");
       field_str8<u32>("Type Alias: %s");
       field_str8<u32>("Description: %s");
+
+      if (!old_version) {
+        if (flags & RNTupleSerializer::kFlagRepetitiveField)
+          field_le<u64>("N Repetitions: %" PRIu64);
+        if (flags & RNTupleSerializer::kFlagProjectedField)
+          field_le<u32>("On disk proj.src id: %u");
+        if (flags & RNTupleSerializer::kFlagHasTypeChecksum)
+          field_le<u32>("Checksum: %u");
+      }
     });
   }
 
@@ -495,8 +507,12 @@ struct Sec_Hover_Fn {
       frame<Frame_List>("Extra Type Infos", [this] (u32 idx) {
         frame<Frame_Record>(push_str8f(arena, "Extra Type Info %u", idx).c(), [this] {
           field_le<u32>("Content identifier: %lu");
-          field_le<u32>("Type version from: %lu");
-          field_le<u32>("Type version to: %lu");
+          if (old_version) {
+            field_le<u32>("Type version from: %lu");
+            field_le<u32>("Type version to: %lu");
+          } else {
+            field_le<u32>("Type version: %lu");
+          }
         });
       });     
     });
@@ -889,9 +905,11 @@ struct Sec_Hover_Fn {
           frame<Frame_Record>("Schema Extension", [this] {
             schema_description("Schema Extension");
           });
-          frame<Frame_List>("Column Groups", [this] (u32) {
-            field_le<u32>("Column Id: %u");                  
-          });
+          if (old_version) {
+            frame<Frame_List>("Column Groups", [this] (u32) {
+              field_le<u32>("Column Id: %u");                  
+            });
+          }
           frame<Frame_List>("Cluster Groups", [this] (u32) {
             cluster_group();
           });
@@ -941,7 +959,7 @@ struct Sec_Hover_Fn {
 
 // `off` is the absolute offset into `data`.
 internal
-Sec_Hover_Info get_section_hover_info(Arena *arena, Section section, u64 off, const u8 *data, b8 display_grouped)
+Sec_Hover_Info get_section_hover_info(Arena *arena, Section section, u64 off, const u8 *data, b8 display_grouped, b8 old_version)
 {
   Sec_Hover_Info info {};
 
@@ -961,7 +979,7 @@ Sec_Hover_Info get_section_hover_info(Arena *arena, Section section, u64 off, co
   }
 
   u64 cur_field_off = section.range.start - section.pre_size;
-  Sec_Hover_Fn hover { off, data, section, arena, info, cur_field_off, display_grouped };
+  Sec_Hover_Fn hover { off, data, section, arena, info, cur_field_off, display_grouped, old_version };
   
   switch (section.id) {
   case Sec_RNTuple_Anchor: 
diff --git a/src/render.cpp b/src/render.cpp
index f3fe825..57de613 100644
--- a/src/render.cpp
+++ b/src/render.cpp
@@ -251,7 +251,11 @@ void update_and_render(Arena *arena, App_State &app, f32 delta_time_ms)
   if (ImGui::Begin("main", nullptr, main_win_flags)) {
         
     String8 ntpl_desc = rntuple_description(scratch.arena, app.tfile_data.rntuple_anchor);
-    ImGui::Text("RNTuple '%s' (%s) from file \"%s\"", app.ntpl_name.c(), ntpl_desc.c(), app.inspected_file.name.c());
+    if (rntuple_is_old_version(app.tfile_data.rntuple_anchor))
+      ImGui::TextColored(ImColor(1.f, 0.f, 0.f), "RNTuple '%s' (%s) from file \"%s\" ** old version, some data missing! **", 
+                         app.ntpl_name.c(), ntpl_desc.c(), app.inspected_file.name.c());
+    else
+      ImGui::Text("RNTuple '%s' (%s) from file \"%s\"", app.ntpl_name.c(), ntpl_desc.c(), app.inspected_file.name.c());
 
     // Draw stats
     {
@@ -398,12 +402,13 @@ void update_and_render(Arena *arena, App_State &app, f32 delta_time_ms)
 
       if (hovered_off)
       {
+        const ROOT::RNTuple &anchor = app.tfile_data.rntuple_anchor;
         ImGui::TextColored(ImColor(0.f, 0.65f, 0.f), "Offset: 0x%" PRIX64, hovered_off - 1);
         Section hovered_section = find_section(app, hovered_off - 1);
         b8 hover_display_grouped = !(app.user_input.key_state[KEY_ALT] & KEY_STATE_IS_DOWN);
+        b8 old_version = rntuple_is_old_version(anchor);
         Sec_Hover_Info hover_info = get_section_hover_info(scratch.arena, hovered_section, hovered_off - 1, 
-                                                           app.inspected_file.mem, hover_display_grouped);
-        const ROOT::RNTuple &anchor = app.tfile_data.rntuple_anchor;
+                                                           app.inspected_file.mem, hover_display_grouped, old_version);
         b8 header_is_compressed = anchor.GetNBytesHeader() != anchor.GetLenHeader();
         if (!header_is_compressed)
           ImGui::TextColored(ImColor(0.5f, 0.5f, 0.5f), "(Hint: press Alt for single-field hover information)");
diff --git a/src/rntuple.cpp b/src/rntuple.cpp
index dae56cf..0d3de8d 100644
--- a/src/rntuple.cpp
+++ b/src/rntuple.cpp
@@ -1,3 +1,9 @@
+internal
+b8 rntuple_is_old_version(const ROOT::RNTuple &ntuple)
+{
+  return ntuple.GetVersionEpoch() == 0 && ntuple.GetVersionMajor() < 3;
+}
+  
 internal
 String8 rntuple_description(Arena *arena, const ROOT::RNTuple &ntuple)
 {
@@ -23,6 +29,8 @@ ROOT::Experimental::RNTupleDescriptor create_descriptor(Arena *arena, const TFil
   defer { scratch_end(scratch); };
 
   const ROOT::RNTuple &anchor = tfile_data.rntuple_anchor;
+  if (rntuple_is_old_version(anchor))
+    fprintf(stderr, "Warning: the RNTuple being read is an old version. We'll probably fail to read some metadata.\n");
   
   // Read compressed header+footer
   u8 *header_zip = arena_push_array_nozero<u8>(scratch.arena, anchor.GetNBytesHeader());
@@ -39,8 +47,8 @@ ROOT::Experimental::RNTupleDescriptor create_descriptor(Arena *arena, const TFil
   // Deserialize header+footer
   RNTupleDescriptorBuilder desc_builder;
   try {
-    RNTupleSerializer::DeserializeHeader(header, anchor.GetLenHeader(), desc_builder);
-    RNTupleSerializer::DeserializeFooter(footer, anchor.GetLenFooter(), desc_builder);
+    RNTupleSerializer::DeserializeHeader(header, anchor.GetLenHeader(), desc_builder).ThrowOnError();
+    RNTupleSerializer::DeserializeFooter(footer, anchor.GetLenFooter(), desc_builder).ThrowOnError();
   } catch (...) {
     fprintf(stderr, "Failed to deserialize header/footer!\n");
   }
diff --git a/test_old.root b/test_old.root
deleted file mode 100644
index bbdcc889707ce6243d95a0b590f3c0da131810a2..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 1387
zcmXTQ&o5zM`0mQUz>vbgz?u!jCP2115HkX?6$_C5$-uz87D%@<F!H|s-Bxo|@cqmz
z$=$sT``!bU5CzH@fCe#mmX-YoWY7hh473esSBP6?PAYd!ZfZq|kzNtVEhroYR*(*`
zE(V55pav@-2I~Ym$%LSDrZK+(s$U7#uLZUh$Yr<%B7oo)Ymie;ei8#iR4`*QP#FV*
z##a5m3M;QNF+5>r1oA;n&MPU%;RVt`{{A5fWoCND#(D;ZNB)Dt#(;qtNT%hKu;wS0
zJP;9NQ2262%Vbqh>jyJ#27QjUQ{qz?f9^BNQMa6`&BXfn*glqt%#lDHW?)ybpt_2&
z04M_lj0G@P0iENtm~YZzNw2(iphO*5R}Gr3WnfJVjLTrUfPV32V5oumrACyAVF?p6
zkPma&9kA0S7#I(nxdHOuEXJQezf755lkQrb-Neb@J|QZR;n7}~vXCjF-<cvAl(+>z
zeysxAz5vyBCKZV7Oe#pWyE8B>fZD#`D<eY)6BCdRv)$s$|09r~W2^}QYQ7-yP*d7+
z<<?i63^tqhrEE*$n4|L`F3#^jqK&b&i~<u-$uw{@_<?Qq0L3BGJfLWbG$=x>tXwM!
zQj0QkQ}ap^bF8d_{6b0#a#C49k;apsl$DxXqEM1ql9TGdz~IEd2Gj>K5egVV-Uopk
z2n9+2Ai(4Yp&0_8^a2p=0K{Q;nfy-*-o6H8R)SsS19lZSJp)rC&{bH{Gf)`hW2$%q
zoCkr<X88iP*a2iRC})B!_Q@<R;R!A&N=?j7E%MAu%NKIVFHOp+RLIH9%T7%JQpF{}
z#9_zC@P!4O&=bBeFXd$T<Y#7@(0xh5AVq>Hdxb{VB8{ZktQF_q)t=1ju8UqAvHL<y
zu4?X9@s4|$+$=`tHcfkY)%D7Q?JBJLZhLl=S~&X5Ep~k8?3S?MWk61}rT4Q*4gZ~r
zCaE#mr#co$>XfbbDPj-|41DP3X5}t$`J?2#`l)^w+ZduGyJnjNw*6sUbpDE7(Xrk<
z_1S->)?dA0e?oY5;SKe?3rWA!J8KR)dWpKpopt-lT@mzHHB(LJ@J1b>HAUVN*Ol#x
z5L<S!Kudn1-w$&G_pjAyn;P>t_121CD~){~_;<xh#(yj77}XUXFin(vTcG6W;n`#_
zV8UtPvt+5z5|x){OcdYsu<~*m1qQ|xr*VbVoxMKC)w-!xE#|XKLf3xJ>Hn5*3=~`A
z>iA3c^`EaCY~}H6CXcUl%-i+B?RokhWnh4tgX5nI5&z&)6Knhf<A^o8+;j>90C>!a
A{r~^~

diff --git a/test_uncomp_old.root b/test_uncomp_old.root
deleted file mode 100644
index 735d3d4d00bb5f102ed0c02f916027a449285e2a..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 2537
zcmcguO=uHQ5T0z3(togcXz3*)YV}ZBszq|BYcM5h`ePd^_F&m0FYUIQ-LTm-O<N(N
zP&{~%Vy}gQQalKHEcgRGi8l|5dhnvOV5x;dp$K*6?Iv!dzs5T7=FOY;X1<wuvoFy#
z%>dZ&13(m@Y#GNBl-qDPa0Fb)kX&g1_gQdk{@m0jT8^wfou6B{pM9}v?(WU+0y*j)
z)jzEOx<MJy&}FDyR#=S^XJbb5KuV2h@kFCeA#JAvH`#L^09iB-;NX4$oEv)v_s;np
z&(CxFGdu=d!V)p0C3lZc(ZZDWys5D`1+E$ig_cz~db+wop3&CEmX^k*=EW_OD5EAi
zu?;y<7gG#3pEL=}ZPFK;?NLit3LZ-WShw~`VVAvA`gnOHcoNmEJSA6QN{$87g<~O?
z5<r7*uKK}T-4%5T_a1Sp$v>>tEUUGgl@lhpDu?&k7H_S2IL|46qF1&vZ*B4in@l1V
z^=r<ETbk_IR;=N|o#_y+-tZ`A3!@Zf%yYs_E=mDrO_jxS(Vn-~_R1Yp-tBgC!P9Kk
z$(-v26ZlmB@t4m-CvM^DA#eUpo=Jcj&nclcT2Gzi_4>yWOqb(KH6+FB?dc4q5(;xs
z$5m?KVHPnwhHNNI1n@x#+FAZl0!IyTq+G{Zv+&wf=Swq7YY|6j`q;OL75`%tvplLG
zkBWbi_z7WDJAab6OUeF|Z1`(}P2gJR_#%0xH-_+oa?+^mHFPG$nSNP~X*HL$R9MM)
z6j>c%QJj*72(BOC=JBABNe)zgq~;3QjWKQ4B9w^$r|~!?z|+{R_;6dr;{YXSdXGEo
z3J+h@btyy6(%>w_t)R0aK&k-SCne=bD3f5c)ei#l5V(-n=fePeP-1;dPs*C=PiT=L
zR6r#TfrOo?I;AG%K@|&;9MW{G1cb8y?{VH6r9&FlbaH&SD6;w=P`V}KuPZiSRqQ$l
zBEU6%FLm~NsfhJ5HWFY`l<|611AaR=cBHEOttgs0C;~`X^HOerfUDl^uD;WkF<7z~
zkee1r9|!5?Ahq^9%40#M7K5<QO10x}_Mum*7?Ax{su+ZQRH{Q7yUH@X@;C#e1NIb|
awDC8){P&y9|E%ryX5)ibwwyjU4Zi>{#19t$