1 #ifndef ROMALYZER_H 2 #define ROMALYZER_H 3 4 #include <QtGui> 5 #include <QtXml> 6 #include <QThread> 7 #include <QMutex> 8 #include <QWaitCondition> 9 #include <QTime> 10 #include <QTimer> 11 #include <QMap> 12 #include <QHash> 13 #include <QPixmap> 14 #include <QStringList> 15 16 #include "macros.h" 17 #include "checksumdbmgr.h" 18 #include "checksumscannerlog.h" 19 #include "collectionrebuilder.h" 20 #include "rompathcleaner.h" 21 #include "ui_romalyzer.h" 22 23 #define QMC2_ROMALYZER_PAGE_REPORT 0 24 #define QMC2_ROMALYZER_PAGE_LOG 1 25 #define QMC2_ROMALYZER_PAGE_SETTINGS 2 26 #define QMC2_ROMALYZER_PAGE_CSF 3 // CSF: Check-sum finder 27 #if defined(QMC2_WIP_ENABLED) // FIXME: WIP 28 #define QMC2_ROMALYZER_PAGE_RPC 4 // RPC: ROM path cleaner 29 #define QMC2_ROMALYZER_PAGE_RCR 5 // RCR: ROM collection rebuilder 30 #else 31 #define QMC2_ROMALYZER_PAGE_RCR 4 32 #endif 33 34 #define QMC2_ROMALYZER_COLUMN_SET 0 35 #define QMC2_ROMALYZER_COLUMN_MERGE 1 36 #define QMC2_ROMALYZER_COLUMN_TYPE 2 37 #define QMC2_ROMALYZER_COLUMN_EMUSTATUS 3 38 #define QMC2_ROMALYZER_COLUMN_FILESTATUS 4 39 #define QMC2_ROMALYZER_COLUMN_SIZE 5 40 #define QMC2_ROMALYZER_COLUMN_CRC 6 41 #define QMC2_ROMALYZER_COLUMN_SHA1 7 42 #define QMC2_ROMALYZER_COLUMN_MD5 8 43 44 #define QMC2_ROMALYZER_CSF_COLUMN_ID 0 45 #define QMC2_ROMALYZER_CSF_COLUMN_FILENAME 1 46 #define QMC2_ROMALYZER_CSF_COLUMN_STATUS 2 47 #define QMC2_ROMALYZER_CSF_COLUMN_TYPE 3 48 #define QMC2_ROMALYZER_CSF_COLUMN_PATH 4 49 50 #define QMC2_ROMALYZER_CSF_HASHTYPE_SHA1 0 51 #define QMC2_ROMALYZER_CSF_HASHTYPE_CRC 1 52 53 #define QMC2_ROMALYZER_MERGE_STATUS_OK 0 54 #define QMC2_ROMALYZER_MERGE_STATUS_WARN 1 55 #define QMC2_ROMALYZER_MERGE_STATUS_CRIT 2 56 57 #if defined(QMC2_LIBARCHIVE_ENABLED) 58 #define QMC2_ROMALYZER_RT_ZIP_BUILTIN 0 59 #define QMC2_ROMALYZER_RT_ZIP_LIBARCHIVE 1 60 #define QMC2_ROMALYZER_RT_FOLDERS 2 61 #else 62 #define QMC2_ROMALYZER_RT_ZIP_BUILTIN 0 63 #define QMC2_ROMALYZER_RT_FOLDERS 1 64 #endif 65 66 #define QMC2_ROMALYZER_EMUSTATUS_GOOD 0x00000001 67 #define QMC2_ROMALYZER_EMUSTATUS_NODUMP 0x00000020 68 #define QMC2_ROMALYZER_EMUSTATUS_BADDUMP 0x00000400 69 #define QMC2_ROMALYZER_EMUSTATUS_UNKNOWN 0x00008000 70 71 #define QMC2_ROMALYZER_PAUSE_TIMEOUT 250 72 #define QMC2_ROMALYZER_FLASH_TIME 100 73 #define QMC2_ROMALYZER_XMLPOSCACHE_SIZE 1000 74 #define QMC2_ROMALYZER_SEARCH_RESPONSE 5000 75 #define QMC2_ROMALYZER_EXPORT_RESPONSE 10 76 #define QMC2_ROMALYZER_CKSUM_SEARCH_RESPONSE 500 77 78 #define QMC2_ROMALYZER_FILE_TOO_BIG "QMC2_FILE_TOO_BIG" 79 #define QMC2_ROMALYZER_FILE_ERROR "QMC2_FILE_ERROR" 80 #define QMC2_ROMALYZER_FILE_NOT_SUPPORTED "QMC2_FILE_NOT_SUPPORTED" 81 #define QMC2_ROMALYZER_FILE_NOT_FOUND "QMC2_FILE_NOT_FOUND" 82 #define QMC2_ROMALYZER_NO_DUMP "QMC2_NO_DUMP" 83 84 #define QMC2_ROMALYZER_ZIP_BUFFER_SIZE QMC2_ZIP_BUFFER_SIZE 85 #define QMC2_ROMALYZER_FILE_BUFFER_SIZE QMC2_FILE_BUFFER_SIZE 86 #define QMC2_ROMALYZER_PROGRESS_THRESHOLD QMC2_ONE_MEGABYTE 87 88 #define QMC2_CHD_HEADER_TAG_OFFSET 0 89 #define QMC2_CHD_HEADER_TAG_LENGTH 8 90 #define QMC2_CHD_HEADER_VERSION_OFFSET 12 91 #define QMC2_CHD_HEADER_FLAGS_OFFSET 16 92 #define QMC2_CHD_HEADER_FLAG_HASPARENT 0x00000001 93 #define QMC2_CHD_HEADER_FLAG_ALLOWSWRITES 0x00000002 94 #define QMC2_CHD_HEADER_COMPRESSION_OFFSET 20 95 #define QMC2_CHD_HEADER_COMPRESSION_NONE 0 96 #define QMC2_CHD_HEADER_COMPRESSION_ZLIB 1 97 #define QMC2_CHD_HEADER_COMPRESSION_ZLIB_PLUS 2 98 #define QMC2_CHD_HEADER_COMPRESSION_AV 3 99 100 #define QMC2_CHD_HEADER_V3_TAG_OFFSET QMC2_CHD_HEADER_TAG_OFFSET 101 #define QMC2_CHD_HEADER_V3_TAG_LENGTH QMC2_CHD_HEADER_TAG_LENGTH 102 #define QMC2_CHD_HEADER_V3_VERSION_OFFSET QMC2_CHD_HEADER_VERSION_OFFSET 103 #define QMC2_CHD_HEADER_V3_TOTALHUNKS_OFFSET 24 104 #define QMC2_CHD_HEADER_V3_LOGICALBYTES_OFFSET 28 105 #define QMC2_CHD_HEADER_V3_MD5_OFFSET 44 106 #define QMC2_CHD_HEADER_V3_MD5_LENGTH 16 107 #define QMC2_CHD_HEADER_V3_PARENTMD5_OFFSET 60 108 #define QMC2_CHD_HEADER_V3_PARENTMD5_LENGTH 16 109 #define QMC2_CHD_HEADER_V3_HUNKBYTES_OFFSET 76 110 #define QMC2_CHD_HEADER_V3_SHA1_OFFSET 80 111 #define QMC2_CHD_HEADER_V3_SHA1_LENGTH 20 112 #define QMC2_CHD_HEADER_V3_PARENTSHA1_OFFSET 100 113 #define QMC2_CHD_HEADER_V3_PARENTSHA1_LENGTH 20 114 #define QMC2_CHD_HEADER_V3_LENGTH 120 115 116 #define QMC2_CHD_HEADER_V4_TAG_OFFSET QMC2_CHD_HEADER_TAG_OFFSET 117 #define QMC2_CHD_HEADER_V4_TAG_LENGTH QMC2_CHD_HEADER_TAG_LENGTH 118 #define QMC2_CHD_HEADER_V4_VERSION_OFFSET QMC2_CHD_HEADER_VERSION_OFFSET 119 #define QMC2_CHD_HEADER_V4_TOTALHUNKS_OFFSET 24 120 #define QMC2_CHD_HEADER_V4_LOGICALBYTES_OFFSET 28 121 #define QMC2_CHD_HEADER_V4_HUNKBYTES_OFFSET 44 122 #define QMC2_CHD_HEADER_V4_SHA1_OFFSET 48 123 #define QMC2_CHD_HEADER_V4_SHA1_LENGTH 20 124 #define QMC2_CHD_HEADER_V4_PARENTSHA1_OFFSET 68 125 #define QMC2_CHD_HEADER_V4_PARENTSHA1_LENGTH 20 126 #define QMC2_CHD_HEADER_V4_RAWSHA1_OFFSET 88 127 #define QMC2_CHD_HEADER_V4_RAWSHA1_LENGTH 20 128 #define QMC2_CHD_HEADER_V4_LENGTH 108 129 130 #define QMC2_CHD_HEADER_V5_TAG_OFFSET QMC2_CHD_HEADER_TAG_OFFSET 131 #define QMC2_CHD_HEADER_V5_TAG_LENGTH QMC2_CHD_HEADER_TAG_LENGTH 132 #define QMC2_CHD_HEADER_V5_VERSION_OFFSET QMC2_CHD_HEADER_VERSION_OFFSET 133 #define QMC2_CHD_HEADER_V5_COMPRESSORS_OFFSET 16 134 #define QMC2_CHD_HEADER_V5_COMPRESSORS_COUNT 4 // 4 x UINT32 135 #define QMC2_CHD_HEADER_V5_LOGICALBYTES_OFFSET 32 136 #define QMC2_CHD_HEADER_V5_HUNKBYTES_OFFSET 56 137 #define QMC2_CHD_HEADER_V5_UNITBYTES_OFFSET 60 138 #define QMC2_CHD_HEADER_V5_RAWSHA1_OFFSET 64 139 #define QMC2_CHD_HEADER_V5_RAWSHA1_LENGTH 20 140 #define QMC2_CHD_HEADER_V5_SHA1_OFFSET 84 141 #define QMC2_CHD_HEADER_V5_SHA1_LENGTH 20 142 #define QMC2_CHD_HEADER_V5_PARENTSHA1_OFFSET 104 143 #define QMC2_CHD_HEADER_V5_PARENTSHA1_LENGTH 20 144 #define QMC2_CHD_HEADER_V5_LENGTH 124 145 146 #define QMC2_CHD_CURRENT_VERSION 5 147 #define QMC2_CHD_CHECK_NULL_SHA1(ba) ((ba).startsWith(QByteArray("00000000000000000000"))) 148 149 #define crcToString(crc) QString::number((crc), 16).rightJustified(8, '0') 150 151 #define QMC2_CHECKSUM_SCANNER_FILE_UNKNOWN -2 152 #define QMC2_CHECKSUM_SCANNER_FILE_NO_ACCESS -1 153 #define QMC2_CHECKSUM_SCANNER_FILE_ZIP 0 154 #define QMC2_CHECKSUM_SCANNER_FILE_7Z 1 155 #define QMC2_CHECKSUM_SCANNER_FILE_CHD 2 156 #define QMC2_CHECKSUM_SCANNER_FILE_REGULAR 3 157 #define QMC2_CHECKSUM_SCANNER_FILE_ARCHIVE 4 158 159 #define QMC2_CHECKSUM_SCANNER_MAX_QUEUED_MSGS 50 160 161 #define QMC2_CHECKSUM_DB_QUERY_STATUS_UNKNOWN -1 162 #define QMC2_CHECKSUM_DB_QUERY_STATUS_GOOD 0 163 #define QMC2_CHECKSUM_DB_QUERY_STATUS_BAD 1 164 165 #define QMC2_ROMALYZER_REBUILD_ANIM_SPEED 500 166 167 class CheckSumScannerThread : public QThread 168 { 169 Q_OBJECT 170 171 public: 172 bool exitThread; 173 bool stopScan; 174 bool isActive; 175 bool isWaiting; 176 bool isPaused; 177 bool pauseRequested; 178 bool scanIncrementally; 179 bool deepScan; 180 bool useHashCache; 181 #if defined(QMC2_LIBARCHIVE_ENABLED) 182 bool useLibArchive; 183 #endif 184 QMutex mutex; 185 QMutex logSyncMutex; 186 QWaitCondition waitCondition; 187 QStringList scannedPaths; 188 QTime scanTimer; 189 190 CheckSumScannerThread(CheckSumScannerLog *scannerLog, QString settingsKey, QObject *parent = 0); 191 ~CheckSumScannerThread(); 192 checkSumDb()193 CheckSumDatabaseManager *checkSumDb() { return m_checkSumDb; } pendingUpdates()194 quint64 pendingUpdates() { return m_pendingUpdates; } 195 QString status(); 196 void reopenCheckSumDb(); 197 int fileType(QString, bool &, bool &); 198 void prepareIncrementalScan(QStringList *fileList); 199 QString scanTime(); 200 void emitlog(QString); 201 void flushMessageQueue(); 202 203 public slots: 204 void pause(); 205 void resume(); 206 207 signals: 208 void log(const QString &); 209 void scanStarted(); 210 void scanFinished(); 211 void scanPaused(); 212 void scanResumed(); 213 void progressTextChanged(const QString &); 214 void progressRangeChanged(int, int); 215 void progressChanged(int); 216 217 protected: 218 void run(); 219 220 private: 221 CheckSumDatabaseManager *m_checkSumDb; 222 CheckSumScannerLog *m_scannerLog; 223 quint64 m_pendingUpdates; 224 bool m_preparingIncrementalScan; 225 QString m_settingsKey; 226 QHash<QString, bool> m_hashCache; 227 QStringList m_queuedMessages; 228 bool checkSumExists(QString sha1, QString crc, quint64 size = 0); 229 void recursiveFileList(const QString &, QStringList *); 230 bool scanZip(QString, QStringList *, QList<quint64> *, QStringList *, QStringList *); 231 bool scanSevenZip(QString, QStringList *, QList<quint64> *, QStringList *, QStringList *); 232 #if defined(QMC2_LIBARCHIVE_ENABLED) 233 bool scanArchive(QString, QStringList *, QList<quint64> *, QStringList *, QStringList *); 234 #endif 235 bool scanChd(QString, quint64 *, QString *); 236 bool scanRegularFile(QString, quint64 *, QString *, QString *); 237 }; 238 239 class ROMAlyzerXmlHandler : public QXmlDefaultHandler 240 { 241 public: 242 QString currentText; 243 QTreeWidgetItem *parentItem; 244 QTreeWidgetItem *childItem; 245 QList<QTreeWidgetItem *> childItems; 246 QStringList deviceReferences; 247 QStringList optionalROMs; 248 bool autoExpand; 249 bool autoScroll; 250 int emuStatus; 251 int fileCounter; 252 int romalyzerMode; 253 QBrush redBrush; 254 QBrush greenBrush; 255 QBrush blueBrush; 256 QBrush yellowBrush; 257 QBrush brownBrush; 258 QBrush greyBrush; 259 260 ROMAlyzerXmlHandler(QTreeWidgetItem *, bool expand = false, bool scroll = false, int mode = QMC2_ROMALYZER_MODE_SYSTEM); 261 262 bool startElement(const QString &, const QString &, const QString &, const QXmlAttributes &); 263 bool endElement(const QString &, const QString &, const QString &); 264 bool characters(const QString &); 265 }; 266 267 class ROMAlyzer : public QDialog, public Ui::ROMAlyzer 268 { 269 Q_OBJECT 270 271 public: 272 QTimer animTimer; 273 QTimer checkSumDbStatusTimer; 274 QTime miscTimer; 275 int animSeq; 276 QStringList romPaths; 277 QStringList chdCompressionTypes; 278 QMap<QString, QString> chdCompressionTypesV5; 279 bool chdManagerRunning; 280 bool chdManagerMD5Success; 281 bool chdManagerSHA1Success; 282 quint64 chdManagerCurrentHunk; 283 quint64 chdManagerTotalHunks; 284 QMenu *romFileContextMenu; 285 QMenu *romSetContextMenu; 286 QMenu *toolsMenu; 287 QAction *actionRewriteSet; 288 QAction *actionAnalyzeDeviceRefs; 289 QAction *actionImportFromDataFile; 290 QAction *actionExportToDataFile; 291 QAction *actionCopyBadToClipboard; 292 QString currentFilesSHA1Checksum; 293 QString currentFilesCrcChecksum; 294 quint64 currentFilesSize; 295 QStringList wizardSelectedSets; 296 QStringList analyzerBadSets; 297 QMultiMap<QString, QStringList> setRewriterFileMap; 298 QString setRewriterSetName; 299 QTreeWidgetItem *setRewriterItem; 300 int setRewriterSetCount; 301 bool wizardSearch; 302 bool quickSearch; 303 qint64 lastRowCount; 304 305 ROMAlyzer(QWidget *, int romalyzerMode = QMC2_ROMALYZER_MODE_SYSTEM); 306 ~ROMAlyzer(); 307 saveState()308 void saveState() { closeEvent(0); } 309 bool readSevenZipFileData(QString, QString, QString, QByteArray *); 310 bool readZipFileData(QString, QString, QString, QByteArray *); 311 bool readFileData(QString, QString, QByteArray *); 312 bool writeAllZipData(QString, QMap<QString, QByteArray> *, bool writeLog = false, QProgressBar *pBar = 0); 313 #if defined(QMC2_LIBARCHIVE_ENABLED) 314 bool writeAllArchiveData(QString, QMap<QString, QByteArray> *, bool writeLog = false, QProgressBar *pBar = 0); 315 #endif 316 bool writeAllFileData(QString, QMap<QString, QByteArray> *, bool writeLog = false, QProgressBar *pBar = 0); 317 static QString humanReadable(quint64, int digits = 2); 318 static QString &getXmlData(QString, bool includeDTD = false); 319 static QString &getSoftwareXmlData(QString, QString, bool includeDTD = false); 320 QString &getEffectiveFile(QTreeWidgetItem *, QString, QString, QString, QString, QString, QString, QString, QByteArray *, QString *, QString *, bool *, bool *, bool *, int, QString *, bool, bool *); 321 bool createBackup(QString filePath); checkSumDb()322 CheckSumDatabaseManager *checkSumDb() { return m_checkSumDb; } checkSumScannerLog()323 CheckSumScannerLog *checkSumScannerLog() { return m_checkSumScannerLog; } checkSumScannerThread()324 CheckSumScannerThread *checkSumScannerThread() { return m_checkSumScannerThread; } collectionRebuilder()325 CollectionRebuilder *collectionRebuilder() { return m_collectionRebuilder; } romPathCleaner()326 RomPathCleaner *romPathCleaner() { return m_romPathCleaner; } mode()327 int mode() { return m_currentMode; } 328 void setMode(int mode); active()329 bool active() { return m_active; } setActive(bool active)330 void setActive(bool active) { m_active = active; } paused()331 bool paused() { return m_paused; } setPaused(bool paused)332 void setPaused(bool paused) { m_paused = paused; } settingsKey()333 QString settingsKey() { return m_settingsKey; } rebuilderActive()334 bool rebuilderActive() { return collectionRebuilder() ? collectionRebuilder()->active() : false; } 335 336 public slots: 337 // callback functions 338 void on_pushButtonAnalyze_clicked(); 339 void on_pushButtonPause_clicked(); 340 void on_pushButtonClose_clicked(); 341 void on_pushButtonSearchForward_clicked(); 342 void on_pushButtonSearchBackward_clicked(); 343 void on_lineEditSoftwareLists_textChanged(QString); 344 void on_lineEditSets_textChanged(QString); 345 void on_treeWidgetChecksums_itemSelectionChanged(); 346 void on_spinBoxMaxLogSize_valueChanged(int); 347 void on_toolButtonBrowseBackupFolder_clicked(); 348 void on_toolButtonBrowseCHDManagerExecutableFile_clicked(); 349 void on_toolButtonBrowseTemporaryWorkingDirectory_clicked(); 350 void on_toolButtonBrowseSetRewriterOutputPath_clicked(); 351 void on_toolButtonBrowseSetRewriterAdditionalRomPath_clicked(); 352 void on_toolButtonSaveLog_clicked(); 353 void on_checkBoxCalculateCRC_toggled(bool); 354 void on_checkBoxCalculateMD5_toggled(bool); 355 void on_checkBoxCalculateSHA1_toggled(bool); 356 void on_comboBoxChecksumWizardHashType_currentIndexChanged(int); 357 void on_lineEditChecksumWizardHash_textChanged(const QString &); 358 void lineEditChecksumWizardHash_textChanged_delayed(); 359 void on_pushButtonChecksumWizardSearch_clicked(); 360 void on_treeWidgetChecksums_customContextMenuRequested(const QPoint &); 361 void on_treeWidgetChecksumWizardSearchResult_itemSelectionChanged(); 362 void on_pushButtonChecksumWizardAnalyzeSelectedSets_clicked(); 363 void on_tabWidgetAnalysis_currentChanged(int); 364 void on_toolButtonCheckSumDbAddPath_clicked(); 365 void on_toolButtonCheckSumDbRemovePath_clicked(); 366 void on_lineEditCheckSumDbDatabasePath_textChanged(const QString &); 367 void on_toolButtonBrowseCheckSumDbDatabasePath_clicked(); 368 void on_toolButtonCheckSumDbViewLog_clicked(); 369 void on_pushButtonCheckSumDbScan_clicked(); 370 void on_pushButtonCheckSumDbPauseResumeScan_clicked(); 371 void on_listWidgetCheckSumDbScannedPaths_customContextMenuRequested(const QPoint &); 372 void on_listWidgetCheckSumDbScannedPaths_itemSelectionChanged(); 373 void checkSumScannerLog_windowClosed(); 374 void checkSumScannerLog_windowOpened(); 375 void checkSumScannerThread_scanStarted(); 376 void checkSumScannerThread_scanFinished(); 377 void checkSumScannerThread_scanPaused(); 378 void checkSumScannerThread_scanResumed(); 379 void switchToCollectionRebuilder(); 380 381 // miscellaneous slots 382 void animationTimeout(); 383 void analyze(); 384 void selectItem(QString); enableSearchEdit()385 void enableSearchEdit() { lineEditSearchString->setEnabled(true); } 386 void adjustIconSizes(); 387 void runChecksumWizard(); 388 void runSetRewriter(); 389 void copyToClipboard(bool onlyBadOrMissing = false); 390 void copyBadToClipboard(); 391 void analyzeDeviceRefs(); 392 void importFromDataFile(); 393 void exportToDataFile(); 394 void updateCheckSumDbStatus(); 395 void log(const QString &); 396 void indicateCheckSumDbQueryStatusGood(); 397 void indicateCheckSumDbQueryStatusBad(); 398 void indicateCheckSumDbQueryStatusUnknown(); 399 void softwareListLoadFinished(bool); 400 void on_groupBoxSetRewriter_toggled(bool); 401 void on_groupBoxCheckSumDatabase_toggled(bool); 402 403 // CHD manager process control 404 void chdManagerStarted(); 405 void chdManagerFinished(int, QProcess::ExitStatus); 406 void chdManagerReadyReadStandardOutput(); 407 void chdManagerReadyReadStandardError(); 408 void chdManagerError(QProcess::ProcessError); 409 410 protected: 411 void closeEvent(QCloseEvent *); 412 void showEvent(QShowEvent *); 413 void hideEvent(QHideEvent *); 414 void moveEvent(QMoveEvent *); 415 void resizeEvent(QResizeEvent *); 416 417 private: 418 CheckSumDatabaseManager *m_checkSumDb; 419 CheckSumScannerLog *m_checkSumScannerLog; 420 CheckSumScannerThread *m_checkSumScannerThread; 421 QPixmap m_checkSumDbQueryStatusPixmap; 422 QTimer m_checkSumTextChangedTimer; 423 CollectionRebuilder *m_collectionRebuilder; 424 RomPathCleaner *m_romPathCleaner; 425 int m_currentMode; 426 bool m_active; 427 bool m_paused; 428 QString m_settingsKey; 429 }; 430 431 #endif 432