PageRenderTime 57ms CodeModel.GetById 15ms app.highlight 38ms RepoModel.GetById 1ms app.codeStats 0ms

/src/scanner.cpp

https://code.google.com/p/dwarftherapist/
C++ | 471 lines | 387 code | 59 blank | 25 comment | 38 complexity | da0bea3ba6f3885dff20684349bf9d4d MD5 | raw file
  1/*
  2Dwarf Therapist
  3Copyright (c) 2009 Trey Stout (chmod)
  4
  5Permission is hereby granted, free of charge, to any person obtaining a copy
  6of this software and associated documentation files (the "Software"), to deal
  7in the Software without restriction, including without limitation the rights
  8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9copies of the Software, and to permit persons to whom the Software is
 10furnished to do so, subject to the following conditions:
 11
 12The above copyright notice and this permission notice shall be included in
 13all copies or substantial portions of the Software.
 14
 15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 21THE SOFTWARE.
 22*/
 23#include <QThread>
 24#include "scanner.h"
 25#include "dfinstance.h"
 26#include "gamedatareader.h"
 27#include "dwarftherapist.h"
 28#include "scannerthread.h"
 29#include "defines.h"
 30#include "selectparentlayoutdialog.h"
 31#include "layoutcreator.h"
 32#include "word.h"
 33
 34Scanner::Scanner(DFInstance *df, MainWindow *parent)
 35    : QDialog(parent)
 36    , m_df(df)
 37    , m_thread(0)
 38    , ui(new Ui::ScannerDialog)
 39    , m_stop_scanning(false)
 40{
 41    ui->setupUi(this);
 42    set_ui_enabled(true);
 43}
 44
 45void Scanner::cancel_scan() {
 46    m_stop_scanning = true;
 47    m_df->cancel_scan();
 48}
 49
 50void Scanner::set_ui_enabled(bool enabled) {
 51    m_stop_scanning = enabled;
 52    ui->gb_scan_targets->setEnabled(enabled);
 53    ui->gb_search->setEnabled(enabled);
 54    ui->gb_brute_force->setEnabled(enabled);
 55    ui->gb_progress->setEnabled(!enabled);
 56    ui->btn_cancel_scan->setEnabled(!enabled);
 57    ui->lbl_scan_progress->setText(tr("Not Scanning"));
 58    ui->pb_main->reset();
 59    ui->pb_sub->reset();
 60}
 61
 62void Scanner::report_address(const QString &msg, const quint32 &addr) {
 63    VIRTADDR corrected_addr = addr - m_df->get_memory_correction();
 64    QString out = QString("<b>%1\t= <font color=blue>%2</font> "
 65                          "(uncorrected:%3)\n")
 66        .arg(msg)
 67        .arg(hexify(corrected_addr))
 68        .arg(hexify(addr));
 69    ui->text_output->append(out);
 70    LOGD << "ADDRESS FOR:" << msg << hexify(corrected_addr) << "UNCORRECTED:" <<
 71            hexify(addr);
 72}
 73
 74void Scanner::report_offset(const QString &msg, const int &addr) {
 75    QString out = QString("<b>%1\t= <font color=blue>%2</font></b>\n")
 76        .arg(msg)
 77        .arg(hexify(addr));
 78    ui->text_output->append(out);
 79    LOGD << "OFFSET FOR:" << msg << hexify(addr);
 80}
 81
 82void Scanner::get_brute_force_address_range(uint &start_addr, uint &end_addr) {
 83    QString start = ui->le_start_address->text();
 84    QString end = ui->le_end_address->text();
 85    bool ok;
 86
 87    start_addr = start.toUInt(&ok, 16);
 88    if( !ok ) {
 89        start_addr = 0;
 90    }
 91    end_addr = end.toUInt(&ok, 16);
 92    if( !ok ) {
 93        end_addr = 0xFFFFFFFF;
 94    }
 95}
 96
 97
 98void Scanner::prepare_new_thread(SCANNER_JOB_TYPE type) {
 99    if (m_thread && m_thread->isRunning()) {
100        m_thread->terminate();
101        m_thread->wait(3000);
102        m_thread->deleteLater();
103        m_thread = 0;
104    }
105
106    m_thread = new ScannerThread(m_df);
107    m_thread->set_job(type);
108    connect(m_thread, SIGNAL(main_scan_total_steps(int)),
109            ui->pb_main, SLOT(setMaximum(int)));
110    connect(m_thread, SIGNAL(main_scan_progress(int)),
111            ui->pb_main, SLOT(setValue(int)));
112    connect(m_thread, SIGNAL(sub_scan_total_steps(int)),
113            ui->pb_sub, SLOT(setMaximum(int)));
114    connect(m_thread, SIGNAL(sub_scan_progress(int)),
115            ui->pb_sub, SLOT(setValue(int)));
116    connect(m_thread, SIGNAL(scan_message(const QString&)),
117            ui->lbl_scan_progress, SLOT(setText(const QString&)));
118    connect(m_thread, SIGNAL(found_address(const QString&, const quint32&)),
119            SLOT(report_address(const QString&, const quint32&)));
120    connect(m_thread, SIGNAL(found_offset(const QString&, const int&)),
121            SLOT(report_offset(const QString&, const int&)));
122}
123
124void Scanner::run_thread_and_wait() {
125    if (!m_thread) {
126        LOGW << "can't run a thread that was never set up! (m_thread == 0)";
127        return;
128    }
129    m_thread->start();
130    while (!m_thread->wait(200)) {
131        if (m_stop_scanning || !m_thread->isRunning() || m_thread->isFinished())
132            break;
133        //ui->text_output->append("waiting on thread...");
134        DT->processEvents();
135    }
136    m_thread->terminate();
137    if (m_thread->wait(5000)) {
138        delete m_thread;
139    } else {
140        LOGE << "Scanning thread failed to stop for 5 seconds after killed!";
141    }
142    m_thread = 0;
143}
144
145void Scanner::find_translations_vector() {
146    set_ui_enabled(false);
147    prepare_new_thread(FIND_TRANSLATIONS_VECTOR);
148    run_thread_and_wait();
149    set_ui_enabled(true);
150}
151
152void Scanner::find_dwarf_race_index() {
153    set_ui_enabled(false);
154    prepare_new_thread(FIND_DWARF_RACE_INDEX);
155    run_thread_and_wait();
156    set_ui_enabled(true);
157}
158
159void Scanner::find_creature_vector() {
160    set_ui_enabled(false);
161    prepare_new_thread(FIND_CREATURE_VECTOR);
162    run_thread_and_wait();
163    set_ui_enabled(true);
164}
165
166void Scanner::find_vector_by_length() {
167    VectorSearchParams params;
168
169    set_ui_enabled(false);
170    uint target_count = ui->sb_vector_entries->value();
171    QString op = ui->btn_find_vector_operator->text();
172
173    ui->text_output->append(tr("Vectors %1 %2 entries").arg(op).arg(target_count));
174    prepare_new_thread(FIND_VECTORS_OF_SIZE);
175
176    get_brute_force_address_range(params.start_addr, params.end_addr);
177    params.target_count = target_count;
178    params.op = op.at(0).toAscii();
179
180    QByteArray needle((const char *)&params, sizeof(params));
181    m_thread->set_meta(needle);
182    run_thread_and_wait();
183    set_ui_enabled(true);
184}
185
186void Scanner::find_stone_vector() {
187    set_ui_enabled(false);
188    prepare_new_thread(FIND_STONE_VECTOR);
189    run_thread_and_wait();
190    set_ui_enabled(true);
191}
192
193void Scanner::find_metal_vector() {
194    set_ui_enabled(false);
195    set_ui_enabled(true);
196}
197
198void Scanner::find_position_vector() {
199    set_ui_enabled(false);
200    prepare_new_thread(FIND_POSITION_VECTOR);
201    run_thread_and_wait();
202    set_ui_enabled(true);
203}
204
205void Scanner::create_memory_layout() {
206    set_ui_enabled(false);
207
208    SelectParentLayoutDialog dlg(m_df, this);
209    int ret = dlg.exec();
210
211    if(QDialog::Accepted == ret)
212    {
213        GameDataReader * gdr = GameDataReader::ptr();
214        QString out = QString("<b><font color=blue>Make sure that your first dwarf from embark has a nickname of '%1' and a custom profession of '%2'</font></b>\n")
215                      .arg(gdr->get_string_for_key("ram_guesser/dwarf_nickname"))
216                      .arg(gdr->get_string_for_key("ram_guesser/dwarf_custom_profession"));
217        ui->text_output->append(out);
218        MemoryLayout * parent = dlg.get_layout();
219        LOGD << "Attempting to create layout from " << parent->game_version() << " for version "
220                << dlg.get_version_name() << " and filename " << dlg.get_file_name();
221
222        LayoutCreator * creator = new LayoutCreator(m_df, parent, dlg.get_file_name(), dlg.get_version_name());
223        m_df->set_memory_layout(parent);
224
225        ScannerJob::m_layout_override_checksum = parent->checksum();
226
227        prepare_new_thread(FIND_DWARF_RACE_INDEX);
228        connect(m_thread, SIGNAL(found_address(const QString&, const quint32&)), creator,
229                SLOT(report_address(const QString&, const quint32&)));
230        run_thread_and_wait();
231
232        prepare_new_thread(FIND_TRANSLATIONS_VECTOR);
233        connect(m_thread, SIGNAL(found_address(const QString&, const quint32&)), creator,
234                SLOT(report_address(const QString&, const quint32&)));
235        run_thread_and_wait();
236
237        prepare_new_thread(FIND_CREATURE_VECTOR);
238        connect(m_thread, SIGNAL(found_address(const QString&, const quint32&)), creator,
239                SLOT(report_address(const QString&, const quint32&)));
240        run_thread_and_wait();
241
242        prepare_new_thread(FIND_CURRENT_YEAR);
243        connect(m_thread, SIGNAL(found_address(const QString&, const quint32&)), creator,
244                SLOT(report_address(const QString&, const quint32&)));
245        run_thread_and_wait();
246
247        prepare_new_thread(FIND_SQUADS_VECTOR);
248        connect(m_thread, SIGNAL(found_address(const QString&, const quint32&)), creator,
249                SLOT(report_address(const QString&, const quint32&)));
250        run_thread_and_wait();
251
252        ScannerJob::m_layout_override_checksum = "";
253
254        LOGD << "Finished reading layouts, writing to disk.";
255        if(creator->write_file()) {
256            out = QString("<b><font color=green>Finished. Created new file: %1</font></b>\n").arg(dlg.get_file_name());
257            ui->text_output->append(out);
258            out = QString("<b><font color=red>Please restart DwarfTherapist!</font></b>\n");
259            ui->text_output->append(out);
260
261            LOGD << "Finished writing file " << dlg.get_file_name() << " to disk.";
262        } else {
263            out = QString("<b><font color=red>Unable to write to file, please check your disk!</font></b>\n");
264            ui->text_output->append(out);
265        }
266        delete creator;
267    }
268
269    set_ui_enabled(true);
270}
271
272void Scanner::find_std_string() {
273    set_ui_enabled(false);
274    prepare_new_thread(FIND_STD_STRING);
275    QByteArray needle = ui->le_null_terminated_string->text().toAscii();
276    m_thread->set_meta(needle);
277    run_thread_and_wait();
278    set_ui_enabled(true);
279}
280
281void Scanner::find_null_terminated_string() {
282    NullTerminatedStringSearchParams params;
283    set_ui_enabled(false);
284    prepare_new_thread(FIND_NULL_TERMINATED_STRING);
285    QByteArray text = ui->le_null_terminated_string->text().toLocal8Bit();
286
287    get_brute_force_address_range(params.start_addr, params.end_addr);
288    params.size = qMin((size_t)text.size(), sizeof(params.data));
289    memcpy(params.data, text.data(), params.size);
290
291    QByteArray needle((const char *)&params, sizeof(params));
292    m_thread->set_meta(needle);
293    run_thread_and_wait();
294    set_ui_enabled(true);
295}
296
297void Scanner::find_number_or_address() {
298    NullTerminatedStringSearchParams params;
299    set_ui_enabled(false);
300    //re-use the basic bit searcher
301    prepare_new_thread(FIND_NULL_TERMINATED_STRING);
302    bool ok;
303    QByteArray text = encode(ui->le_find_address->text().
304                               toUInt(&ok, ui->rb_hex->isChecked() ? 16 : 10));
305    get_brute_force_address_range(params.start_addr, params.end_addr);
306    params.size = qMin((size_t)text.size(), sizeof(params.data));
307    memcpy(params.data, text.data(), params.size);
308
309    QByteArray needle((const char *)&params, sizeof(params));
310    m_thread->set_meta(needle);
311    run_thread_and_wait();
312    set_ui_enabled(true);
313}
314
315void Scanner::brute_force_read() {
316    set_ui_enabled(false);
317    bool ok; // for base conversions
318    VIRTADDR addr = ui->le_address->text().toUInt(&ok, 16);
319    if (m_df && m_df->is_ok()) {
320        switch(ui->cb_interpret_as_type->currentIndex()) {
321        case 0: // std::string
322            ui->le_read_output->setText(m_df->read_string(addr));
323            break;
324        case 1: // null terminated string
325            {
326                QByteArray str(512, 0);
327                m_df->read_raw(addr, 512, str);
328                ui->le_read_output->setText(QString(str));
329            }
330            break;
331        case 2: // int
332            ui->le_read_output->setText(QString::number(m_df->read_int(addr)));
333            break;
334        case 3: // uint
335            ui->le_read_output->setText(QString::number(m_df->read_addr(addr)));
336            break;
337        case 4: // short
338            ui->le_read_output->setText(QString::number(m_df->read_short(addr)));
339            break;
340        case 5: // ushort
341            ui->le_read_output->setText(QString::number(m_df->read_word(addr)));
342            break;
343        case 6: // std::vector<void*>
344            {
345                QVector<uint> addresses = m_df->enumerate_vector(addr);
346                ui->text_output->append(QString("Vector at %1 contains %2 "
347                                                "entries...").arg(hexify(addr))
348                                        .arg(addresses.size()));
349                foreach(uint a, addresses) {
350                    ui->text_output->append(hexify(a));
351                }
352            }
353            break;
354        case 7: // raw
355            ui->text_output->append(m_df->pprint(addr, 0xA00));
356            break;
357        case 8: // word
358            {
359                Word * word = m_df->read_dwarf_word(addr);
360                if( word ) {
361                    ui->le_read_output->setText(word->base());
362                } else {
363                    ui->le_read_output->setText(("<unknown>"));
364                }
365            }
366            break;
367        case 9: // name
368            {
369                QString name = m_df->read_dwarf_name(addr);
370                ui->le_read_output->setText(name);
371            }
372            break;
373        }
374    } else {
375        LOGE << "Cannot brute-force read. DF Connection is not ok.";
376
377    }
378    set_ui_enabled(true);
379}
380
381void Scanner::find_narrowing() {
382    set_ui_enabled(false);
383    uint target_count = ui->le_narrowing_value->text().toInt();
384    prepare_new_thread(FIND_NARROWING_VECTORS_OF_SIZE);
385    QByteArray needle = QString("%1").arg(target_count).toAscii();
386    m_thread->set_meta(needle);
387
388    if(ui->lbl_narrowing_result->text() != "nil") {
389        m_thread->set_search_vector(m_narrow);
390    }
391
392    m_thread->start();
393    while (!m_thread->wait(200)) {
394        if (m_stop_scanning || !m_thread->isRunning() || m_thread->isFinished())
395            break;
396        //ui->text_output->append("waiting on thread...");
397        DT->processEvents();
398    }
399    m_thread->terminate();
400    if (!m_thread->wait(5000)) {
401        LOGE << "Scanning thread failed to stop for 5 seconds after killed!";
402        return;
403    }
404
405    QVector<VIRTADDR> * result = (QVector<VIRTADDR> *)m_thread->get_result();
406    if(result == NULL) {
407        ui->lbl_narrowing_result->setText(tr("0"));
408        m_narrow.clear();
409    } else {
410        ui->lbl_narrowing_result->setText(QString("%1").arg(result->size()));
411        m_narrow = *result;
412        m_thread->clear_result();
413        delete result;
414    }
415
416    delete m_thread;
417    m_thread = 0;
418
419    set_ui_enabled(true);
420}
421
422void Scanner::reset_narrowing() {
423    LOGD << "Reset narrowing search";
424    m_narrow.clear();
425    ui->lbl_narrowing_result->setText(tr("nil"));
426    ui->le_narrowing_value->setText("");
427}
428
429void Scanner::print_narrowing() {
430    if(m_narrow.size() > 200) {
431        QString out = QString("<b><font color=red>There are a total of %1 vectors, only printing 200.</font></b>\n")
432            .arg(m_narrow.size());
433
434        ui->text_output->append(out);
435    }
436
437    int i = 0;
438    foreach(uint addr, m_narrow) {
439        report_address("vector found at", addr);
440
441        if(i++ >= 200)
442            break;
443    }
444}
445
446void Scanner::find_squad_vector() {
447    set_ui_enabled(false);
448    prepare_new_thread(FIND_SQUADS_VECTOR);
449    run_thread_and_wait();
450    set_ui_enabled(true);
451}
452
453void Scanner::change_operator() {
454    QString op = ui->btn_find_vector_operator->text();
455    if(op == "=") {
456        op = "<";
457    } else if(op == "<") {
458        op = ">";
459    } else {
460        op = "=";
461    }
462    ui->btn_find_vector_operator->setText(op);
463}
464
465void Scanner::find_current_year() {
466    set_ui_enabled(false);
467    prepare_new_thread(FIND_CURRENT_YEAR);
468    run_thread_and_wait();
469    set_ui_enabled(true);
470}
471