diff --git a/src/hover.cpp b/src/hover.cpp index a272508..80acb96 100644 --- a/src/hover.cpp +++ b/src/hover.cpp @@ -34,6 +34,11 @@ String8_Node *hover_display_val_le_abs(Arena *arena, String8_Node *prev, const c return push_str8_node_child(arena, prev, fmt, std::abs(val)); } +String8_Node *hover_display_generic_range(Arena *arena, String8_Node *prev, const char *desc, const u8 *) +{ + return push_str8_node_child(arena, prev, desc); +} + internal String8_Node *hover_display_datetime_str(Arena *arena, String8_Node *prev, const char *fmt_pre, u32 datetime) { @@ -84,351 +89,559 @@ String8_Node *display_val_rootzip(Arena *arena, String8_Node *prev, const char * template using Display_Fn = String8_Node *(*)(Arena *, String8_Node *, const char *, T); -template -internal -T read_buf(const void *buf, u64 &off) -{ - T val; - memcpy(&val, (u8 *)buf + off, sizeof(val)); - off += sizeof(val); - return val; -} - // Functor used by get_section_hover_info to describe the structure of a section and print data about it. struct Sec_Hover_Fn { u64 start; // the start of the section (including the pre_size, e.g. the TKey) u64 roff; // the offset relative to the section start const u8 *data; // the entire file data + const Section §ion; Arena *arena; Sec_Hover_Info &info; u64 &cur_field_off; b8 display_grouped; + b8 hovered = false; + b8 ended = false; template - b8 titled_section(const char *title, F &&fn) const + void titled_section(const char *title, F &&fn) { + if (ended) + return; + String8_Node *prev_desc = info.desc; info.desc = push_str8_node_child(arena, prev_desc, title); - b8 hovered = fn(); + u64 sec_start = cur_field_off; + fn(); if (!hovered) { + // the entire section was not hovered: don't display its description. pop_str8_node_child(prev_desc, info.desc); - info.desc = prev_desc; + } else if (display_grouped) { + // if we're in display_grouped mode, we want to highlight the entire range of the section; + assert(sec_start <= cur_field_off); + u64 sec_len = cur_field_off - sec_start; + hovered = roff >= sec_start && roff < sec_start + sec_len; + if (hovered) { + info.rng = { start + sec_start, sec_len }; + ended = true; + } } - return hovered; + info.desc = prev_desc; + return; } - // Returns true if this field is being hovered + // returns true if `val_read` was read template - b8 field(const char *desc_fmt, Display_Fn display_val, T *val_read = nullptr) const + b8 field(const char *desc_fmt, Display_Fn display_val, T *val_read = nullptr) { static_assert(!std::is_same_v, "use field_str8 instead."); + if (ended) + return false; + u64 field_len = sizeof(T); - u64 field_off = cur_field_off; - cur_field_off += field_len; - if (display_grouped || roff < field_off + field_len) { - info.rng = { start + field_off, field_len }; - T val = read_buf(data + start, field_off); + if (display_grouped || roff < cur_field_off + field_len) { + info.rng = { start + cur_field_off, field_len }; + T val; + memcpy(&val, (u8 *)data + start + cur_field_off, field_len); display_val(arena, info.desc, desc_fmt, val); if (val_read) *val_read = val; - return !display_grouped; + hovered = true; + // truncate the hovered section here if we're not in display_grouped mode. + ended = !display_grouped; } + cur_field_off += field_len; return false; } template - b8 field_str8(const char *desc_fmt, Display_Fn display_val = hover_display_val_str8) const + void field_str8(const char *desc_fmt, Display_Fn display_val = hover_display_val_str8) { + if (ended) + return; + // String size can be stored as different types, like u8 (by ROOT I/O) or u32 (by RNTuple). TStrSize str_size; memcpy(&str_size, data + start + cur_field_off, sizeof(TStrSize)); - u64 field_off = cur_field_off; + // DEBUG + if (str_size > 1000) { + printf("read str_size = %u at offset 0x%lX!\n", str_size, start + cur_field_off); + ended = true; + return; + } u64 field_len = sizeof(TStrSize) + (u64)str_size; - cur_field_off += field_len; - if (display_grouped || roff < field_off + field_len) { - info.rng = { start + field_off, field_len }; + hovered = roff < cur_field_off + field_len; + if (display_grouped || hovered) { + info.rng = { start + cur_field_off, field_len }; u8 *buf = arena_push_array_nozero(arena, str_size + 1); - memcpy(buf, data + start + field_off + sizeof(TStrSize), str_size); + memcpy(buf, data + start + cur_field_off + sizeof(TStrSize), str_size); buf[str_size] = 0; String8 s = { buf, str_size }; display_val(arena, info.desc, desc_fmt, s); - return !display_grouped; + ended = !display_grouped; } - return false; + cur_field_off += field_len; } template - b8 field_be(const char *desc_fmt) const + b8 field_be(const char *desc_fmt, T *val_read = nullptr) { - return field(desc_fmt, hover_display_val_be); + return field(desc_fmt, hover_display_val_be, val_read); } template - b8 field_le(const char *desc_fmt) const + b8 field_le(const char *desc_fmt, T *val_read = nullptr) { - return field(desc_fmt, hover_display_val_le); + return field(desc_fmt, hover_display_val_le, val_read); } - b8 range(const char *desc, u64 range_len) const + // An unspecified range of bytes + void range(const char *desc, u64 range_len, Display_Fn display_val = hover_display_generic_range) { - if (roff < cur_field_off + range_len) { - info.rng = { start + cur_field_off, range_len }; - push_str8_node_child(arena, info.desc, "%s", desc); - return true; - } - cur_field_off += range_len; - return false; - } + if (ended) + return; - b8 range_data(const char *desc, u64 range_len, Display_Fn display_val) const - { - if (roff < cur_field_off + range_len) { + if (display_grouped || roff < cur_field_off + range_len) { info.rng = { start + cur_field_off, range_len }; display_val(arena, info.desc, desc, data + start + cur_field_off); - return true; + hovered = true; + ended = !display_grouped; } cur_field_off += range_len; - return false; } - b8 maybe_rootzip(b8 *was_zipped = nullptr) const + // Returns true if `was_zipped` was read. + b8 maybe_rootzip(b8 *was_zipped = nullptr) { + if (ended) + return false; + // TODO boundary checks const u64 range_len = 9; if (display_val_rootzip(arena, info.desc, "Zipped Block", data + start + cur_field_off)) { if (was_zipped) *was_zipped = true; - if (roff < cur_field_off + range_len) { + if (display_grouped || roff < cur_field_off + range_len) { info.rng = { start + cur_field_off, range_len }; - hover_display_val_be(arena, info.desc, "", data + start + cur_field_off); - return true; - } - // discard the description (it's fine since it's allocated in the scratch arena) - if (info.desc->first_child == info.desc->last_child) { - info.desc->first_child = info.desc->last_child = nullptr; - } else { - info.desc->last_child = info.desc->last_child->prev; + hovered = true; + ended = !display_grouped; } cur_field_off += range_len; } else if (was_zipped) { *was_zipped = false; } - return false; + + return true; } - b8 tkey() const + void tkey() { - return titled_section("TKey", [this] { + titled_section("TKey", [this] { u16 version_be; memcpy(&version_be, data + start + 4, sizeof(u16)); u32 version = bswap(version_be); b8 is_big = version > 1000; if (is_big) { - return field_be("NBytes: %u") - || field("Version: %u", [] (Arena *arena, String8_Node *prev, const char *fmt, u16 x) { + field_be("NBytes: %u"); + field("Version: %u", [] (Arena *arena, String8_Node *prev, const char *fmt, u16 x) { x = bswap(x); x -= 1000; return push_str8_node_child(arena, prev, fmt, x); - }) - || field_be("Obj Len: %u") - || field("Datetime: ", hover_display_datetime_str) - || field_be("Key Len: %u") - || field_be("Cycle: %u") - || field_be("Seek Key: 0x%" PRIX64) - || field_be("Seek Pdir: 0x%" PRIX64) - || field_str8("Class Name: %s") - || field_str8("Obj Name: %s") - || field_str8("Obj Title: %s") - ; + }); + field_be("Obj Len: %u"); + field("Datetime: ", hover_display_datetime_str); + field_be("Key Len: %u"); + field_be("Cycle: %u"); + field_be("Seek Key: 0x%" PRIX64); + field_be("Seek Pdir: 0x%" PRIX64); + field_str8("Class Name: %s"); + field_str8("Obj Name: %s"); + field_str8("Obj Title: %s"); } else { - return field_be("NBytes: %u") - || field("Version: %u", [] (Arena *arena, String8_Node *prev, const char *fmt, u16 x) { + field_be("NBytes: %u"); + field("Version: %u", [] (Arena *arena, String8_Node *prev, const char *fmt, u16 x) { x = bswap(x); return push_str8_node_child(arena, prev, fmt, x); - }) - || field_be("Obj Len: %u") - || field("Datetime: ", hover_display_datetime_str) - || field_be("Key Len: %u") - || field_be("Cycle: %u") - || field_be("Seek Key: 0x%" PRIX64) - || field_be("Seek Pdir: 0x%" PRIX64) - || field_str8("Class Name: %s") - || field_str8("Obj Name: %s") - || field_str8("Obj Title: %s") - ; + }); + field_be("Obj Len: %u"); + field("Datetime: ", hover_display_datetime_str); + field_be("Key Len: %u"); + field_be("Cycle: %u"); + field_be("Seek Key: 0x%" PRIX64); + field_be("Seek Pdir: 0x%" PRIX64); + field_str8("Class Name: %s"); + field_str8("Obj Name: %s"); + field_str8("Obj Title: %s"); } }); } - b8 envelope_preamble() const + void envelope_preamble() { static const char *const envelope_names[] = { "INVALID", "Header", "Footer", "Page List" }; - return titled_section("Envelope Preamble", [this] { - return field("Envelope type: %s", [] (Arena *arena, String8_Node *prev, const char *fmt, u16 val) { - const char *name = (val >= countof(envelope_names)) ? "Unknown" : envelope_names[val]; - return push_str8_node_child(arena, prev, fmt, name); - }) - || range_data("Envelope size: %s", 6, [] (Arena *arena, String8_Node *prev, const char *fmt, const u8 *payload) { - u64 size; - memcpy(&size, payload, 6); - return push_str8_node_child(arena, prev, fmt, to_pretty_size(arena, size)); - }); + titled_section("Envelope Preamble", [this] { + field("Envelope type: %s", [] (Arena *arena, String8_Node *prev, const char *fmt, u16 val) { + const char *name = (val >= countof(envelope_names)) ? "Unknown" : envelope_names[val]; + return push_str8_node_child(arena, prev, fmt, name); + }); + range("Envelope size: %s", 6, [] (Arena *arena, String8_Node *prev, const char *fmt, const u8 *payload) { + u64 size; + memcpy(&size, payload, 6); + return push_str8_node_child(arena, prev, fmt, to_pretty_size(arena, size)); + }); }); } - b8 frame_header(const char *title = nullptr) const + enum Frame_Type { + Frame_Record, + Frame_List + }; + + Frame_Type frame_header(u64 &size, u32 *n_items = nullptr, const char *title = nullptr) { String8 titlestr = title ? push_str8f(arena, "Frame Header: %s", title) : str8("Frame Header"); - return titled_section(titlestr.c(), [this] { + Frame_Type frame_type = Frame_Record; + titled_section(titlestr.c(), [this, &frame_type, &frame_size = size, n_items] { i64 size; memcpy(&size, data + start + cur_field_off, sizeof(size)); - if (size >= 0) - return field("Record frame size: %" PRIi64 " B", hover_display_val_le_abs); - else if (roff < cur_field_off + 12) { - info.rng = { start + cur_field_off, 12 }; - b8 ok = titled_section("List Frame", [this] { - return field("Size: %" PRIi64 " B", hover_display_val_le_abs) - || field_le("N Items: %u") - ; + if (size >= 0) { + frame_type = Frame_Record; + field("Record frame size: %" PRIi64 " B", hover_display_val_le_abs); + } else { + frame_type = Frame_List; + assert(n_items); + memcpy(n_items, data + start + cur_field_off + sizeof(i64), sizeof(*n_items)); + titled_section("List Frame", [this] { + field("Size: %" PRIi64 " B", hover_display_val_le_abs); + field_le("N Items: %u"); }); - if (ok) - return ok; } - cur_field_off += 12; - return false; + + frame_size = std::abs(size); }); + return frame_type; } - b8 field_desc() const + void field_desc() { static const char *const field_struct_names[] = { "Leaf", "Collection", "Record", "Variant", "Unsplit" }; - i64 size; - memcpy(&size, data + start + cur_field_off, sizeof(size)); - u64 field_desc_len = (u64)std::abs(size); - if (roff < cur_field_off + field_desc_len) { - info.rng = { start + cur_field_off, (u64)field_desc_len }; - return titled_section("Field", [this] { - b8 ok = field_le("Size: %" PRIi64 " B") - || field_le("Field version: %u") - || field_le("Type version: %u") - || field_le("On-disk parent id: %u") - || field("Field structure: %s", [] (Arena *arena, String8_Node *prev, const char *fmt, u16 type) { - const char *name = (type >= countof(field_struct_names)) ? "Unknown" : field_struct_names[type]; - return push_str8_node_child(arena, prev, fmt, name); - }); - if (ok) - return true; - - u16 flags; - ok = field("Flags: 0b%b", hover_display_val_le, &flags); - - if (flags & RNTupleSerializer::kFlagRepetitiveField) - ok = ok || field_le("N Repetitions: %" PRIu64); - if (flags & RNTupleSerializer::kFlagProjectedField) - ok = ok || field_le("On disk proj.src id: %u"); - if (flags & RNTupleSerializer::kFlagHasTypeChecksum) - ok = ok || field_le("Checksum: %u"); - - ok = ok || field_str8("Name: %s") - || field_str8("Type Name: %s") - || field_str8("Type Alias: %s") - || field_str8("Description: %s") - ; - return ok; + titled_section("Field", [this] { + u64 start_off = cur_field_off; + u64 size; + Frame_Type ftype = frame_header(size); + assert(ftype == Frame_Record); + // DEBUG + if (size > 100000) { + printf("read field_frame_size = %lu at offset 0x%lX!\n", size, start + cur_field_off); + ended = true; + return; + } + field_le("Field version: %u"); + field_le("Type version: %u"); + field_le("On-disk parent id: %u"); + field("Field structure: %s", [] (Arena *arena, String8_Node *prev, const char *fmt, u16 type) { + const char *name = (type >= countof(field_struct_names)) ? "Unknown" : field_struct_names[type]; + return push_str8_node_child(arena, prev, fmt, name); }); - } - cur_field_off += field_desc_len; - return false; + + u16 flags; + if (!field("Flags: 0b%b", hover_display_val_le, &flags)) + return; + + if (flags & RNTupleSerializer::kFlagRepetitiveField) + field_le("N Repetitions: %" PRIu64); + if (flags & RNTupleSerializer::kFlagProjectedField) + field_le("On disk proj.src id: %u"); + if (flags & RNTupleSerializer::kFlagHasTypeChecksum) + field_le("Checksum: %u"); + + field_str8("Name: %s"); + field_str8("Type Name: %s"); + field_str8("Type Alias: %s"); + field_str8("Description: %s"); + + u64 extra_size = size - (cur_field_off - start_off); + if (extra_size > 0) + range("Unknown", extra_size); + }); } - b8 column_desc(const char *title) const + void column_desc(const char *title) { - i64 size; - memcpy(&size, data + start + cur_field_off, sizeof(size)); - u64 col_desc_len = (u64)std::abs(size); - if (roff < cur_field_off + col_desc_len) { - info.rng = { start + cur_field_off, col_desc_len }; - return titled_section(title, [this] { - b8 ok = field_le("Size: %" PRIi64 " B") - || field("Column type: %s", [](Arena *arena, String8_Node *prev, const char *fmt, u16 val) { - const char *readable_col_type = get_column_type_name(val); - return push_str8_node_child(arena, prev, fmt, readable_col_type); - }) - || field_le("Bits on storage: %u") - || field_le("Field ID: %u") - ; - if (ok) - return true; - - u16 flags; - ok = field("Flags: 0b%b", hover_display_val_le, &flags); - ok = ok || field_le("Representation idx: %u"); - if (flags & RNTupleSerializer::kFlagDeferredColumn) - ok = ok || field_le("First element: %" PRIu64); - if (flags & RNTupleSerializer::kFlagHasValueRange) { - ok = ok || field_le("Value Min: %f") - || field_le("Value Max: %f"); - } - return ok; + titled_section(title, [this] { + u64 start_off = cur_field_off; + u64 size; + Frame_Type ftype = frame_header(size); + assert(ftype == Frame_Record); + // DEBUG + if (size > 100000) { + printf("read column_desc_size = %lu at offset 0x%lX!\n", size, start + cur_field_off); + ended = true; + return; + } + field_le("Size: %" PRIi64 " B"); + field("Column type: %s", [](Arena *arena, String8_Node *prev, const char *fmt, u16 val) { + const char *readable_col_type = get_column_type_name(val); + return push_str8_node_child(arena, prev, fmt, readable_col_type); }); - } - cur_field_off += col_desc_len; - return false; + field_le("Bits on storage: %u"); + field_le("Field ID: %u"); + + u16 flags; + if (!field("Flags: 0b%b", hover_display_val_le, &flags)) + return; + + field_le("Representation idx: %u"); + if (flags & RNTupleSerializer::kFlagDeferredColumn) { + field_le("First element: %" PRIu64); + } + if (flags & RNTupleSerializer::kFlagHasValueRange) { + field_le("Value Min: %f"); + field_le("Value Max: %f"); + } + u64 extra_size = size - (cur_field_off - start_off); + if (extra_size > 0) + range("Unknown", extra_size); + }); } template - b8 list_frame(const char *title, F &&fn) const + void list_frame(const char *title, F &&fn) { - if (frame_header(title)) - return true; - // we need to read back the number of entries to know how long is the next section. - u64 n_elems_off = cur_field_off - sizeof(u32); + u64 size; u32 n_elems; - memcpy(&n_elems, data + start + n_elems_off, sizeof(n_elems)); - for (u32 i = 0; i < n_elems; ++i) - if (fn()) - return true; - return false; + Frame_Type ftype = frame_header(size, &n_elems, title); + // assert(ftype == Frame_List); + + if (ended) + return; + + // DEBUG + if (n_elems > 100000) { + printf("read n_elems = %u at offset 0x%lX!\n", n_elems, start + cur_field_off); + ended = true; + return; + } + for (u32 i = 0; i < n_elems; ++i) { + fn(); + if (ended) + break; + } } - b8 schema_description(const char *title) const + void schema_description(const char *title) { - return titled_section(title, [this] { + titled_section(title, [this] { // TODO: Columns and alias columns are not the same - return list_frame("Fields", [this] { return field_desc(); }) - || list_frame("Columns", [this] { return column_desc("Column"); }) - || list_frame("Alias Columns", [this] { return column_desc("Alias Column"); }) - || list_frame("Extra Type Infos", [this] { - return field_le("Content identifier: %lu") - || field_le("Type version from: %lu") - || field_le("Type version to: %lu"); - }); + list_frame("Fields", [this] { return field_desc(); }); + list_frame("Columns", [this] { return column_desc("Column"); }); + list_frame("Alias Columns", [this] { return column_desc("Alias Column"); }); + list_frame("Extra Type Infos", [this] { + field_le("Content identifier: %lu"); + field_le("Type version from: %lu"); + field_le("Type version to: %lu"); + }); }); } - b8 locator(const char *title) const + void locator(const char *title) { // TODO - return titled_section(title, [this] { - return true; + // return titled_section(title, [this] { + // return true; + // }); + } + + void cluster_group() + { + titled_section("Cluster Group", [this] { + u64 size; + u32 n_items; + Frame_Type ftype = frame_header(size, &n_items); + assert(ftype == Frame_List); + for (u32 i = 0; i < n_items; ++i) { + field_le("Min Entry: %" PRIu64); + field_le("Entry Span: %" PRIu64); + field_le("N Clusters: %u"); + field_le("Env.Link Len: %" PRIu64); + locator("Env.Link Locator"); + } }); } - b8 cluster_group() const + void rntuple_anchor() { - return titled_section("Cluster Group", [this] { - return frame_header() - || field_le("Min Entry: %" PRIu64) - || field_le("Entry Span: %" PRIu64) - || field_le("N Clusters: %u") - || field_le("Env.Link Len: %" PRIu64) - || locator("Env.Link Locator") - ; + titled_section("RNTuple Anchor", [this] { + tkey(); + titled_section("Data", [this] { + field("Object len: %u", [] (Arena *arena, String8_Node *prev, const char *fmt, u32 x) { + x = bswap(x); + x -= 0x4000'0000; + return push_str8_node_child(arena, prev, fmt, x); + }); + field_be("Class version: %u"); + field_be("Version Epoch: %u"); + field_be("Version Major: %u"); + field_be("Version Minor: %u"); + field_be("Version Patch: %u"); + field_be("Seek Header: 0x%" PRIX64); + field_be("NBytes Header: %u"); + field_be("Len Header: %u"); + field_be("Seek Footer: 0x%" PRIX64); + field_be("NBytes Footer: %u"); + field_be("Len Footer: %u"); + field_be("Max Key Size: %u"); + field_le("Checksum: 0x%" PRIX64); + }); + }); + } + + void rntuple_header() + { + titled_section("RNTuple Header", [this] { + tkey(); + b8 zipped; + if (!maybe_rootzip(&zipped)) + return; + + if (zipped) { + // XXX: why -1? + range("Compressed payload", section.range.len - section.post_size - sizeof(u64) - 1); + field_le("Checksum: 0x%" PRIX64); + } else { + envelope_preamble(); + // NOTE: flags in principle require a more complex handling, but for now they are unused, + // so they're always occupying only 8 bytes. + field_le("Flags: 0x%" PRIX64); + field_str8("Name: %s"); + field_str8("Description: %s"); + field_str8("ROOT version: %s"); + schema_description("Schema Description"); + field_le("Checksum: 0x%" PRIX64); + } + }); + } + + void rntuple_footer() + { + titled_section("RNTuple Footer", [this] { + tkey(); + b8 zipped; + if (!maybe_rootzip(&zipped)) + return; + + if (zipped) { + // XXX: why -1? + range("Payload", section.range.len - section.post_size - sizeof(u64) - 1); + field_le("Checksum: 0x%" PRIX64); + } else { + envelope_preamble(); + // NOTE: flags in principle require a more complex handling, but for now they are unused, + // so they're always occupying only 8 bytes. + field_le("Flags: 0x%" PRIX64); + field_le("Header checksum: 0x%" PRIX64); + u64 size; + Frame_Type ftype = frame_header(size); + assert(ftype == Frame_Record); + schema_description("Schema Extension"); + // - list of column group record frames (TODO) + //frame_header("Column Groups"); + // - list of cluster group record frames (TODO) + //frame_header("Cluster Groups"); + range("Payload", section.range.len - cur_field_off); + field_le("Checksum: 0x%" PRIX64); + } + }); + } + + void tfile_header() + { + titled_section("TFile Header", [this] { + u32 root_version_be; + memcpy(&root_version_be, data + start + 4, sizeof(u32)); + u32 root_version = bswap(root_version_be); + b8 is_big = root_version > 1000000; + + if (is_big) { + field_be("ROOT magic number"); + field("ROOT version: %u", [] (Arena *arena, String8_Node *prev, const char *fmt, u32 x) { + x = bswap(x); + x -= 1000000; + return push_str8_node_child(arena, prev, fmt, x); + }); + field_be("fBEGIN: 0x%" PRIX64); + field_be("fEND: 0x%" PRIX64); + field_be("Seek Free: 0x%" PRIX64); + field_be("NBytes Free: %u"); + field_be("N Free: %u"); + field_be("NBytes Name: %u"); + field_be("Units: %u"); + field_be("Compression: %u"); + field_be("Seek Info: 0x%" PRIX64); + field_be("NBytes Info: %u"); + range("Padding", section.post_size); + } else { + field_be("ROOT magic number"); + field_be("ROOT version: %u"); + field_be("fBEGIN: 0x%" PRIX64); + field_be("fEND: 0x%" PRIX64); + field_be("Seek Free: 0x%" PRIX64); + field_be("NBytes Free: %u"); + field_be("N Free: %u"); + field_be("NBytes Name: %u"); + field_be("Units: %u"); + field_be("Compression: %u"); + field_be("Seek Info: 0x%" PRIX64); + field_be("NBytes Info: %u"); + range("Padding", section.post_size); + } + }); + } + + void tfile_object() + { + titled_section("TFile Object", [this] { + tkey(); + field_str8("File Name: %s"); + field_str8("File Title: %s"); + + u16 version_be; + memcpy(&version_be, data + cur_field_off, sizeof(u16)); + u16 version = bswap(version_be); + b8 is_big = version > 1000; + + if (is_big) { + field("Version: %u", [] (Arena *arena, String8_Node *prev, const char *fmt, u16 x) { + x = bswap(x); + x -= 1000; + return push_str8_node_child(arena, prev, fmt, x); + }); + field("Created: ", hover_display_datetime_str); + field("Modified: ", hover_display_datetime_str); + field_be("NBytes Key: %u"); + field_be("NBytes Name: %u"); + field_be("Seek Dir: 0x%" PRIX64) ; + field_be("Seek Parent: 0x%" PRIX64) ; + field_be("Seek Keys: 0x%" PRIX64) ; + field_be("UUID Vers.Class: %u"); + field_le("UUID: %u"); + } else { + field_be("Version: %u"); + field("Created: ", hover_display_datetime_str); + field("Modified: ", hover_display_datetime_str); + field_be("NBytes Key: %u"); + field_be("NBytes Name: %u"); + field_be("Seek Dir: 0x%" PRIX64) ; + field_be("Seek Parent: 0x%" PRIX64) ; + field_be("Seek Keys: 0x%" PRIX64) ; + field_be("UUID Vers.Class: %u"); + field_le("UUID: %u"); + range("Padding", 3 * sizeof(u32)); + } }); } }; @@ -459,170 +672,30 @@ Sec_Hover_Info get_section_hover_info(Arena *arena, Section section, u64 off, co u64 start = section.range.start - section.pre_size; u64 roff = off - start; // offset relative to `section` u64 cur_field_off = 0; - Sec_Hover_Fn hover { start, roff, data, arena, info, cur_field_off, display_grouped }; + Sec_Hover_Fn hover { start, roff, data, section, arena, info, cur_field_off, display_grouped }; switch (section.id) { case Sec_RNTuple_Anchor: { - hover.tkey() - || hover.field("Object len: %u", [] (Arena *arena, String8_Node *prev, const char *fmt, u32 x) { - x = bswap(x); - x -= 0x4000'0000; - return push_str8_node_child(arena, prev, fmt, x); - }) - || hover.field_be("Class version: %u") - || hover.field_be("Version Epoch: %u") - || hover.field_be("Version Major: %u") - || hover.field_be("Version Minor: %u") - || hover.field_be("Version Patch: %u") - || hover.field_be("Seek Header: 0x%" PRIX64) - || hover.field_be("NBytes Header: %u") - || hover.field_be("Len Header: %u") - || hover.field_be("Seek Footer: 0x%" PRIX64) - || hover.field_be("NBytes Footer: %u") - || hover.field_be("Len Footer: %u") - || hover.field_be("Max Key Size: %u") - || hover.field_le("Checksum: 0x%" PRIX64) - ; + hover.rntuple_anchor(); } break; case Sec_TFile_Header: { - u32 root_version_be; - memcpy(&root_version_be, data + start + 4, sizeof(u32)); - u32 root_version = bswap(root_version_be); - b8 is_big = root_version > 1000000; - - if (is_big) { - hover.field_be("ROOT magic number") - || hover.field("ROOT version: %u", [] (Arena *arena, String8_Node *prev, const char *fmt, u32 x) { - x = bswap(x); - x -= 1000000; - return push_str8_node_child(arena, prev, fmt, x); - }) - || hover.field_be("fBEGIN: 0x%" PRIX64) - || hover.field_be("fEND: 0x%" PRIX64) - || hover.field_be("Seek Free: 0x%" PRIX64) - || hover.field_be("NBytes Free: %u") - || hover.field_be("N Free: %u") - || hover.field_be("NBytes Name: %u") - || hover.field_be("Units: %u") - || hover.field_be("Compression: %u") - || hover.field_be("Seek Info: 0x%" PRIX64) - || hover.field_be("NBytes Info: %u") - || hover.range("Padding", section.post_size) - ; - } else { - hover.field_be("ROOT magic number") - || hover.field_be("ROOT version: %u") - || hover.field_be("fBEGIN: 0x%" PRIX64) - || hover.field_be("fEND: 0x%" PRIX64) - || hover.field_be("Seek Free: 0x%" PRIX64) - || hover.field_be("NBytes Free: %u") - || hover.field_be("N Free: %u") - || hover.field_be("NBytes Name: %u") - || hover.field_be("Units: %u") - || hover.field_be("Compression: %u") - || hover.field_be("Seek Info: 0x%" PRIX64) - || hover.field_be("NBytes Info: %u") - || hover.range("Padding", section.post_size) - ; - } + hover.tfile_header(); } break; case Sec_TFile_Object: { - if (!hover.tkey()) { - b8 ok = hover.field_str8("File Name: %s") - || hover.field_str8("File Title: %s") - ; - if (!ok) { - u16 version_be; - memcpy(&version_be, data + cur_field_off, sizeof(u16)); - u16 version = bswap(version_be); - b8 is_big = version > 1000; - - if (is_big) { - ok = ok || hover.field("Version: %u", [] (Arena *arena, String8_Node *prev, const char *fmt, u16 x) { - x = bswap(x); - x -= 1000; - return push_str8_node_child(arena, prev, fmt, x); - }) - || hover.field("Created: ", hover_display_datetime_str) - || hover.field("Modified: ", hover_display_datetime_str) - || hover.field_be("NBytes Key: %u") - || hover.field_be("NBytes Name: %u") - || hover.field_be("Seek Dir: 0x%" PRIX64) - || hover.field_be("Seek Parent: 0x%" PRIX64) - || hover.field_be("Seek Keys: 0x%" PRIX64) - || hover.field_be("UUID Vers.Class: %u") - || hover.field_le("UUID: %u") - ; - } else { - ok = ok || hover.field_be("Version: %u") - || hover.field("Created: ", hover_display_datetime_str) - || hover.field("Modified: ", hover_display_datetime_str) - || hover.field_be("NBytes Key: %u") - || hover.field_be("NBytes Name: %u") - || hover.field_be("Seek Dir: 0x%" PRIX64) - || hover.field_be("Seek Parent: 0x%" PRIX64) - || hover.field_be("Seek Keys: 0x%" PRIX64) - || hover.field_be("UUID Vers.Class: %u") - || hover.field_le("UUID: %u") - || hover.range("Padding", 3 * sizeof(u32)) - ; - } - } - } + hover.tfile_object(); + } break; + + case Sec_RNTuple_Header: { + hover.rntuple_header(); } break; - case Sec_RNTuple_Header: - if (!hover.tkey()) { - b8 zipped; - if (!hover.maybe_rootzip(&zipped)) { - if (zipped) { - hover.range("Payload", section.range.len - section.post_size) - || hover.field_le("Checksum: 0x%" PRIX64) - ; - } else { - hover.envelope_preamble() - // NOTE: flags in principle require a more complex handling, but for now they are unused, - // so they're always occupying only 8 bytes. - || hover.field_le("Flags: 0x%" PRIX64) - || hover.field_str8("Name: %s") - || hover.field_str8("Description: %s") - || hover.field_str8("ROOT version: %s") - || hover.schema_description("Schema Description") - || hover.field_le("Checksum: 0x%" PRIX64) - ; - } - } - } - break; case Sec_RNTuple_Footer: { - if (!hover.tkey()) { - b8 zipped; - if (!hover.maybe_rootzip(&zipped)) { - if (zipped) { - hover.range("Payload", section.range.len - section.post_size) - || hover.field_le("Checksum: 0x%" PRIX64) - ; - } else { - hover.envelope_preamble() - // NOTE: flags in principle require a more complex handling, but for now they are unused, - // so they're always occupying only 8 bytes. - || hover.field_le("Flags: 0x%" PRIX64) - || hover.field_le("Header checksum: 0x%" PRIX64) - || hover.frame_header() - || hover.schema_description("Schema Extension") - // - list of column group record frames (TODO) - || hover.frame_header("Column Groups") - // - list of cluster group record frames (TODO) - || hover.frame_header("Cluster Groups") - || hover.range("Payload", section.range.len - hover.cur_field_off) - || hover.field_le("Checksum: 0x%" PRIX64) - ; - } - } - } + hover.rntuple_footer(); } break; + + #if 0 case Sec_Page_List: { hover.tkey() || hover.maybe_rootzip() @@ -642,7 +715,7 @@ Sec_Hover_Info get_section_hover_info(Arena *arena, Section section, u64 off, co case Sec_TFile_Info: { hover.tkey() - || hover.maybe_rootzip() + hover.maybe_rootzip() // || hover.field("Byte Count: %u", [] (Arena *arena, String8_Node *prev, const char *fmt, u32 x) { // x = bswap(x); // x -= 0x400000000; @@ -683,6 +756,7 @@ Sec_Hover_Info get_section_hover_info(Arena *arena, Section section, u64 off, co } } } break; + #endif default:; }