Core: Memory search repeat and refresh
Vicki Pfau vi@endrift.com
Mon, 05 Jun 2017 18:01:58 -0700
5 files changed,
208 insertions(+),
57 deletions(-)
M
include/mgba/core/mem-search.h
→
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
M
src/core/mem-search.c
→
src/core/mem-search.c
@@ -284,3 +284,73 @@ }
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; + } + } +}
M
src/platform/qt/MemorySearch.cpp
→
src/platform/qt/MemorySearch.cpp
@@ -7,7 +7,6 @@
#include "MemorySearch.h" #include <mgba/core/core.h> -#include <mgba/core/mem-search.h> #include "GameController.h"@@ -19,112 +18,164 @@ , m_controller(controller)
{ 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); } -void MemorySearch::search() { - mCoreMemorySearchResults res; - mCoreMemorySearchResultsInit(&res, 0); - - mCoreMemorySearchParams params; - params.memoryFlags = mCORE_MEMORY_RW; +MemorySearch::~MemorySearch() { + mCoreMemorySearchResultsDeinit(&m_results); +} - GameController::Interrupter interrupter(m_controller); - if (!m_controller->isLoaded()) { - return; - } +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; + params->type = mCORE_MEMORY_SEARCH_8; } if (m_ui.bits16->isChecked()) { - params.type = mCORE_MEMORY_SEARCH_16; + params->type = mCORE_MEMORY_SEARCH_16; } if (m_ui.bits32->isChecked()) { - params.type = mCORE_MEMORY_SEARCH_32; + 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) { + switch (params->type) { case mCORE_MEMORY_SEARCH_8: ok = v < 0x100; - params.value8 = v; + params->value8 = v; break; case mCORE_MEMORY_SEARCH_16: ok = v < 0x10000; - params.value16 = v; + params->value16 = v; break; case mCORE_MEMORY_SEARCH_32: - params.value32 = v; + 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) { + switch (params->type) { case mCORE_MEMORY_SEARCH_8: ok = v < 0x100; - params.value8 = v; + params->value8 = v; break; case mCORE_MEMORY_SEARCH_16: ok = v < 0x10000; - params.value16 = v; + params->value16 = v; break; case mCORE_MEMORY_SEARCH_32: - params.value32 = v; + 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); + 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() { + mCoreMemorySearchResultsClear(&m_results); + + mCoreMemorySearchParams params; + + GameController::Interrupter interrupter(m_controller); + if (!m_controller->isLoaded()) { + return; + } + mCore* core = m_controller->thread()->core; + + if (createParams(¶ms)) { + mCoreMemorySearch(core, ¶ms, &m_results, LIMIT); + } + + 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->clear(); - m_ui.results->setRowCount(mCoreMemorySearchResultsSize(&res)); - for (size_t i = 0; i < mCoreMemorySearchResultsSize(&res); ++i) { - mCoreMemorySearchResult* result = mCoreMemorySearchResultsGetPointer(&res, i); + 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); }
M
src/platform/qt/MemorySearch.h
→
src/platform/qt/MemorySearch.h
@@ -8,6 +8,8 @@ #define QGBA_MEMORY_SEARCH
#include "ui_MemorySearch.h" +#include <mgba/core/mem-search.h> + 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; }; }
M
src/platform/qt/MemorySearch.ui
→
src/platform/qt/MemorySearch.ui
@@ -28,6 +28,9 @@ <horstretch>1</horstretch>
<verstretch>0</verstretch> </sizepolicy> </property> + <property name="selectionBehavior"> + <enum>QAbstractItemView::SelectRows</enum> + </property> <property name="showGrid"> <bool>false</bool> </property>@@ -75,6 +78,9 @@ <widget class="QRadioButton" name="typeNum">
<property name="text"> <string>Numeric</string> </property> + <property name="checked"> + <bool>true</bool> + </property> <attribute name="buttonGroup"> <string notr="true">type</string> </attribute>@@ -122,6 +128,9 @@ <widget class="QRadioButton" name="bits32">
<property name="text"> <string>4 Bytes (32-bit)</string> </property> + <property name="checked"> + <bool>true</bool> + </property> <attribute name="buttonGroup"> <string notr="true">width</string> </attribute>@@ -135,14 +144,17 @@ </property>
</widget> </item> <item row="6" column="1"> - <widget class="QCheckBox" name="numHex"> + <widget class="QRadioButton" name="numHex"> <property name="text"> <string>Hexadecimal</string> + </property> + <property name="checked"> + <bool>true</bool> </property> </widget> </item> <item row="7" column="1"> - <widget class="QCheckBox" name="numDec"> + <widget class="QRadioButton" name="numDec"> <property name="text"> <string>Decimal</string> </property>@@ -168,9 +180,6 @@ </widget>
</item> <item> <widget class="QPushButton" name="searchWithin"> - <property name="enabled"> - <bool>false</bool> - </property> <property name="text"> <string>Search Within</string> </property>@@ -186,6 +195,13 @@ <string>View in Memory View</string>
</property> </widget> </item> + <item> + <widget class="QPushButton" name="refresh"> + <property name="text"> + <string>Refresh</string> + </property> + </widget> + </item> </layout> </item> </layout>@@ -195,5 +211,6 @@ <connections/>
<buttongroups> <buttongroup name="type"/> <buttongroup name="width"/> + <buttongroup name="numType"/> </buttongroups> </ui>