From 331eec77e6bb0a15d79ec2d20a8c894d369f6be6 Mon Sep 17 00:00:00 2001 From: silverweed Date: Thu, 26 Sep 2024 14:11:25 +0200 Subject: [PATCH] introduce frame() --- src/hover.cpp | 421 +++++++++++++++++++++++++------------------------- 1 file changed, 210 insertions(+), 211 deletions(-) diff --git a/src/hover.cpp b/src/hover.cpp index 67a30b3..8d24726 100644 --- a/src/hover.cpp +++ b/src/hover.cpp @@ -273,38 +273,26 @@ struct Sec_Hover_Fn { u32 version = bswap(version_be); b8 is_big = version > 1000; + field_be("NBytes: %u"); + field("Version: %u", [] (Arena *arena, String8_Node *prev, const char *fmt, u16 x) { + x = bswap(x); + x -= (x > 1000) * 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"); if (is_big) { - 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"); } else { - 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_str8("Class Name: %s"); + field_str8("Obj Name: %s"); + field_str8("Obj Title: %s"); }, HoverSec_HideIfNotHovered); } @@ -334,47 +322,40 @@ struct Sec_Hover_Fn { { String8 titlestr = title ? push_str8f(arena, "Frame Header: %s", title) : str8("Frame Header"); Frame_Type frame_type = Frame_INVALID; - titled_section(titlestr.c(), [this, &frame_type, &frame_size = size, n_items, titlestr] { + 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) { 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 (!n_items) { + // Since the caller didn't pass us a pointer to n_items, they think we're supposed + // to be parsing a record frame. But it turns out this is actually a frame list! + // Something fishy is going on, so just bail out. + frame_type = Frame_INVALID; + } else { + frame_type = Frame_List; + memcpy(n_items, data + start + cur_field_off + sizeof(i64), sizeof(u32)); + titled_section("List Frame", [this] { + field("Size: %" PRIi64 " B", hover_display_val_le_abs); + field_le("N Items: %u"); + }); + } } frame_size = std::abs(size); }); - assert(frame_type == Frame_Record || frame_type == Frame_List); return frame_type; } - void field_desc() + void field_desc(const char *title) { static const char *const field_struct_names[] = { "Leaf", "Collection", "Record", "Variant", "Unsplit" }; - titled_section("Field", [this] { - u64 start_off = cur_field_off; - u64 size; - Frame_Type ftype = frame_header(size); - if (ftype != Frame_Record) - return; - - // DEBUG - if (size > 100000) { - printf("read field_frame_size = %lu at offset 0x%lX!\n", size, start + cur_field_off); - // ended = true; - return; - } + frame(title, [this] { field_le("Field version: %u"); field_le("Type version: %u"); field_le("On-disk parent id: %u"); @@ -398,29 +379,12 @@ struct Sec_Hover_Fn { 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); }, HoverSec_HideIfNotHovered); } void column_desc(const char *title) { - titled_section(title, [this, title] { - u64 start_off = cur_field_off; - u64 size; - Frame_Type ftype = frame_header(size); - if (ftype != Frame_Record) - return; - - // DEBUG - if (size > 100000) { - printf("read column_desc_size = %lu at offset 0x%lX!\n", size, start + cur_field_off); - // ended = true; - return; - } - + frame(title, [this] { 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); @@ -436,56 +400,21 @@ struct Sec_Hover_Fn { if (flags & RNTupleSerializer::kFlagDeferredColumn) { field_le("First element: %" PRIu64); } - if (flags & RNTupleSerializer::kFlagHasValueRange) { - field_le("Value Min: %f"); - field_le("Value Max: %f"); - } - - assert(cur_field_off >= start_off); - if (size < cur_field_off - start_off) { - printf("column_desc(%s) should be of size %lu but we allocated %lu bytes for it?\n", title, size, cur_field_off - start_off); - return; - } - u64 extra_size = size - (cur_field_off - start_off); - printf("extra size: %lu - %lu = %lu\n", size, cur_field_off - start_off, extra_size); - if (extra_size > 0) - range("Unknown", extra_size); + // if (flags & RNTupleSerializer::kFlagHasValueRange) { + // field_le("Value Min: %f"); + // field_le("Value Max: %f"); + // } }, HoverSec_HideIfNotHovered); } - template - void list_frame(const char *title, F &&per_elem_fn) - { - if (ended) - return; - - u64 size; - u32 n_elems; - Frame_Type ftype = frame_header(size, &n_elems, title); - if (ftype != Frame_List) - 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) { - per_elem_fn(); - if (ended) - break; - } - } - void schema_description(const char *title) { titled_section(title, [this] { // TODO: Columns and alias columns are not the same - list_frame("Fields", [this] { field_desc(); }); - list_frame("Columns", [this] { column_desc("Column"); }); - list_frame("Alias Columns", [this] { column_desc("Alias Column"); }); - list_frame("Extra Type Infos", [this] { + frame("Fields", [this] (u32 idx) { field_desc(push_str8f(arena, "Field %u", idx).c()); }); + frame("Columns", [this] (u32 idx) { column_desc(push_str8f(arena, "Column %u", idx).c()); }); + frame("Alias Columns", [this] (u32 idx) { column_desc(push_str8f(arena, "Alias Column %u", idx).c()); }); + frame("Extra Type Infos", [this] (u32) { field_le("Content identifier: %lu"); field_le("Type version from: %lu"); field_le("Type version to: %lu"); @@ -503,18 +432,12 @@ struct Sec_Hover_Fn { 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"); - } + frame("Cluster Group", [this] (u32) { + 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"); }); } @@ -592,9 +515,6 @@ struct Sec_Hover_Fn { // 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"); @@ -607,6 +527,84 @@ struct Sec_Hover_Fn { }); } + void cluster_summary() + { + frame("Cluster Summary", [this] { + field_le("First Entry: %" PRIu64); + field("", [] (Arena *arena, String8_Node *prev, const char *, u64 x) { + u64 entries = (x << 8) >> 8; + u8 flags = x >> 56; + String8_Node *sn = push_str8_node_child(arena, prev, "Entries: %" PRIu64, entries); + return push_str8_node(arena, sn, "Flags: 0b%b", flags); + }); + }); + } + + void cluster() + { + frame("Cluster", [this] (u32 col_idx) { + titled_section(push_str8f(arena, "Column %u", col_idx).c(), [this] { + frame("Pages", [this] (u32 page_idx) { + titled_section(push_str8f(arena, "Page %u", page_idx).c(), [this] { + field("", [] (Arena *arena, String8_Node *prev, const char *, i32 n_elems) { + b8 has_checksum = n_elems < 0; + String8_Node *sn = push_str8_node_child(arena, prev, "N Elements: %u", std::abs(n_elems)); + return push_str8_node(arena, sn, "Has Checksum: %s", has_checksum ? "yes" : "no"); + }); + locator("Element Locator"); + }, HoverSec_HideIfNotHovered); + }); + + i64 n_cols; + if (!field("", [] (Arena *arena, String8_Node *prev, const char *, i64 n_cols) { + if (n_cols < 0) { + return push_str8_node_child(arena, prev, "Element Offset: "); + } + return push_str8_node_child(arena, prev, "Element Offset: %" PRIi64, n_cols); + }, &n_cols)) + { + return; + } + if (n_cols >= 0) + field_le("Compression Settings: %d"); + }, HoverSec_HideIfNotHovered); + }); + } + + template + void frame(const char *title, F &&frame_body_fn, u64 sec_flags = 0) + { + u64 start_off = cur_field_off; + u64 size; + + titled_section(title, [this, title, start_off, &size, &frame_body_fn] { + u32 n_items = 0; + Frame_Type ftype = frame_header(size, &n_items); + if (ftype != FType) + return; + + if constexpr (FType == Frame_List) { + for (u32 i = 0; i < n_items; ++i) + frame_body_fn(i); + } else { + frame_body_fn(); + } + + assert(cur_field_off >= start_off); + u64 allocated_size = cur_field_off - start_off; + if (size < allocated_size) { + fprintf(stderr, "Frame %s told us its size was %" PRIu64 " but we accounted for %" PRIu64 " bytes!\n", + title, size, allocated_size); + } + + u64 extra_size = size - allocated_size; + if (extra_size > 0) + range("Unknown", extra_size); + }, sec_flags); + + cur_field_off = start_off + size; + } + void page_list() { titled_section("Page List", [this] { @@ -620,7 +618,10 @@ struct Sec_Hover_Fn { range("Payload", section.range.len - section.post_size - sizeof(u64) - 1); field_le("Checksum: 0x%" PRIX64); } else { - // TODO + envelope_preamble(); + field_le("Header checksum: 0x%" PRIX64); + frame("Cluster Summaries", [this] (u32) { cluster_summary(); }); + frame("Clusters", [this] (u32) { cluster(); }); } }, HoverSec_HideIfNotHovered); }); @@ -632,41 +633,33 @@ struct Sec_Hover_Fn { 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; + b8 is_big = root_version > 1000'000; + field_be("ROOT magic number"); + field("ROOT version: %u", [] (Arena *arena, String8_Node *prev, const char *fmt, u32 x) { + x = bswap(x); + x -= (x > 1000'000) * 1000'000; + return push_str8_node_child(arena, prev, fmt, x); + }); + field_be("fBEGIN: 0x%" PRIX64); 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); } + field_be("NBytes Free: %u"); + field_be("N Free: %u"); + field_be("NBytes Name: %u"); + field_be("Units: %u"); + field_be("Compression: %u"); + if (is_big) + field_be("Seek Info: 0x%" PRIX64); + else + field_be("Seek Info: 0x%" PRIX64); + field_be("NBytes Info: %u"); + range("Padding", section.post_size); }); } @@ -682,33 +675,75 @@ struct Sec_Hover_Fn { u16 version = bswap(version_be); b8 is_big = version > 1000; + field("Version: %u", [] (Arena *arena, String8_Node *prev, const char *fmt, u16 x) { + x = bswap(x); + x -= (x > 1000) * 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"); 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"); + } + field_be("UUID Vers.Class: %u"); + field_le("UUID: %u"); + if (!is_big) range("Padding", 3 * sizeof(u32)); + }); + } + + void tfile_info() + { + titled_section("TFile Info", [this] { + tkey(); + b8 zipped; + if (!maybe_rootzip(&zipped)) + return; + + if (zipped) { + range("Compressed Payload", section.range.len); + } else { + field("Byte Count: %u", [] (Arena *arena, String8_Node *prev, const char *fmt, u32 x) { + x = bswap(x); + x -= 0x400000000; + return push_str8_node_child(arena, prev, fmt, x); + }); + field_be("Version: %u"); + // hover_try_object(hover) + field_be("Name: %u"); + field_be("N Objects: %u");; + } + }); + } + + void tfile_freelist() + { + titled_section("TFile FreeList", [this] { + tkey(); + u16 version_be; + memcpy(&version_be, data + start + cur_field_off, sizeof(u16)); + u32 version = bswap(version_be); + b8 is_big = version > 1000; + + field("Version: %u", [] (Arena *arena, String8_Node *prev, const char *fmt, u16 x) { + x = bswap(x); + x -= (x > 1000) * 1000; + return push_str8_node_child(arena, prev, fmt, x); + }); + if (is_big) { + field_be("First: 0x%" PRIX64); + field_be("Last: 0x%" PRIX64); + } else { + field_be("First: 0x%X"); + field_be("Last: 0x%X"); } }); } @@ -778,50 +813,14 @@ Sec_Hover_Info get_section_hover_info(Arena *arena, Section section, u64 off, co } break; case Sec_TFile_Info: { - hover.tkey() - hover.maybe_rootzip() - // || hover.field("Byte Count: %u", [] (Arena *arena, String8_Node *prev, const char *fmt, u32 x) { - // x = bswap(x); - // x -= 0x400000000; - // return push_str8_node_child(arena, prev, fmt, x); - // }) - // || hover.field_be("Version: %u") - // || hover_try_object(hover) - // || hover.field_be("Name: %u") - // || hover.field_be("N Objects: %u") - || hover.range("Payload", section.range.len) // TODO: improve - ; - } break; - - case Sec_TFile_FreeList: { - if (!hover.tkey()) { - u16 version_be; - memcpy(&version_be, data + start + hover.cur_field_off, sizeof(u16)); - u32 version = bswap(version_be); - b8 is_big = version > 1000; - - if (is_big) { - 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_be("First: 0x%" PRIX64) - || hover.field_be("Last: 0x%" PRIX64) - ; - } else { - hover.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); - }) - || hover.field_be("First: 0x%X") - || hover.field_be("Last: 0x%X") - ; - } - } + hover.tfile_info(); } break; #endif + case Sec_TFile_FreeList: { + hover.tfile_freelist(); + } break; + default:; }