From 6e1f226aa0978673d852452078f154bac37e6f91 Mon Sep 17 00:00:00 2001 From: Nikolaj Schlej Date: Mon, 14 Jul 2014 00:38:34 +0200 Subject: [PATCH] UEFITool 0.18.3 - added pattern-based search for hex patterns, '.' (dot) means "any hex digit" - added pattern-based search for GUIDs - added copy action for messages - focus is now setting properly for all search window tabs --- ffsengine.cpp | 104 +++++++++++++++++++++++++++++++++++++++++------ ffsengine.h | 5 ++- searchdialog.cpp | 23 ++++++++++- searchdialog.h | 6 ++- searchdialog.ui | 92 ++++++++++++++++++++++++++++++++++++++++- uefitool.cpp | 39 +++++++++++++++++- uefitool.h | 9 ++-- uefitool.ui | 60 ++++++++------------------- 8 files changed, 274 insertions(+), 64 deletions(-) diff --git a/ffsengine.cpp b/ffsengine.cpp index 7f1f6b5..351ad5a 100644 --- a/ffsengine.cpp +++ b/ffsengine.cpp @@ -2961,9 +2961,9 @@ UINT8 FfsEngine::reconstructImageFile(QByteArray & reconstructed) } // Search routines -UINT8 FfsEngine::findHexPattern(const QModelIndex & index, const QByteArray & pattern, const UINT8 mode) +UINT8 FfsEngine::findHexPattern(const QModelIndex & index, const QByteArray & hexPattern, const UINT8 mode) { - if (pattern.isEmpty()) + if (hexPattern.isEmpty()) return ERR_INVALID_PARAMETER; if (!index.isValid()) @@ -2971,7 +2971,7 @@ UINT8 FfsEngine::findHexPattern(const QModelIndex & index, const QByteArray & pa bool hasChildren = (model->rowCount(index) > 0); for (int i = 0; i < model->rowCount(index); i++) { - findHexPattern(index.child(i, index.column()), pattern, mode); + findHexPattern(index.child(i, index.column()), hexPattern, mode); } QByteArray data; @@ -2988,13 +2988,93 @@ UINT8 FfsEngine::findHexPattern(const QModelIndex & index, const QByteArray & pa data.append(model->header(index)).append(model->body(index)).append(model->tail(index)); } - int offset = -1; - while ((offset = data.indexOf(pattern, offset + 1)) >= 0) { - msg(tr("Hex pattern \"%1\" found in %2 at offset %3") - .arg(QString(pattern.toHex())) - .arg(model->nameString(index)) - .arg(offset, 8, 16, QChar('0')), - index); + // Check for "all substrings" pattern + if (hexPattern.count('.') == hexPattern.length()) + return ERR_SUCCESS; + + QString hexBody = QString(data.toHex()); + QRegExp regexp = QRegExp(QString(hexPattern), Qt::CaseInsensitive); + INT32 offset = regexp.indexIn(hexBody); + while (offset >= 0) { + if (offset % 2 == 0) { + msg(tr("Hex pattern \"%1\" found as \"%2\" in %3 at %4-offset %5") + .arg(QString(hexPattern)) + .arg(hexBody.mid(offset, hexPattern.length())) + .arg(model->nameString(index)) + .arg(mode == SEARCH_MODE_BODY ? tr("body") : tr("header")) + .arg(offset/2, 8, 16, QChar('0')), + index); + } + offset = regexp.indexIn(hexBody, offset + 1); + } + + return ERR_SUCCESS; +} + +UINT8 FfsEngine::findGuidPattern(const QModelIndex & index, const QByteArray & guidPattern, const UINT8 mode) +{ + if (guidPattern.isEmpty()) + return ERR_INVALID_PARAMETER; + + if (!index.isValid()) + return ERR_SUCCESS; + + bool hasChildren = (model->rowCount(index) > 0); + for (int i = 0; i < model->rowCount(index); i++) { + findGuidPattern(index.child(i, index.column()), guidPattern, mode); + } + + QByteArray data; + if (hasChildren) { + if (mode != SEARCH_MODE_BODY) + data = model->header(index); + } + else { + if (mode == SEARCH_MODE_HEADER) + data.append(model->header(index)).append(model->tail(index)); + else if (mode == SEARCH_MODE_BODY) + data.append(model->body(index)); + else + data.append(model->header(index)).append(model->body(index)).append(model->tail(index)); + } + + QString hexBody = QString(data.toHex()); + QList list = guidPattern.split('-'); + if (list.count() != 5) + return ERR_INVALID_PARAMETER; + + QByteArray hexPattern; + // Reverse first GUID block + hexPattern.append(list.at(0).mid(6, 2)); + hexPattern.append(list.at(0).mid(4, 2)); + hexPattern.append(list.at(0).mid(2, 2)); + hexPattern.append(list.at(0).mid(0, 2)); + // Reverse second GUID block + hexPattern.append(list.at(1).mid(2, 2)); + hexPattern.append(list.at(1).mid(0, 2)); + // Reverse third GUID block + hexPattern.append(list.at(2).mid(2, 2)); + hexPattern.append(list.at(2).mid(0, 2)); + // Append fourth and fifth GUID blocks as is + hexPattern.append(list.at(3)).append(list.at(4)); + + // Check for "all substrings" pattern + if (hexPattern.count('.') == hexPattern.length()) + return ERR_SUCCESS; + + QRegExp regexp = QRegExp(QString(hexPattern), Qt::CaseInsensitive); + INT32 offset = regexp.indexIn(hexBody); + while (offset >= 0) { + if (offset % 2 == 0) { + msg(tr("GUID pattern \"%1\" found as \"%2\" in %3 at %4-offset %5") + .arg(QString(guidPattern)) + .arg(hexBody.mid(offset, hexPattern.length())) + .arg(model->nameString(index)) + .arg(mode == SEARCH_MODE_BODY ? tr("body") : tr("header")) + .arg(offset / 2, 8, 16, QChar('0')), + index); + } + offset = regexp.indexIn(hexBody, offset + 1); } return ERR_SUCCESS; @@ -3480,7 +3560,7 @@ UINT8 FfsEngine::patchViaOffset(QByteArray & data, const UINT32 offset, const QB return ERR_SUCCESS; } -UINT8 FfsEngine::patchViaPattern(QByteArray & data, const QByteArray hexFindPattern, const QByteArray & hexReplacePattern) +UINT8 FfsEngine::patchViaPattern(QByteArray & data, const QByteArray & hexFindPattern, const QByteArray & hexReplacePattern) { QByteArray body = data; @@ -3491,7 +3571,7 @@ UINT8 FfsEngine::patchViaPattern(QByteArray & data, const QByteArray hexFindPatt // Convert file body to hex; QString hexBody = QString(body.toHex()); QRegExp regexp = QRegExp(QString(hexFindPattern), Qt::CaseInsensitive); - INT64 offset = regexp.indexIn(hexBody); + INT32 offset = regexp.indexIn(hexBody); while (offset >= 0) { if (offset % 2 == 0) { UINT8 result = patchViaOffset(body, offset/2, hexReplacePattern); diff --git a/ffsengine.h b/ffsengine.h index cc9e291..22cc077 100644 --- a/ffsengine.h +++ b/ffsengine.h @@ -98,7 +98,8 @@ public: UINT8 patch(const QModelIndex & index, const QVector & patches); // Search routines - UINT8 findHexPattern(const QModelIndex & index, const QByteArray & pattern, const UINT8 mode); + UINT8 findHexPattern(const QModelIndex & index, const QByteArray & hexPattern, const UINT8 mode); + UINT8 findGuidPattern(const QModelIndex & index, const QByteArray & guidPattern, const UINT8 mode); UINT8 findTextPattern(const QModelIndex & index, const QString & pattern, const bool unicode, const Qt::CaseSensitivity caseSensitive); private: @@ -129,7 +130,7 @@ private: // Patch helpers UINT8 patchViaOffset(QByteArray & data, const UINT32 offset, const QByteArray & hexReplacePattern); - UINT8 patchViaPattern(QByteArray & data, const QByteArray hexFindPattern, const QByteArray & hexReplacePattern); + UINT8 patchViaPattern(QByteArray & data, const QByteArray & hexFindPattern, const QByteArray & hexReplacePattern); #ifndef _CONSOLE QQueue messageItems; diff --git a/searchdialog.cpp b/searchdialog.cpp index 68a4c7e..e332fa8 100644 --- a/searchdialog.cpp +++ b/searchdialog.cpp @@ -15,13 +15,34 @@ SearchDialog::SearchDialog(QWidget *parent) : QDialog(parent), - ui(new Ui::SearchDialog) + ui(new Ui::SearchDialog), + hexValidator(QRegExp("([0-9a-fA-F\\.])*")), + guidValidator(QRegExp("[0-9a-fA-F\\.]{8}-[0-9a-fA-F\\.]{4}-[0-9a-fA-F\\.]{4}-[0-9a-fA-F\\.]{4}-[0-9a-fA-F\\.]{12}")) { // Create UI ui->setupUi(this); + ui->hexEdit->setValidator(&hexValidator); + ui->guidEdit->setValidator(&guidValidator); + + // Connect + connect(ui->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(setEditFocus(int))); + + // Set initial focus + setEditFocus(ui->tabWidget->currentIndex()); } SearchDialog::~SearchDialog() { delete ui; } + +void SearchDialog::setEditFocus(int index) +{ + if (index == 0) // Hex pattern + ui->hexEdit->setFocus(); + else if (index == 1) // GUID + ui->guidEdit->setFocus(); + else if (index == 2) // Text + ui->textEdit->setFocus(); +} + diff --git a/searchdialog.h b/searchdialog.h index 382003d..852aabf 100644 --- a/searchdialog.h +++ b/searchdialog.h @@ -15,6 +15,7 @@ #define SEARCHDIALOG_H #include +#include #include "ui_searchdialog.h" class SearchDialog : public QDialog @@ -27,8 +28,11 @@ public: Ui::SearchDialog* ui; private slots: - //void setEditMask(); + void setEditFocus(int index); +private: + QRegExpValidator hexValidator; + QRegExpValidator guidValidator; }; #endif diff --git a/searchdialog.ui b/searchdialog.ui index 2e9bd0f..5f3b25d 100644 --- a/searchdialog.ui +++ b/searchdialog.ui @@ -35,7 +35,17 @@ - + + + + Consolas + 9 + + + + + + @@ -78,6 +88,78 @@ + + + GUID + + + + + + GUID: + + + + + + + + Consolas + 9 + + + + xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx; + + + ........-....-....-....-............ + + + + + + + Search scope + + + + 6 + + + 9 + + + + + Header and body + + + false + + + + + + + Header only + + + true + + + + + + + Body only + + + + + + + + Text @@ -136,7 +218,15 @@ + tabWidget + hexEdit + hexScopeFullRadioButton + hexScopeHeaderRadioButton + hexScopeBodyRadioButton buttonBox + textEdit + textUnicodeCheckBox + textCaseSensitiveCheckBox diff --git a/uefitool.cpp b/uefitool.cpp index f53db94..439b56c 100644 --- a/uefitool.cpp +++ b/uefitool.cpp @@ -18,6 +18,8 @@ UEFITool::UEFITool(QWidget *parent) : QMainWindow(parent), ui(new Ui::UEFITool) { + clipboard = QApplication::clipboard(); + // Create UI ui->setupUi(this); searchDialog = new SearchDialog(this); @@ -36,6 +38,7 @@ UEFITool::UEFITool(QWidget *parent) : connect(ui->actionReplaceBody, SIGNAL(triggered()), this, SLOT(replaceBody())); connect(ui->actionRemove, SIGNAL(triggered()), this, SLOT(remove())); connect(ui->actionRebuild, SIGNAL(triggered()), this, SLOT(rebuild())); + connect(ui->actionMessagesCopy, SIGNAL(triggered()), this, SLOT(copyMessage())); connect(ui->actionMessagesClear, SIGNAL(triggered()), this, SLOT(clearMessages())); connect(ui->actionAbout, SIGNAL(triggered()), this, SLOT(about())); connect(ui->actionAboutQt, SIGNAL(triggered()), this, SLOT(aboutQt())); @@ -73,6 +76,7 @@ void UEFITool::init() ui->menuVolumeActions->setDisabled(true); ui->menuFileActions->setDisabled(true); ui->menuSectionActions->setDisabled(true); + ui->actionMessagesCopy->setDisabled(true); // Make new ffsEngine if (ffsEngine) @@ -84,6 +88,7 @@ void UEFITool::init() connect(ui->structureTreeView->selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)), this, SLOT(populateUi(const QModelIndex &))); connect(ui->messageListWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(scrollTreeView(QListWidgetItem*))); + connect(ui->messageListWidget, SIGNAL(itemEntered(QListWidgetItem*)), this, SLOT(enableMessagesCopyAction(QListWidgetItem*))); } void UEFITool::populateUi(const QModelIndex ¤t) @@ -119,6 +124,7 @@ void UEFITool::populateUi(const QModelIndex ¤t) ui->actionInsertAfter->setEnabled(type == Types::File || type == Types::Section); ui->actionReplace->setEnabled((type == Types::Region && subtype != Subtypes::DescriptorRegion) || type == Types::File || type == Types::Section); ui->actionReplaceBody->setEnabled(type == Types::File || type == Types::Section); + ui->actionMessagesCopy->setEnabled(false); } void UEFITool::search() @@ -130,7 +136,8 @@ void UEFITool::search() int index = searchDialog->ui->tabWidget->currentIndex(); if (index == 0) { // Hex pattern - QByteArray pattern = QByteArray::fromHex(searchDialog->ui->hexEdit->text().toLatin1()); + searchDialog->ui->hexEdit->setFocus(); + QByteArray pattern = searchDialog->ui->hexEdit->text().toLatin1(); if (pattern.isEmpty()) return; UINT8 mode; @@ -143,7 +150,23 @@ void UEFITool::search() ffsEngine->findHexPattern(rootIndex, pattern, mode); showMessages(); } - else if (index == 1) { // Text string + else if (index == 1) { // GUID + searchDialog->ui->guidEdit->setFocus(); + QByteArray pattern = searchDialog->ui->guidEdit->text().toLatin1(); + if (pattern.isEmpty()) + return; + UINT8 mode; + if (searchDialog->ui->guidScopeHeaderRadioButton->isChecked()) + mode = SEARCH_MODE_HEADER; + else if (searchDialog->ui->guidScopeBodyRadioButton->isChecked()) + mode = SEARCH_MODE_BODY; + else + mode = SEARCH_MODE_ALL; + ffsEngine->findGuidPattern(rootIndex, pattern, mode); + showMessages(); + } + else if (index == 2) { // Text string + searchDialog->ui->textEdit->setFocus(); QString pattern = searchDialog->ui->textEdit->text(); if (pattern.isEmpty()) return; @@ -526,11 +549,23 @@ void UEFITool::openImageFile(QString path) ui->actionSearch->setEnabled(true); } +void UEFITool::copyMessage() +{ + clipboard->clear(); + clipboard->setText(ui->messageListWidget->currentItem()->text()); +} + +void UEFITool::enableMessagesCopyAction(QListWidgetItem* item) +{ + ui->actionMessagesCopy->setEnabled(item != NULL); +} + void UEFITool::clearMessages() { ffsEngine->clearMessages(); messageItems.clear(); ui->messageListWidget->clear(); + ui->actionMessagesCopy->setEnabled(false); } void UEFITool::dragEnterEvent(QDragEnterEvent* event) diff --git a/uefitool.h b/uefitool.h index 3d93f35..af6cec2 100644 --- a/uefitool.h +++ b/uefitool.h @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -54,7 +55,6 @@ public: private slots: void init(); void populateUi(const QModelIndex ¤t); - //void resizeTreeViewColumns(); void scrollTreeView(QListWidgetItem* item); void openImageFile(); @@ -78,8 +78,10 @@ private slots: void remove(); + void copyMessage(); + void enableMessagesCopyAction(QListWidgetItem* item); void clearMessages(); - + void about(); void aboutQt(); @@ -90,8 +92,9 @@ private: Ui::UEFITool* ui; FfsEngine* ffsEngine; SearchDialog* searchDialog; - + QClipboard* clipboard; QQueue messageItems; + void showMessages(); void dragEnterEvent(QDragEnterEvent* event); diff --git a/uefitool.ui b/uefitool.ui index 8110339..6a6c46c 100644 --- a/uefitool.ui +++ b/uefitool.ui @@ -20,7 +20,7 @@ true - UEFITool 0.18.2 + UEFITool 0.18.3 @@ -33,16 +33,7 @@ 0 - - 0 - - - 0 - - - 0 - - + 0 @@ -62,16 +53,7 @@ 0 - - 5 - - - 5 - - - 5 - - + 5 @@ -115,16 +97,7 @@ 0 - - 5 - - - 5 - - - 5 - - + 5 @@ -160,16 +133,7 @@ 0 - - 5 - - - 5 - - - 5 - - + 5 @@ -180,6 +144,9 @@ 9 + + true + @@ -301,6 +268,7 @@ &Messages + @@ -494,7 +462,7 @@ - &Clear + Cl&ear Clear messages @@ -517,6 +485,14 @@ Ctrl+Shift+R + + + &Copy + + + Ctrl+Shift+C + +