nkeynes@2: /** nkeynes@484: * $Id: dump_win.c,v 1.7 2007-10-31 12:23:19 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@484: #include nkeynes@484: #include nkeynes@2: #include "mem.h" nkeynes@435: #include "gui/gtkui.h" nkeynes@2: nkeynes@2: #define MAX_DUMP_SIZE 4096 nkeynes@2: nkeynes@457: #define DUMP_WINDOW_TAG 0xD4B9DA7A nkeynes@2: nkeynes@457: struct dump_window_info { 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@457: GtkWidget *window; nkeynes@457: GtkWidget *fromInput, *toInput; nkeynes@457: GtkWidget *textArea; nkeynes@2: GtkTextTag *changedTag; nkeynes@2: GtkTextBuffer *textBuffer; nkeynes@457: struct dump_window_info *next; nkeynes@457: }; nkeynes@2: nkeynes@457: static dump_window_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@457: void dump_window_set_text( dump_window_t data, unsigned char *old_data, unsigned char *new_data ); nkeynes@2: nkeynes@2: nkeynes@457: dump_window_t dump_window_new( const gchar *title ) nkeynes@457: { nkeynes@457: GtkWidget *vbox3; nkeynes@457: GtkWidget *hbox2; nkeynes@457: GtkWidget *dump_view_button; nkeynes@457: GtkWidget *scrolledwindow9; nkeynes@457: nkeynes@457: dump_window_t dump = g_malloc0( sizeof( struct dump_window_info ) ); nkeynes@457: nkeynes@457: dump->_tag = DUMP_WINDOW_TAG; nkeynes@457: dump->next = dump_list_head; nkeynes@457: dump_list_head = dump; nkeynes@457: dump->data = NULL; nkeynes@457: dump->start = 0; nkeynes@457: dump->end = 0; nkeynes@457: dump->window = gtk_window_new (GTK_WINDOW_TOPLEVEL); nkeynes@457: gtk_window_set_title (GTK_WINDOW (dump->window), _("Memory dump")); nkeynes@457: nkeynes@457: vbox3 = gtk_vbox_new (FALSE, 0); nkeynes@457: gtk_container_add (GTK_CONTAINER (dump->window), vbox3); nkeynes@457: nkeynes@457: hbox2 = gtk_hbox_new (FALSE, 0); nkeynes@457: dump->fromInput = gtk_entry_new (); nkeynes@457: gtk_entry_set_text( GTK_ENTRY(dump->fromInput), "" ); nkeynes@457: dump->toInput = gtk_entry_new (); nkeynes@457: gtk_entry_set_text( GTK_ENTRY(dump->toInput), "" ); nkeynes@457: dump_view_button = gtk_button_new_with_mnemonic (_("View")); nkeynes@457: nkeynes@457: gtk_box_pack_start (GTK_BOX (hbox2), gtk_label_new(_(" From ")), FALSE, FALSE, 0); nkeynes@457: gtk_box_pack_start (GTK_BOX (hbox2), dump->fromInput, FALSE, TRUE, 0); nkeynes@457: gtk_box_pack_start (GTK_BOX (hbox2), gtk_label_new(_(" To ")), FALSE, FALSE, 0); nkeynes@457: gtk_box_pack_start (GTK_BOX (hbox2), dump->toInput, FALSE, TRUE, 0); nkeynes@457: gtk_box_pack_start (GTK_BOX (hbox2), dump_view_button, FALSE, FALSE, 0); nkeynes@457: gtk_box_pack_start (GTK_BOX (hbox2), gtk_label_new (_(" ")), TRUE, TRUE, 0); nkeynes@457: gtk_box_pack_start (GTK_BOX (vbox3), hbox2, FALSE, TRUE, 3); nkeynes@457: nkeynes@457: dump->textArea = gtk_text_view_new (); nkeynes@457: dump->textBuffer = gtk_text_buffer_new(NULL); nkeynes@457: dump->changedTag = gtk_text_buffer_create_tag(dump->textBuffer, "changed", nkeynes@457: "foreground", "blue", NULL); nkeynes@457: gtk_widget_modify_font(GTK_WIDGET(dump->textArea),gui_fixed_font); nkeynes@457: gtk_text_view_set_editable(GTK_TEXT_VIEW(dump->textArea), FALSE); nkeynes@457: gtk_text_view_set_buffer(GTK_TEXT_VIEW(dump->textArea), dump->textBuffer); nkeynes@457: scrolledwindow9 = gtk_scrolled_window_new (NULL, NULL); nkeynes@457: gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow9), GTK_SHADOW_IN); nkeynes@457: gtk_container_add (GTK_CONTAINER (scrolledwindow9), dump->textArea); nkeynes@457: gtk_box_pack_start (GTK_BOX (vbox3), scrolledwindow9, TRUE, TRUE, 0); nkeynes@2: nkeynes@457: g_signal_connect (dump->window, "delete_event", nkeynes@455: G_CALLBACK (on_dump_window_delete_event), nkeynes@457: dump); nkeynes@457: g_signal_connect (dump_view_button, "clicked", nkeynes@455: G_CALLBACK (on_dump_window_button_view_clicked), nkeynes@457: dump); nkeynes@457: gtk_widget_show_all( dump->window ); nkeynes@457: nkeynes@457: return dump; nkeynes@2: } nkeynes@2: nkeynes@457: void gtk_entry_set_hex_value( GtkEntry *entry, uint32_t value ) nkeynes@457: { nkeynes@457: char buf[10]; nkeynes@457: sprintf( buf, "%08X", value ); nkeynes@457: gtk_entry_set_text( entry, buf ); nkeynes@457: } 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@455: gboolean on_dump_window_delete_event( GtkWidget *widget, GdkEvent *event, nkeynes@2: gpointer user_data ) nkeynes@2: { nkeynes@457: dump_window_t data = (dump_window_t)user_data; nkeynes@2: if( data->data != NULL ) nkeynes@2: free( data->data ); nkeynes@457: dump_window_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@457: dump_window_t data = (dump_window_t)user_data; nkeynes@2: uint32_t startVal, endVal; nkeynes@2: nkeynes@2: assert( data != NULL ); nkeynes@457: assert( data->_tag == DUMP_WINDOW_TAG ); nkeynes@2: nkeynes@457: startVal = gtk_entry_get_hex_value(GTK_ENTRY(data->fromInput), data->start); nkeynes@457: endVal = gtk_entry_get_hex_value(GTK_ENTRY(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@457: gtk_entry_set_hex_value(GTK_ENTRY(data->fromInput),startVal); nkeynes@457: gtk_entry_set_hex_value(GTK_ENTRY(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@457: void dump_window_update( dump_window_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@457: dump_window_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@457: void dump_window_set_text( dump_window_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: }