GUI: added basic PatchDialog (ctrl+p)
This commit is contained in:
		
							parent
							
								
									da63daf89c
								
							
						
					
					
						commit
						9c241e8e9b
					
				|  | @ -75,7 +75,8 @@ SOURCES += \ | |||
|     Src/QHexEdit/ArrayCommand.cpp \ | ||||
|     Src/QHexEdit/QHexEdit.cpp \ | ||||
|     Src/QHexEdit/QHexEditPrivate.cpp \ | ||||
|     Src/QHexEdit/XByteArray.cpp | ||||
|     Src/QHexEdit/XByteArray.cpp \ | ||||
|     Src/Gui/PatchDialog.cpp | ||||
| 
 | ||||
| 
 | ||||
| HEADERS += \ | ||||
|  | @ -129,7 +130,8 @@ HEADERS += \ | |||
|     Src/QHexEdit/ArrayCommand.h \ | ||||
|     Src/QHexEdit/QHexEdit.h \ | ||||
|     Src/QHexEdit/QHexEditPrivate.h \ | ||||
|     Src/QHexEdit/XByteArray.h | ||||
|     Src/QHexEdit/XByteArray.h \ | ||||
|     Src/Gui/PatchDialog.h | ||||
| 
 | ||||
| 
 | ||||
| INCLUDEPATH += \ | ||||
|  | @ -158,7 +160,8 @@ FORMS += \ | |||
|     Src/Gui/CommandHelpView.ui \ | ||||
|     Src/Gui/AppearanceDialog.ui \ | ||||
|     Src/Gui/CloseDialog.ui \ | ||||
|     Src/Gui/HexEditDialog.ui | ||||
|     Src/Gui/HexEditDialog.ui \ | ||||
|     Src/Gui/PatchDialog.ui | ||||
| 
 | ||||
| INCLUDEPATH += $$PWD/Src/Bridge | ||||
| 
 | ||||
|  |  | |||
|  | @ -8,7 +8,7 @@ HexEditDialog::HexEditDialog(QWidget *parent) : | |||
|     ui(new Ui::HexEditDialog) | ||||
| { | ||||
|     ui->setupUi(this); | ||||
|     setModal(true); | ||||
| 
 | ||||
|     setWindowFlags(Qt::Dialog | Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::MSWindowsFixedSizeDialogHint); | ||||
|     setFixedSize(this->size()); //fixed size
 | ||||
|     setModal(true); //modal window
 | ||||
|  |  | |||
|  | @ -102,7 +102,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi | |||
|     mLastLogLabel=new StatusLabel(); | ||||
|     ui->statusBar->addPermanentWidget(mLastLogLabel, 1); | ||||
| 
 | ||||
| 
 | ||||
|     mPatchDialog = new PatchDialog(this); | ||||
| 
 | ||||
|     // Setup Signals/Slots
 | ||||
|     connect(mCmdLineEdit, SIGNAL(returnPressed()), this, SLOT(executeCommand())); | ||||
|  | @ -136,6 +136,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi | |||
|     connect(ui->actionStrings,SIGNAL(triggered()),this,SLOT(findStrings())); | ||||
|     connect(ui->actionCalls,SIGNAL(triggered()),this,SLOT(findModularCalls())); | ||||
|     connect(ui->actionAppearance,SIGNAL(triggered()),this,SLOT(openAppearance())); | ||||
|     connect(ui->actionPatches,SIGNAL(triggered()),this,SLOT(patchWindow())); | ||||
| 
 | ||||
|     connect(Bridge::getBridge(), SIGNAL(updateWindowTitle(QString)), this, SLOT(updateWindowTitleSlot(QString))); | ||||
|     connect(Bridge::getBridge(), SIGNAL(addRecentFile(QString)), this, SLOT(addRecentFile(QString))); | ||||
|  | @ -742,3 +743,9 @@ void MainWindow::getStrWindow(const QString title, QString *text) | |||
|     *text=mLineEdit.editText; | ||||
|     Bridge::getBridge()->BridgeSetResult(bResult); | ||||
| } | ||||
| 
 | ||||
| void MainWindow::patchWindow() | ||||
| { | ||||
|     mPatchDialog->show(); | ||||
|     mPatchDialog->setFocus(); | ||||
| } | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ | |||
| #include "Configuration.h" | ||||
| #include "AppearanceDialog.h" | ||||
| #include "CloseDialog.h" | ||||
| #include "PatchDialog.h" | ||||
| 
 | ||||
| namespace Ui | ||||
| { | ||||
|  | @ -78,6 +79,7 @@ public slots: | |||
|     void menuEntrySlot(); | ||||
|     void runSelection(); | ||||
|     void getStrWindow(const QString title, QString* text); | ||||
|     void patchWindow(); | ||||
| 
 | ||||
| private: | ||||
|     Ui::MainWindow *ui; | ||||
|  | @ -93,6 +95,7 @@ private: | |||
|     ScriptView* mScriptView; | ||||
|     ReferenceView* mReferenceView; | ||||
|     ThreadView* mThreadView; | ||||
|     PatchDialog* mPatchDialog; | ||||
| 
 | ||||
|     StatusLabel* mStatusLabel; | ||||
|     StatusLabel* mLastLogLabel; | ||||
|  |  | |||
|  | @ -53,6 +53,7 @@ | |||
|     <addaction name="actionSymbolInfo"/> | ||||
|     <addaction name="actionReferences"/> | ||||
|     <addaction name="actionThreads"/> | ||||
|     <addaction name="actionPatches"/> | ||||
|    </widget> | ||||
|    <widget class="QMenu" name="menuDebug"> | ||||
|     <property name="title"> | ||||
|  | @ -520,6 +521,21 @@ | |||
|     <string>Find Intermodular Calls</string> | ||||
|    </property> | ||||
|   </action> | ||||
|   <action name="actionPatches"> | ||||
|    <property name="icon"> | ||||
|     <iconset resource="../../resource.qrc"> | ||||
|      <normaloff>:/icons/images/patch.png</normaloff>:/icons/images/patch.png</iconset> | ||||
|    </property> | ||||
|    <property name="text"> | ||||
|     <string>Patches</string> | ||||
|    </property> | ||||
|    <property name="toolTip"> | ||||
|     <string>Patches</string> | ||||
|    </property> | ||||
|    <property name="shortcut"> | ||||
|     <string>Ctrl+P</string> | ||||
|    </property> | ||||
|   </action> | ||||
|  </widget> | ||||
|  <layoutdefault spacing="6" margin="11"/> | ||||
|  <resources> | ||||
|  |  | |||
|  | @ -0,0 +1,211 @@ | |||
| #include "PatchDialog.h" | ||||
| #include "ui_PatchDialog.h" | ||||
| 
 | ||||
| PatchDialog::PatchDialog(QWidget *parent) : | ||||
|     QDialog(parent), | ||||
|     ui(new Ui::PatchDialog) | ||||
| { | ||||
|     ui->setupUi(this); | ||||
| 
 | ||||
|     setWindowFlags(Qt::Dialog | Qt::WindowSystemMenuHint | Qt::WindowMinimizeButtonHint | Qt::WindowTitleHint | Qt::MSWindowsFixedSizeDialogHint); | ||||
|     setFixedSize(this->size()); //fixed size
 | ||||
|     setModal(false); //non-modal window
 | ||||
| 
 | ||||
|     connect(Bridge::getBridge(), SIGNAL(updatePatches()), this, SLOT(updatePatches())); | ||||
| 
 | ||||
|     mPatches = new PatchMap(); | ||||
| } | ||||
| 
 | ||||
| PatchDialog::~PatchDialog() | ||||
| { | ||||
|     delete ui; | ||||
| } | ||||
| 
 | ||||
| bool PatchDialog::isPartOfPreviousGroup(PatchInfoList & patchList, int index) | ||||
| { | ||||
|     if(!index) | ||||
|         return true; | ||||
|     uint addr=patchList.at(index).first.addr; | ||||
|     uint prevAddr=patchList.at(index-1).first.addr; | ||||
|     for(int i=1; i<10; i++) //10 bytes in between groups
 | ||||
|         if(addr-i==prevAddr) | ||||
|             return true; | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| void PatchDialog::updatePatches() | ||||
| { | ||||
|     mIsAdding=true; | ||||
|     //clear GUI
 | ||||
|     ui->listModules->clear(); | ||||
|     ui->listPatches->clear(); | ||||
|     delete mPatches; | ||||
|     mPatches = new PatchMap(); | ||||
| 
 | ||||
|     //get patches from DBG
 | ||||
|     size_t cbsize; | ||||
|     if(!DbgFunctions()->PatchEnum(0, &cbsize)) | ||||
|         return; | ||||
|     int numPatches = cbsize/sizeof(DBGPATCHINFO); | ||||
|     if(!numPatches) | ||||
|         return; | ||||
|     DBGPATCHINFO* patches = new DBGPATCHINFO[numPatches]; | ||||
|     memset(patches, 0, numPatches*sizeof(DBGPATCHINFO)); | ||||
|     if(!DbgFunctions()->PatchEnum(patches, 0)) | ||||
|     { | ||||
|         delete [] patches; | ||||
|         mIsAdding=false; | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     //fill the patch list
 | ||||
|     STATUSINFO defaultStatus; | ||||
|     defaultStatus.group=0; | ||||
|     defaultStatus.checked=false; | ||||
|     for(int i=0; i<numPatches; i++) | ||||
|     { | ||||
|         if(!patches[i].addr) | ||||
|             continue; | ||||
|         QString mod(patches[i].mod); | ||||
|         PatchMap::iterator found = mPatches->find(mod); | ||||
|         if(found != mPatches->end()) //found
 | ||||
|             (*mPatches)[mod].append(PatchPair(patches[i], defaultStatus)); | ||||
|         else //not found
 | ||||
|         { | ||||
|             PatchInfoList patchList; | ||||
|             patchList.append(PatchPair(patches[i], defaultStatus)); | ||||
|             mPatches->insert(mod, patchList); | ||||
|         } | ||||
|     } | ||||
|     delete [] patches; | ||||
| 
 | ||||
|     //sort the patches by address
 | ||||
|     for(PatchMap::iterator i=mPatches->begin(); i!=mPatches->end(); ++i) | ||||
|     { | ||||
|         qSort(i.value().begin(), i.value().end(), PatchInfoLess); | ||||
|         PatchInfoList & curPatchList = i.value(); | ||||
|         //group the patched bytes
 | ||||
|         for(int j=0,group=0; j<curPatchList.size(); j++) | ||||
|         { | ||||
|             if(!isPartOfPreviousGroup(curPatchList, j)) | ||||
|                 group++; | ||||
|             curPatchList[j].second.group=group; | ||||
|         } | ||||
|         ui->listModules->addItem(i.key()); | ||||
|     } | ||||
|     mIsAdding=false; | ||||
| } | ||||
| 
 | ||||
| void PatchDialog::on_listModules_itemSelectionChanged() | ||||
| { | ||||
|     if(!ui->listModules->selectedItems().size()) | ||||
|         return; | ||||
|     QString mod(ui->listModules->selectedItems().at(0)->text()); | ||||
|     PatchMap::iterator found = mPatches->find(mod); | ||||
|     if(found == mPatches->end()) //not found
 | ||||
|         return; | ||||
|     mIsAdding=true; | ||||
|     PatchInfoList patchList = found.value(); | ||||
|     ui->listPatches->clear(); | ||||
|     for(int i=0; i<patchList.size(); i++) | ||||
|     { | ||||
|         const DBGPATCHINFO curPatch = patchList.at(i).first; | ||||
|         QString addrText = QString("%1").arg(curPatch.addr, sizeof(int_t)*2, 16, QChar('0')).toUpper(); | ||||
|         QListWidgetItem* item = new QListWidgetItem(QString().sprintf("%d", patchList.at(i).second.group).rightJustified(4, ' ', true) + "|" + addrText + QString().sprintf(":%.2X->%.2X", curPatch.oldbyte, curPatch.newbyte), ui->listPatches); | ||||
|         item->setFlags(item->flags() | Qt::ItemIsUserCheckable); | ||||
|         item->setCheckState(Qt::Unchecked); | ||||
|     } | ||||
|     mIsAdding=false; | ||||
| } | ||||
| 
 | ||||
| void PatchDialog::on_listPatches_itemChanged(QListWidgetItem *item) //checkbox changed
 | ||||
| { | ||||
|     if(mIsAdding || !ui->listModules->selectedItems().size()) | ||||
|         return; | ||||
|     QString mod = ui->listModules->selectedItems().at(0)->text(); | ||||
|     PatchMap::iterator found = mPatches->find(mod); | ||||
|     if(found == mPatches->end()) //not found
 | ||||
|         return; | ||||
|     bool checked=item->checkState()==Qt::Checked; | ||||
|     PatchInfoList & curPatchList = found.value(); | ||||
|     PatchPair & patch = curPatchList[ui->listPatches->row(item)]; | ||||
|     if(patch.second.checked == checked) //check state did not change
 | ||||
|         return; | ||||
|     patch.second.checked = checked; | ||||
|     //check state changed
 | ||||
|     if((QApplication::keyboardModifiers() & Qt::ControlModifier) == Qt::ControlModifier) | ||||
|         return; //control held down -> do not check/uncheck group
 | ||||
|     mIsAdding=true; | ||||
|     //check/uncheck the complete group
 | ||||
|     for(int i=0; i<curPatchList.size(); i++) | ||||
|         if(curPatchList.at(i).second.group==patch.second.group) | ||||
|         { | ||||
|             curPatchList[i].second.checked=checked; | ||||
|             ui->listPatches->item(i)->setCheckState(item->checkState()); | ||||
|         } | ||||
|     mIsAdding=false; | ||||
| } | ||||
| 
 | ||||
| void PatchDialog::on_btnSelectAll_clicked() | ||||
| { | ||||
|     if(!ui->listModules->selectedItems().size()) | ||||
|         return; | ||||
|     QString mod = ui->listModules->selectedItems().at(0)->text(); | ||||
|     PatchMap::iterator found = mPatches->find(mod); | ||||
|     if(found == mPatches->end()) //not found
 | ||||
|         return; | ||||
|     mIsAdding=true; | ||||
|     PatchInfoList & curPatchList = found.value(); | ||||
|     for(int i=0; i<curPatchList.size(); i++) | ||||
|     { | ||||
|         ui->listPatches->item(i)->setCheckState(Qt::Checked); | ||||
|         curPatchList[i].second.checked=true; | ||||
|     } | ||||
|     mIsAdding=false; | ||||
| } | ||||
| 
 | ||||
| void PatchDialog::on_btnDeselectAll_clicked() | ||||
| { | ||||
|     if(!ui->listModules->selectedItems().size()) | ||||
|         return; | ||||
|     QString mod = ui->listModules->selectedItems().at(0)->text(); | ||||
|     PatchMap::iterator found = mPatches->find(mod); | ||||
|     if(found == mPatches->end()) //not found
 | ||||
|         return; | ||||
|     mIsAdding=true; | ||||
|     PatchInfoList & curPatchList = found.value(); | ||||
|     for(int i=0; i<curPatchList.size(); i++) | ||||
|     { | ||||
|         ui->listPatches->item(i)->setCheckState(Qt::Unchecked); | ||||
|         curPatchList[i].second.checked=false; | ||||
|     } | ||||
|     mIsAdding=false; | ||||
| } | ||||
| 
 | ||||
| void PatchDialog::on_btnRestoreSelected_clicked() | ||||
| { | ||||
|     if(!ui->listModules->selectedItems().size()) | ||||
|         return; | ||||
|     int selModIdx = ui->listModules->row(ui->listModules->selectedItems().at(0)); | ||||
|     QString mod = ui->listModules->selectedItems().at(0)->text(); | ||||
|     PatchMap::iterator found = mPatches->find(mod); | ||||
|     if(found == mPatches->end()) //not found
 | ||||
|         return; | ||||
|     mIsAdding=true; | ||||
|     PatchInfoList & curPatchList = found.value(); | ||||
|     int removed=0; | ||||
|     int total=curPatchList.size(); | ||||
|     for(int i=0; i<total; i++) | ||||
|     { | ||||
|         if(curPatchList.at(i).second.checked) | ||||
|         { | ||||
|             DbgFunctions()->PatchRestore(curPatchList.at(i).first.addr); | ||||
|             removed++; | ||||
|         } | ||||
|     } | ||||
|     mIsAdding=false; | ||||
|     updatePatches(); | ||||
|     if(removed!=total) | ||||
|         ui->listModules->setCurrentRow(selModIdx); | ||||
|     GuiUpdateAllViews(); | ||||
| } | ||||
|  | @ -0,0 +1,50 @@ | |||
| #ifndef PATCHDIALOG_H | ||||
| #define PATCHDIALOG_H | ||||
| 
 | ||||
| #include <QDialog> | ||||
| #include "Bridge.h" | ||||
| 
 | ||||
| namespace Ui { | ||||
|     class PatchDialog; | ||||
| } | ||||
| 
 | ||||
| class PatchDialog : public QDialog | ||||
| { | ||||
|     Q_OBJECT | ||||
| 
 | ||||
|     struct STATUSINFO | ||||
|     { | ||||
|         bool checked; | ||||
|         int group; | ||||
|     }; | ||||
| 
 | ||||
|     typedef QPair<DBGPATCHINFO, STATUSINFO> PatchPair; | ||||
|     typedef QList<PatchPair> PatchInfoList; | ||||
|     typedef QMap<QString, PatchInfoList> PatchMap; | ||||
| 
 | ||||
|     static bool PatchInfoLess(const PatchPair & a, const PatchPair & b) | ||||
|     { | ||||
|         return a.first.addr < b.first.addr; | ||||
|     } | ||||
| 
 | ||||
| public: | ||||
|     explicit PatchDialog(QWidget *parent = 0); | ||||
|     ~PatchDialog(); | ||||
| 
 | ||||
| private: | ||||
|     Ui::PatchDialog *ui; | ||||
|     PatchMap* mPatches; | ||||
|     bool mIsAdding; | ||||
| 
 | ||||
|     bool isPartOfPreviousGroup(PatchInfoList & patchList, int index); | ||||
| 
 | ||||
| private slots: | ||||
|     void updatePatches(); | ||||
|     void on_listModules_itemSelectionChanged(); | ||||
|     void on_listPatches_itemChanged(QListWidgetItem *item); | ||||
|     void on_btnSelectAll_clicked(); | ||||
|     void on_btnDeselectAll_clicked(); | ||||
|     void on_btnRestoreSelected_clicked(); | ||||
| }; | ||||
| 
 | ||||
| #endif // PATCHDIALOG_H
 | ||||
|  | @ -0,0 +1,147 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <ui version="4.0"> | ||||
|  <class>PatchDialog</class> | ||||
|  <widget class="QDialog" name="PatchDialog"> | ||||
|   <property name="geometry"> | ||||
|    <rect> | ||||
|     <x>0</x> | ||||
|     <y>0</y> | ||||
|     <width>511</width> | ||||
|     <height>452</height> | ||||
|    </rect> | ||||
|   </property> | ||||
|   <property name="windowTitle"> | ||||
|    <string>Patches</string> | ||||
|   </property> | ||||
|   <property name="windowIcon"> | ||||
|    <iconset resource="../../resource.qrc"> | ||||
|     <normaloff>:/icons/images/patch.png</normaloff>:/icons/images/patch.png</iconset> | ||||
|   </property> | ||||
|   <widget class="QGroupBox" name="groupPatches"> | ||||
|    <property name="geometry"> | ||||
|     <rect> | ||||
|      <x>230</x> | ||||
|      <y>10</y> | ||||
|      <width>271</width> | ||||
|      <height>361</height> | ||||
|     </rect> | ||||
|    </property> | ||||
|    <property name="title"> | ||||
|     <string>&Patches</string> | ||||
|    </property> | ||||
|    <widget class="QListWidget" name="listPatches"> | ||||
|     <property name="geometry"> | ||||
|      <rect> | ||||
|       <x>10</x> | ||||
|       <y>20</y> | ||||
|       <width>251</width> | ||||
|       <height>331</height> | ||||
|      </rect> | ||||
|     </property> | ||||
|     <property name="font"> | ||||
|      <font> | ||||
|       <family>Courier New</family> | ||||
|      </font> | ||||
|     </property> | ||||
|    </widget> | ||||
|   </widget> | ||||
|   <widget class="QGroupBox" name="groupModules"> | ||||
|    <property name="geometry"> | ||||
|     <rect> | ||||
|      <x>10</x> | ||||
|      <y>10</y> | ||||
|      <width>211</width> | ||||
|      <height>431</height> | ||||
|     </rect> | ||||
|    </property> | ||||
|    <property name="title"> | ||||
|     <string>&Modules</string> | ||||
|    </property> | ||||
|    <widget class="QListWidget" name="listModules"> | ||||
|     <property name="geometry"> | ||||
|      <rect> | ||||
|       <x>10</x> | ||||
|       <y>20</y> | ||||
|       <width>191</width> | ||||
|       <height>401</height> | ||||
|      </rect> | ||||
|     </property> | ||||
|     <property name="font"> | ||||
|      <font> | ||||
|       <family>Courier New</family> | ||||
|      </font> | ||||
|     </property> | ||||
|    </widget> | ||||
|   </widget> | ||||
|   <widget class="QWidget" name=""> | ||||
|    <property name="geometry"> | ||||
|     <rect> | ||||
|      <x>230</x> | ||||
|      <y>380</y> | ||||
|      <width>271</width> | ||||
|      <height>58</height> | ||||
|     </rect> | ||||
|    </property> | ||||
|    <layout class="QVBoxLayout" name="verticalLayout"> | ||||
|     <item> | ||||
|      <layout class="QHBoxLayout" name="horizontalLayout"> | ||||
|       <item> | ||||
|        <widget class="QPushButton" name="btnSelectAll"> | ||||
|         <property name="text"> | ||||
|          <string>Select All</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item> | ||||
|        <widget class="QPushButton" name="btnDeselectAll"> | ||||
|         <property name="text"> | ||||
|          <string>Deselect All</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item> | ||||
|        <widget class="QPushButton" name="btnRestoreSelected"> | ||||
|         <property name="text"> | ||||
|          <string>Restore Selected</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|      </layout> | ||||
|     </item> | ||||
|     <item> | ||||
|      <layout class="QHBoxLayout" name="horizontalLayout_2"> | ||||
|       <item> | ||||
|        <widget class="QPushButton" name="btnPickGroups"> | ||||
|         <property name="enabled"> | ||||
|          <bool>false</bool> | ||||
|         </property> | ||||
|         <property name="text"> | ||||
|          <string>Pick Groups</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item> | ||||
|        <widget class="QPushButton" name="btnPatchFile"> | ||||
|         <property name="enabled"> | ||||
|          <bool>false</bool> | ||||
|         </property> | ||||
|         <property name="text"> | ||||
|          <string>Patch File</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|      </layout> | ||||
|     </item> | ||||
|    </layout> | ||||
|   </widget> | ||||
|  </widget> | ||||
|  <tabstops> | ||||
|   <tabstop>listModules</tabstop> | ||||
|   <tabstop>listPatches</tabstop> | ||||
|   <tabstop>btnPatchFile</tabstop> | ||||
|  </tabstops> | ||||
|  <resources> | ||||
|   <include location="../../resource.qrc"/> | ||||
|  </resources> | ||||
|  <connections/> | ||||
| </ui> | ||||
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 769 B | 
|  | @ -33,5 +33,6 @@ | |||
|         <file>images/color-swatches.png</file> | ||||
|         <file>images/call.png</file> | ||||
|         <file>images/document-binary.png</file> | ||||
|         <file>images/patch.png</file> | ||||
|     </qresource> | ||||
| </RCC> | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue