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(¶ms)) {
118 mCoreMemorySearch(core, ¶ms, &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(¶ms)) {
131 mCoreMemorySearchRepeat(core, ¶ms, &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}