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 uint32_t v = m_ui.value->text().toUInt(&ok, 16);
53 if (ok) {
54 switch (params->type) {
55 case mCORE_MEMORY_SEARCH_8:
56 ok = v < 0x100;
57 params->value8 = v;
58 break;
59 case mCORE_MEMORY_SEARCH_16:
60 ok = v < 0x10000;
61 params->value16 = v;
62 break;
63 case mCORE_MEMORY_SEARCH_32:
64 params->value32 = v;
65 break;
66 default:
67 ok = false;
68 }
69 }
70 }
71 if (m_ui.numDec->isChecked()) {
72 uint32_t v = m_ui.value->text().toUInt(&ok, 10);
73 if (ok) {
74 switch (params->type) {
75 case mCORE_MEMORY_SEARCH_8:
76 ok = v < 0x100;
77 params->value8 = v;
78 break;
79 case mCORE_MEMORY_SEARCH_16:
80 ok = v < 0x10000;
81 params->value16 = v;
82 break;
83 case mCORE_MEMORY_SEARCH_32:
84 params->value32 = v;
85 break;
86 default:
87 ok = false;
88 }
89 }
90 }
91 if (m_ui.numGuess->isChecked()) {
92 params->type = mCORE_MEMORY_SEARCH_GUESS;
93 m_string = m_ui.value->text().toLocal8Bit();
94 params->valueStr = m_string.constData();
95 ok = true;
96 }
97 }
98 if (m_ui.typeStr->isChecked()) {
99 params->type = mCORE_MEMORY_SEARCH_STRING;
100 m_string = m_ui.value->text().toLocal8Bit();
101 params->valueStr = m_string.constData();
102 ok = true;
103 }
104 return ok;
105}
106
107void MemorySearch::search() {
108 mCoreMemorySearchResultsClear(&m_results);
109
110 mCoreMemorySearchParams params;
111
112 GameController::Interrupter interrupter(m_controller);
113 if (!m_controller->isLoaded()) {
114 return;
115 }
116 mCore* core = m_controller->thread()->core;
117
118 if (createParams(¶ms)) {
119 mCoreMemorySearch(core, ¶ms, &m_results, LIMIT);
120 }
121
122 refresh();
123}
124
125void MemorySearch::searchWithin() {
126 mCoreMemorySearchParams params;
127
128 GameController::Interrupter interrupter(m_controller);
129 if (!m_controller->isLoaded()) {
130 return;
131 }
132 mCore* core = m_controller->thread()->core;
133
134 if (createParams(¶ms)) {
135 mCoreMemorySearchRepeat(core, ¶ms, &m_results);
136 }
137
138 refresh();
139}
140
141void MemorySearch::refresh() {
142 GameController::Interrupter interrupter(m_controller);
143 if (!m_controller->isLoaded()) {
144 return;
145 }
146 mCore* core = m_controller->thread()->core;
147
148 m_ui.results->clearContents();
149 m_ui.results->setRowCount(mCoreMemorySearchResultsSize(&m_results));
150 for (size_t i = 0; i < mCoreMemorySearchResultsSize(&m_results); ++i) {
151 mCoreMemorySearchResult* result = mCoreMemorySearchResultsGetPointer(&m_results, i);
152 QTableWidgetItem* item = new QTableWidgetItem(QString("%1").arg(result->address, 8, 16, QChar('0')));
153 m_ui.results->setItem(i, 0, item);
154 QTableWidgetItem* type;
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 QString divisor;
187 if (result->guessDivisor > 1) {
188 divisor = tr(" (⅟%0×)").arg(result->guessDivisor);
189 }
190 switch (result->type) {
191 case mCORE_MEMORY_SEARCH_8:
192 type = new QTableWidgetItem(tr("1 byte%0").arg(divisor));
193 break;
194 case mCORE_MEMORY_SEARCH_16:
195 type = new QTableWidgetItem(tr("2 bytes%0").arg(divisor));
196 break;
197 case mCORE_MEMORY_SEARCH_GUESS:
198 case mCORE_MEMORY_SEARCH_32:
199 type = new QTableWidgetItem(tr("4 bytes%0").arg(divisor));
200 break;
201 case mCORE_MEMORY_SEARCH_STRING:
202 item = new QTableWidgetItem("?"); // TODO
203 }
204 m_ui.results->setItem(i, 1, item);
205 m_ui.results->setItem(i, 2, type);
206 }
207 m_ui.results->sortItems(0);
208 m_ui.results->resizeColumnsToContents();
209 m_ui.results->resizeRowsToContents();
210}
211
212void MemorySearch::openMemory() {
213 auto items = m_ui.results->selectedItems();
214 if (items.empty()) {
215 return;
216 }
217 QTableWidgetItem* item = items[0];
218 uint32_t address = item->text().toUInt(nullptr, 16);
219
220 MemoryView* memView = new MemoryView(m_controller);
221 memView->jumpToAddress(address);
222
223 connect(m_controller, &GameController::gameStopped, memView, &QWidget::close);
224 memView->setAttribute(Qt::WA_DeleteOnClose);
225 memView->show();
226}