mirror of https://github.com/mgba-emu/mgba.git
Core: Memory search repeat and refresh
This commit is contained in:
parent
f2db707bb2
commit
cf7017dd86
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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, ¶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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue