major refactor
This commit is contained in:
parent
9f358b56bf
commit
a0aa6a8d36
1 changed files with 438 additions and 364 deletions
802
src/hover.cpp
802
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 <typename T>
|
||||
using Display_Fn = String8_Node *(*)(Arena *, String8_Node *, const char *, T);
|
||||
|
||||
template <typename T>
|
||||
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 <typename F>
|
||||
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 <typename T>
|
||||
b8 field(const char *desc_fmt, Display_Fn<T> display_val, T *val_read = nullptr) const
|
||||
b8 field(const char *desc_fmt, Display_Fn<T> display_val, T *val_read = nullptr)
|
||||
{
|
||||
static_assert(!std::is_same_v<T, String8>, "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<T>(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 <typename TStrSize>
|
||||
b8 field_str8(const char *desc_fmt, Display_Fn<String8> display_val = hover_display_val_str8) const
|
||||
void field_str8(const char *desc_fmt, Display_Fn<String8> 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<u8>(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 <typename T>
|
||||
b8 field_be(const char *desc_fmt) const
|
||||
b8 field_be(const char *desc_fmt, T *val_read = nullptr)
|
||||
{
|
||||
return field<T>(desc_fmt, hover_display_val_be<T>);
|
||||
return field<T>(desc_fmt, hover_display_val_be<T>, val_read);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
b8 field_le(const char *desc_fmt) const
|
||||
b8 field_le(const char *desc_fmt, T *val_read = nullptr)
|
||||
{
|
||||
return field<T>(desc_fmt, hover_display_val_le<T>);
|
||||
return field<T>(desc_fmt, hover_display_val_le<T>, 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<const u8 *> 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<const u8 *> 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<u32>("NBytes: %u")
|
||||
|| field<u16>("Version: %u", [] (Arena *arena, String8_Node *prev, const char *fmt, u16 x) {
|
||||
field_be<u32>("NBytes: %u");
|
||||
field<u16>("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<u32>("Obj Len: %u")
|
||||
|| field<u32>("Datetime: ", hover_display_datetime_str)
|
||||
|| field_be<u16>("Key Len: %u")
|
||||
|| field_be<u16>("Cycle: %u")
|
||||
|| field_be<u64>("Seek Key: 0x%" PRIX64)
|
||||
|| field_be<u64>("Seek Pdir: 0x%" PRIX64)
|
||||
|| field_str8<u8>("Class Name: %s")
|
||||
|| field_str8<u8>("Obj Name: %s")
|
||||
|| field_str8<u8>("Obj Title: %s")
|
||||
;
|
||||
});
|
||||
field_be<u32>("Obj Len: %u");
|
||||
field<u32>("Datetime: ", hover_display_datetime_str);
|
||||
field_be<u16>("Key Len: %u");
|
||||
field_be<u16>("Cycle: %u");
|
||||
field_be<u64>("Seek Key: 0x%" PRIX64);
|
||||
field_be<u64>("Seek Pdir: 0x%" PRIX64);
|
||||
field_str8<u8>("Class Name: %s");
|
||||
field_str8<u8>("Obj Name: %s");
|
||||
field_str8<u8>("Obj Title: %s");
|
||||
} else {
|
||||
return field_be<u32>("NBytes: %u")
|
||||
|| field<u16>("Version: %u", [] (Arena *arena, String8_Node *prev, const char *fmt, u16 x) {
|
||||
field_be<u32>("NBytes: %u");
|
||||
field<u16>("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<u32>("Obj Len: %u")
|
||||
|| field<u32>("Datetime: ", hover_display_datetime_str)
|
||||
|| field_be<u16>("Key Len: %u")
|
||||
|| field_be<u16>("Cycle: %u")
|
||||
|| field_be<u32>("Seek Key: 0x%" PRIX64)
|
||||
|| field_be<u32>("Seek Pdir: 0x%" PRIX64)
|
||||
|| field_str8<u8>("Class Name: %s")
|
||||
|| field_str8<u8>("Obj Name: %s")
|
||||
|| field_str8<u8>("Obj Title: %s")
|
||||
;
|
||||
});
|
||||
field_be<u32>("Obj Len: %u");
|
||||
field<u32>("Datetime: ", hover_display_datetime_str);
|
||||
field_be<u16>("Key Len: %u");
|
||||
field_be<u16>("Cycle: %u");
|
||||
field_be<u32>("Seek Key: 0x%" PRIX64);
|
||||
field_be<u32>("Seek Pdir: 0x%" PRIX64);
|
||||
field_str8<u8>("Class Name: %s");
|
||||
field_str8<u8>("Obj Name: %s");
|
||||
field_str8<u8>("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<u16>("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<u16>("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<i64>("Record frame size: %" PRIi64 " B", hover_display_val_le_abs<i64>);
|
||||
else if (roff < cur_field_off + 12) {
|
||||
info.rng = { start + cur_field_off, 12 };
|
||||
b8 ok = titled_section("List Frame", [this] {
|
||||
return field<i64>("Size: %" PRIi64 " B", hover_display_val_le_abs<i64>)
|
||||
|| field_le<u32>("N Items: %u")
|
||||
;
|
||||
if (size >= 0) {
|
||||
frame_type = Frame_Record;
|
||||
field<i64>("Record frame size: %" PRIi64 " B", hover_display_val_le_abs<i64>);
|
||||
} 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<i64>("Size: %" PRIi64 " B", hover_display_val_le_abs<i64>);
|
||||
field_le<u32>("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<i64>("Size: %" PRIi64 " B")
|
||||
|| field_le<u32>("Field version: %u")
|
||||
|| field_le<u32>("Type version: %u")
|
||||
|| field_le<u32>("On-disk parent id: %u")
|
||||
|| field<u16>("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<u16>("Flags: 0b%b", hover_display_val_le, &flags);
|
||||
|
||||
if (flags & RNTupleSerializer::kFlagRepetitiveField)
|
||||
ok = ok || field_le<u64>("N Repetitions: %" PRIu64);
|
||||
if (flags & RNTupleSerializer::kFlagProjectedField)
|
||||
ok = ok || field_le<u32>("On disk proj.src id: %u");
|
||||
if (flags & RNTupleSerializer::kFlagHasTypeChecksum)
|
||||
ok = ok || field_le<u32>("Checksum: %u");
|
||||
|
||||
ok = ok || field_str8<u32>("Name: %s")
|
||||
|| field_str8<u32>("Type Name: %s")
|
||||
|| field_str8<u32>("Type Alias: %s")
|
||||
|| field_str8<u32>("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<u32>("Field version: %u");
|
||||
field_le<u32>("Type version: %u");
|
||||
field_le<u32>("On-disk parent id: %u");
|
||||
field<u16>("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<u16>("Flags: 0b%b", hover_display_val_le, &flags))
|
||||
return;
|
||||
|
||||
if (flags & RNTupleSerializer::kFlagRepetitiveField)
|
||||
field_le<u64>("N Repetitions: %" PRIu64);
|
||||
if (flags & RNTupleSerializer::kFlagProjectedField)
|
||||
field_le<u32>("On disk proj.src id: %u");
|
||||
if (flags & RNTupleSerializer::kFlagHasTypeChecksum)
|
||||
field_le<u32>("Checksum: %u");
|
||||
|
||||
field_str8<u32>("Name: %s");
|
||||
field_str8<u32>("Type Name: %s");
|
||||
field_str8<u32>("Type Alias: %s");
|
||||
field_str8<u32>("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<i64>("Size: %" PRIi64 " B")
|
||||
|| field<u16>("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<u16>("Bits on storage: %u")
|
||||
|| field_le<u32>("Field ID: %u")
|
||||
;
|
||||
if (ok)
|
||||
return true;
|
||||
|
||||
u16 flags;
|
||||
ok = field<u16>("Flags: 0b%b", hover_display_val_le, &flags);
|
||||
ok = ok || field_le<u16>("Representation idx: %u");
|
||||
if (flags & RNTupleSerializer::kFlagDeferredColumn)
|
||||
ok = ok || field_le<u64>("First element: %" PRIu64);
|
||||
if (flags & RNTupleSerializer::kFlagHasValueRange) {
|
||||
ok = ok || field_le<double>("Value Min: %f")
|
||||
|| field_le<double>("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<i64>("Size: %" PRIi64 " B");
|
||||
field<u16>("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<u16>("Bits on storage: %u");
|
||||
field_le<u32>("Field ID: %u");
|
||||
|
||||
u16 flags;
|
||||
if (!field<u16>("Flags: 0b%b", hover_display_val_le, &flags))
|
||||
return;
|
||||
|
||||
field_le<u16>("Representation idx: %u");
|
||||
if (flags & RNTupleSerializer::kFlagDeferredColumn) {
|
||||
field_le<u64>("First element: %" PRIu64);
|
||||
}
|
||||
if (flags & RNTupleSerializer::kFlagHasValueRange) {
|
||||
field_le<double>("Value Min: %f");
|
||||
field_le<double>("Value Max: %f");
|
||||
}
|
||||
u64 extra_size = size - (cur_field_off - start_off);
|
||||
if (extra_size > 0)
|
||||
range("Unknown", extra_size);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
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<u32>("Content identifier: %lu")
|
||||
|| field_le<u32>("Type version from: %lu")
|
||||
|| field_le<u32>("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<u32>("Content identifier: %lu");
|
||||
field_le<u32>("Type version from: %lu");
|
||||
field_le<u32>("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<u64>("Min Entry: %" PRIu64);
|
||||
field_le<u64>("Entry Span: %" PRIu64);
|
||||
field_le<u32>("N Clusters: %u");
|
||||
field_le<u64>("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<u64>("Min Entry: %" PRIu64)
|
||||
|| field_le<u64>("Entry Span: %" PRIu64)
|
||||
|| field_le<u32>("N Clusters: %u")
|
||||
|| field_le<u64>("Env.Link Len: %" PRIu64)
|
||||
|| locator("Env.Link Locator")
|
||||
;
|
||||
titled_section("RNTuple Anchor", [this] {
|
||||
tkey();
|
||||
titled_section("Data", [this] {
|
||||
field<u32>("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<u16>("Class version: %u");
|
||||
field_be<u16>("Version Epoch: %u");
|
||||
field_be<u16>("Version Major: %u");
|
||||
field_be<u16>("Version Minor: %u");
|
||||
field_be<u16>("Version Patch: %u");
|
||||
field_be<u64>("Seek Header: 0x%" PRIX64);
|
||||
field_be<u64>("NBytes Header: %u");
|
||||
field_be<u64>("Len Header: %u");
|
||||
field_be<u64>("Seek Footer: 0x%" PRIX64);
|
||||
field_be<u64>("NBytes Footer: %u");
|
||||
field_be<u64>("Len Footer: %u");
|
||||
field_be<u64>("Max Key Size: %u");
|
||||
field_le<u64>("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<u64>("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<u64>("Flags: 0x%" PRIX64);
|
||||
field_str8<u32>("Name: %s");
|
||||
field_str8<u32>("Description: %s");
|
||||
field_str8<u32>("ROOT version: %s");
|
||||
schema_description("Schema Description");
|
||||
field_le<u64>("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<u64>("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<u64>("Flags: 0x%" PRIX64);
|
||||
field_le<u64>("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<u64>("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<u32>("ROOT magic number");
|
||||
field<u32>("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<u32>("fBEGIN: 0x%" PRIX64);
|
||||
field_be<u64>("fEND: 0x%" PRIX64);
|
||||
field_be<u64>("Seek Free: 0x%" PRIX64);
|
||||
field_be<u32>("NBytes Free: %u");
|
||||
field_be<u32>("N Free: %u");
|
||||
field_be<u32>("NBytes Name: %u");
|
||||
field_be<u8>("Units: %u");
|
||||
field_be<u32>("Compression: %u");
|
||||
field_be<u64>("Seek Info: 0x%" PRIX64);
|
||||
field_be<u32>("NBytes Info: %u");
|
||||
range("Padding", section.post_size);
|
||||
} else {
|
||||
field_be<u32>("ROOT magic number");
|
||||
field_be<u32>("ROOT version: %u");
|
||||
field_be<u32>("fBEGIN: 0x%" PRIX64);
|
||||
field_be<u32>("fEND: 0x%" PRIX64);
|
||||
field_be<u32>("Seek Free: 0x%" PRIX64);
|
||||
field_be<u32>("NBytes Free: %u");
|
||||
field_be<u32>("N Free: %u");
|
||||
field_be<u32>("NBytes Name: %u");
|
||||
field_be<u8>("Units: %u");
|
||||
field_be<u32>("Compression: %u");
|
||||
field_be<u32>("Seek Info: 0x%" PRIX64);
|
||||
field_be<u32>("NBytes Info: %u");
|
||||
range("Padding", section.post_size);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void tfile_object()
|
||||
{
|
||||
titled_section("TFile Object", [this] {
|
||||
tkey();
|
||||
field_str8<u8>("File Name: %s");
|
||||
field_str8<u8>("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<u16>("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<u32>("Created: ", hover_display_datetime_str);
|
||||
field<u32>("Modified: ", hover_display_datetime_str);
|
||||
field_be<u32>("NBytes Key: %u");
|
||||
field_be<u32>("NBytes Name: %u");
|
||||
field_be<u64>("Seek Dir: 0x%" PRIX64) ;
|
||||
field_be<u64>("Seek Parent: 0x%" PRIX64) ;
|
||||
field_be<u64>("Seek Keys: 0x%" PRIX64) ;
|
||||
field_be<u16>("UUID Vers.Class: %u");
|
||||
field_le<u16>("UUID: %u");
|
||||
} else {
|
||||
field_be<u16>("Version: %u");
|
||||
field<u32>("Created: ", hover_display_datetime_str);
|
||||
field<u32>("Modified: ", hover_display_datetime_str);
|
||||
field_be<u32>("NBytes Key: %u");
|
||||
field_be<u32>("NBytes Name: %u");
|
||||
field_be<u32>("Seek Dir: 0x%" PRIX64) ;
|
||||
field_be<u32>("Seek Parent: 0x%" PRIX64) ;
|
||||
field_be<u32>("Seek Keys: 0x%" PRIX64) ;
|
||||
field_be<u16>("UUID Vers.Class: %u");
|
||||
field_le<u16>("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<u32>("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<u16>("Class version: %u")
|
||||
|| hover.field_be<u16>("Version Epoch: %u")
|
||||
|| hover.field_be<u16>("Version Major: %u")
|
||||
|| hover.field_be<u16>("Version Minor: %u")
|
||||
|| hover.field_be<u16>("Version Patch: %u")
|
||||
|| hover.field_be<u64>("Seek Header: 0x%" PRIX64)
|
||||
|| hover.field_be<u64>("NBytes Header: %u")
|
||||
|| hover.field_be<u64>("Len Header: %u")
|
||||
|| hover.field_be<u64>("Seek Footer: 0x%" PRIX64)
|
||||
|| hover.field_be<u64>("NBytes Footer: %u")
|
||||
|| hover.field_be<u64>("Len Footer: %u")
|
||||
|| hover.field_be<u64>("Max Key Size: %u")
|
||||
|| hover.field_le<u64>("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<u32>("ROOT magic number")
|
||||
|| hover.field<u32>("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<u32>("fBEGIN: 0x%" PRIX64)
|
||||
|| hover.field_be<u64>("fEND: 0x%" PRIX64)
|
||||
|| hover.field_be<u64>("Seek Free: 0x%" PRIX64)
|
||||
|| hover.field_be<u32>("NBytes Free: %u")
|
||||
|| hover.field_be<u32>("N Free: %u")
|
||||
|| hover.field_be<u32>("NBytes Name: %u")
|
||||
|| hover.field_be<u8>("Units: %u")
|
||||
|| hover.field_be<u32>("Compression: %u")
|
||||
|| hover.field_be<u64>("Seek Info: 0x%" PRIX64)
|
||||
|| hover.field_be<u32>("NBytes Info: %u")
|
||||
|| hover.range("Padding", section.post_size)
|
||||
;
|
||||
} else {
|
||||
hover.field_be<u32>("ROOT magic number")
|
||||
|| hover.field_be<u32>("ROOT version: %u")
|
||||
|| hover.field_be<u32>("fBEGIN: 0x%" PRIX64)
|
||||
|| hover.field_be<u32>("fEND: 0x%" PRIX64)
|
||||
|| hover.field_be<u32>("Seek Free: 0x%" PRIX64)
|
||||
|| hover.field_be<u32>("NBytes Free: %u")
|
||||
|| hover.field_be<u32>("N Free: %u")
|
||||
|| hover.field_be<u32>("NBytes Name: %u")
|
||||
|| hover.field_be<u8>("Units: %u")
|
||||
|| hover.field_be<u32>("Compression: %u")
|
||||
|| hover.field_be<u32>("Seek Info: 0x%" PRIX64)
|
||||
|| hover.field_be<u32>("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<u8>("File Name: %s")
|
||||
|| hover.field_str8<u8>("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<u16>("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<u32>("Created: ", hover_display_datetime_str)
|
||||
|| hover.field<u32>("Modified: ", hover_display_datetime_str)
|
||||
|| hover.field_be<u32>("NBytes Key: %u")
|
||||
|| hover.field_be<u32>("NBytes Name: %u")
|
||||
|| hover.field_be<u64>("Seek Dir: 0x%" PRIX64)
|
||||
|| hover.field_be<u64>("Seek Parent: 0x%" PRIX64)
|
||||
|| hover.field_be<u64>("Seek Keys: 0x%" PRIX64)
|
||||
|| hover.field_be<u16>("UUID Vers.Class: %u")
|
||||
|| hover.field_le<u16>("UUID: %u")
|
||||
;
|
||||
} else {
|
||||
ok = ok || hover.field_be<u16>("Version: %u")
|
||||
|| hover.field<u32>("Created: ", hover_display_datetime_str)
|
||||
|| hover.field<u32>("Modified: ", hover_display_datetime_str)
|
||||
|| hover.field_be<u32>("NBytes Key: %u")
|
||||
|| hover.field_be<u32>("NBytes Name: %u")
|
||||
|| hover.field_be<u32>("Seek Dir: 0x%" PRIX64)
|
||||
|| hover.field_be<u32>("Seek Parent: 0x%" PRIX64)
|
||||
|| hover.field_be<u32>("Seek Keys: 0x%" PRIX64)
|
||||
|| hover.field_be<u16>("UUID Vers.Class: %u")
|
||||
|| hover.field_le<u16>("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<u64>("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<u64>("Flags: 0x%" PRIX64)
|
||||
|| hover.field_str8<u32>("Name: %s")
|
||||
|| hover.field_str8<u32>("Description: %s")
|
||||
|| hover.field_str8<u32>("ROOT version: %s")
|
||||
|| hover.schema_description("Schema Description")
|
||||
|| hover.field_le<u64>("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<u64>("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<u64>("Flags: 0x%" PRIX64)
|
||||
|| hover.field_le<u64>("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<u64>("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<u32>("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:;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue