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