190 lines
6.3 KiB
C++
190 lines
6.3 KiB
C++
internal
|
|
Term_Viewer make_term_viewer()
|
|
{
|
|
Term_Viewer viewer {};
|
|
viewer.col_key = ACol_Green;
|
|
viewer.col_page_start = ACol_Bright_Magenta;
|
|
viewer.col_checksum = ACol_Yellow;
|
|
viewer.col_highlight = ACol_Bright_White;
|
|
viewer.col_section[Sec_RNTuple_Anchor] = ACol_Bright_Yellow;
|
|
viewer.col_section[Sec_RNTuple_Header] = ACol_Cyan;
|
|
viewer.col_section[Sec_RNTuple_Footer] = ACol_Blue;
|
|
viewer.col_section[Sec_TFile_Header] = ACol_White;
|
|
viewer.col_section[Sec_TFile_Object] = ACol_Grey;
|
|
viewer.col_section[Sec_TFile_Info] = ACol_Red;
|
|
viewer.col_section[Sec_TFile_FreeList] = ACol_Bright_Yellow;
|
|
viewer.col_section[Sec_Page] = ACol_Magenta;
|
|
viewer.col_section[Sec_Page_List] = ACol_Bright_Cyan;
|
|
viewer.col_section[Sec_TKey_List] = ACol_Bright_Green;
|
|
return viewer;
|
|
}
|
|
|
|
internal
|
|
Ansi_Color ansi_color_for_offset(u64 off, App_State &app, const Term_Viewer &viewer)
|
|
{
|
|
off += app.base_display_addr;
|
|
|
|
Section section = find_section(app, off);
|
|
|
|
if (section.highlighted) return viewer.col_highlight;
|
|
if (section.id == Sec_Page && off == section.range.start) return viewer.col_page_start;
|
|
if (off < section.range.start) return viewer.col_key;
|
|
if (section.range.end() - section.post_size <= off && off < section.range.end()) return viewer.col_checksum;
|
|
return viewer.col_section[section.id];
|
|
}
|
|
|
|
internal
|
|
String8 render_legend_to_string(Arena *arena, const Term_Viewer &viewer, const App_State &app)
|
|
{
|
|
Temp scratch = scratch_begin(&arena, 1);
|
|
defer { scratch_end(scratch); };
|
|
|
|
struct String8_Node {
|
|
String8_Node *next;
|
|
String8 str;
|
|
} *head = nullptr, *tail = nullptr;
|
|
|
|
String8 color_none = ansi_color_table[ACol_None];
|
|
u64 tot_len = 0;
|
|
for (u64 section = 1; section < Sec_COUNT; ++section) {
|
|
Ansi_Color color = viewer.col_section[section];
|
|
String8 color_str = ansi_color_table[color];
|
|
String8 sec_name = section_names[section];
|
|
Byte_Range range = get_section_range(app, static_cast<Section_Id>(section));
|
|
String8 s;
|
|
if (range.len)
|
|
s = push_str8f(scratch.arena, "%s%20s %s0x%lX - 0x%lX [%lu B]\n",
|
|
color_str.c(), sec_name.c(), color_none.c(),
|
|
range.start, range.end(), range.len);
|
|
else if (section == Sec_Page)
|
|
s = push_str8f(scratch.arena, "%s%20s %s(%lu) [%lu B] \n",
|
|
color_str.c(), sec_name.c(), color_none.c(), app.rndata.n_pages, app.rndata.tot_page_size);
|
|
else if (section == Sec_Page_List)
|
|
s = push_str8f(scratch.arena, "%s%20s %s(%lu) [%lu B]\n",
|
|
color_str.c(), sec_name.c(), color_none.c(), app.rndata.n_cluster_groups, app.rndata.tot_page_list_size);
|
|
String8_Node *node = arena_push<String8_Node>(scratch.arena);
|
|
node->str = s;
|
|
if (!tail) {
|
|
head = node;
|
|
} else {
|
|
tail->next = node;
|
|
}
|
|
tail = node;
|
|
tot_len += s.size;
|
|
}
|
|
|
|
String8 legend { arena_push_array_nozero<u8>(arena, tot_len + 1), tot_len + 1 };
|
|
legend.str[tot_len] = 0;
|
|
u64 cur_size = 0;
|
|
|
|
for (String8_Node *node = head; node; node = node->next) {
|
|
memcpy(legend.str + cur_size, node->str.str, node->str.size);
|
|
cur_size += node->str.size;
|
|
}
|
|
|
|
return legend;
|
|
}
|
|
|
|
internal
|
|
String8 render_range_to_string(Arena *arena, App_State &app, u64 len, u64 n_cols)
|
|
{
|
|
Term_Viewer viewer = make_term_viewer();
|
|
|
|
String8 legend = render_legend_to_string(arena, viewer, app);
|
|
|
|
// scratch must be created after `render_legend_to_string`
|
|
Temp scratch = scratch_begin(&arena, 1);
|
|
defer { scratch_end(scratch); };
|
|
|
|
String8 ntpl_desc = rntuple_description(scratch.arena, app.rndata);
|
|
String8 header_str = push_str8f(scratch.arena, "RNTuple '%s' (%s) from file \"%s\"",
|
|
app.ntpl_name.c(), ntpl_desc.c(), app.inspected_file.name.c());
|
|
|
|
if (n_cols == 0)
|
|
n_cols = 32;
|
|
u64 n_lines = len / n_cols;
|
|
u64 max_addr = app.inspected_file.size;
|
|
|
|
// Calculate how much space do we need to fix line addr numbers.
|
|
// The biggest address is gonna take up the most space
|
|
const f32 RECP_LOG_16 = 0.360673760222f;
|
|
// NOTE: +1 for the ":"
|
|
u64 max_addr_len = 1 + ceilf(logf(max_addr + 1) * RECP_LOG_16);
|
|
const u64 n_spaces_after_line_addr = 3;
|
|
u64 line_addr_size = (max_addr_len + n_spaces_after_line_addr) * n_lines;
|
|
String8 line_addr_fmt = push_str8f(scratch.arena, "%%0%dlX:", max_addr_len - 1);
|
|
|
|
// NOTE: +3 because we need 2 chars for each byte + 1 whitespace.
|
|
u64 buf_size = (ACOL_MAX_LEN + 3) * len;
|
|
buf_size += n_lines; // one newline per line
|
|
buf_size += n_lines * ACOL_MAX_LEN; // reset color every line
|
|
buf_size += line_addr_size;
|
|
buf_size += 1; // initial newline
|
|
buf_size += header_str.size;
|
|
buf_size += 2; // two newlines after header
|
|
buf_size += 2; // two newlines before legend
|
|
buf_size += legend.size;
|
|
buf_size += 1; // trailing zero
|
|
char *buf = arena_push_array_nozero<char>(arena, buf_size);
|
|
buf[len] = 0;
|
|
|
|
u64 start = app.base_display_addr;
|
|
|
|
// We need to properly initialize this before calling mem_edit_bg_color_fn!
|
|
app.last_pinfo = &invalid_pinfo;
|
|
|
|
const u8 *data = app.inspected_file.mem;
|
|
assert(start <= max_addr);
|
|
len = min(len, max_addr - start);
|
|
|
|
char *cur = buf;
|
|
*cur++ = '\n';
|
|
|
|
// header
|
|
memcpy(cur, header_str.str, header_str.size);
|
|
cur += header_str.size;
|
|
*cur++ = '\n';
|
|
*cur++ = '\n';
|
|
|
|
// first line addr
|
|
cur += sprintf(cur, line_addr_fmt.c(), start);
|
|
for (u32 i = 0; i < n_spaces_after_line_addr; ++i)
|
|
*cur++ = ' ';
|
|
|
|
String8 col_none = ansi_color_table[ACol_None];
|
|
|
|
for (u64 i = 0; i < len; ++i) {
|
|
u64 off = start + i;
|
|
|
|
/// Select color
|
|
Ansi_Color acol = ansi_color_for_offset(i, app, viewer);
|
|
String8 acol_str = ansi_color_table[acol];
|
|
memcpy(cur, acol_str.str, acol_str.size);
|
|
cur += acol_str.size;
|
|
|
|
/// Write the human-readable byte
|
|
cur += sprintf(cur, "%02X ", data[off]);
|
|
|
|
// new line
|
|
if ((i + 1) % n_cols == 0) {
|
|
*cur++ = '\n';
|
|
memcpy(cur, col_none.c(), col_none.size);
|
|
cur += col_none.size;
|
|
cur += sprintf(cur, line_addr_fmt.c(), off + 1);
|
|
for (u32 i = 0; i < n_spaces_after_line_addr; ++i)
|
|
*cur++ = ' ';
|
|
}
|
|
|
|
assert((u64)(cur - buf) < (u64)buf_size);
|
|
}
|
|
|
|
*cur++ = '\n';
|
|
*cur++ = '\n';
|
|
memcpy(cur, legend.str, legend.size);
|
|
cur += legend.size;
|
|
|
|
*cur++ = 0;
|
|
u64 len_used = (u64)(cur - buf);
|
|
|
|
return { (u8 *)buf, len_used };
|
|
}
|