179 lines
5.0 KiB
C
179 lines
5.0 KiB
C
|
#include <gtk/gtk.h>
|
||
|
#include <glib.h>
|
||
|
#include <stdint.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/stat.h>
|
||
|
#include <sys/mman.h>
|
||
|
#include <fcntl.h>
|
||
|
|
||
|
#include <error-mem-viewer/err-mem-viewer-address-cell-renderer.h>
|
||
|
|
||
|
enum memory_view_columns {
|
||
|
MEM_VIEW_COL_ADDRESS = 0,
|
||
|
MEM_VIEW_COL_DATA,
|
||
|
MEM_VIEW_COL_INTERPRETATION,
|
||
|
MEM_VIEW_COLUMN_COUNT
|
||
|
};
|
||
|
|
||
|
struct application_data {
|
||
|
GtkWidget *borrowed_main_window;
|
||
|
GtkTreeView *borrowed_tree_view;
|
||
|
GtkHeaderBar *borrowed_header_bar;
|
||
|
const char *error_memory_data;
|
||
|
size_t file_size;
|
||
|
};
|
||
|
|
||
|
static void tree_view_show_error_memory(GtkTreeView *tree_view, const char *memory, size_t len)
|
||
|
{
|
||
|
GtkListStore *store;
|
||
|
GtkTreeIter _iter;
|
||
|
GtkTreeIter *iter = &_iter;
|
||
|
|
||
|
store = GTK_LIST_STORE(gtk_tree_view_get_model(tree_view));
|
||
|
if (store) {
|
||
|
for (unsigned int i = 0; i < 0xFFFF; i+=4) {
|
||
|
gtk_list_store_append(store, iter);
|
||
|
gtk_list_store_set(store, iter, MEM_VIEW_COL_ADDRESS, i, MEM_VIEW_COL_INTERPRETATION, "Test", MEM_VIEW_COL_DATA, i % 12, -1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
void setup_tree_view(GtkTreeView *tree_view)
|
||
|
{
|
||
|
GtkListStore *list_store;
|
||
|
GtkCellRenderer *string_renderer;
|
||
|
GtkCellRenderer *hex_renderer;
|
||
|
GtkTreeViewColumn *column;
|
||
|
|
||
|
g_return_if_fail(GTK_IS_TREE_VIEW(tree_view));
|
||
|
|
||
|
list_store = gtk_list_store_new(MEM_VIEW_COLUMN_COUNT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING);
|
||
|
gtk_tree_view_set_model(tree_view, GTK_TREE_MODEL(list_store));
|
||
|
|
||
|
string_renderer = gtk_cell_renderer_text_new();
|
||
|
hex_renderer = err_mem_view_address_cell_renderer_new();
|
||
|
|
||
|
column = gtk_tree_view_column_new_with_attributes("Address", hex_renderer, "hex-num", MEM_VIEW_COL_ADDRESS, NULL);
|
||
|
gtk_tree_view_append_column(tree_view, column);
|
||
|
column = gtk_tree_view_column_new_with_attributes("Data", hex_renderer, "hex-num", MEM_VIEW_COL_DATA, NULL);
|
||
|
gtk_tree_view_append_column(tree_view, column);
|
||
|
column = gtk_tree_view_column_new_with_attributes("Interpretation", string_renderer, "text", MEM_VIEW_COL_INTERPRETATION, NULL);
|
||
|
gtk_tree_view_append_column(tree_view, column);
|
||
|
}
|
||
|
|
||
|
static int64_t get_file_size(int file)
|
||
|
{
|
||
|
off_t size;
|
||
|
|
||
|
|
||
|
if (!file)
|
||
|
return -1L;
|
||
|
|
||
|
size = lseek(file, 0, SEEK_END);
|
||
|
if (size == (off_t)-1)
|
||
|
return -1;
|
||
|
|
||
|
|
||
|
return (int64_t)size;
|
||
|
}
|
||
|
|
||
|
static const char *map_file_to_memory(const char *name, size_t *detected_size)
|
||
|
{
|
||
|
const char *ret = NULL;
|
||
|
int file;
|
||
|
int64_t file_size;
|
||
|
|
||
|
file = open(name, O_RDONLY);
|
||
|
if (file < 0)
|
||
|
goto exit;
|
||
|
|
||
|
file_size = get_file_size(file);
|
||
|
if (file_size < 0)
|
||
|
goto exit;
|
||
|
|
||
|
if (detected_size)
|
||
|
*detected_size = (size_t)file_size;
|
||
|
|
||
|
ret = (const char *)mmap(NULL, (size_t)file_size, PROT_READ, MAP_SHARED, file, (off_t)0L);
|
||
|
exit:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
G_MODULE_EXPORT
|
||
|
void open_button_clicked_cb(GtkButton *button, gpointer *user_data)
|
||
|
{
|
||
|
struct application_data *data = (struct application_data *)user_data;
|
||
|
(void)button;
|
||
|
GtkDialog *dialog;
|
||
|
gint res;
|
||
|
gchar *filename;
|
||
|
|
||
|
dialog = GTK_DIALOG(gtk_file_chooser_dialog_new("Open File", GTK_WINDOW(data->borrowed_main_window),
|
||
|
GTK_FILE_CHOOSER_ACTION_OPEN,
|
||
|
"Cancel", GTK_RESPONSE_CANCEL,
|
||
|
"Open", GTK_RESPONSE_ACCEPT,
|
||
|
NULL));
|
||
|
res = gtk_dialog_run(dialog);
|
||
|
if (res == GTK_RESPONSE_ACCEPT) {
|
||
|
filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
|
||
|
data->error_memory_data = map_file_to_memory(filename, &data->file_size);
|
||
|
if (!data->error_memory_data) {
|
||
|
g_warning("File could not be loaded");
|
||
|
g_free(filename);
|
||
|
goto ret_destroy_dialog;
|
||
|
}
|
||
|
|
||
|
gtk_header_bar_set_subtitle(data->borrowed_header_bar, filename);
|
||
|
g_free(filename);
|
||
|
}
|
||
|
|
||
|
tree_view_show_error_memory(data->borrowed_tree_view, data->error_memory_data, data->file_size);
|
||
|
|
||
|
ret_destroy_dialog:
|
||
|
gtk_widget_destroy(GTK_WIDGET(dialog));
|
||
|
}
|
||
|
|
||
|
static void app_activated(GApplication *app, gpointer user_data)
|
||
|
{
|
||
|
(void)user_data;
|
||
|
GtkBuilder *builder;
|
||
|
GtkWindow *main_window;
|
||
|
static struct application_data data;
|
||
|
|
||
|
builder = gtk_builder_new_from_resource("/gui/main");
|
||
|
main_window = GTK_WINDOW(gtk_builder_get_object(builder, "main-window"));
|
||
|
data.borrowed_main_window = GTK_WIDGET(main_window);
|
||
|
data.error_memory_data = NULL;
|
||
|
data.borrowed_tree_view = GTK_TREE_VIEW(gtk_builder_get_object(builder, "error-mem-tree-view"));
|
||
|
data.borrowed_header_bar = GTK_HEADER_BAR(gtk_builder_get_object(builder, "header-bar"));
|
||
|
|
||
|
setup_tree_view(data.borrowed_tree_view);
|
||
|
|
||
|
gtk_builder_connect_signals(builder, &data);
|
||
|
g_object_unref(builder);
|
||
|
gtk_application_add_window(GTK_APPLICATION(app), main_window);
|
||
|
gtk_widget_show(GTK_WIDGET(main_window));
|
||
|
}
|
||
|
|
||
|
static int start_gui(int argc, char **argv)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
GtkApplication *g_app;
|
||
|
|
||
|
/* Create a new G application which will start a completely new process for each call to the program (NON_UNIQUE) instead
|
||
|
* of creating an additional window in the same process
|
||
|
*/
|
||
|
g_app = gtk_application_new("de.shimatta.reflow.error-mem-viewer", G_APPLICATION_NON_UNIQUE);
|
||
|
g_signal_connect(g_app, "activate", G_CALLBACK(app_activated), NULL);
|
||
|
ret = g_application_run(G_APPLICATION(g_app), argc, argv);
|
||
|
g_object_unref(g_app);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
int main(int argc, char **argv)
|
||
|
{
|
||
|
return start_gui(argc, argv);
|
||
|
}
|