From b758f63ed3679d08e800a5ad54b885b988c4e3e5 Mon Sep 17 00:00:00 2001 From: silverweed Date: Mon, 29 Jul 2024 23:01:11 +0200 Subject: [PATCH] add hover info for tfile object --- src/rntuple.cpp | 219 +++++++++++++++++++++++++--------- src/root/RMicroFileReader.cxx | 10 +- 2 files changed, 172 insertions(+), 57 deletions(-) diff --git a/src/rntuple.cpp b/src/rntuple.cpp index 0715235..ce7fdaf 100644 --- a/src/rntuple.cpp +++ b/src/rntuple.cpp @@ -457,6 +457,13 @@ String8_Node *hover_display_val(Arena *arena, String8_Node *prev, const char *fm return push_str8_node(arena, prev, fmt, val); } +template <> +String8_Node *hover_display_val(Arena *arena, String8_Node *prev, const char *fmt, String8 val) +{ + hover_postproc_val(val); + return push_str8_node(arena, prev, fmt, val.c()); +} + internal String8_Node *hover_display_datetime_str(Arena *arena, String8_Node *prev, const char *fmt_pre, u32 datetime) { @@ -464,7 +471,7 @@ String8_Node *hover_display_datetime_str(Arena *arena, String8_Node *prev, const // datetime: // year (6b) | month (4b) | day (5b) | hour (5b) | min (6b) | sec (6b) - u32 year = (datetime >> 26) - 1900 + 1995; + u32 year = (datetime >> 26) + 1995; u32 month = ((datetime & 0x3ff'ffff) >> 22) - 1; u32 day = (datetime & 0x3f'ffff) >> 17; u32 hour = (datetime & 0x1'ffff) >> 12; @@ -482,9 +489,9 @@ struct Try_Sec_Hover_Fn { u64 &cur_field_off; template - bool operator()(const char *desc_fmt, - String8_Node *(*display_val)(Arena *, String8_Node *, const char *, TField_Type) = hover_display_val - ) const + bool field(const char *desc_fmt, + String8_Node *(*display_val)(Arena *, String8_Node *, const char *, TField_Type) = hover_display_val + ) const { u64 field_len = sizeof(TField_Type); if (roff < cur_field_off + field_len) { @@ -497,8 +504,77 @@ struct Try_Sec_Hover_Fn { cur_field_off += field_len; return false; } + + template <> + bool field(const char *desc_fmt, + String8_Node *(*display_val)(Arena *, String8_Node *, const char *, String8) + ) const + { + u8 str_size = data[start + cur_field_off]; + if (roff < cur_field_off + 1 + str_size) { + info.rng = { start + cur_field_off, 1 + (u64)str_size }; + u8 *buf = arena_push_array_nozero(arena, str_size + 1); + memcpy(buf, data + start + cur_field_off + 1, str_size); + buf[str_size] = 0; + String8 s = { buf, str_size }; + display_val(arena, info.desc, desc_fmt, s); + return true; + } + cur_field_off += 1 + str_size; + return false; + } + + bool range(const char *desc, u64 range_len) const + { + if (roff < cur_field_off + range_len) { + info.rng = { start + cur_field_off, range_len }; + push_str8_node(arena, info.desc, "%s", desc); + return true; + } + cur_field_off += range_len; + return false; + } }; +internal +bool hover_try_key(const Try_Sec_Hover_Fn &try_sec_hover, const u8 *data, u64 start) +{ + u16 version_be; + memcpy(&version_be, data + start + 4, sizeof(u16)); + u32 version = bswap_16(version_be); + b8 is_big = version > 1000; + + if (is_big) { + return try_sec_hover.field("NBytes: %u") + || try_sec_hover.field("Version: %u", [] (Arena *arena, String8_Node *prev, const char *fmt, u16 x) { + x = bswap_16(x); + x -= (x > 1000) * 1000; + return push_str8_node(arena, prev, fmt, x); + }) + || try_sec_hover.field("Obj Len: %u") + || try_sec_hover.field("Datetime: ", hover_display_datetime_str) + || try_sec_hover.field("Key Len: %u") + || try_sec_hover.field("Cycle: %u") + || try_sec_hover.field("Seek Key: 0x%lX") + || try_sec_hover.field("Seek Pdir: 0x%lX") + ; + } else { + return try_sec_hover.field("NBytes: %u") + || try_sec_hover.field("Version: %u", [] (Arena *arena, String8_Node *prev, const char *fmt, u16 x) { + x = bswap_16(x); + x -= (x > 1000) * 1000; + return push_str8_node(arena, prev, fmt, x); + }) + || try_sec_hover.field("Obj Len: %u") + || try_sec_hover.field("Datetime: ", hover_display_datetime_str) + || try_sec_hover.field("Key Len: %u") + || try_sec_hover.field("Cycle: %u") + || try_sec_hover.field("Seek Key: 0x%lX") + || try_sec_hover.field("Seek Pdir: 0x%lX") + ; + } +} + // `off` is the absolute offset into `data`. internal Sec_Hover_Info get_section_hover_info(Arena *arena, Section section, u64 off, const u8 *data) @@ -520,23 +596,23 @@ Sec_Hover_Info get_section_hover_info(Arena *arena, Section section, u64 off, co switch (section.id) { case Sec_RNTuple_Anchor: { - try_sec_hover.operator()("Object len: %u", [] (Arena *arena, String8_Node *prev, const char *fmt, u32 x) { + try_sec_hover.field("Object len: %u", [] (Arena *arena, String8_Node *prev, const char *fmt, u32 x) { x = bswap_32(x); x -= 0x4000'0000; return push_str8_node(arena, prev, fmt, x); }) - || try_sec_hover.operator()("Class version: %u") - || try_sec_hover.operator()("Version Epoch: %u") - || try_sec_hover.operator()("Version Major: %u") - || try_sec_hover.operator()("Version Minor: %u") - || try_sec_hover.operator()("Version Patch: %u") - || try_sec_hover.operator()("Seek Header: %u") - || try_sec_hover.operator()("NBytes Header: %u") - || try_sec_hover.operator()("Len Header: %u") - || try_sec_hover.operator()("Seek Footer: %u") - || try_sec_hover.operator()("NBytes Footer: %u") - || try_sec_hover.operator()("Len Footer: %u") - || try_sec_hover.operator()("Max Key Size: %u") + || try_sec_hover.field("Class version: %u") + || try_sec_hover.field("Version Epoch: %u") + || try_sec_hover.field("Version Major: %u") + || try_sec_hover.field("Version Minor: %u") + || try_sec_hover.field("Version Patch: %u") + || try_sec_hover.field("Seek Header: %u") + || try_sec_hover.field("NBytes Header: %u") + || try_sec_hover.field("Len Header: %u") + || try_sec_hover.field("Seek Footer: %u") + || try_sec_hover.field("NBytes Footer: %u") + || try_sec_hover.field("Len Footer: %u") + || try_sec_hover.field("Max Key Size: %u") ; } break; @@ -544,56 +620,91 @@ Sec_Hover_Info get_section_hover_info(Arena *arena, Section section, u64 off, co u32 root_version_be; memcpy(&root_version_be, data + start + 4, sizeof(u32)); u32 root_version = bswap_32(root_version_be); - b32x is_big = root_version > 1000000; + b8 is_big = root_version > 1000000; if (is_big) { - try_sec_hover.operator()("ROOT magic number") - || try_sec_hover.operator()("ROOT version: %u", [] (Arena *arena, String8_Node *prev, const char *fmt, u32 x) { + try_sec_hover.field("ROOT magic number") + || try_sec_hover.field("ROOT version: %u", [] (Arena *arena, String8_Node *prev, const char *fmt, u32 x) { x = bswap_32(x); x -= 1000000; return push_str8_node(arena, prev, fmt, x); }) - || try_sec_hover.operator()("fBEGIN: 0x%lX") - || try_sec_hover.operator()("fEND: 0x%lX") - || try_sec_hover.operator()("Seek Free: 0x%lX") - || try_sec_hover.operator()("NBytes Free: %u") - || try_sec_hover.operator()("N Free: %u") - || try_sec_hover.operator()("NBytes Name: %u") - || try_sec_hover.operator()("Units: %u") - || try_sec_hover.operator()("Compression: %u") - || try_sec_hover.operator()("Seek Info: 0x%lX") - || try_sec_hover.operator()("NBytes Info: %u") + || try_sec_hover.field("fBEGIN: 0x%lX") + || try_sec_hover.field("fEND: 0x%lX") + || try_sec_hover.field("Seek Free: 0x%lX") + || try_sec_hover.field("NBytes Free: %u") + || try_sec_hover.field("N Free: %u") + || try_sec_hover.field("NBytes Name: %u") + || try_sec_hover.field("Units: %u") + || try_sec_hover.field("Compression: %u") + || try_sec_hover.field("Seek Info: 0x%lX") + || try_sec_hover.field("NBytes Info: %u") ; } else { - try_sec_hover.operator()("ROOT magic number") - || try_sec_hover.operator()("ROOT version: %u") - || try_sec_hover.operator()("fBEGIN: 0x%lX") - || try_sec_hover.operator()("fEND: 0x%lX") - || try_sec_hover.operator()("Seek Free: 0x%lX") - || try_sec_hover.operator()("NBytes Free: %u") - || try_sec_hover.operator()("N Free: %u") - || try_sec_hover.operator()("NBytes Name: %u") - || try_sec_hover.operator()("Units: %u") - || try_sec_hover.operator()("Compression: %u") - || try_sec_hover.operator()("Seek Info: 0x%lX") - || try_sec_hover.operator()("NBytes Info: %u") + try_sec_hover.field("ROOT magic number") + || try_sec_hover.field("ROOT version: %u") + || try_sec_hover.field("fBEGIN: 0x%lX") + || try_sec_hover.field("fEND: 0x%lX") + || try_sec_hover.field("Seek Free: 0x%lX") + || try_sec_hover.field("NBytes Free: %u") + || try_sec_hover.field("N Free: %u") + || try_sec_hover.field("NBytes Name: %u") + || try_sec_hover.field("Units: %u") + || try_sec_hover.field("Compression: %u") + || try_sec_hover.field("Seek Info: 0x%lX") + || try_sec_hover.field("NBytes Info: %u") ; } } break; case Sec_TFile_Object: { - // FIXME - try_sec_hover.operator()("ROOT magic number") - || try_sec_hover.operator()("Class version: %u", [] (Arena *arena, String8_Node *prev, const char *fmt, u16 x) { - x = bswap_16(x); - x -= (x > 1000) * 1000; - return push_str8_node(arena, prev, fmt, x); - }) - || try_sec_hover.operator()("Created: ", hover_display_datetime_str) - || try_sec_hover.operator()("Modified: ", hover_display_datetime_str) - || try_sec_hover.operator()("NBytes Keys %u") - || try_sec_hover.operator()("NBytes Name %u") - ; + if (!hover_try_key(try_sec_hover, data, start)) { + b8 ok = try_sec_hover.field("Class Name: %s") + || try_sec_hover.field("Obj Name: %s") + || try_sec_hover.field("Obj Title: %s") + || try_sec_hover.field("File Name: %s") + || try_sec_hover.field("File Title: %s") + ; + + if (!ok) { + u16 version_be; + memcpy(&version_be, data + cur_field_off, sizeof(u16)); + u16 version = bswap_16(version_be); + b8 is_big = version > 1000; + + if (is_big) { + ok = ok || try_sec_hover.field("Version: %u", [] (Arena *arena, String8_Node *prev, const char *fmt, u16 x) { + x = bswap_16(x); + x -= 1000; + return push_str8_node(arena, prev, fmt, x); + }) + || try_sec_hover.field("Created: ", hover_display_datetime_str) + || try_sec_hover.field("Modified: ", hover_display_datetime_str) + || try_sec_hover.field("NBytes Key: %u") + || try_sec_hover.field("NBytes Name: %u") + || try_sec_hover.field("Seek Dir: 0x%lX") + || try_sec_hover.field("Seek Parent: 0x%lX") + || try_sec_hover.field("Seek Keys: 0x%lX") + ; + } else { + ok = ok || try_sec_hover.field("Version: %u") + || try_sec_hover.field("Created: ", hover_display_datetime_str) + || try_sec_hover.field("Modified: ", hover_display_datetime_str) + || try_sec_hover.field("NBytes Key: %u") + || try_sec_hover.field("NBytes Name: %u") + || try_sec_hover.field("Seek Dir: 0x%lX") + || try_sec_hover.field("Seek Parent: 0x%lX") + || try_sec_hover.field("Seek Keys: 0x%lX") + ; + } + ok = ok || try_sec_hover.field("UUID Vers.Class: %u") + || try_sec_hover.field("UUID: %u", [] (Arena *arena, String8_Node *prev, const char *fmt, u16 x) { + return push_str8_node(arena, prev, fmt, x); + }) + || try_sec_hover.range("Padding", 3 * sizeof(u32)) + ; + } + } } break; default:; diff --git a/src/root/RMicroFileReader.cxx b/src/root/RMicroFileReader.cxx index d23d143..6482500 100644 --- a/src/root/RMicroFileReader.cxx +++ b/src/root/RMicroFileReader.cxx @@ -1077,12 +1077,16 @@ Root_File_Info get_root_file_info(const char *fname, bool is_big_file) header.SetBigFile(); fileInfo.tfile_header_nbytes = header.GetSize(); fileInfo.tfile_obj_seek = 100; // kBEGIN - fileInfo.tfile_obj_nbytes = sizeof(RTFFile) + fileName.GetSize() + RTFString{}.GetSize() + RTFUUID{}.GetSize(); + RTFKey fileHeader { + 100, 0, RTFString{ "TFile" }, fileName, RTFString{}, + sizeof(RTFFile) + fileName.GetSize() + RTFString{}.GetSize() + RTFUUID{}.GetSize() + }; + fileInfo.tfile_obj_nbytes = fileHeader.GetSize(); fileInfo.version_seek = offsetof(RTFHeader, fVersion); fileInfo.compression_seek = is_big_file ? offsetof(RTFHeader, fInfoLong.fCompress) : offsetof(RTFHeader, fInfoShort.fCompress); - fileInfo.info_seek_seek = is_big_file ? offsetof(RTFHeader, fInfoLong.fSeekInfo) : offsetof(RTFHeader, fInfoShort.fSeekInfo); + fileInfo.info_seek_seek = is_big_file ? offsetof(RTFHeader, fInfoLong.fSeekInfo) : offsetof(RTFHeader, fInfoShort.fSeekInfo); fileInfo.info_nbytes_seek = is_big_file ? offsetof(RTFHeader, fInfoLong.fNbytesInfo) : offsetof(RTFHeader, fInfoShort.fNbytesInfo); - fileInfo.free_seek_seek = is_big_file ? offsetof(RTFHeader, fInfoLong.fSeekFree) : offsetof(RTFHeader, fInfoShort.fSeekFree); + fileInfo.free_seek_seek = is_big_file ? offsetof(RTFHeader, fInfoLong.fSeekFree) : offsetof(RTFHeader, fInfoShort.fSeekFree); fileInfo.free_nbytes_seek = is_big_file ? offsetof(RTFHeader, fInfoLong.fNbytesFree) : offsetof(RTFHeader, fInfoShort.fNbytesFree); return fileInfo; }