all repos — mgba @ e9c393b8767aa0656359ffe5df43777d47ed31b2

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 "CoreController.h"
 12#include "MemoryView.h"
 13
 14using namespace QGBA;
 15
 16MemorySearch::MemorySearch(std::shared_ptr<CoreController> 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	connect(controller.get(), &CoreController::stopping, this, &QWidget::close);
 31}
 32
 33MemorySearch::~MemorySearch() {
 34	mCoreMemorySearchResultsDeinit(&m_results);
 35}
 36
 37bool MemorySearch::createParams(mCoreMemorySearchParams* params) {
 38	params->memoryFlags = mCORE_MEMORY_RW;
 39	mCore* core = m_controller->thread()->core;
 40
 41	QByteArray string;
 42	bool ok = false;
 43	if (m_ui.typeNum->isChecked()) {
 44		if (m_ui.bits8->isChecked()) {
 45			params->type = mCORE_MEMORY_SEARCH_8;
 46		}
 47		if (m_ui.bits16->isChecked()) {
 48			params->type = mCORE_MEMORY_SEARCH_16;
 49		}
 50		if (m_ui.bits32->isChecked()) {
 51			params->type = mCORE_MEMORY_SEARCH_32;
 52		}
 53		if (m_ui.numHex->isChecked()) {
 54			uint32_t v = m_ui.value->text().toUInt(&ok, 16);
 55			if (ok) {
 56				switch (params->type) {
 57				case mCORE_MEMORY_SEARCH_8:
 58					ok = v < 0x100;
 59					params->value8 = v;
 60					break;
 61				case mCORE_MEMORY_SEARCH_16:
 62					ok = v < 0x10000;
 63					params->value16 = v;
 64					break;
 65				case mCORE_MEMORY_SEARCH_32:
 66					params->value32 = v;
 67					break;
 68				default:
 69					ok = false;
 70				}
 71			}
 72		}
 73		if (m_ui.numDec->isChecked()) {
 74			uint32_t v = m_ui.value->text().toUInt(&ok, 10);
 75			if (ok) {
 76				switch (params->type) {
 77				case mCORE_MEMORY_SEARCH_8:
 78					ok = v < 0x100;
 79					params->value8 = v;
 80					break;
 81				case mCORE_MEMORY_SEARCH_16:
 82					ok = v < 0x10000;
 83					params->value16 = v;
 84					break;
 85				case mCORE_MEMORY_SEARCH_32:
 86					params->value32 = v;
 87					break;
 88				default:
 89					ok = false;
 90				}
 91			}
 92		}
 93		if (m_ui.numGuess->isChecked()) {
 94			params->type = mCORE_MEMORY_SEARCH_GUESS;
 95			m_string = m_ui.value->text().toLocal8Bit();
 96			params->valueStr = m_string.constData();
 97			ok = true;
 98		}
 99	}
100	if (m_ui.typeStr->isChecked()) {
101		params->type = mCORE_MEMORY_SEARCH_STRING;
102		m_string = m_ui.value->text().toLocal8Bit();
103		params->valueStr = m_string.constData();
104		ok = true;
105	}
106	return ok;
107}
108
109void MemorySearch::search() {
110	mCoreMemorySearchResultsClear(&m_results);
111
112	mCoreMemorySearchParams params;
113
114	CoreController::Interrupter interrupter(m_controller);
115	mCore* core = m_controller->thread()->core;
116
117	if (createParams(&params)) {
118		mCoreMemorySearch(core, &params, &m_results, LIMIT);
119	}
120
121	refresh();
122}
123
124void MemorySearch::searchWithin() {
125	mCoreMemorySearchParams params;
126
127	CoreController::Interrupter interrupter(m_controller);
128	mCore* core = m_controller->thread()->core;
129
130	if (createParams(&params)) {
131		mCoreMemorySearchRepeat(core, &params, &m_results);
132	}
133
134	refresh();
135}
136
137void MemorySearch::refresh() {
138	CoreController::Interrupter interrupter(m_controller);
139	mCore* core = m_controller->thread()->core;
140
141	m_ui.results->clearContents();
142	m_ui.results->setRowCount(mCoreMemorySearchResultsSize(&m_results));
143	for (size_t i = 0; i < mCoreMemorySearchResultsSize(&m_results); ++i) {
144		mCoreMemorySearchResult* result = mCoreMemorySearchResultsGetPointer(&m_results, i);
145		QTableWidgetItem* item = new QTableWidgetItem(QString("%1").arg(result->address, 8, 16, QChar('0')));
146		m_ui.results->setItem(i, 0, item);
147		QTableWidgetItem* type;
148		if (m_ui.numHex->isChecked()) {
149			switch (result->type) {
150			case mCORE_MEMORY_SEARCH_8:
151				item = new QTableWidgetItem(QString("%1").arg(core->rawRead8(core, result->address, result->segment), 2, 16, QChar('0')));
152				break;
153			case mCORE_MEMORY_SEARCH_16:
154				item = new QTableWidgetItem(QString("%1").arg(core->rawRead16(core, result->address, result->segment), 4, 16, QChar('0')));
155				break;
156			case mCORE_MEMORY_SEARCH_GUESS:
157			case mCORE_MEMORY_SEARCH_32:
158				item = new QTableWidgetItem(QString("%1").arg(core->rawRead32(core, result->address, result->segment), 8, 16, QChar('0')));
159				break;
160			case mCORE_MEMORY_SEARCH_STRING:
161				item = new QTableWidgetItem("?"); // TODO
162			}
163		} else {
164			switch (result->type) {
165			case mCORE_MEMORY_SEARCH_8:
166				item = new QTableWidgetItem(QString::number(core->rawRead8(core, result->address, result->segment)));
167				break;
168			case mCORE_MEMORY_SEARCH_16:
169				item = new QTableWidgetItem(QString::number(core->rawRead16(core, result->address, result->segment)));
170				break;
171			case mCORE_MEMORY_SEARCH_GUESS:
172			case mCORE_MEMORY_SEARCH_32:
173				item = new QTableWidgetItem(QString::number(core->rawRead32(core, result->address, result->segment)));
174				break;
175			case mCORE_MEMORY_SEARCH_STRING:
176				item = new QTableWidgetItem("?"); // TODO
177			}
178		}
179		QString divisor;
180		if (result->guessDivisor > 1) {
181			divisor = tr(" (⅟%0×)").arg(result->guessDivisor);
182		}
183		switch (result->type) {
184		case mCORE_MEMORY_SEARCH_8:
185			type = new QTableWidgetItem(tr("1 byte%0").arg(divisor));
186			break;
187		case mCORE_MEMORY_SEARCH_16:
188			type = new QTableWidgetItem(tr("2 bytes%0").arg(divisor));
189			break;
190		case mCORE_MEMORY_SEARCH_GUESS:
191		case mCORE_MEMORY_SEARCH_32:
192			type = new QTableWidgetItem(tr("4 bytes%0").arg(divisor));
193			break;
194		case mCORE_MEMORY_SEARCH_STRING:
195			item = new QTableWidgetItem("?"); // TODO
196		}
197		m_ui.results->setItem(i, 1, item);
198		m_ui.results->setItem(i, 2, type);
199	}
200	m_ui.results->sortItems(0);
201	m_ui.results->resizeColumnsToContents();
202	m_ui.results->resizeRowsToContents();
203}
204
205void MemorySearch::openMemory() {
206	auto items = m_ui.results->selectedItems();
207	if (items.empty()) {
208		return;
209	}
210	QTableWidgetItem* item = items[0];
211	uint32_t address = item->text().toUInt(nullptr, 16);
212
213	MemoryView* memView = new MemoryView(m_controller);
214	memView->jumpToAddress(address);
215
216	memView->setAttribute(Qt::WA_DeleteOnClose);
217	memView->show();
218}