add colors for header/footer

This commit is contained in:
silverweed 2024-07-11 14:00:43 +02:00
parent f683654ba0
commit b9a490d8cc
15 changed files with 309 additions and 147 deletions

3
.gitignore vendored
View file

@ -3,4 +3,5 @@ build/
*.swo *.swo
*.swp *.swp
rntviewer rntviewer
*.gdbhist .gdbhist
.gdb_history

View file

@ -13,7 +13,10 @@ build/imgui.o: src/imgui_inc.cpp third_party/imgui/imgui.h
$(CXX) -O3 -fPIC -c -Ithird_party/imgui $< -o $@ $(CXX) -O3 -fPIC -c -Ithird_party/imgui $< -o $@
d: d:
$(MOLD) $(CXX) -DDEBUG -g -O0 $(CFLAGS) -fsanitize=undefined $(INC) $(ROOTFLAGS) -o rntviewer src/rntviewer.cpp build/imgui.o -lasan $(ROOTLIBS) $(LIBS) $(MOLD) $(CXX) -DDEBUG -g -O0 -DENABLE_ASAN $(CFLAGS) -fsanitize=undefined $(INC) $(ROOTFLAGS) -o rntviewer src/rntviewer.cpp build/imgui.o -lasan $(ROOTLIBS) $(LIBS)
noasan:
$(MOLD) $(CXX) -DDEBUG -g -O0 $(CFLAGS) -fsanitize=undefined $(INC) $(ROOTFLAGS) -o rntviewer src/rntviewer.cpp build/imgui.o $(ROOTLIBS) $(LIBS)
r: r:
$(MOLD) $(CXX) -O2 $(CFLAGS) $(INC) $(ROOTFLAGS) -o rntviewer src/rntviewer.cpp build/imgui.o $(ROOTLIBS) $(LIBS) $(MOLD) $(CXX) -O2 $(CFLAGS) $(INC) $(ROOTFLAGS) -o rntviewer src/rntviewer.cpp build/imgui.o $(ROOTLIBS) $(LIBS)

View file

@ -8,7 +8,7 @@ Size=1152,1414
[Window][main] [Window][main]
Pos=0,0 Pos=0,0
Size=1143,1388 Size=1775,680
[Window][Hex View] [Window][Hex View]
Pos=91,62 Pos=91,62

View file

@ -1,57 +1,23 @@
enum Input_Key {
KEY_UP,
KEY_DOWN,
KEY_LEFT,
KEY_RIGHT,
KEY_Q,
KEY_ALT,
KEY_TAB,
KEY_COUNT
};
enum Mouse_Button {
MOUSE_BTN_LEFT,
MOUSE_BTN_RIGHT,
MOUSE_BTN_COUNT
};
enum Mouse_Button_State : u16 {
MOUSE_BTN_STATE_IS_DOWN = 0x1,
MOUSE_BTN_STATE_JUST_PRESSED = 0x2,
MOUSE_BTN_STATE_JUST_RELEASED = 0x4,
};
enum Key_State : u16 {
KEY_STATE_IS_DOWN = 0x1,
KEY_STATE_JUST_PRESSED = 0x2,
KEY_STATE_JUST_RELEASED = 0x4,
};
struct User_Input {
u16 key_state[KEY_COUNT];
u16 mouse_btn_state[MOUSE_BTN_COUNT];
struct { i32 x; i32 y; } mouse_pos;
};
struct Window_Data {
// Real width and height of the window
i32 width;
i32 height;
bool size_just_changed;
f32 desired_aspect_ratio;
};
struct App_State { struct App_State {
Window_Data win_data; Window_Data win_data;
User_Input user_input; User_Input user_input;
RNTuple_Info *rntinfo;
FILE *inspected_file; FILE *inspected_file;
u8 *inspected_fmem; u8 *inspected_fmem;
u64 inspected_file_size; u64 inspected_file_size;
// @Platform: inotify file descriptor // @Platform: inotify file descriptor
int inot; int inot;
const char *ntpl_name;
}; };
internal
size_t file_size(FILE *f)
{
fseek(f, 0, SEEK_END);
size_t res = ftell(f);
fseek(f, 0, SEEK_SET);
return res;
}

View file

@ -1,12 +1,3 @@
internal
size_t file_size(FILE *f)
{
fseek(f, 0, SEEK_END);
size_t res = ftell(f);
fseek(f, 0, SEEK_SET);
return res;
}
internal internal
void monitor_key(GLFWwindow *window, u16 *key_state, i32 glfw_key, Input_Key haru_key) { void monitor_key(GLFWwindow *window, u16 *key_state, i32 glfw_key, Input_Key haru_key) {
u16& state = key_state[haru_key]; u16& state = key_state[haru_key];

View file

@ -4,7 +4,7 @@
#define SLLStackPush_N(f,n,next) ((n)->next=(f), (f)=(n)) #define SLLStackPush_N(f,n,next) ((n)->next=(f), (f)=(n))
#define SLLStackPop_N(f,next) ((f)=(f)->next) #define SLLStackPop_N(f,next) ((f)=(f)->next)
#ifdef DEBUG #ifdef ENABLE_ASAN
#define asan_poison_memory_region(mem, cmt) __asan_poison_memory_region(mem, cmt) #define asan_poison_memory_region(mem, cmt) __asan_poison_memory_region(mem, cmt)
#define asan_unpoison_memory_region(mem, cmt) __asan_unpoison_memory_region(mem, cmt) #define asan_unpoison_memory_region(mem, cmt) __asan_unpoison_memory_region(mem, cmt)
#else #else
@ -12,27 +12,6 @@
#define asan_unpoison_memory_region(mem, cmt) #define asan_unpoison_memory_region(mem, cmt)
#endif #endif
// @Platform
internal
void *os_reserve(u64 size)
{
return mmap(0, size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
}
// @Platform
internal
void os_release(void *mem, u64 size)
{
munmap(mem, size);
}
// @Platform
internal
b32x os_commit(void *addr, u64 size)
{
return mprotect(addr, size, PROT_READ|PROT_WRITE) == 0;
}
// init_res: initial reserved size // init_res: initial reserved size
// init_cmt: initial committed size // init_cmt: initial committed size
internal internal
@ -143,6 +122,15 @@ T *arena_push(Arena *arena)
return (T *)mem; return (T *)mem;
} }
template <typename T>
internal
T *arena_push_zeroed(Arena *arena)
{
T *mem = arena_push<T>(arena);
memset(mem, 0, sizeof(T));
return mem;
}
template <typename T> template <typename T>
internal internal
T *arena_push_array_no_zero(Arena *arena, u64 count) T *arena_push_array_no_zero(Arena *arena, u64 count)
@ -181,7 +169,7 @@ u64 arena_pos(Arena *arena)
internal internal
void arena_pop_to(Arena *arena, u64 big_pos_unclamped) void arena_pop_to(Arena *arena, u64 big_pos_unclamped)
{ {
u64 big_pos = min(ARENA_HEADER_SIZE, big_pos_unclamped); u64 big_pos = max(ARENA_HEADER_SIZE, big_pos_unclamped);
// unroll the chain // unroll the chain
Arena *current = arena->cur; Arena *current = arena->cur;

65
src/platform_linux.h Normal file
View file

@ -0,0 +1,65 @@
#include <sys/mman.h>
#include <sys/inotify.h>
#include <unistd.h>
#include <limits.h> // for NAME_MAX
internal
void os_open_and_map_file(const char *fname, App_State &app)
{
FILE *file = fopen(fname, "rb");
int fd = fileno(file);
size_t fsize = file_size(file);
void *fmem = mmap(0, fsize, PROT_READ, MAP_SHARED_VALIDATE, fd, 0);
if (!fmem)
fprintf(stderr, "Failed to open file %s\n", fname);
app.inspected_file = file;
app.inspected_file_size = fsize;
app.inspected_fmem = reinterpret_cast<u8*>(fmem);
}
internal
void os_unmap_file(u8 *&mem, u64 size)
{
if (mem) munmap(mem, size);
mem = nullptr;
}
internal
void os_start_file_watch(const char *fname, App_State &app)
{
int inot = inotify_init1(IN_NONBLOCK);
if (inot == -1)
fprintf(stderr, "Failed to init inotify: %s (%d)\n", strerror(errno), errno);
if (inotify_add_watch(inot, fname, IN_MODIFY) == -1)
fprintf(stderr, "Failed to add inotify watch: %s (%d)\n", strerror(errno), errno);
app.inot = inot;
}
internal
void os_stop_file_watch(App_State &app)
{
if (app.inot != -1) close(app.inot);
app.inot = -1;
}
internal
void *os_reserve(u64 size)
{
return mmap(0, size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
}
internal
void os_release(void *mem, u64 size)
{
munmap(mem, size);
}
internal
b32x os_commit(void *addr, u64 size)
{
return mprotect(addr, size, PROT_READ|PROT_WRITE) == 0;
}

View file

@ -1,34 +1,53 @@
internal internal
MemoryEditor make_memory_editor() u32 mem_edit_bg_color_fn(const u8 *data, u64 off, const void *user_data)
{
const RNTuple_Info *ntinfo = reinterpret_cast<const RNTuple_Info *>(user_data);
if (ntinfo->header.start <= off && off <= ntinfo->header.end())
return IM_COL32(200, 0, 50, 255);
if (ntinfo->footer.start <= off && off <= ntinfo->footer.end())
return IM_COL32(50, 0, 200, 255);
return IM_COL32(0, 0, 0, 0);
}
internal
MemoryEditor make_memory_editor(const RNTuple_Info &ntpl_info)
{ {
MemoryEditor mem_edit; MemoryEditor mem_edit;
// mem_edit.ReadOnly = true; // mem_edit.ReadOnly = true;
mem_edit.Cols = 32; mem_edit.Cols = 32;
mem_edit.BgColorFn = mem_edit_bg_color_fn;
mem_edit.BgColorFnUserData = &ntpl_info;
return mem_edit; return mem_edit;
} }
internal internal
void update_and_render(Arena *arena, App_State &app, f32 delta_time) void update_and_render(Arena *arena, App_State &app, f32 delta_time)
{ {
(void)delta_time;
ImGui::SetNextWindowPos({ 0, 0 }); ImGui::SetNextWindowPos({ 0, 0 });
ImGui::SetNextWindowSize({ (f32)app.win_data.width, (f32)app.win_data.height }); ImGui::SetNextWindowSize({ (f32)app.win_data.width, (f32)app.win_data.height });
Temp scratch = temp_begin(arena); Temp scratch = temp_begin(arena);
defer { temp_end(scratch); }; defer { temp_end(scratch); };
u64 text_buf_size = min(app.inspected_file_size * 2, 2048); const u64 inspected_max_size = 2048;
u64 text_buf_size = min(app.inspected_file_size * 2, inspected_max_size);
char *text_buf = arena_push_array_no_zero<char>(scratch.arena, text_buf_size + 1); char *text_buf = arena_push_array_no_zero<char>(scratch.arena, text_buf_size + 1);
// TODO: convert file content to human readable // Convert file content to human readable
// @Speed: maybe do this only when the file changes
for (u64 i = 0; i < text_buf_size / 2; ++i) for (u64 i = 0; i < text_buf_size / 2; ++i)
sprintf(&text_buf[2 * i], "%02X", app.inspected_fmem[i]); sprintf(&text_buf[2 * i], "%02X", app.inspected_fmem[i]);
text_buf[text_buf_size] = 0; text_buf[text_buf_size] = 0;
if (ImGui::Begin("main")) { if (ImGui::Begin("main")) {
// ImGui::SetNextWindowContentSize({ 500, 600 }); ImGui::Text("Inspecting RNTuple '%s' (%s)", app.ntpl_name,
// ImGui::SetCursorX(30); (const char *)rntuple_description(scratch.arena, app.rntinfo->anchor));
// ImGui::TextWrapped("%s", text_buf);
static MemoryEditor mem_edit = make_memory_editor(); static MemoryEditor mem_edit = make_memory_editor(*app.rntinfo);
mem_edit.DrawWindow("Hex View", app.inspected_fmem, app.inspected_file_size); mem_edit.DrawWindow("Hex View", app.inspected_fmem, app.inspected_file_size);
ImGui::End(); ImGui::End();
} }
} }

38
src/rntuple.cpp Normal file
View file

@ -0,0 +1,38 @@
internal
String8 rntuple_description(Arena *arena, const RNTuple &anchor)
{
String8 desc = push_str8f(arena, "version %u.%u.%u.%u",
anchor.GetVersionEpoch(),
anchor.GetVersionMajor(),
anchor.GetVersionMinor(),
anchor.GetVersionPatch());
return desc;
}
internal
RNTuple_Info *get_rntuple_info(Arena *arena, const char *fname, const char *ntpl_name)
{
RNTuple_Info *info = arena_push_zeroed<RNTuple_Info>(arena);
// Open the TFile
TFile *tfile = TFile::Open(fname, "READ");
if (!tfile) {
fprintf(stderr, "Failed to open TFile.\n");
return info;
}
defer { delete tfile; };
// Get the RNTuple information
const RNTuple *anchor = tfile->Get<RNTuple>(ntpl_name);
if (anchor) {
info->anchor = *anchor;
info->header.start = anchor->GetSeekHeader();
info->header.len = anchor->GetNBytesHeader();
info->footer.start = anchor->GetSeekFooter();
info->footer.len = anchor->GetNBytesFooter();
} else {
fprintf(stderr, "RNTuple '%s' not found in %s.\n", ntpl_name, fname);
}
return info;
}

13
src/rntuple.h Normal file
View file

@ -0,0 +1,13 @@
using RNTuple = ROOT::Experimental::RNTuple;
struct Byte_Range {
u64 start, len;
u64 end() const { return start + len; }
};
struct RNTuple_Info {
RNTuple anchor;
Byte_Range header;
Byte_Range footer;
};

View file

@ -6,12 +6,6 @@
#include <cstdint> #include <cstdint>
#include <chrono> #include <chrono>
// @Platform
#include <sys/mman.h>
#include <sys/inotify.h>
#include <unistd.h>
#include <limits.h> // for NAME_MAX
#ifdef DEBUG #ifdef DEBUG
#include <sanitizer/asan_interface.h> #include <sanitizer/asan_interface.h>
#endif #endif
@ -27,11 +21,19 @@
#include "types.h" #include "types.h"
#include "defer.hpp" #include "defer.hpp"
#include "mem.h" #include "mem.h"
#include "str.h"
#include "rntuple.h"
#include "window.h"
#include "app_state.h" #include "app_state.h"
// @Platform
#include "platform_linux.h"
namespace chr = std::chrono; namespace chr = std::chrono;
#include "mem.cpp" #include "mem.cpp"
#include "str.cpp"
#include "rntuple.cpp"
#include "render.cpp" #include "render.cpp"
#include "mainloop.cpp" #include "mainloop.cpp"
@ -86,16 +88,25 @@ GLFWwindow* init_glfw(i32 desired_win_width, i32 desired_win_height)
return window; return window;
} }
internal
void app_cleanup(App_State &app)
{
os_stop_file_watch(app);
os_unmap_file(app.inspected_fmem, app.inspected_file_size);
if (app.inspected_file) fclose(app.inspected_file);
app.inspected_file = nullptr;
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
if (argc < 3) { if (argc > 1 && argv[1][0] == '-') {
fprintf(stderr, "Usage: %s <ntuple_name> <ntuple_file.root>\n", argv[0]); fprintf(stderr, "Usage: %s <ntuple_name> <ntuple_file.root>\n", argv[0]);
return 1; return 1;
} }
// Collect arguments // Collect arguments
const char *ntpl_name = argv[1]; const char *ntpl_name = argc > 1 ? argv[1] : nullptr;
const char *fname = argv[2]; const char *fname = argc > 2 ? argv[2] : nullptr;
// Allocate program memory // Allocate program memory
Arena *arena = arena_alloc(); Arena *arena = arena_alloc();
@ -118,57 +129,22 @@ int main(int argc, char **argv)
return 1; return 1;
} }
// Open and map te file App_State app {};
FILE *file = fopen(fname, "rb"); defer { app_cleanup(app); };
defer { fclose(file); };
int fd = fileno(file); // Open and map the file
size_t fsize = file_size(file); if (fname) {
// @Platform os_open_and_map_file(fname, app);
void *fmem = mmap(0, fsize, PROT_READ, MAP_SHARED_VALIDATE, fd, 0);
if (!fmem) {
fprintf(stderr, "Failed to open file %s\n", fname);
return 1;
}
defer { munmap(fmem, fsize); };
// @Platform: watch file for changes (to adapt the displayed file size - otherwise // Watch file for changes (to adapt the displayed file size - otherwise
// we may try to access invalid memory when the file gets shrunk) // we may try to access invalid memory when the file gets shrunk)
int inot = inotify_init1(IN_NONBLOCK); os_start_file_watch(fname, app);
if (inot == -1) {
fprintf(stderr, "Failed to init inotify: %s (%d)\n", strerror(errno), errno);
return 1;
} }
if (inotify_add_watch(inot, fname, IN_MODIFY) == -1) {
fprintf(stderr, "Failed to add inotify watch: %s (%d)\n", strerror(errno), errno);
return 1;
}
defer { close(inot); };
// Open the TFile app.ntpl_name = ntpl_name;
#if 0 app.rntinfo = get_rntuple_info(arena, fname, ntpl_name);
TFile *tfile = TFile::Open(fname, "READ");
if (!tfile) {
fprintf(stderr, "Failed to open TFile.\n");
return 1;
}
defer { delete tfile; };
// Get the RNTuple information
const RNTuple *anchor = tfile->Get<RNTuple>(ntpl_name);
if (!anchor) {
fprintf(stderr, "RNTuple '%s' not found in %s.\n", ntpl_name, fname);
return 1;
}
#endif
// Start main loop // Start main loop
App_State app {};
app.inspected_file = file;
app.inspected_fmem = (u8*)fmem;
app.inspected_file_size = fsize;
app.inot = inot;
run_main_loop(window, arena, app); run_main_loop(window, arena, app);
return 0; return 0;

22
src/str.cpp Normal file
View file

@ -0,0 +1,22 @@
internal
String8 push_str8fv(Arena *arena, const char *fmt, va_list args)
{
va_list args2;
va_copy(args2, args);
u32 needed_bytes = vsnprintf(0, 0, fmt, args) + 1;
String8 result = {};
result.str = arena_push_array_no_zero<u8>(arena, needed_bytes);
result.size = vsnprintf((char*)result.str, needed_bytes, fmt, args2);
result.str[result.size] = 0;
va_end(args2);
return result;
}
String8 push_str8f(Arena *arena, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
String8 result = push_str8fv(arena, fmt, args);
va_end(args);
return result;
}

12
src/str.h Normal file
View file

@ -0,0 +1,12 @@
struct String8 {
u8* str;
u64 size;
operator const char *() const {
return (const char *)str;
}
};
#define str8(s) String8((u8*)(s), sizeof(s) - 1)
String8 push_str8f(Arena *arena, char *fmt, ...);

47
src/window.h Normal file
View file

@ -0,0 +1,47 @@
enum Input_Key {
KEY_UP,
KEY_DOWN,
KEY_LEFT,
KEY_RIGHT,
KEY_Q,
KEY_ALT,
KEY_TAB,
KEY_COUNT
};
enum Mouse_Button {
MOUSE_BTN_LEFT,
MOUSE_BTN_RIGHT,
MOUSE_BTN_COUNT
};
enum Mouse_Button_State : u16 {
MOUSE_BTN_STATE_IS_DOWN = 0x1,
MOUSE_BTN_STATE_JUST_PRESSED = 0x2,
MOUSE_BTN_STATE_JUST_RELEASED = 0x4,
};
enum Key_State : u16 {
KEY_STATE_IS_DOWN = 0x1,
KEY_STATE_JUST_PRESSED = 0x2,
KEY_STATE_JUST_RELEASED = 0x4,
};
struct User_Input {
u16 key_state[KEY_COUNT];
u16 mouse_btn_state[MOUSE_BTN_COUNT];
struct { i32 x; i32 y; } mouse_pos;
};
struct Window_Data {
// Real width and height of the window
i32 width;
i32 height;
bool size_just_changed;
f32 desired_aspect_ratio;
};

View file

@ -94,6 +94,8 @@ struct MemoryEditor
ImU8 (*ReadFn)(const ImU8* data, size_t off); // = 0 // optional handler to read bytes. ImU8 (*ReadFn)(const ImU8* data, size_t off); // = 0 // optional handler to read bytes.
void (*WriteFn)(ImU8* data, size_t off, ImU8 d); // = 0 // optional handler to write bytes. void (*WriteFn)(ImU8* data, size_t off, ImU8 d); // = 0 // optional handler to write bytes.
bool (*HighlightFn)(const ImU8* data, size_t off);//= 0 // optional handler to return Highlight property (to support non-contiguous highlighting). bool (*HighlightFn)(const ImU8* data, size_t off);//= 0 // optional handler to return Highlight property (to support non-contiguous highlighting).
ImU32 (*BgColorFn)(const ImU8* data, size_t off, const void *UserData); // = 0 // optional handler to return custom background color of individual bytes.
const void *BgColorFnUserData;
// [Internal State] // [Internal State]
bool ContentsWidthChanged; bool ContentsWidthChanged;
@ -126,6 +128,8 @@ struct MemoryEditor
ReadFn = NULL; ReadFn = NULL;
WriteFn = NULL; WriteFn = NULL;
HighlightFn = NULL; HighlightFn = NULL;
BgColorFn = NULL;
BgColorFnUserData = NULL;
// State/Internals // State/Internals
ContentsWidthChanged = false; ContentsWidthChanged = false;
@ -302,6 +306,19 @@ struct MemoryEditor
} }
draw_list->AddRectFilled(pos, ImVec2(pos.x + highlight_width, pos.y + s.LineHeight), HighlightColor); draw_list->AddRectFilled(pos, ImVec2(pos.x + highlight_width, pos.y + s.LineHeight), HighlightColor);
} }
else if (BgColorFn)
{
ImVec2 pos = ImGui::GetCursorScreenPos();
float highlight_width = s.GlyphWidth * 2;
bool is_next_byte_highlighted = (addr + 1 < mem_size) && ((BgColorFn(mem_data, addr + 1, BgColorFnUserData) & IM_COL32_A_MASK) != 0);
if (is_next_byte_highlighted || (n + 1 == Cols))
{
highlight_width = s.HexCellWidth;
if (OptMidColsCount > 0 && n > 0 && (n + 1) < Cols && ((n + 1) % OptMidColsCount) == 0)
highlight_width += s.SpacingBetweenMidCols;
}
draw_list->AddRectFilled(pos, ImVec2(pos.x + highlight_width, pos.y + s.LineHeight), BgColorFn(mem_data, addr, BgColorFnUserData));
}
if (DataEditingAddr == addr) if (DataEditingAddr == addr)
{ {
@ -413,6 +430,10 @@ struct MemoryEditor
draw_list->AddRectFilled(pos, ImVec2(pos.x + s.GlyphWidth, pos.y + s.LineHeight), ImGui::GetColorU32(ImGuiCol_FrameBg)); draw_list->AddRectFilled(pos, ImVec2(pos.x + s.GlyphWidth, pos.y + s.LineHeight), ImGui::GetColorU32(ImGuiCol_FrameBg));
draw_list->AddRectFilled(pos, ImVec2(pos.x + s.GlyphWidth, pos.y + s.LineHeight), ImGui::GetColorU32(ImGuiCol_TextSelectedBg)); draw_list->AddRectFilled(pos, ImVec2(pos.x + s.GlyphWidth, pos.y + s.LineHeight), ImGui::GetColorU32(ImGuiCol_TextSelectedBg));
} }
else if (BgColorFn)
{
draw_list->AddRectFilled(pos, ImVec2(pos.x + s.GlyphWidth, pos.y + s.LineHeight), BgColorFn(mem_data, addr, BgColorFnUserData));
}
unsigned char c = ReadFn ? ReadFn(mem_data, addr) : mem_data[addr]; unsigned char c = ReadFn ? ReadFn(mem_data, addr) : mem_data[addr];
char display_c = (c < 32 || c >= 128) ? '.' : c; char display_c = (c < 32 || c >= 128) ? '.' : c;
draw_list->AddText(pos, (display_c == c) ? color_text : color_disabled, &display_c, &display_c + 1); draw_list->AddText(pos, (display_c == c) ? color_text : color_disabled, &display_c, &display_c + 1);