all repos — mgba @ 77cf8699414b30b2901f941cd06810e1d5b2e7a8

mGBA Game Boy Advance Emulator

src/platform/qt/MemorySearch.cpp (view raw)

  1/* Copyright (c) 2013-2017 Jeffrey Pfau
  2 *
  3 * This Source Code Form is subject to the terms of the Mozilla Public
  4 * License, v. 2.0. If a copy of the MPL was not distributed with this
  5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6
  7#include "MemorySearch.h"
  8
  9#include <mgba/core/core.h>
 10
 11#include "GameController.h"
 12#include "MemoryView.h"
 13
 14using namespace QGBA;
 15
 16MemorySearch::MemorySearch(GameController* controller, QWidget* parent)
 17	: QWidget(parent)
 18	, m_controller(controller)
 19{
 20	m_ui.setupUi(this);
 21
 22	mCoreMemorySearchResultsInit(&m_results, 0);
 23	connect(m_ui.search, &QPushButton::clicked, this, &MemorySearch::search);
 24	connect(m_ui.searchWithin, &QPushButton::clicked, this, &MemorySearch::searchWithin);
 25	connect(m_ui.refresh, &QPushButton::clicked, this, &MemorySearch::refresh);
 26	connect(m_ui.numHex, &QPushButton::clicked, this, &MemorySearch::refresh);
 27	connect(m_ui.numDec, &QPushButton::clicked, this, &MemorySearch::refresh);
 28	connect(m_ui.viewMem, &QPushButton::clicked, this, &MemorySearch::openMemory);
 29}
 30
 31MemorySearch::~MemorySearch() {
 32	mCoreMemorySearchResultsDeinit(&m_results);
 33}
 34
 35bool MemorySearch::createParams(mCoreMemorySearchParams* params) {
 36	params->memoryFlags = mCORE_MEMORY_RW;
 37	mCore* core = m_controller->thread()->core;
 38
 39	QByteArray string;
 40	bool ok = false;
 41	if (m_ui.typeNum->isChecked()) {
 42		if (m_ui.bits8->isChecked()) {
 43			params->type = mCORE_MEMORY_SEARCH_8;
 44		}
 45		if (m_ui.bits16->isChecked()) {
 46			params->type = mCORE_MEMORY_SEARCH_16;
 47		}
 48		if (m_ui.bits32->isChecked()) {
 49			params->type = mCORE_MEMORY_SEARCH_32;
 50		}
 51		if (m_ui.numHex->isChecked()) {
 52			bool ok;
 53			uint32_t v = m_ui.value->text().toUInt(&ok, 16);
 54			if (ok) {
 55				switch (params->type) {
 56				case mCORE_MEMORY_SEARCH_8:
 57					ok = v < 0x100;
 58					params->value8 = v;
 59					break;
 60				case mCORE_MEMORY_SEARCH_16:
 61					ok = v < 0x10000;
 62					params->value16 = v;
 63					break;
 64				case mCORE_MEMORY_SEARCH_32:
 65					params->value32 = v;
 66					break;
 67				default:
 68					ok = false;
 69				}
 70			}
 71		}
 72		if (m_ui.numDec->isChecked()) {
 73			uint32_t v = m_ui.value->text().toUInt(&ok, 10);
 74			if (ok) {
 75				switch (params->type) {
 76				case mCORE_MEMORY_SEARCH_8:
 77					ok = v < 0x100;
 78					params->value8 = v;
 79					break;
 80				case mCORE_MEMORY_SEARCH_16:
 81					ok = v < 0x10000;
 82					params->value16 = v;
 83					break;
 84				case mCORE_MEMORY_SEARCH_32:
 85					params->value32 = v;
 86					break;
 87				default:
 88					ok = false;
 89				}
 90			}
 91		}
 92		if (m_ui.numGuess->isChecked()) {
 93			params->type = mCORE_MEMORY_SEARCH_GUESS;
 94			m_string = m_ui.value->text().toLocal8Bit();
 95			params->valueStr = m_string.constData();
 96			ok = true;
 97		}
 98	}
 99	if (m_ui.typeStr->isChecked()) {
100		params->type = mCORE_MEMORY_SEARCH_STRING;
101		m_string = m_ui.value->text().toLocal8Bit();
102		params->valueStr = m_string.constData();
103		ok = true;
104	}
105	return ok;
106}
107
108void MemorySearch::search() {
109	mCoreMemorySearchResultsClear(&m_results);
110
111	mCoreMemorySearchParams params;
112
113	GameController::Interrupter interrupter(m_controller);
114	if (!m_controller->isLoaded()) {
115		return;
116	}
117	mCore* core = m_controller->thread()->core;
118
119	if (createParams(&params)) {
120		mCoreMemorySearch(core, &params, &m_results, LIMIT);
121	}
122
123	refresh();
124}
125
126void MemorySearch::searchWithin() {
127	mCoreMemorySearchParams params;
128
129	GameController::Interrupter interrupter(m_controller);
130	if (!m_controller->isLoaded()) {
131		return;
132	}
133	mCore* core = m_controller->thread()->core;
134
135	if (createParams(&params)) {
136		mCoreMemorySearchRepeat(core, &params, &m_results);
137	}
138
139	refresh();
140}
141
142void MemorySearch::refresh() {
143	GameController::Interrupter interrupter(m_controller);
144	if (!m_controller->isLoaded()) {
145		return;
146	}
147	mCore* core = m_controller->thread()->core;
148
149	m_ui.results->clearContents();
150	m_ui.results->setRowCount(mCoreMemorySearchResultsSize(&m_results));
151	for (size_t i = 0; i < mCoreMemorySearchResultsSize(&m_results); ++i) {
152		mCoreMemorySearchResult* result = mCoreMemorySearchResultsGetPointer(&m_results, i);
153		QTableWidgetItem* item = new QTableWidgetItem(QString("%1").arg(result->address, 8, 16, QChar('0')));
154		m_ui.results->setItem(i, 0, item);
155		if (m_ui.numHex->isChecked()) {
156			switch (result->type) {
157			case mCORE_MEMORY_SEARCH_8:
158				item = new QTableWidgetItem(QString("%1").arg(core->rawRead8(core, result->address, result->segment), 2, 16, QChar('0')));
159				break;
160			case mCORE_MEMORY_SEARCH_16:
161				item = new QTableWidgetItem(QString("%1").arg(core->rawRead16(core, result->address, result->segment), 4, 16, QChar('0')));
162				break;
163			case mCORE_MEMORY_SEARCH_GUESS:
164			case mCORE_MEMORY_SEARCH_32:
165				item = new QTableWidgetItem(QString("%1").arg(core->rawRead32(core, result->address, result->segment), 8, 16, QChar('0')));
166				break;
167			case mCORE_MEMORY_SEARCH_STRING:
168				item = new QTableWidgetItem("?"); // TODO
169			}
170		} else {
171			switch (result->type) {
172			case mCORE_MEMORY_SEARCH_8:
173				item = new QTableWidgetItem(QString::number(core->rawRead8(core, result->address, result->segment)));
174				break;
175			case mCORE_MEMORY_SEARCH_16:
176				item = new QTableWidgetItem(QString::number(core->rawRead16(core, result->address, result->segment)));
177				break;
178			case mCORE_MEMORY_SEARCH_GUESS:
179			case mCORE_MEMORY_SEARCH_32:
180				item = new QTableWidgetItem(QString::number(core->rawRead32(core, result->address, result->segment)));
181				break;
182			case mCORE_MEMORY_SEARCH_STRING:
183				item = new QTableWidgetItem("?"); // TODO
184			}
185		}
186		m_ui.results->setItem(i, 1, item);
187	}
188	m_ui.results->sortItems(0);
189}
190
191void MemorySearch::openMemory() {
192	auto items = m_ui.results->selectedItems();
193	if (items.empty()) {
194		return;
195	}
196	QTableWidgetItem* item = items[0];
197	uint32_t address = item->text().toUInt(nullptr, 16);
198
199	MemoryView* memView = new MemoryView(m_controller);
200	memView->jumpToAddress(address);
201
202	connect(m_controller, &GameController::gameStopped, memView, &QWidget::close);
203	memView->setAttribute(Qt::WA_DeleteOnClose);
204	memView->show();
205}