Compare commits

...

5 commits

Author SHA1 Message Date
silverweed
7be716aa5e tkeys list still not working 2024-09-27 17:18:03 +02:00
silverweed
76d5cdf433 fix(??) ntuple_footer hover 2024-09-27 17:10:53 +02:00
silverweed
55983fb292 update README 2024-09-27 16:33:46 +02:00
silverweed
bb4e43a901 formatting 2024-09-27 16:31:21 +02:00
silverweed
9ecc970aff fix rootzip 2024-09-27 16:23:50 +02:00
9 changed files with 237 additions and 174 deletions

View file

@ -10,8 +10,7 @@ $ git clone --recurse-submodules <repo_url>
``` ```
### Dependencies ### Dependencies
rntviewer currently only fully works on Linux, with the terminal-only version working rntviewer currently only fully works on Linux, with the terminal-only version working on MacOS as well.
on MacOS as well (PRs welcome).
The dependencies are: The dependencies are:
- GLFW3 (`libglfw3-dev` on debian, `glfw-devel` on fedora, `glfw` on arch) - GLFW3 (`libglfw3-dev` on debian, `glfw-devel` on fedora, `glfw` on arch)
@ -20,7 +19,7 @@ The dependencies are:
Other than those, rntviewer depends on Dear ImGui and GLAD (both included in the source tree). Other than those, rntviewer depends on Dear ImGui and GLAD (both included in the source tree).
The machine must support OpenGL 3.3 or higher. For the graphical version, the OS must support OpenGL 3.3 or higher.
For the terminal-only version you don't need GLFW3, ImGui or OpenGL support. For the terminal-only version you don't need GLFW3, ImGui or OpenGL support.

View file

@ -124,12 +124,15 @@ using Display_Range_Fn = String8_Node *(*)(Arena *, String8_Node *, const char *
enum Hover_Section_Flags { enum Hover_Section_Flags {
HoverSec_None = 0, HoverSec_None = 0,
// Hide = don't show at all, even the title
HoverSec_HideIfNotHovered = 1, HoverSec_HideIfNotHovered = 1,
// Collapse = only show the title
HoverSec_CollapseIfNotHovered = 2,
}; };
// Functor used by get_section_hover_info to describe the structure of a section and print data about it. // Functor used by get_section_hover_info to describe the structure of a section and print data about it.
struct Sec_Hover_Fn { struct Sec_Hover_Fn {
u64 off; // the offset relative to the start of `data` u64 off; // the hovered offset relative to the start of `data`
const u8 *data; // the entire file data const u8 *data; // the entire file data
const Section &section; const Section &section;
Arena *arena; Arena *arena;
@ -139,6 +142,20 @@ struct Sec_Hover_Fn {
u8 cur_section_nesting = 0; u8 cur_section_nesting = 0;
u8 innermost_section_highlighted = 0; u8 innermost_section_highlighted = 0;
template <typename T>
b8 read(T *val, u64 offset, u64 *size = nullptr) const
{
u64 nb = size ? *size : sizeof(T);
if (offset + nb > section.range.end()) {
fprintf(stderr, "Trying to read bytes 0x%" PRIX64 "-0x%" PRIX64 " which are past the end of the section 0x%" PRIX64 "!\n",
offset, offset + nb, section.range.end());
return false;
}
memcpy(val, data + offset, nb);
return true;
}
template <typename F> template <typename F>
void titled_section(const char *title, F &&sec_body_fn, u64 flags = 0) void titled_section(const char *title, F &&sec_body_fn, u64 flags = 0)
{ {
@ -150,11 +167,19 @@ struct Sec_Hover_Fn {
sec_body_fn(); sec_body_fn();
assert(cur_field_off >= sec_start); // assert(cur_field_off >= sec_start);
if (cur_field_off < sec_start) {// TEMP DEBUG
fprintf(stderr, "Something wrong going on in %s!\n", title);
return;
}
b8 hovered = off >= sec_start && off <= cur_field_off; b8 hovered = off >= sec_start && off <= cur_field_off;
if (!hovered & (flags & HoverSec_HideIfNotHovered)) { if (!hovered) {
if (flags & HoverSec_HideIfNotHovered)
pop_str8_node_child(prev_desc, info.desc); pop_str8_node_child(prev_desc, info.desc);
else if (flags & HoverSec_CollapseIfNotHovered)
info.desc->first_child = info.desc->last_child = nullptr;
} else if (display_grouped) { } else if (display_grouped) {
// if we're in display_grouped mode, we want to highlight the entire range of the section; // if we're in display_grouped mode, we want to highlight the entire range of the section;
u64 sec_len = cur_field_off - sec_start; u64 sec_len = cur_field_off - sec_start;
@ -186,7 +211,9 @@ struct Sec_Hover_Fn {
b8 hovered = cur_field_off <= off && off < cur_field_off + field_len; b8 hovered = cur_field_off <= off && off < cur_field_off + field_len;
T val; T val;
memcpy(&val, (u8 *)data + cur_field_off, field_len); if (!read(&val, cur_field_off))
return false;
String8_Node *desc = display_val(arena, info.desc, desc_fmt, val); String8_Node *desc = display_val(arena, info.desc, desc_fmt, val);
if (hovered && !display_grouped) if (hovered && !display_grouped)
info.highlighted_desc = desc; info.highlighted_desc = desc;
@ -205,7 +232,9 @@ struct Sec_Hover_Fn {
{ {
// String size can be stored as different types, like u8 (by ROOT I/O) or u32 (by RNTuple). // String size can be stored as different types, like u8 (by ROOT I/O) or u32 (by RNTuple).
TStrSize str_size; TStrSize str_size;
memcpy(&str_size, data + cur_field_off, sizeof(TStrSize)); if (!read(&str_size, cur_field_off))
return;
// DEBUG // DEBUG
if (str_size > 1000) { if (str_size > 1000) {
printf("read str_size = %u at offset 0x%lX!\n", str_size, cur_field_off); printf("read str_size = %u at offset 0x%lX!\n", str_size, cur_field_off);
@ -215,7 +244,10 @@ struct Sec_Hover_Fn {
b8 hovered = cur_field_off <= off && off < cur_field_off + field_len; b8 hovered = cur_field_off <= off && off < cur_field_off + field_len;
u8 *buf = arena_push_array_nozero<u8>(arena, str_size + 1); u8 *buf = arena_push_array_nozero<u8>(arena, str_size + 1);
memcpy(buf, data + cur_field_off + sizeof(TStrSize), str_size); u64 size_to_read = str_size;
if (!read(buf, cur_field_off + sizeof(TStrSize), &size_to_read))
return;
buf[str_size] = 0; buf[str_size] = 0;
String8 s = { buf, str_size }; String8 s = { buf, str_size };
String8_Node *desc = display_val(arena, info.desc, desc_fmt, s); String8_Node *desc = display_val(arena, info.desc, desc_fmt, s);
@ -244,6 +276,8 @@ struct Sec_Hover_Fn {
void range(const char *desc, u64 range_len, Display_Range_Fn display_val = hover_display_generic_range) void range(const char *desc, u64 range_len, Display_Range_Fn display_val = hover_display_generic_range)
{ {
b8 hovered = cur_field_off <= off && off < cur_field_off + range_len; b8 hovered = cur_field_off <= off && off < cur_field_off + range_len;
if (cur_field_off + range_len > section.range.end())
return;
String8_Node *dsc = display_val(arena, info.desc, desc, data + cur_field_off, range_len); String8_Node *dsc = display_val(arena, info.desc, desc, data + cur_field_off, range_len);
if (hovered && !display_grouped) if (hovered && !display_grouped)
info.highlighted_desc = dsc; info.highlighted_desc = dsc;
@ -257,13 +291,15 @@ struct Sec_Hover_Fn {
// Returns true if `was_zipped` was read. // Returns true if `was_zipped` was read.
b8 maybe_rootzip(b8 *was_zipped = nullptr) b8 maybe_rootzip(b8 *was_zipped = nullptr)
{ {
// TODO boundary checks
const u64 range_len = 9; const u64 range_len = 9;
if (cur_field_off + range_len > section.range.end())
return false;
b8 hovered = cur_field_off <= off && off < cur_field_off + range_len; b8 hovered = cur_field_off <= off && off < cur_field_off + range_len;
if (display_val_rootzip(arena, info.desc, "Zipped Block", data + cur_field_off)) { if (display_val_rootzip(arena, info.desc, "Zipped Block", data + cur_field_off)) {
if (display_grouped || hovered) {
if (was_zipped) if (was_zipped)
*was_zipped = true; *was_zipped = true;
if (display_grouped || hovered) {
info.rng = { cur_field_off, range_len }; info.rng = { cur_field_off, range_len };
if (hovered) if (hovered)
info.highlighted_desc = info.desc; info.highlighted_desc = info.desc;
@ -280,7 +316,9 @@ struct Sec_Hover_Fn {
{ {
titled_section(title, [this] { titled_section(title, [this] {
u16 version_be; u16 version_be;
memcpy(&version_be, data + cur_field_off + 4, sizeof(u16)); if (!read(&version_be, cur_field_off + 4))
return;
u32 version = bswap(version_be); u32 version = bswap(version_be);
b8 is_big = version > 1000; b8 is_big = version > 1000;
@ -318,7 +356,7 @@ struct Sec_Hover_Fn {
range("Envelope size: %s", 6, [] (Arena *arena, String8_Node *prev, const char *fmt, const u8 *payload, u64) { range("Envelope size: %s", 6, [] (Arena *arena, String8_Node *prev, const char *fmt, const u8 *payload, u64) {
u64 size; u64 size;
memcpy(&size, payload, 6); memcpy(&size, payload, 6);
return push_str8_node_child(arena, prev, fmt, to_pretty_size(arena, size)); return push_str8_node_child(arena, prev, fmt, to_pretty_size(arena, size).c());
}); });
}); });
} }
@ -326,7 +364,12 @@ struct Sec_Hover_Fn {
enum Frame_Type { enum Frame_Type {
Frame_INVALID, Frame_INVALID,
Frame_Record, Frame_Record,
Frame_List Frame_List,
Frame_COUNT
};
static constexpr const char *frame_type_str[Frame_COUNT] = {
"INVALID", "Record", "List"
}; };
Frame_Type frame_header(u64 &size, u32 *n_items = nullptr, const char *title = nullptr) Frame_Type frame_header(u64 &size, u32 *n_items = nullptr, const char *title = nullptr)
@ -335,7 +378,11 @@ struct Sec_Hover_Fn {
Frame_Type frame_type = Frame_INVALID; Frame_Type frame_type = Frame_INVALID;
titled_section(titlestr.c(), [this, &frame_type, &frame_size = size, n_items] { titled_section(titlestr.c(), [this, &frame_type, &frame_size = size, n_items] {
i64 size; i64 size;
memcpy(&size, data + cur_field_off, sizeof(size)); if (!read(&size, cur_field_off)) {
frame_size = 0;
frame_type = Frame_INVALID;
return;
}
// Sanity check // Sanity check
if (size > 1000000) { if (size > 1000000) {
fprintf(stderr, "Frame size read at 0x%" PRIX64 " looks bogus" fprintf(stderr, "Frame size read at 0x%" PRIX64 " looks bogus"
@ -357,7 +404,11 @@ struct Sec_Hover_Fn {
frame_type = Frame_INVALID; frame_type = Frame_INVALID;
} else { } else {
frame_type = Frame_List; frame_type = Frame_List;
memcpy(n_items, data + cur_field_off + sizeof(i64), sizeof(u32)); if (!read(n_items, cur_field_off + sizeof(i64))) {
frame_size = 0;
frame_type = Frame_INVALID;
return;
}
field<i64>("List frame size: %" PRIi64 " B", hover_display_val_le_abs<i64>); field<i64>("List frame size: %" PRIi64 " B", hover_display_val_le_abs<i64>);
field_le<u32>("List frame n.items: %u"); field_le<u32>("List frame n.items: %u");
} }
@ -399,7 +450,7 @@ struct Sec_Hover_Fn {
field_str8<u32>("Type Name: %s"); field_str8<u32>("Type Name: %s");
field_str8<u32>("Type Alias: %s"); field_str8<u32>("Type Alias: %s");
field_str8<u32>("Description: %s"); field_str8<u32>("Description: %s");
}, HoverSec_HideIfNotHovered); });
} }
void column_desc(const char *title) void column_desc(const char *title)
@ -424,13 +475,15 @@ struct Sec_Hover_Fn {
field_le<double>("Value Min: %f"); field_le<double>("Value Min: %f");
field_le<double>("Value Max: %f"); field_le<double>("Value Max: %f");
} }
}, HoverSec_HideIfNotHovered); });
} }
void schema_description(const char *title) void schema_description(const char *title)
{ {
titled_section(title, [this] { titled_section(title, [this] {
frame<Frame_List>("Fields", [this] (u32 idx) { field_desc(push_str8f(arena, "Field %u", idx).c()); }); frame<Frame_List>("Fields", [this] (u32 idx) {
field_desc(push_str8f(arena, "Field %u", idx).c());
});
frame<Frame_List>("Columns", [this] (u32 idx) { column_desc(push_str8f(arena, "Column %u", idx).c()); }); frame<Frame_List>("Columns", [this] (u32 idx) { column_desc(push_str8f(arena, "Column %u", idx).c()); });
frame<Frame_List>("Alias Columns", [this] (u32 idx) { frame<Frame_List>("Alias Columns", [this] (u32 idx) {
frame<Frame_Record>(push_str8f(arena, "Alias Column %u", idx).c(), [this] { frame<Frame_Record>(push_str8f(arena, "Alias Column %u", idx).c(), [this] {
@ -504,7 +557,7 @@ struct Sec_Hover_Fn {
void cluster_group() void cluster_group()
{ {
frame<Frame_List>("Cluster Group", [this] (u32) { frame<Frame_Record>("Cluster Group", [this] {
field_le<u64>("Min Entry: %" PRIu64); field_le<u64>("Min Entry: %" PRIu64);
field_le<u64>("Entry Span: %" PRIu64); field_le<u64>("Entry Span: %" PRIu64);
field_le<u32>("N Clusters: %u"); field_le<u32>("N Clusters: %u");
@ -545,7 +598,7 @@ struct Sec_Hover_Fn {
b8 has_checksum = n_elems < 0; b8 has_checksum = n_elems < 0;
push_str8_node_child(arena, info.desc, "Has Checksum: %s", has_checksum ? "yes" : "no"); push_str8_node_child(arena, info.desc, "Has Checksum: %s", has_checksum ? "yes" : "no");
locator("Element Locator"); locator("Element Locator");
}, HoverSec_HideIfNotHovered); });
} }
i64 n_cols; i64 n_cols;
@ -561,12 +614,12 @@ struct Sec_Hover_Fn {
if (n_cols >= 0) if (n_cols >= 0)
field_le<i32>("Compression Settings: %d"); field_le<i32>("Compression Settings: %d");
}); });
}, HoverSec_HideIfNotHovered); });
}); });
} }
template <Frame_Type FType, typename F> template <Frame_Type FType, typename F>
void frame(const char *title, F &&frame_body_fn, u64 sec_flags = 0) void frame(const char *title, F &&frame_body_fn, u64 sec_flags = HoverSec_CollapseIfNotHovered)
{ {
u64 start_off = cur_field_off; u64 start_off = cur_field_off;
u64 size; u64 size;
@ -574,8 +627,11 @@ struct Sec_Hover_Fn {
titled_section(title, [this, title, start_off, &size, &frame_body_fn] { titled_section(title, [this, title, start_off, &size, &frame_body_fn] {
u32 n_items = 0; u32 n_items = 0;
Frame_Type ftype = frame_header(size, &n_items); Frame_Type ftype = frame_header(size, &n_items);
if (ftype != FType) if (ftype != FType) {
fprintf(stderr, "Frame %s was supposed to be of type %s but it's of type %s\n",
title, frame_type_str[FType], frame_type_str[ftype]);
return; return;
}
if constexpr (FType == Frame_List) { if constexpr (FType == Frame_List) {
// Sadness here. // Sadness here.
@ -625,7 +681,8 @@ struct Sec_Hover_Fn {
{ {
titled_section("TFile Header", [this] { titled_section("TFile Header", [this] {
u32 root_version_be; u32 root_version_be;
memcpy(&root_version_be, data + cur_field_off + 4, sizeof(u32)); if (!read(&root_version_be, cur_field_off + 4))
return;
u32 root_version = bswap(root_version_be); u32 root_version = bswap(root_version_be);
b8 is_big = root_version > 1000'000; b8 is_big = root_version > 1000'000;
@ -665,7 +722,8 @@ struct Sec_Hover_Fn {
field_str8<u8>("File Title: %s"); field_str8<u8>("File Title: %s");
u16 version_be; u16 version_be;
memcpy(&version_be, data + cur_field_off, sizeof(u16)); if (!read(&version_be, cur_field_off))
return;
u16 version = bswap(version_be); u16 version = bswap(version_be);
b8 is_big = version > 1000; b8 is_big = version > 1000;
@ -721,7 +779,8 @@ struct Sec_Hover_Fn {
titled_section("TFile FreeList", [this] { titled_section("TFile FreeList", [this] {
tkey(); tkey();
u16 version_be; u16 version_be;
memcpy(&version_be, data + cur_field_off, sizeof(u16)); if (!read(&version_be, cur_field_off))
return;
u32 version = bswap(version_be); u32 version = bswap(version_be);
b8 is_big = version > 1000; b8 is_big = version > 1000;
@ -794,7 +853,6 @@ struct Sec_Hover_Fn {
if (zipped) { if (zipped) {
// XXX: why -1? // XXX: why -1?
range("Compressed payload", section.range.len - section.post_size - sizeof(u64) - 1); range("Compressed payload", section.range.len - section.post_size - sizeof(u64) - 1);
field_le<u64>("Checksum: 0x%" PRIX64);
} else { } else {
envelope_preamble(); envelope_preamble();
// NOTE: flags in principle require a more complex handling, but for now they are unused, // NOTE: flags in principle require a more complex handling, but for now they are unused,
@ -804,8 +862,8 @@ struct Sec_Hover_Fn {
field_str8<u32>("Description: %s"); field_str8<u32>("Description: %s");
field_str8<u32>("ROOT version: %s"); field_str8<u32>("ROOT version: %s");
schema_description("Schema Description"); schema_description("Schema Description");
field_le<u64>("Checksum: 0x%" PRIX64);
} }
field_le<u64>("Checksum: 0x%" PRIX64);
}, HoverSec_HideIfNotHovered); }, HoverSec_HideIfNotHovered);
}); });
} }
@ -822,20 +880,23 @@ struct Sec_Hover_Fn {
if (zipped) { if (zipped) {
// XXX: why -1? // XXX: why -1?
range("Payload", section.range.len - section.post_size - sizeof(u64) - 1); range("Payload", section.range.len - section.post_size - sizeof(u64) - 1);
field_le<u64>("Checksum: 0x%" PRIX64);
} else { } else {
envelope_preamble(); envelope_preamble();
// NOTE: flags in principle require a more complex handling, but for now they are unused, // TODO: flags in principle require a more complex handling, but for now they are unused,
// so they're always occupying only 8 bytes. // so they're always occupying only 8 bytes.
field_le<u64>("Flags: 0x%" PRIX64); field_le<u64>("Flags: 0x%" PRIX64);
field_le<u64>("Header checksum: 0x%" PRIX64); field_le<u64>("Header checksum: 0x%" PRIX64);
frame<Frame_Record>("Schema Extension", [this] {
schema_description("Schema Extension"); schema_description("Schema Extension");
// NOTE: Column groups are currently unused, so this should always be empty });
frame<Frame_List>("Column Groups", [] (u32) {}); frame<Frame_List>("Column Groups", [this] (u32) {
frame<Frame_List>("Cluster Groups", [this] (u32) { cluster_group(); }); field_le<u32>("Column Id: %u");
range("Payload", section.range.len - cur_field_off); });
field_le<u64>("Checksum: 0x%" PRIX64); frame<Frame_List>("Cluster Groups", [this] (u32) {
cluster_group();
});
} }
field_le<u64>("Checksum: 0x%" PRIX64);
}, HoverSec_HideIfNotHovered); }, HoverSec_HideIfNotHovered);
}); });
} }
@ -863,13 +924,13 @@ struct Sec_Hover_Fn {
if (zipped) { if (zipped) {
// XXX: why -1? // XXX: why -1?
range("Payload", section.range.len - section.post_size - sizeof(u64) - 1); range("Payload", section.range.len - section.post_size - sizeof(u64) - 1);
field_le<u64>("Checksum: 0x%" PRIX64);
} else { } else {
envelope_preamble(); envelope_preamble();
field_le<u64>("Header checksum: 0x%" PRIX64); field_le<u64>("Header checksum: 0x%" PRIX64);
frame<Frame_List>("Cluster Summaries", [this] (u32) { cluster_summary(); }); frame<Frame_List>("Cluster Summaries", [this] (u32) { cluster_summary(); });
frame<Frame_List>("Clusters", [this] (u32) { cluster(); }); frame<Frame_List>("Clusters", [this] (u32) { cluster(); });
} }
field_le<u64>("Checksum: 0x%" PRIX64);
}, HoverSec_HideIfNotHovered); }, HoverSec_HideIfNotHovered);
}); });
} }
@ -938,6 +999,7 @@ Sec_Hover_Info get_section_hover_info(Arena *arena, Section section, u64 off, co
break; break;
case Sec_TKey_List: case Sec_TKey_List:
printf("0x%lX - 0x%lX (pre %lu)\n", section.range.start, section.range.end(), section.pre_size);
hover.tkey_list(); hover.tkey_list();
break; break;

View file

@ -618,7 +618,9 @@ Section find_section(App_State &app, u64 off, i64 hilite_cluster = -1)
if (rdata.rng_tkeys_list.start <= off && off < rdata.rng_tkeys_list.end()) { if (rdata.rng_tkeys_list.start <= off && off < rdata.rng_tkeys_list.end()) {
sec.id = Sec_TKey_List; sec.id = Sec_TKey_List;
sec.range = rdata.rng_tkeys_list; sec.range = rdata.rng_tkeys_list;
sec.pre_size = rblob_sz; // FIXME!
// sec.range.len += rblob_sz;
// printf("with rblob_sz: 0x%lX\n", sec.range.end());
return sec; return sec;
} }