From cf7017dd867a542f3808f1e6287b683da92d0553 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Mon, 5 Jun 2017 18:01:58 -0700 Subject: [PATCH] Core: Memory search repeat and refresh --- include/mgba/core/mem-search.h | 1 + src/core/mem-search.c | 70 ++++++++++ src/platform/qt/MemorySearch.cpp | 227 +++++++++++++++++++------------ src/platform/qt/MemorySearch.h | 12 ++ src/platform/qt/MemorySearch.ui | 27 +++- 5 files changed, 244 insertions(+), 93 deletions(-) diff --git a/include/mgba/core/mem-search.h b/include/mgba/core/mem-search.h index 96d8947b5..ded5bc44f 100644 --- a/include/mgba/core/mem-search.h +++ b/include/mgba/core/mem-search.h @@ -41,6 +41,7 @@ DECLARE_VECTOR(mCoreMemorySearchResults, struct mCoreMemorySearchResult); struct mCore; void mCoreMemorySearch(struct mCore* core, const struct mCoreMemorySearchParams* params, struct mCoreMemorySearchResults* out, size_t limit); +void mCoreMemorySearchRepeat(struct mCore* core, const struct mCoreMemorySearchParams* params, struct mCoreMemorySearchResults* inout); CXX_GUARD_END diff --git a/src/core/mem-search.c b/src/core/mem-search.c index 7e6c3e8a8..68b6cb0b1 100644 --- a/src/core/mem-search.c +++ b/src/core/mem-search.c @@ -284,3 +284,73 @@ void mCoreMemorySearch(struct mCore* core, const struct mCoreMemorySearchParams* found += _search(mem, size, block, params, out, limit ? limit - found : 0); } } + +void mCoreMemorySearchRepeat(struct mCore* core, const struct mCoreMemorySearchParams* params, struct mCoreMemorySearchResults* inout) { + size_t i; + for (i = 0; i < mCoreMemorySearchResultsSize(inout); ++i) { + struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsGetPointer(inout, i); + switch (res->type) { + case mCORE_MEMORY_SEARCH_8: + switch (params->type) { + case mCORE_MEMORY_SEARCH_8: + case mCORE_MEMORY_SEARCH_GUESS: + if (core->rawRead8(core, res->address, res->segment) != params->value8) { + mCoreMemorySearchResultsShift(inout, i, 1); + --i; + } + break; + case mCORE_MEMORY_SEARCH_16: + if (core->rawRead8(core, res->address, res->segment) != params->value16) { + mCoreMemorySearchResultsShift(inout, i, 1); + --i; + } + break; + case mCORE_MEMORY_SEARCH_32: + if (core->rawRead32(core, res->address, res->segment) != params->value32) { + mCoreMemorySearchResultsShift(inout, i, 1); + --i; + } + break; + default: + break; + } + break; + case mCORE_MEMORY_SEARCH_16: + switch (params->type) { + case mCORE_MEMORY_SEARCH_16: + case mCORE_MEMORY_SEARCH_GUESS: + if (core->rawRead16(core, res->address, res->segment) != params->value16) { + mCoreMemorySearchResultsShift(inout, i, 1); + --i; + } + break; + case mCORE_MEMORY_SEARCH_32: + if (core->rawRead32(core, res->address, res->segment) != params->value32) { + mCoreMemorySearchResultsShift(inout, i, 1); + --i; + } + break; + default: + break; + } + break; + case mCORE_MEMORY_SEARCH_32: + switch (params->type) { + case mCORE_MEMORY_SEARCH_32: + case mCORE_MEMORY_SEARCH_GUESS: + if (core->rawRead32(core, res->address, res->segment) != params->value32) { + mCoreMemorySearchResultsShift(inout, i, 1); + --i; + } + break; + default: + break; + } + break; + case mCORE_MEMORY_SEARCH_STRING: + case mCORE_MEMORY_SEARCH_GUESS: + // TOOD + break; + } + } +} diff --git a/src/platform/qt/MemorySearch.cpp b/src/platform/qt/MemorySearch.cpp index 2c700b163..b5de7c95a 100644 --- a/src/platform/qt/MemorySearch.cpp +++ b/src/platform/qt/MemorySearch.cpp @@ -7,7 +7,6 @@ #include "MemorySearch.h" #include -#include #include "GameController.h" @@ -19,15 +18,89 @@ MemorySearch::MemorySearch(GameController* controller, QWidget* parent) { m_ui.setupUi(this); + mCoreMemorySearchResultsInit(&m_results, 0); connect(m_ui.search, &QPushButton::clicked, this, &MemorySearch::search); + connect(m_ui.searchWithin, &QPushButton::clicked, this, &MemorySearch::searchWithin); + connect(m_ui.refresh, &QPushButton::clicked, this, &MemorySearch::refresh); + connect(m_ui.numHex, &QPushButton::clicked, this, &MemorySearch::refresh); + connect(m_ui.numDec, &QPushButton::clicked, this, &MemorySearch::refresh); +} + +MemorySearch::~MemorySearch() { + mCoreMemorySearchResultsDeinit(&m_results); +} + +bool MemorySearch::createParams(mCoreMemorySearchParams* params) { + params->memoryFlags = mCORE_MEMORY_RW; + mCore* core = m_controller->thread()->core; + + QByteArray string; + bool ok = false; + if (m_ui.typeNum->isChecked()) { + if (m_ui.bits8->isChecked()) { + params->type = mCORE_MEMORY_SEARCH_8; + } + if (m_ui.bits16->isChecked()) { + params->type = mCORE_MEMORY_SEARCH_16; + } + if (m_ui.bits32->isChecked()) { + params->type = mCORE_MEMORY_SEARCH_32; + } + if (m_ui.numHex->isChecked()) { + bool ok; + uint32_t v = m_ui.value->text().toUInt(&ok, 16); + if (ok) { + switch (params->type) { + case mCORE_MEMORY_SEARCH_8: + ok = v < 0x100; + params->value8 = v; + break; + case mCORE_MEMORY_SEARCH_16: + ok = v < 0x10000; + params->value16 = v; + break; + case mCORE_MEMORY_SEARCH_32: + params->value32 = v; + break; + default: + ok = false; + } + } + } + if (m_ui.numDec->isChecked()) { + uint32_t v = m_ui.value->text().toUInt(&ok, 10); + if (ok) { + switch (params->type) { + case mCORE_MEMORY_SEARCH_8: + ok = v < 0x100; + params->value8 = v; + break; + case mCORE_MEMORY_SEARCH_16: + ok = v < 0x10000; + params->value16 = v; + break; + case mCORE_MEMORY_SEARCH_32: + params->value32 = v; + break; + default: + ok = false; + } + } + } + } + if (m_ui.typeStr->isChecked()) { + params->type = mCORE_MEMORY_SEARCH_STRING; + m_string = m_ui.value->text().toLocal8Bit(); + params->valueStr = m_string.constData(); + ok = true; + } + return ok; } void MemorySearch::search() { - mCoreMemorySearchResults res; - mCoreMemorySearchResultsInit(&res, 0); + mCoreMemorySearchResultsClear(&m_results); mCoreMemorySearchParams params; - params.memoryFlags = mCORE_MEMORY_RW; GameController::Interrupter interrupter(m_controller); if (!m_controller->isLoaded()) { @@ -35,96 +108,74 @@ void MemorySearch::search() { } mCore* core = m_controller->thread()->core; - QByteArray string; - if (m_ui.typeNum->isChecked()) { - if (m_ui.bits8->isChecked()) { - params.type = mCORE_MEMORY_SEARCH_8; - } - if (m_ui.bits16->isChecked()) { - params.type = mCORE_MEMORY_SEARCH_16; - } - if (m_ui.bits32->isChecked()) { - params.type = mCORE_MEMORY_SEARCH_32; - } - if (m_ui.numHex->isChecked()) { - bool ok; - uint32_t v = m_ui.value->text().toUInt(&ok, 16); - if (ok) { - switch (params.type) { - case mCORE_MEMORY_SEARCH_8: - ok = v < 0x100; - params.value8 = v; - break; - case mCORE_MEMORY_SEARCH_16: - ok = v < 0x10000; - params.value16 = v; - break; - case mCORE_MEMORY_SEARCH_32: - params.value32 = v; - break; - default: - ok = false; - } - } - if (ok) { - mCoreMemorySearch(core, ¶ms, &res, 10000); - } - } - if (m_ui.numDec->isChecked()) { - bool ok; - uint32_t v = m_ui.value->text().toUInt(&ok, 10); - if (ok) { - switch (params.type) { - case mCORE_MEMORY_SEARCH_8: - ok = v < 0x100; - params.value8 = v; - break; - case mCORE_MEMORY_SEARCH_16: - ok = v < 0x10000; - params.value16 = v; - break; - case mCORE_MEMORY_SEARCH_32: - params.value32 = v; - break; - default: - ok = false; - } - } - if (ok) { - mCoreMemorySearch(core, ¶ms, &res, 10000); - } - } - } - if (m_ui.typeStr->isChecked()) { - params.type = mCORE_MEMORY_SEARCH_STRING; - string = m_ui.value->text().toLocal8Bit(); - params.valueStr = string; - mCoreMemorySearch(core, ¶ms, &res, 10000); + if (createParams(¶ms)) { + mCoreMemorySearch(core, ¶ms, &m_results, LIMIT); } - m_ui.results->clear(); - m_ui.results->setRowCount(mCoreMemorySearchResultsSize(&res)); - for (size_t i = 0; i < mCoreMemorySearchResultsSize(&res); ++i) { - mCoreMemorySearchResult* result = mCoreMemorySearchResultsGetPointer(&res, i); + refresh(); +} + +void MemorySearch::searchWithin() { + mCoreMemorySearchParams params; + + GameController::Interrupter interrupter(m_controller); + if (!m_controller->isLoaded()) { + return; + } + mCore* core = m_controller->thread()->core; + + if (createParams(¶ms)) { + mCoreMemorySearchRepeat(core, ¶ms, &m_results); + } + + refresh(); +} + +void MemorySearch::refresh() { + GameController::Interrupter interrupter(m_controller); + if (!m_controller->isLoaded()) { + return; + } + mCore* core = m_controller->thread()->core; + + m_ui.results->clearContents(); + m_ui.results->setRowCount(mCoreMemorySearchResultsSize(&m_results)); + for (size_t i = 0; i < mCoreMemorySearchResultsSize(&m_results); ++i) { + mCoreMemorySearchResult* result = mCoreMemorySearchResultsGetPointer(&m_results, i); QTableWidgetItem* item = new QTableWidgetItem(QString("%1").arg(result->address, 8, 16, QChar('0'))); m_ui.results->setItem(i, 0, item); - switch (result->type) { - case mCORE_MEMORY_SEARCH_8: - item = new QTableWidgetItem(QString("%1").arg(core->rawRead8(core, result->address, -1), 2, 16, QChar('0'))); - break; - case mCORE_MEMORY_SEARCH_16: - item = new QTableWidgetItem(QString("%1").arg(core->rawRead16(core, result->address, -1), 4, 16, QChar('0'))); - break; - case mCORE_MEMORY_SEARCH_GUESS: - case mCORE_MEMORY_SEARCH_32: - item = new QTableWidgetItem(QString("%1").arg(core->rawRead32(core, result->address, -1), 8, 16, QChar('0'))); - break; - case mCORE_MEMORY_SEARCH_STRING: - item = new QTableWidgetItem(params.valueStr); // TODO + if (m_ui.numHex->isChecked()) { + switch (result->type) { + case mCORE_MEMORY_SEARCH_8: + item = new QTableWidgetItem(QString("%1").arg(core->rawRead8(core, result->address, result->segment), 2, 16, QChar('0'))); + break; + case mCORE_MEMORY_SEARCH_16: + item = new QTableWidgetItem(QString("%1").arg(core->rawRead16(core, result->address, result->segment), 4, 16, QChar('0'))); + break; + case mCORE_MEMORY_SEARCH_GUESS: + case mCORE_MEMORY_SEARCH_32: + item = new QTableWidgetItem(QString("%1").arg(core->rawRead32(core, result->address, result->segment), 8, 16, QChar('0'))); + break; + case mCORE_MEMORY_SEARCH_STRING: + item = new QTableWidgetItem("?"); // TODO + } + } else { + switch (result->type) { + case mCORE_MEMORY_SEARCH_8: + item = new QTableWidgetItem(QString::number(core->rawRead8(core, result->address, result->segment))); + break; + case mCORE_MEMORY_SEARCH_16: + item = new QTableWidgetItem(QString::number(core->rawRead16(core, result->address, result->segment))); + break; + case mCORE_MEMORY_SEARCH_GUESS: + case mCORE_MEMORY_SEARCH_32: + item = new QTableWidgetItem(QString::number(core->rawRead32(core, result->address, result->segment))); + break; + case mCORE_MEMORY_SEARCH_STRING: + item = new QTableWidgetItem("?"); // TODO + } } m_ui.results->setItem(i, 1, item); } m_ui.results->sortItems(0); - - mCoreMemorySearchResultsDeinit(&res); } diff --git a/src/platform/qt/MemorySearch.h b/src/platform/qt/MemorySearch.h index 7d2c6faa5..3ca37c34c 100644 --- a/src/platform/qt/MemorySearch.h +++ b/src/platform/qt/MemorySearch.h @@ -8,6 +8,8 @@ #include "ui_MemorySearch.h" +#include + namespace QGBA { class GameController; @@ -16,15 +18,25 @@ class MemorySearch : public QWidget { Q_OBJECT public: + static constexpr size_t LIMIT = 10000; + MemorySearch(GameController* controller, QWidget* parent = nullptr); + ~MemorySearch(); public slots: + void refresh(); void search(); + void searchWithin(); private: + bool createParams(mCoreMemorySearchParams*); + Ui::MemorySearch m_ui; GameController* m_controller; + + mCoreMemorySearchResults m_results; + QByteArray m_string; }; } diff --git a/src/platform/qt/MemorySearch.ui b/src/platform/qt/MemorySearch.ui index b68b19ee2..ce000b55f 100644 --- a/src/platform/qt/MemorySearch.ui +++ b/src/platform/qt/MemorySearch.ui @@ -28,6 +28,9 @@ 0 + + QAbstractItemView::SelectRows + false @@ -75,6 +78,9 @@ Numeric + + true + type @@ -122,6 +128,9 @@ 4 Bytes (32-bit) + + true + width @@ -135,14 +144,17 @@ - + Hexadecimal + + true + - + Decimal @@ -168,9 +180,6 @@ - - false - Search Within @@ -186,6 +195,13 @@ + + + + Refresh + + + @@ -195,5 +211,6 @@ +