nkeynes@2: /** nkeynes@455: * $Id: dump_win.c,v 1.5 2007-10-21 05:21:35 nkeynes Exp $ nkeynes@31: * nkeynes@2: * Implements the memory dump window. nkeynes@31: * nkeynes@31: * Copyright (c) 2005 Nathan Keynes. nkeynes@31: * nkeynes@31: * This program is free software; you can redistribute it and/or modify nkeynes@31: * it under the terms of the GNU General Public License as published by nkeynes@31: * the Free Software Foundation; either version 2 of the License, or nkeynes@31: * (at your option) any later version. nkeynes@31: * nkeynes@31: * This program is distributed in the hope that it will be useful, nkeynes@31: * but WITHOUT ANY WARRANTY; without even the implied warranty of nkeynes@31: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nkeynes@31: * GNU General Public License for more details. nkeynes@2: */ nkeynes@31: nkeynes@2: #include nkeynes@2: #include nkeynes@2: #include nkeynes@2: #include "mem.h" nkeynes@435: #include "gui/gtkui.h" nkeynes@435: #include "gui/debugif.h" nkeynes@2: nkeynes@2: #define MAX_DUMP_SIZE 4096 nkeynes@2: nkeynes@2: #define DUMP_DATA_TAG 0xD4B9DA7A nkeynes@2: nkeynes@2: typedef struct dump_data { nkeynes@2: uint32_t _tag; nkeynes@2: uint32_t start; nkeynes@2: uint32_t end; nkeynes@2: int flags; nkeynes@430: unsigned char *data; nkeynes@2: nkeynes@2: GtkEntry *fromInput, *toInput; nkeynes@2: GtkTextView *textArea; nkeynes@2: GtkTextTag *changedTag; nkeynes@2: GtkTextBuffer *textBuffer; nkeynes@2: struct dump_data *next; nkeynes@2: } *dump_data_t; nkeynes@2: nkeynes@2: static dump_data_t dump_list_head = NULL; nkeynes@2: nkeynes@455: gboolean on_dump_window_delete_event( GtkWidget *widget, GdkEvent *event, nkeynes@2: gpointer user_data ); nkeynes@455: void on_dump_window_button_view_clicked( GtkWidget *widget, gpointer user_data ); nkeynes@455: void dump_window_set_text( dump_data_t data, unsigned char *old_data, unsigned char *new_data ); nkeynes@2: nkeynes@2: nkeynes@455: void dump_window_new( const gchar *title ) { nkeynes@2: GtkWidget *win = create_dump_win(); nkeynes@2: GtkWidget *dump_view_button = (GtkWidget *)g_object_get_data(G_OBJECT(win), "dump_view_button"); nkeynes@2: dump_data_t data = malloc( sizeof(struct dump_data) ); nkeynes@2: data->_tag = DUMP_DATA_TAG; nkeynes@2: data->fromInput = (GtkEntry *)g_object_get_data(G_OBJECT(win), "dump_from"); nkeynes@2: data->toInput = (GtkEntry *)g_object_get_data(G_OBJECT(win), "dump_to"); nkeynes@2: data->textArea = (GtkTextView *)g_object_get_data(G_OBJECT(win), "dump_text"); nkeynes@2: data->next = dump_list_head; nkeynes@2: dump_list_head = data; nkeynes@2: data->data = NULL; nkeynes@2: data->start = 0; nkeynes@2: data->end = 0; nkeynes@2: gtk_entry_set_text( data->fromInput, "" ); nkeynes@2: gtk_entry_set_text( data->toInput, "" ); nkeynes@2: data->textBuffer = gtk_text_buffer_new(NULL); nkeynes@2: data->changedTag = gtk_text_buffer_create_tag(data->textBuffer, "changed", nkeynes@2: "foreground", "blue", nkeynes@2: NULL); nkeynes@2: gtk_text_view_set_buffer(data->textArea, data->textBuffer); nkeynes@2: gtk_text_view_set_editable(data->textArea, FALSE); nkeynes@435: gtk_widget_modify_font(GTK_WIDGET(data->textArea),gui_fixed_font); nkeynes@2: nkeynes@2: g_signal_connect ((gpointer) win, "delete_event", nkeynes@455: G_CALLBACK (on_dump_window_delete_event), nkeynes@2: data); nkeynes@2: g_signal_connect ((gpointer) dump_view_button, "clicked", nkeynes@455: G_CALLBACK (on_dump_window_button_view_clicked), nkeynes@2: data); nkeynes@2: gtk_widget_show( GTK_WIDGET(win) ); nkeynes@2: } nkeynes@2: nkeynes@2: nkeynes@435: nkeynes@435: uint32_t gtk_entry_get_hex_value( GtkEntry *entry, uint32_t defaultValue ) nkeynes@435: { nkeynes@435: const gchar *text = gtk_entry_get_text(entry); nkeynes@435: if( text == NULL ) nkeynes@435: return defaultValue; nkeynes@435: gchar *endptr; nkeynes@435: uint32_t value = strtoul( text, &endptr, 16 ); nkeynes@435: if( text == endptr ) { /* invalid input */ nkeynes@435: value = defaultValue; nkeynes@435: gtk_entry_set_hex_value( entry, value ); nkeynes@435: } nkeynes@435: return value; nkeynes@435: } nkeynes@435: nkeynes@435: void gtk_entry_set_hex_value( GtkEntry *entry, uint32_t value ) nkeynes@435: { nkeynes@435: char buf[10]; nkeynes@435: sprintf( buf, "%08X", value ); nkeynes@435: gtk_entry_set_text( entry, buf ); nkeynes@435: } nkeynes@435: nkeynes@2: nkeynes@455: gboolean on_dump_window_delete_event( GtkWidget *widget, GdkEvent *event, nkeynes@2: gpointer user_data ) nkeynes@2: { nkeynes@2: dump_data_t data = (dump_data_t)user_data; nkeynes@2: if( data->data != NULL ) nkeynes@2: free( data->data ); nkeynes@2: dump_data_t node = dump_list_head; nkeynes@2: if( node == data ) nkeynes@2: dump_list_head = data->next; nkeynes@2: else { nkeynes@2: while( node->next != data ) { nkeynes@2: node = node->next; nkeynes@2: assert( node != NULL ); nkeynes@2: } nkeynes@2: node->next = data->next; nkeynes@2: } nkeynes@2: free( data ); nkeynes@2: return FALSE; nkeynes@2: } nkeynes@2: nkeynes@455: void on_dump_window_button_view_clicked( GtkWidget *widget, gpointer user_data ) nkeynes@2: { nkeynes@2: dump_data_t data = (dump_data_t)user_data; nkeynes@2: uint32_t startVal, endVal; nkeynes@2: nkeynes@2: assert( data != NULL ); nkeynes@2: assert( data->_tag == DUMP_DATA_TAG ); nkeynes@2: nkeynes@2: startVal = gtk_entry_get_hex_value(data->fromInput, data->start); nkeynes@2: endVal = gtk_entry_get_hex_value(data->toInput, data->end); nkeynes@2: if( startVal != data->start || endVal != data->end ) { nkeynes@2: if( startVal > endVal ) { nkeynes@2: int tmp = endVal; nkeynes@2: endVal = startVal; nkeynes@2: startVal = tmp; nkeynes@2: } nkeynes@2: if( endVal > startVal + MAX_DUMP_SIZE ) nkeynes@2: endVal = startVal + MAX_DUMP_SIZE; nkeynes@2: nkeynes@2: gtk_entry_set_hex_value(data->fromInput,startVal); nkeynes@2: gtk_entry_set_hex_value(data->toInput,endVal); nkeynes@2: data->start = startVal; nkeynes@2: data->end = endVal; nkeynes@2: nkeynes@2: if( data->data != NULL ) { nkeynes@2: free( data->data ); nkeynes@2: data->data = NULL; nkeynes@2: } nkeynes@2: if( startVal != endVal ) { nkeynes@2: data->data = malloc( endVal - startVal ); nkeynes@2: mem_copy_from_sh4( data->data, startVal, endVal-startVal ); nkeynes@455: dump_window_set_text( data, data->data, data->data ); nkeynes@2: } nkeynes@2: } nkeynes@2: } nkeynes@2: nkeynes@455: void dump_window_update( dump_data_t data ) nkeynes@2: { nkeynes@2: if( data->data == NULL ) nkeynes@2: return; nkeynes@430: unsigned char tmp[data->end-data->start]; nkeynes@2: int length = data->end-data->start; nkeynes@2: memcpy( tmp, data->data, length ); nkeynes@2: mem_copy_from_sh4( data->data, data->start, length ); nkeynes@455: dump_window_set_text( data, tmp, data->data ); nkeynes@2: } nkeynes@2: nkeynes@455: void dump_window_update_all( ) nkeynes@2: { nkeynes@2: dump_data_t node = dump_list_head; nkeynes@2: while( node != NULL ) { nkeynes@455: dump_window_update(node); nkeynes@2: node = node->next; nkeynes@2: } nkeynes@2: } nkeynes@2: nkeynes@455: void dump_window_set_text( dump_data_t data, unsigned char *old_data, unsigned char *new_data ) nkeynes@2: { nkeynes@2: GtkTextBuffer *buf = data->textBuffer; nkeynes@2: GtkTextTag *changedTag = data->changedTag; nkeynes@2: GtkTextIter iter, endIter; nkeynes@2: int i, j, offset; nkeynes@2: /* Clear out the buffer */ nkeynes@2: gtk_text_buffer_get_start_iter(buf,&iter); nkeynes@2: gtk_text_buffer_get_end_iter(buf,&endIter); nkeynes@2: gtk_text_buffer_delete(buf,&iter,&endIter); nkeynes@2: gtk_text_buffer_get_start_iter(buf,&iter); nkeynes@2: nkeynes@2: for( offset = 0, i=data->start; iend; i+=16, offset+=16 ) { nkeynes@2: char text[80]; nkeynes@2: sprintf(text, "%08X:", i ); nkeynes@2: gtk_text_buffer_insert( buf, &iter, text, 9 ); nkeynes@2: for( j=0; j<16; j++ ) { nkeynes@2: if( j%4 == 0 ) nkeynes@2: gtk_text_buffer_insert( buf, &iter, " ", 1 ); nkeynes@2: if( i+j < data->end ) { nkeynes@2: int oldVal = ((int)old_data[offset+j])&0xFF; nkeynes@2: int newVal = ((int)new_data[offset+j])&0xFF; nkeynes@2: sprintf(text, "%02X ", newVal); nkeynes@2: if( oldVal == newVal ) nkeynes@2: gtk_text_buffer_insert( buf, &iter, text, 3 ); nkeynes@2: else nkeynes@2: gtk_text_buffer_insert_with_tags( buf, &iter, text, 3, nkeynes@2: changedTag, NULL ); nkeynes@2: } else { nkeynes@2: gtk_text_buffer_insert( buf, &iter, " ", 3 ); nkeynes@2: } nkeynes@2: } nkeynes@2: gtk_text_buffer_insert( buf, &iter, " ", 2 ); nkeynes@2: for( j=0; j<16 && i+j < data->end; j++ ) { nkeynes@2: int oldVal = ((int)old_data[offset+j])&0xFF; nkeynes@2: int newVal = ((int)new_data[offset+j])&0xFF; nkeynes@2: if( isprint(newVal) ) nkeynes@2: sprintf( text, "%c", newVal ); nkeynes@2: else strcpy( text, "." ); nkeynes@2: if( oldVal == newVal ) nkeynes@2: gtk_text_buffer_insert( buf, &iter, text, 1 ); nkeynes@2: else nkeynes@2: gtk_text_buffer_insert_with_tags( buf, &iter, text, 1, nkeynes@2: changedTag, NULL ); nkeynes@2: } nkeynes@2: gtk_text_buffer_insert( buf, &iter, "\n", 1 ); nkeynes@2: } nkeynes@2: }