mirror of https://github.com/mgba-emu/mgba.git
Core: Basic memory search
This commit is contained in:
parent
202b7b1509
commit
f2db707bb2
|
@ -0,0 +1,47 @@
|
|||
/* Copyright (c) 2013-2017 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#ifndef CORE_MEM_SEARCH_H
|
||||
#define CORE_MEM_SEARCH_H
|
||||
|
||||
#include <mgba-util/common.h>
|
||||
|
||||
CXX_GUARD_START
|
||||
|
||||
#include <mgba-util/vector.h>
|
||||
|
||||
enum mCoreMemorySearchType {
|
||||
mCORE_MEMORY_SEARCH_32,
|
||||
mCORE_MEMORY_SEARCH_16,
|
||||
mCORE_MEMORY_SEARCH_8,
|
||||
mCORE_MEMORY_SEARCH_STRING,
|
||||
mCORE_MEMORY_SEARCH_GUESS,
|
||||
};
|
||||
|
||||
struct mCoreMemorySearchParams {
|
||||
int memoryFlags;
|
||||
enum mCoreMemorySearchType type;
|
||||
union {
|
||||
const char* valueStr;
|
||||
uint32_t value32;
|
||||
uint32_t value16;
|
||||
uint32_t value8;
|
||||
};
|
||||
};
|
||||
|
||||
struct mCoreMemorySearchResult {
|
||||
uint32_t address;
|
||||
int segment;
|
||||
enum mCoreMemorySearchType type;
|
||||
};
|
||||
|
||||
DECLARE_VECTOR(mCoreMemorySearchResults, struct mCoreMemorySearchResult);
|
||||
|
||||
struct mCore;
|
||||
void mCoreMemorySearch(struct mCore* core, const struct mCoreMemorySearchParams* params, struct mCoreMemorySearchResults* out, size_t limit);
|
||||
|
||||
CXX_GUARD_END
|
||||
|
||||
#endif
|
|
@ -0,0 +1,286 @@
|
|||
/* Copyright (c) 2013-2017 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include <mgba/core/mem-search.h>
|
||||
|
||||
#include <mgba/core/core.h>
|
||||
#include <mgba/core/interface.h>
|
||||
|
||||
DEFINE_VECTOR(mCoreMemorySearchResults, struct mCoreMemorySearchResult);
|
||||
|
||||
static size_t _search32(const void* mem, size_t size, const struct mCoreMemoryBlock* block, uint32_t value32, struct mCoreMemorySearchResults* out, size_t limit) {
|
||||
const uint32_t* mem32 = mem;
|
||||
size_t found = 0;
|
||||
uint32_t start = block->start;
|
||||
uint32_t end = size; // TODO: Segments
|
||||
size_t i;
|
||||
// TODO: Big endian
|
||||
for (i = 0; (!limit || found < limit) && i < end; i += 16) {
|
||||
int mask = 0;
|
||||
mask |= (mem32[(i >> 2) + 0] == value32) << 0;
|
||||
mask |= (mem32[(i >> 2) + 1] == value32) << 1;
|
||||
mask |= (mem32[(i >> 2) + 2] == value32) << 2;
|
||||
mask |= (mem32[(i >> 2) + 3] == value32) << 3;
|
||||
if (!mask) {
|
||||
continue;
|
||||
}
|
||||
if ((mask & 1) && (!limit || found < limit)) {
|
||||
struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
|
||||
res->address = start + i;
|
||||
res->type = mCORE_MEMORY_SEARCH_32;
|
||||
res->segment = -1; // TODO
|
||||
++found;
|
||||
}
|
||||
if ((mask & 2) && (!limit || found < limit)) {
|
||||
struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
|
||||
res->address = start + i + 4;
|
||||
res->type = mCORE_MEMORY_SEARCH_32;
|
||||
res->segment = -1; // TODO
|
||||
++found;
|
||||
}
|
||||
if ((mask & 4) && (!limit || found < limit)) {
|
||||
struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
|
||||
res->address = start + i + 8;
|
||||
res->type = mCORE_MEMORY_SEARCH_32;
|
||||
res->segment = -1; // TODO
|
||||
++found;
|
||||
}
|
||||
if ((mask & 8) && (!limit || found < limit)) {
|
||||
struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
|
||||
res->address = start + i + 12;
|
||||
res->type = mCORE_MEMORY_SEARCH_32;
|
||||
res->segment = -1; // TODO
|
||||
++found;
|
||||
}
|
||||
}
|
||||
// TODO: last 12 bytes
|
||||
return found;
|
||||
}
|
||||
|
||||
static size_t _search16(const void* mem, size_t size, const struct mCoreMemoryBlock* block, uint16_t value16, struct mCoreMemorySearchResults* out, size_t limit) {
|
||||
const uint16_t* mem16 = mem;
|
||||
size_t found = 0;
|
||||
uint32_t start = block->start;
|
||||
uint32_t end = size; // TODO: Segments
|
||||
size_t i;
|
||||
// TODO: Big endian
|
||||
for (i = 0; (!limit || found < limit) && i < end; i += 16) {
|
||||
int mask = 0;
|
||||
mask |= (mem16[(i >> 1) + 0] == value16) << 0;
|
||||
mask |= (mem16[(i >> 1) + 1] == value16) << 1;
|
||||
mask |= (mem16[(i >> 1) + 2] == value16) << 2;
|
||||
mask |= (mem16[(i >> 1) + 3] == value16) << 3;
|
||||
mask |= (mem16[(i >> 1) + 4] == value16) << 4;
|
||||
mask |= (mem16[(i >> 1) + 5] == value16) << 5;
|
||||
mask |= (mem16[(i >> 1) + 6] == value16) << 6;
|
||||
mask |= (mem16[(i >> 1) + 7] == value16) << 7;
|
||||
if (!mask) {
|
||||
continue;
|
||||
}
|
||||
if ((mask & 1) && (!limit || found < limit)) {
|
||||
struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
|
||||
res->address = start + i;
|
||||
res->type = mCORE_MEMORY_SEARCH_16;
|
||||
res->segment = -1; // TODO
|
||||
++found;
|
||||
}
|
||||
if ((mask & 2) && (!limit || found < limit)) {
|
||||
struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
|
||||
res->address = start + i + 2;
|
||||
res->type = mCORE_MEMORY_SEARCH_16;
|
||||
res->segment = -1; // TODO
|
||||
++found;
|
||||
}
|
||||
if ((mask & 4) && (!limit || found < limit)) {
|
||||
struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
|
||||
res->address = start + i + 4;
|
||||
res->type = mCORE_MEMORY_SEARCH_16;
|
||||
res->segment = -1; // TODO
|
||||
++found;
|
||||
}
|
||||
if ((mask & 8) && (!limit || found < limit)) {
|
||||
struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
|
||||
res->address = start + i + 6;
|
||||
res->type = mCORE_MEMORY_SEARCH_16;
|
||||
res->segment = -1; // TODO
|
||||
++found;
|
||||
}
|
||||
if ((mask & 16) && (!limit || found < limit)) {
|
||||
struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
|
||||
res->address = start + i + 8;
|
||||
res->type = mCORE_MEMORY_SEARCH_16;
|
||||
res->segment = -1; // TODO
|
||||
++found;
|
||||
}
|
||||
if ((mask & 32) && (!limit || found < limit)) {
|
||||
struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
|
||||
res->address = start + i + 10;
|
||||
res->type = mCORE_MEMORY_SEARCH_16;
|
||||
res->segment = -1; // TODO
|
||||
++found;
|
||||
}
|
||||
if ((mask & 64) && (!limit || found < limit)) {
|
||||
struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
|
||||
res->address = start + i + 12;
|
||||
res->type = mCORE_MEMORY_SEARCH_16;
|
||||
res->segment = -1; // TODO
|
||||
++found;
|
||||
}
|
||||
if ((mask & 128) && (!limit || found < limit)) {
|
||||
struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
|
||||
res->address = start + i + 14;
|
||||
res->type = mCORE_MEMORY_SEARCH_16;
|
||||
res->segment = -1; // TODO
|
||||
++found;
|
||||
}
|
||||
}
|
||||
// TODO: last 14 bytes
|
||||
return found;
|
||||
}
|
||||
|
||||
static size_t _search8(const void* mem, size_t size, const struct mCoreMemoryBlock* block, uint8_t value8, struct mCoreMemorySearchResults* out, size_t limit) {
|
||||
const uint8_t* mem8 = mem;
|
||||
size_t found = 0;
|
||||
uint32_t start = block->start;
|
||||
uint32_t end = size; // TODO: Segments
|
||||
size_t i;
|
||||
for (i = 0; (!limit || found < limit) && i < end; i += 8) {
|
||||
int mask = 0;
|
||||
mask |= (mem8[i + 0] == value8) << 0;
|
||||
mask |= (mem8[i + 1] == value8) << 1;
|
||||
mask |= (mem8[i + 2] == value8) << 2;
|
||||
mask |= (mem8[i + 3] == value8) << 3;
|
||||
mask |= (mem8[i + 4] == value8) << 4;
|
||||
mask |= (mem8[i + 5] == value8) << 5;
|
||||
mask |= (mem8[i + 6] == value8) << 6;
|
||||
mask |= (mem8[i + 7] == value8) << 7;
|
||||
if (!mask) {
|
||||
continue;
|
||||
}
|
||||
if ((mask & 1) && (!limit || found < limit)) {
|
||||
struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
|
||||
res->address = start + i;
|
||||
res->type = mCORE_MEMORY_SEARCH_8;
|
||||
res->segment = -1; // TODO
|
||||
++found;
|
||||
}
|
||||
if ((mask & 2) && (!limit || found < limit)) {
|
||||
struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
|
||||
res->address = start + i + 1;
|
||||
res->type = mCORE_MEMORY_SEARCH_8;
|
||||
res->segment = -1; // TODO
|
||||
++found;
|
||||
}
|
||||
if ((mask & 4) && (!limit || found < limit)) {
|
||||
struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
|
||||
res->address = start + i + 2;
|
||||
res->type = mCORE_MEMORY_SEARCH_8;
|
||||
res->segment = -1; // TODO
|
||||
++found;
|
||||
}
|
||||
if ((mask & 8) && (!limit || found < limit)) {
|
||||
struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
|
||||
res->address = start + i + 3;
|
||||
res->type = mCORE_MEMORY_SEARCH_8;
|
||||
res->segment = -1; // TODO
|
||||
++found;
|
||||
}
|
||||
if ((mask & 16) && (!limit || found < limit)) {
|
||||
struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
|
||||
res->address = start + i + 4;
|
||||
res->type = mCORE_MEMORY_SEARCH_8;
|
||||
res->segment = -1; // TODO
|
||||
++found;
|
||||
}
|
||||
if ((mask & 32) && (!limit || found < limit)) {
|
||||
struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
|
||||
res->address = start + i + 5;
|
||||
res->type = mCORE_MEMORY_SEARCH_8;
|
||||
res->segment = -1; // TODO
|
||||
++found;
|
||||
}
|
||||
if ((mask & 64) && (!limit || found < limit)) {
|
||||
struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
|
||||
res->address = start + i + 6;
|
||||
res->type = mCORE_MEMORY_SEARCH_8;
|
||||
res->segment = -1; // TODO
|
||||
++found;
|
||||
}
|
||||
if ((mask & 128) && (!limit || found < limit)) {
|
||||
struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
|
||||
res->address = start + i + 7;
|
||||
res->type = mCORE_MEMORY_SEARCH_8;
|
||||
res->segment = -1; // TODO
|
||||
++found;
|
||||
}
|
||||
}
|
||||
// TODO: last 7 bytes
|
||||
return found;
|
||||
}
|
||||
|
||||
static size_t _searchStr(const void* mem, size_t size, const struct mCoreMemoryBlock* block, const char* valueStr, struct mCoreMemorySearchResults* out, size_t limit) {
|
||||
const char* memStr = mem;
|
||||
size_t found = 0;
|
||||
size_t len = strlen(valueStr);
|
||||
uint32_t start = block->start;
|
||||
uint32_t end = size; // TODO: Segments
|
||||
size_t i;
|
||||
for (i = 0; (!limit || found < limit) && i < end - len; ++i) {
|
||||
if (!strncmp(valueStr, &memStr[i], len)) {
|
||||
struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsAppend(out);
|
||||
res->address = start + i;
|
||||
res->type = mCORE_MEMORY_SEARCH_STRING;
|
||||
res->segment = -1; // TODO
|
||||
++found;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
static size_t _searchGuess(const void* mem, size_t size, const struct mCoreMemoryBlock* block, const char* valueStr, struct mCoreMemorySearchResults* out, size_t limit) {
|
||||
// TODO: As hex
|
||||
// TODO: As decimal
|
||||
// TODO: As BCD
|
||||
// TODO: As str
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t _search(const void* mem, size_t size, const struct mCoreMemoryBlock* block, const struct mCoreMemorySearchParams* params, struct mCoreMemorySearchResults* out, size_t limit) {
|
||||
switch (params->type) {
|
||||
case mCORE_MEMORY_SEARCH_32:
|
||||
return _search32(mem, size, block, params->value32, out, limit);
|
||||
case mCORE_MEMORY_SEARCH_16:
|
||||
return _search16(mem, size, block, params->value16, out, limit);
|
||||
case mCORE_MEMORY_SEARCH_8:
|
||||
return _search8(mem, size, block, params->value8, out, limit);
|
||||
case mCORE_MEMORY_SEARCH_STRING:
|
||||
return _searchStr(mem, size, block, params->valueStr, out, limit);
|
||||
case mCORE_MEMORY_SEARCH_GUESS:
|
||||
return _searchGuess(mem, size, block, params->valueStr, out, limit);
|
||||
}
|
||||
}
|
||||
|
||||
void mCoreMemorySearch(struct mCore* core, const struct mCoreMemorySearchParams* params, struct mCoreMemorySearchResults* out, size_t limit) {
|
||||
const struct mCoreMemoryBlock* blocks;
|
||||
size_t nBlocks = core->listMemoryBlocks(core, &blocks);
|
||||
size_t found = 0;
|
||||
|
||||
size_t b;
|
||||
for (b = 0; (!limit || found < limit) && b < nBlocks; ++b) {
|
||||
size_t size;
|
||||
const struct mCoreMemoryBlock* block = &blocks[b];
|
||||
if (!(block->flags & params->memoryFlags)) {
|
||||
continue;
|
||||
}
|
||||
void* mem = core->getMemoryBlock(core, block->id, &size);
|
||||
if (!mem) {
|
||||
continue;
|
||||
}
|
||||
if (size > block->end - block->start) {
|
||||
size = block->end - block->start; // TOOD: Segments
|
||||
}
|
||||
found += _search(mem, size, block, params, out, limit ? limit - found : 0);
|
||||
}
|
||||
}
|
|
@ -84,6 +84,7 @@ set(SOURCE_FILES
|
|||
LogController.cpp
|
||||
LogView.cpp
|
||||
MemoryModel.cpp
|
||||
MemorySearch.cpp
|
||||
MemoryView.cpp
|
||||
MessagePainter.cpp
|
||||
MultiplayerController.cpp
|
||||
|
@ -115,6 +116,7 @@ set(UI_FILES
|
|||
IOViewer.ui
|
||||
LoadSaveState.ui
|
||||
LogView.ui
|
||||
MemorySearch.ui
|
||||
MemoryView.ui
|
||||
ObjView.ui
|
||||
OverrideView.ui
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
/* Copyright (c) 2013-2017 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "MemorySearch.h"
|
||||
|
||||
#include <mgba/core/core.h>
|
||||
#include <mgba/core/mem-search.h>
|
||||
|
||||
#include "GameController.h"
|
||||
|
||||
using namespace QGBA;
|
||||
|
||||
MemorySearch::MemorySearch(GameController* controller, QWidget* parent)
|
||||
: QWidget(parent)
|
||||
, m_controller(controller)
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
|
||||
connect(m_ui.search, &QPushButton::clicked, this, &MemorySearch::search);
|
||||
}
|
||||
|
||||
void MemorySearch::search() {
|
||||
mCoreMemorySearchResults res;
|
||||
mCoreMemorySearchResultsInit(&res, 0);
|
||||
|
||||
mCoreMemorySearchParams params;
|
||||
params.memoryFlags = mCORE_MEMORY_RW;
|
||||
|
||||
GameController::Interrupter interrupter(m_controller);
|
||||
if (!m_controller->isLoaded()) {
|
||||
return;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
m_ui.results->clear();
|
||||
m_ui.results->setRowCount(mCoreMemorySearchResultsSize(&res));
|
||||
for (size_t i = 0; i < mCoreMemorySearchResultsSize(&res); ++i) {
|
||||
mCoreMemorySearchResult* result = mCoreMemorySearchResultsGetPointer(&res, 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
|
||||
}
|
||||
m_ui.results->setItem(i, 1, item);
|
||||
}
|
||||
m_ui.results->sortItems(0);
|
||||
|
||||
mCoreMemorySearchResultsDeinit(&res);
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/* Copyright (c) 2013-2017 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#ifndef QGBA_MEMORY_SEARCH
|
||||
#define QGBA_MEMORY_SEARCH
|
||||
|
||||
#include "ui_MemorySearch.h"
|
||||
|
||||
namespace QGBA {
|
||||
|
||||
class GameController;
|
||||
|
||||
class MemorySearch : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MemorySearch(GameController* controller, QWidget* parent = nullptr);
|
||||
|
||||
public slots:
|
||||
void search();
|
||||
|
||||
private:
|
||||
Ui::MemorySearch m_ui;
|
||||
|
||||
GameController* m_controller;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,199 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MemorySearch</class>
|
||||
<widget class="QWidget" name="MemorySearch">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>631</width>
|
||||
<height>378</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>540</width>
|
||||
<height>241</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="1">
|
||||
<widget class="QTableWidget" name="results">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="showGrid">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Address</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Current Value</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Type</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Value</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="value"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Type</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QRadioButton" name="typeNum">
|
||||
<property name="text">
|
||||
<string>Numeric</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">type</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QRadioButton" name="typeStr">
|
||||
<property name="text">
|
||||
<string>Text</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">type</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Width</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QRadioButton" name="bits8">
|
||||
<property name="text">
|
||||
<string>1 Byte (8-bit)</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">width</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QRadioButton" name="bits16">
|
||||
<property name="text">
|
||||
<string>2 Bytes (16-bit)</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">width</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QRadioButton" name="bits32">
|
||||
<property name="text">
|
||||
<string>4 Bytes (32-bit)</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">width</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Number type</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QCheckBox" name="numHex">
|
||||
<property name="text">
|
||||
<string>Hexadecimal</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QCheckBox" name="numDec">
|
||||
<property name="text">
|
||||
<string>Decimal</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Close</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="search">
|
||||
<property name="text">
|
||||
<string>Search</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="searchWithin">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Search Within</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="viewMem">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>View in Memory View</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
<buttongroups>
|
||||
<buttongroup name="type"/>
|
||||
<buttongroup name="width"/>
|
||||
</buttongroups>
|
||||
</ui>
|
|
@ -34,6 +34,7 @@
|
|||
#include "LoadSaveState.h"
|
||||
#include "LogView.h"
|
||||
#include "MultiplayerController.h"
|
||||
#include "MemorySearch.h"
|
||||
#include "MemoryView.h"
|
||||
#include "OverrideView.h"
|
||||
#include "ObjView.h"
|
||||
|
@ -1422,6 +1423,11 @@ void Window::setupMenu(QMenuBar* menubar) {
|
|||
m_gameActions.append(memoryView);
|
||||
addControlledAction(toolsMenu, memoryView, "memoryView");
|
||||
|
||||
QAction* memorySearch = new QAction(tr("Search memory..."), toolsMenu);
|
||||
connect(memorySearch, &QAction::triggered, openTView<MemorySearch>());
|
||||
m_gameActions.append(memorySearch);
|
||||
addControlledAction(toolsMenu, memorySearch, "memorySearch");
|
||||
|
||||
#ifdef M_CORE_GBA
|
||||
QAction* ioViewer = new QAction(tr("View &I/O registers..."), toolsMenu);
|
||||
connect(ioViewer, &QAction::triggered, openTView<IOViewer>());
|
||||
|
|
Loading…
Reference in New Issue