Core: Memory search repeat and refresh

This commit is contained in:
Vicki Pfau 2017-06-05 18:01:58 -07:00
parent f2db707bb2
commit cf7017dd86
5 changed files with 244 additions and 93 deletions

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -7,7 +7,6 @@
#include "MemorySearch.h"
#include <mgba/core/core.h>
#include <mgba/core/mem-search.h>
#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, &params, &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, &params, &res, 10000);
}
}
}
if (m_ui.typeStr->isChecked()) {
params.type = mCORE_MEMORY_SEARCH_STRING;
string = m_ui.value->text().toLocal8Bit();
params.valueStr = string;
mCoreMemorySearch(core, &params, &res, 10000);
if (createParams(&params)) {
mCoreMemorySearch(core, &params, &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(&params)) {
mCoreMemorySearchRepeat(core, &params, &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);
}

View File

@ -8,6 +8,8 @@
#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;
};
}

View File

@ -28,6 +28,9 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="showGrid">
<bool>false</bool>
</property>
@ -75,6 +78,9 @@
<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 @@
<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 @@
</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 @@
</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 @@
</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 @@
<buttongroups>
<buttongroup name="type"/>
<buttongroup name="width"/>
<buttongroup name="numType"/>
</buttongroups>
</ui>