From 9bf2b1e0c563bf8f096bf34a773ab87dd93b5d8e Mon Sep 17 00:00:00 2001 From: silverweed <silverweed14@proton.me> Date: Fri, 24 Jan 2025 12:05:32 +0100 Subject: [PATCH] improve title --- src/render.cpp | 30 +++++++++++++++++------ src/str.cpp | 11 +++++++++ src/tfile.cpp | 58 ++++++++++++++++++++++++-------------------- testdata/multi.root | Bin 0 -> 2382 bytes 4 files changed, 65 insertions(+), 34 deletions(-) create mode 100644 testdata/multi.root diff --git a/src/render.cpp b/src/render.cpp index 50aae8f..05ed1fb 100644 --- a/src/render.cpp +++ b/src/render.cpp @@ -143,19 +143,33 @@ void init_viewer(Arena *arena, App_State &app, u16 n_cols) viewer.mem_edit = make_memory_editor(app, (i32)n_cols); // Init title - if (app.tfile_data.sections[Sec_RNTuple_Anchor].head) { + u32 n_ntuples = app.tfile_data.sections[Sec_RNTuple_Anchor].count; + if (n_ntuples) { Temp scratch = scratch_begin(&arena, 1); defer { scratch_end(scratch); }; - const RNTuple_Anchor_Info *anchor = (const RNTuple_Anchor_Info *)app.tfile_data.sections[Sec_RNTuple_Anchor].head->info; - String8 ntpl_desc = rntuple_description(scratch.arena, anchor->anchor); - if (rntuple_is_old_version(anchor->anchor)) { - viewer.col_title[0] = 1.f; - viewer.title = push_str8f(arena, "\"%s\" (%s) from file \"%s\" ** old version, some data missing! **", - anchor->name.c(), ntpl_desc.c(), app.inspected_file.name.c()); + if (n_ntuples == 1) { + Section *sec = app.tfile_data.sections[Sec_RNTuple_Anchor].head; + const RNTuple_Anchor_Info *anchor = (const RNTuple_Anchor_Info *)sec->info; + String8 ntpl_desc = rntuple_description(scratch.arena, anchor->anchor); + if (rntuple_is_old_version(anchor->anchor)) { + viewer.col_title[0] = 1.f; + viewer.title = push_str8f(arena, "\"%s\" (%s) from file \"%s\" ** old version, some data missing! **", + anchor->name.c(), ntpl_desc.c(), app.inspected_file.name.c()); + } else { + viewer.col_title[0] = viewer.col_title[1] = viewer.col_title[2] = 1.f; + viewer.title = push_str8f(arena, "\"%s\" (%s) from file \"%s\"", anchor->name.c(), ntpl_desc.c(), app.inspected_file.name.c()); + } } else { + String8 title = str8("RNTuples"); + for (Section *sec = app.tfile_data.sections[Sec_RNTuple_Anchor].head; sec; sec = sec->next) { + const RNTuple_Anchor_Info *anchor = (const RNTuple_Anchor_Info *)sec->info; + title = str8_concat(scratch.arena, title, push_str8f(scratch.arena, " \"%s\",", anchor->name)); + } + title.size -= 1; // strip trailing comma + title = str8_concat(scratch.arena, title, push_str8f(scratch.arena, " from file \"%s\"", app.inspected_file.name.c())); viewer.col_title[0] = viewer.col_title[1] = viewer.col_title[2] = 1.f; - viewer.title = push_str8f(arena, "\"%s\" (%s) from file \"%s\"", anchor->name.c(), ntpl_desc.c(), app.inspected_file.name.c()); + viewer.title = str8_from_buf(arena, title.str, title.size); } } else { viewer.col_title[0] = viewer.col_title[1] = viewer.col_title[2] = 1.f; diff --git a/src/str.cpp b/src/str.cpp index 8898c7b..7872403 100644 --- a/src/str.cpp +++ b/src/str.cpp @@ -40,6 +40,17 @@ String8 str8_from_buf(Arena *arena, const u8 *buf, u64 size) return s; } +String8 str8_concat(Arena *arena, String8 a, String8 b) +{ + String8 res; + res.size = a.size + b.size; + res.str = arena_push_array_nozero<u8>(arena, res.size + 1); + memcpy(res.str, a.str, a.size); + memcpy(res.str + a.size, b.str, b.size); + res.str[res.size] = 0; + return res; +} + internal String8 to_pretty_size(Arena *arena, u64 bytes) { diff --git a/src/tfile.cpp b/src/tfile.cpp index 9a14a4e..84ecd1b 100644 --- a/src/tfile.cpp +++ b/src/tfile.cpp @@ -79,8 +79,9 @@ enum { // Examines the innards of a TFile to get byte range info about the TKeys. // Additionally, it returns the names of all the RNTuples stored in it. // `data` should point to the beginning of a ROOT file. +// If `ntpl_name` is non-empty, skip all RNTuples that are not the one specified. internal -b8 walk_tkeys(Arena *arena, const u8 *data, u64 data_len, u32 flags, TFile_Data &tfile_data) +b8 walk_tkeys(Arena *arena, const u8 *data, u64 data_len, u32 flags, TFile_Data &tfile_data, String8 ntpl_name) { u64 cur = 4; // offset of header version if (data_len < cur) { @@ -270,30 +271,34 @@ b8 walk_tkeys(Arena *arena, const u8 *data, u64 data_len, u32 flags, TFile_Data if (key_has_class_name("ROOT::RNTuple") || key_has_class_name("ROOT::Experimental::RNTuple")) { u64 name_off = cname_off + cname_len + 1; u8 name_len = data[name_off]; - RNTuple_Anchor_Info *rntuple_info = arena_push<RNTuple_Anchor_Info>(arena); - rntuple_info->offset_in_file = cur; - if (name_len) { - rntuple_info->name = str8_from_buf(arena, data + name_off + 1, name_len); + const char *rntuple_name = (const char *)data + name_off + 1; + if (!ntpl_name.size || strncmp((const char *)ntpl_name.str, rntuple_name, name_len) == 0) { + RNTuple_Anchor_Info *rntuple_info = arena_push<RNTuple_Anchor_Info>(arena); + rntuple_info->offset_in_file = cur; + if (name_len) { + rntuple_info->name = str8_from_buf(arena, data + name_off + 1, name_len); + } + + u64 anchor_seek = cur + keylen; + RNTuple_Anchor_On_Disk anchor; + memcpy(&anchor, data + anchor_seek, sizeof(anchor)); + + rntuple_info->anchor = ROOT::Experimental::Internal::CreateAnchor( + bswap(anchor.epoch_be), bswap(anchor.major_be), bswap(anchor.minor_be), bswap(anchor.patch_be), + bswap(anchor.seek_header_be), bswap(anchor.nbytes_header_be), bswap(anchor.len_header_be), + bswap(anchor.seek_footer_be), bswap(anchor.nbytes_footer_be), bswap(anchor.len_footer_be), + bswap(anchor.max_key_size_be)); + + Section *sec_anchor = push_section(arena, tfile_data, Sec_RNTuple_Anchor); + sec_anchor->info = rntuple_info; + sec_anchor->id = Sec_RNTuple_Anchor; + sec_anchor->range.start = anchor_seek; + sec_anchor->range.len = n_bytes - keylen; + sec_anchor->pre_size = keylen; + sec_anchor->post_size = 8; + } else { + fprintf(stderr, "Note: skipped RNTuple '%s' because it doesn't match the name '%s' we're looking for.\n", rntuple_name, ntpl_name.c()); } - - u64 anchor_seek = cur + keylen; - RNTuple_Anchor_On_Disk anchor; - memcpy(&anchor, data + anchor_seek, sizeof(anchor)); - - rntuple_info->anchor = ROOT::Experimental::Internal::CreateAnchor( - bswap(anchor.epoch_be), bswap(anchor.major_be), bswap(anchor.minor_be), bswap(anchor.patch_be), - bswap(anchor.seek_header_be), bswap(anchor.nbytes_header_be), bswap(anchor.len_header_be), - bswap(anchor.seek_footer_be), bswap(anchor.nbytes_footer_be), bswap(anchor.len_footer_be), - bswap(anchor.max_key_size_be)); - - Section *sec_anchor = push_section(arena, tfile_data, Sec_RNTuple_Anchor); - sec_anchor->info = rntuple_info; - sec_anchor->id = Sec_RNTuple_Anchor; - sec_anchor->range.start = anchor_seek; - sec_anchor->range.len = n_bytes - keylen; - sec_anchor->pre_size = keylen; - sec_anchor->post_size = 8; - } else if (key_has_class_name("RBlob")) { if (!sections[Sec_Page].head) { push_section(arena, tfile_data, Sec_Page)->pre_size = keylen; @@ -365,6 +370,7 @@ b8 walk_tkeys(Arena *arena, const u8 *data, u64 data_len, u32 flags, TFile_Data return true; } +// Creates the RNTuple_Header and Footer sections by associating them to their proper RBlobs and Anchor. internal void map_rntuple_rblobs(Arena *arena, TFile_Data &tfile_data) { @@ -425,9 +431,9 @@ void map_rntuple_rblobs(Arena *arena, TFile_Data &tfile_data) } internal -b8 get_tfile_data(Arena *arena, const Inspected_File &file, u32 walk_tkeys_flags, String8 &ntpl_name, TFile_Data &tfile_data) +b8 get_tfile_data(Arena *arena, const Inspected_File &file, u32 walk_tkeys_flags, String8 ntpl_name, TFile_Data &tfile_data) { - b8 success = walk_tkeys(arena, file.mem, file.size, walk_tkeys_flags, tfile_data); + b8 success = walk_tkeys(arena, file.mem, file.size, walk_tkeys_flags, tfile_data, ntpl_name); if (success) { // TODO: if ntpl_name is non-empty, only pick the given RNTuple map_rntuple_rblobs(arena, tfile_data); diff --git a/testdata/multi.root b/testdata/multi.root new file mode 100644 index 0000000000000000000000000000000000000000..d1e51377d57255c56c6c92e2e0e9f04db9b6b8fa GIT binary patch literal 2382 zcmb7G3s6%>6uo&#AcT+nL5Vaf$XEU#Ukwo@@)H3SD6J@ohz62@fY`<w6e&`$Q6ngV zqEbbv4x_fE7BGAiwX{06DptqR4k%PnaI`|zNp~NKBamtJ&TMw~y}f(R?!EWCWQ#-+ zfDuCg-~;Hz08s1DI07{)Y8)B>WfXvBg!(-|Nm+REz;B@@Pb!o7UUkZrCuqq#nUwkn zt>fj3n|;6sC~6;sIA-*OMHxZ?Gc#8x$#BcYl-?c#9s7~K06UNe2Q{@XL;1g?z9g}0 zNq^@z*ga?uY<zkgS14KykQ`4*0jLFV{Kow?ySADDJ1PauG1*XjKXFTzB(U@R+`N6= zJUlO|++Yn|C|V`yF}DWxvn_+Bp2GE&)`sjF!uwOJR`yE4rCaHVMP5cydVxjcf?~6^ zLyi0CXqzTXhaw+Ohay66u)R&E06<P5>7>e`nF_T!05agnYLq=-%=X~Krix|7^1U^6 z4UNi6*SdT9hem+LFfcZ^X0h!YT|IpKgE?WmsMv(WlvMs&p;(eHm2D|3DlRGAA>XAa z-&<LApyqJx(Yg~~pK3UL_S?pDO)bi{j*Bp#6UwC-gDfH>-aqVw;ZM<3``YKWmm_vE z@+zg{xf3oV^YPrH0i^1yl-d)}OHk2Vb4hnq_)@Kbuk7lsQmIrWXts|siXMg}bvLcL znZ{&5xSa84b68%2!r}#y1T*!GvCCK*DJJ08Yr$U(pitv0=mhWy0?jq}{?Ak$csmc^ zOP8a58F8#t@@!s7#a~QtKf<}U#Kz_Jh0Da_O-_{0hr1q$Wel{afINE)iS4aPBdUW2 z+YqNmU|?KKLataSpoHQi<pQBuIJS(!R4*5(dz5b2h#O-)#HoA4eJsr#xx|XngS^>j z8UZx)Yl{f@fh*pZtW^Hw+9BUPMMZ0fNAx48-N7Thm<_%PK=<8?cSrG>#2FVkJ|^ux zc}yPm!iLMAG=vtFks~pPmt+f8WeTzvXRQ&LhKX`l3pcWb8CmNEeAMMglA{=56u3`= zd`k1K)|fVqana^=(FuiTE`AYy)iz+6Y1yJfJeyKmAN{C9#Xs;r-15BRhSgK2rV*xX z@TgJX9NLVX#eO3WL7D044<c1b`uAOy?`&0gS#~{`QvR^8vSa#y*?^PyZ@q_>4efnL zsH~i2ck=YNt-C$=;#^_#cds{O3B<!`*V|5QFgk0wR4SG2Ns23v+(>;rHF+uRv-Yx2 z%tary_Vl;)j?i_sHcuN+u6WvTY+7ba>h21Y^Ih>R?$q=4$G^8ZyT@ow%{<!2BctA5 z*#$;)mQ_R!_sx%Wp84ub+T65Gx70-CMz4y&%iBQyoOSq4nrU>zt1CHKWw%oLX2%aW z-#!hVEW<uioy`Him$jsna+%jTr#j`y#Bn?M$pKaO(9gW1GhF+B-5K}C_38*}QrB^x zLVA_+_LuP`ELDN>pT6oghfTYi6Hvf9$=qX-L2=gv1qXI4DC5-<$NVmiG_rl9V?F8k zM*HY@$Na{L%^CnyN2K=E52Aua+E-5^aVKftd6h4u8=yUMB>cd@j4X+_*GdWWn42LT zB#u>v-0KTzHvo4=(G@F2fpmMSSpM=C!vDfyZt;GlX|NF=C)G_%Y@!P4<Z2<d|7{g4 zqd@`#F3A(w{SEmX#<jhvjzf(yo^f~0T8|NBajbPuo!B33Oi-ybx{j_cLyyVSH!w6Z znqq8XVrph?VPR=yJ$33d8y0K2?FVf3jG41$+1bx_aBy^Tc6M={<L2h>;pye&?c?j~ zH`hNPATTI6IAq>@4pPJg3&IvI3J>Qkj);tmibj=fZxX(+gLA{|s*3?@d9Y{&;;vO6 zbtAQ$N~=C<E^nefVwE_kgY_|HR!)%6EJg2q^ilUmE%;jXQG-8GA9Ho(y<4lRMR||@ zLmxMi@-(K8E;w@-;Rtu4#&EUjq7M49k*4_!swG|bx%&AeT})b;x&3j_FoE9hAc0qt cIZo;#`cHsAMw9+ipr?5K`wBU7dDpZ33wx)MA^-pY literal 0 HcmV?d00001