Added ROM edit undo functionality to Qt hex editor.

This commit is contained in:
Matthew Budd 2020-11-19 20:35:44 -05:00
parent 5cbfb8b1a5
commit b1c0f7aaba
3 changed files with 238 additions and 12 deletions

View File

@ -2931,7 +2931,7 @@ void loadGameDebugBreakpoints(void)
else if ( strcmp( id, "flags" ) == 0 )
{
type = 0;
//enable = (data[0] == 'E'); // Always start with breakpoints disabled.
enable = (data[0] == 'E'); // Always start with breakpoints disabled.
if ( data[1] == 'P' )
{

View File

@ -47,6 +47,171 @@ static bool memNeedsCheck = false;
static HexBookMarkManager_t hbm;
static std::list <HexEditorDialog_t*> winList;
static const char *memViewNames[] = { "RAM", "PPU", "OAM", "ROM", NULL };
static int getROM( unsigned int offset);
static int writeMem( int mode, unsigned int addr, int value );
//----------------------------------------------------------------------------
struct romEditEntry_t
{
int addr;
int size;
uint8_t *data;
romEditEntry_t(void)
{
addr = -1; size = 0; data = NULL;
}
~romEditEntry_t(void)
{
if ( data != NULL )
{
free(data); data = NULL;
}
}
};
struct romEditList_t
{
uint8_t *modMem;
int modMemSize;
std::list <romEditEntry_t*> undoList;
//std::list <romEditEntry_t*> redoList; // TODO
romEditList_t(void)
{
modMem = NULL;
modMemSize = 0;
}
~romEditList_t(void)
{
clear();
}
void clear(void)
{
while ( !undoList.empty() )
{
delete undoList.back();
undoList.pop_back();
}
if ( modMem != NULL )
{
free(modMem); modMem = NULL; modMemSize = 0;
}
}
void applyPatch( int addr, int data )
{
uint8_t u8;
u8 = data;
applyPatch( addr, &u8, 1 );
}
void applyPatch( int addr, uint8_t *data, int size )
{
int ofs;
romEditEntry_t *entry;
if ( GameInfo == NULL )
{
return;
}
if ( modMem == NULL )
{
modMemSize = 16 + CHRsize[0] + PRGsize[0];
modMem = (uint8_t*)malloc( modMemSize );
if ( modMem == NULL )
{
printf("Error: Failed to allocate ROM modification memory buffer\n");
return;
}
memset( modMem, 0, modMemSize );
}
entry = new romEditEntry_t();
entry->addr = addr;
entry->size = size;
entry->data = (uint8_t*)malloc(sizeof(uint8_t)*size);
for (int i = 0; i < size; i++)
{
ofs = addr+i;
entry->data[i] = getROM(ofs);
writeMem( QHexEdit::MODE_NES_ROM, ofs, data[i] );
modMem[ofs]++;
}
undoList.push_back( entry );
}
int undoPatch(void)
{
int ofs, ret = -1;
romEditEntry_t *entry;
if ( undoList.empty() )
{
return ret;
}
entry = undoList.back(); undoList.pop_back();
ret = entry->addr;
for (int i=0; i<entry->size; i++)
{
ofs = entry->addr + i;
writeMem( QHexEdit::MODE_NES_ROM, ofs, entry->data[i] );
if ( modMem )
{
if ( (ofs >= 0) && (ofs < modMemSize) )
{
if ( modMem[ofs] > 0 )
{
modMem[ofs]--;
}
}
}
}
delete entry;
return ret;
}
bool isModified( int addr )
{
if ( modMem == NULL )
{
return false;
}
if ( addr < 0 )
{
return false;
}
else if ( addr >= modMemSize )
{
return false;
}
return modMem[addr] ? true : false;
}
size_t undoQueueSize(void)
{
return undoList.size();
}
};
static romEditList_t romEditList;
//----------------------------------------------------------------------------
static int getRAM( unsigned int i )
{
@ -180,6 +345,9 @@ static int writeMem( int mode, unsigned int addr, int value )
}
break;
}
hexEditorRequestUpdateAll();
return 0;
}
//----------------------------------------------------------------------------
@ -745,7 +913,7 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent)
undoEditAct->setShortcut(QKeySequence(tr("U")));
undoEditAct->setStatusTip(tr("Undo Edit"));
undoEditAct->setEnabled(false);
//connect(undoEditAct, SIGNAL(triggered()), this, SLOT(saveRomFile(void)) );
connect(undoEditAct, SIGNAL(triggered()), this, SLOT(undoRomPatch(void)) );
editMenu->addAction(undoEditAct);
editMenu->addSeparator();
@ -1086,7 +1254,7 @@ void HexEditorDialog_t::gotoAddress( int newAddr )
//----------------------------------------------------------------------------
void HexEditorDialog_t::saveRomFile(void)
{
//FlushUndoBuffer();
romEditList.clear();
iNesSave();
//UpdateColorTable();
}
@ -1300,6 +1468,8 @@ void HexEditorDialog_t::openDebugSymbolEditWindow( int addr )
void HexEditorDialog_t::updatePeriodic(void)
{
//printf("Update Periodic\n");
undoEditAct->setEnabled( romEditList.undoQueueSize() > 0 );
if ( fceuWrapperTryLock(0) )
{
@ -1349,6 +1519,17 @@ void HexEditorDialog_t::updatePeriodic(void)
}
}
//----------------------------------------------------------------------------
void HexEditorDialog_t::undoRomPatch(void)
{
int addr = romEditList.undoPatch();
if ( addr >= 0 )
{
editor->setMode( QHexEdit::MODE_NES_ROM );
editor->setAddr( addr );
}
}
//----------------------------------------------------------------------------
void HexEditorDialog_t::openFindDialog(void)
{
if ( findDialog == NULL )
@ -1465,6 +1646,7 @@ QHexEdit::QHexEdit(QWidget *parent)
rvActvTextColor[i].setRgbF( grayScale, grayScale, grayScale );
}
updateRequested = false;
mouseLeftBtnDown = false;
txtHlgtAnchorChar = -1;
@ -1721,6 +1903,11 @@ void QHexEdit::pasteFromClipboard(void)
{
break;
}
if ( viewMode == QHexEdit::MODE_NES_ROM )
{
romEditList.applyPatch( addr, val );
}
writeMem( viewMode, addr, val );
addr++;
@ -2088,8 +2275,12 @@ void QHexEdit::keyPressEvent(QKeyEvent *event)
int offs = (cursorPosX-32);
int addr = 16*(lineOffset+cursorPosY) + offs;
fceuWrapperLock();
if ( viewMode == QHexEdit::MODE_NES_ROM )
{
romEditList.applyPatch( addr, key );
}
writeMem( viewMode, addr, key );
fceuWrapperUnLock();
fceuWrapperUnLock();
editAddr = -1;
editValue = 0;
@ -2115,9 +2306,13 @@ void QHexEdit::keyPressEvent(QKeyEvent *event)
{
nibbleValue = editValue | nibbleValue;
fceuWrapperLock();
writeMem( viewMode, editAddr, nibbleValue );
fceuWrapperUnLock();
fceuWrapperLock();
if ( viewMode == QHexEdit::MODE_NES_ROM )
{
romEditList.applyPatch( editAddr, nibbleValue );
}
writeMem( viewMode, editAddr, nibbleValue );
fceuWrapperUnLock();
editAddr = -1;
editValue = 0;
@ -2768,6 +2963,11 @@ void QHexEdit::jumpToROM(void)
setAddr( jumpToRomValue );
}
//----------------------------------------------------------------------------
void QHexEdit::requestUpdate(void)
{
updateRequested = true;
}
//----------------------------------------------------------------------------
// Calling of checkMemActivity must always be synchronized with the emulation
// thread as calling GetMem while the emulation is executing can mess up certain
// registers (especially controller registers $4016 and $4017)
@ -2779,10 +2979,13 @@ int QHexEdit::checkMemActivity(void)
// 1. In ROM View Mode
// 2. The simulation is not cycling (paused)
if ( ( viewMode == MODE_NES_ROM ) ||
( total_instructions_lp == total_instructions ) )
if ( !updateRequested )
{
return -1;
if ( ( viewMode == MODE_NES_ROM ) ||
( total_instructions_lp == total_instructions ) )
{
return -1;
}
}
for (int i=0; i<mb.size(); i++)
@ -2805,6 +3008,7 @@ int QHexEdit::checkMemActivity(void)
}
}
total_instructions_lp = total_instructions;
updateRequested = false;
return 0;
}
@ -2832,10 +3036,18 @@ int QHexEdit::getRomAddrColor( int addr, QColor &fg, QColor &bg )
{
return -1;
}
mb.buf[addr].data = memAccessFunc(addr);
if ( (txtHlgtStartAddr != txtHlgtEndAddr) && (addr >= txtHlgtStartAddr) && (addr <= txtHlgtEndAddr) )
{
fg = QColor("white");
bg = QColor("blue");
fg.setRgb( 255, 255, 255 ); // white
bg.setRgb( 0, 0, 255 ); // blue
return 0;
}
if ( romEditList.isModified( addr ) )
{
fg.setRgb( 255, 255, 255 ); // white
bg.setRgb( 255, 0, 0 ); // red
return 0;
}
if (cdloggerdataSize == 0)
@ -3274,6 +3486,16 @@ void hexEditorSaveBookmarks(void)
}
}
//----------------------------------------------------------------------------
void hexEditorRequestUpdateAll(void)
{
std::list <HexEditorDialog_t*>::iterator it;
for (it = winList.begin(); it != winList.end(); it++)
{
(*it)->editor->requestUpdate();
}
}
//----------------------------------------------------------------------------
int hexEditorNumWindows(void)
{
return winList.size();

View File

@ -123,6 +123,7 @@ class QHexEdit : public QWidget
void pasteFromClipboard(void);
void clearHighlight(void);
int findPattern( std::vector <unsigned char> &varray, int dir );
void requestUpdate(void);
enum {
MODE_NES_RAM = 0,
@ -212,6 +213,7 @@ class QHexEdit : public QWidget
bool reverseVideo;
bool actvHighlightEnable;
bool mouseLeftBtnDown;
bool updateRequested;
private slots:
void jumpToROM(void);
@ -305,9 +307,11 @@ class HexEditorDialog_t : public QDialog
void copyToClipboard(void);
void pasteFromClipboard(void);
void openFindDialog(void);
void undoRomPatch(void);
};
int hexEditorNumWindows(void);
void hexEditorRequestUpdateAll(void);
void hexEditorUpdateMemoryValues(void);
void hexEditorLoadBookmarks(void);
void hexEditorSaveBookmarks(void);