├── README.md ├── xextractor.pri ├── LICENSE ├── xextractor.cmake ├── xmodel_extractor.h ├── xextractor.h ├── xmodel_extractor.cpp └── xextractor.cpp /README.md: -------------------------------------------------------------------------------- 1 | # XExtractor 2 | -------------------------------------------------------------------------------- /xextractor.pri: -------------------------------------------------------------------------------- 1 | INCLUDEPATH += $$PWD 2 | DEPENDPATH += $$PWD 3 | 4 | XCONFIG += use_dex 5 | XCONFIG += use_pdf 6 | XCONFIG += use_archive 7 | 8 | HEADERS += \ 9 | $$PWD/xextractor.h \ 10 | $$PWD/xmodel_extractor.h 11 | 12 | SOURCES += \ 13 | $$PWD/xextractor.cpp \ 14 | $$PWD/xmodel_extractor.cpp 15 | 16 | !contains(XCONFIG, xformats) { 17 | XCONFIG += xformats 18 | include($$PWD/../Formats/xformats.pri) 19 | } 20 | 21 | !contains(XCONFIG, xmodel) { 22 | XCONFIG += xmodel 23 | include($$PWD/../Controls/xmodel.pri) 24 | } 25 | 26 | DISTFILES += \ 27 | $$PWD/LICENSE \ 28 | $$PWD/README.md \ 29 | $$PWD/xextractor.cmake 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022-2025 hors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /xextractor.cmake: -------------------------------------------------------------------------------- 1 | include_directories(${CMAKE_CURRENT_LIST_DIR}) 2 | 3 | if (NOT DEFINED XFORMATS_SOURCES) 4 | include(${CMAKE_CURRENT_LIST_DIR}/../Formats/xformats.cmake) 5 | set(XEXTRACTOR_SOURCES ${XEXTRACTOR_SOURCES} ${XFORMATS_SOURCES}) 6 | endif() 7 | if (NOT DEFINED XSTATICUNPACKER_SOURCES) 8 | include(${CMAKE_CURRENT_LIST_DIR}/../XStaticUnpacker/xstaticunpacker.cmake) 9 | set(XEXTRACTOR_SOURCES ${XEXTRACTOR_SOURCES} ${XSTATICUNPACKER_SOURCES}) 10 | endif() 11 | if (NOT DEFINED XOPTIONS_SOURCES) 12 | include(${CMAKE_CURRENT_LIST_DIR}/../XOptions/xoptions.cmake) 13 | set(XEXTRACTOR_SOURCES ${XEXTRACTOR_SOURCES} ${XOPTIONS_SOURCES}) 14 | endif() 15 | if (NOT DEFINED XMODEL_SOURCES) 16 | include(${CMAKE_CURRENT_LIST_DIR}/../Controls/xmodel.cmake) 17 | set(XEXTRACTOR_SOURCES ${XEXTRACTOR_SOURCES} ${XMODEL_SOURCES}) 18 | endif() 19 | 20 | set(XEXTRACTOR_SOURCES 21 | ${XEXTRACTOR_SOURCES} 22 | ${CMAKE_CURRENT_LIST_DIR}/xextractor.cpp 23 | ${CMAKE_CURRENT_LIST_DIR}/xextractor.h 24 | ${CMAKE_CURRENT_LIST_DIR}/xmodel_extractor.cpp 25 | ${CMAKE_CURRENT_LIST_DIR}/xmodel_extractor.h 26 | ) 27 | -------------------------------------------------------------------------------- /xmodel_extractor.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2025 hors 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in 11 | * all copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | */ 21 | #ifndef XMODEL_EXTRACTOR_H 22 | #define XMODEL_EXTRACTOR_H 23 | 24 | #include "xmodel.h" 25 | #include "xextractor.h" 26 | 27 | class XModel_Extractor : public XModel { 28 | Q_OBJECT 29 | 30 | enum COLUMN_GENERIC { 31 | COLUMN_GENERIC_NUMBER, 32 | COLUMN_GENERIC_OFFSET, 33 | COLUMN_GENERIC_ADDRESS, 34 | COLUMN_GENERIC_REGION, 35 | COLUMN_GENERIC_SIZE, 36 | COLUMN_GENERIC_METHOD, 37 | __COLUMN_GENERIC_SIZE 38 | }; 39 | 40 | enum COLUMN_RAW { 41 | COLUMN_RAW_TYPE = __COLUMN_GENERIC_SIZE, 42 | COLUMN_RAW_INFO, 43 | __COLUMN_RAW_SIZE 44 | }; 45 | 46 | enum COLUMN_FORMAT { 47 | COLUMN_FORMAT_TYPE = __COLUMN_GENERIC_SIZE, 48 | COLUMN_FORMAT_INFO, 49 | COLUMN_FORMAT_NAME, 50 | __COLUMN_FORMAT_SIZE 51 | }; 52 | 53 | public: 54 | XModel_Extractor(XExtractor::DATA *pData, QObject *pParent = nullptr); 55 | 56 | virtual QVariant data(const QModelIndex &index, int nRole = Qt::DisplayRole) const; 57 | virtual QVariant headerData(int nSection, Qt::Orientation orientation, int nRole = Qt::DisplayRole) const; 58 | virtual SORT_METHOD getSortMethod(qint32 nColumn); 59 | 60 | private: 61 | XExtractor::DATA *m_pData; 62 | XBinary::MODE m_modeAddress; 63 | XBinary::MODE m_modeOffset; 64 | }; 65 | 66 | #endif // XMODEL_EXTRACTOR_H 67 | -------------------------------------------------------------------------------- /xextractor.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2022-2025 hors 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in 11 | * all copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | */ 21 | #ifndef XEXTRACTOR_H 22 | #define XEXTRACTOR_H 23 | 24 | #include "xformats.h" 25 | #include "xcompresseddevice.h" 26 | #include "xthreadobject.h" 27 | #include 28 | 29 | class XExtractor : public XThreadObject { 30 | Q_OBJECT 31 | 32 | public: 33 | enum EMODE { 34 | EMODE_UNKNOWN = 0, 35 | EMODE_RAW, 36 | EMODE_FORMAT, 37 | EMODE_HEURISTIC 38 | }; 39 | 40 | struct OPTIONS { 41 | XBinary::FT fileType; 42 | // XBinary::MAPMODE mapMode; 43 | QList listFileTypes; 44 | bool bAllTypes; // If true, then all file types will be used for scan 45 | qint32 nLimit; 46 | bool bDeepScan; 47 | EMODE emode; // RAW, FORMAT, HEURISTIC, UNPACK 48 | // bool bHeuristicScan; 49 | bool bAnalyze; 50 | bool bExtract; 51 | bool bMenu_Hex; 52 | QString sOutputDirectory; 53 | bool bShowList; 54 | qint64 nBufferSize; 55 | }; 56 | 57 | struct RECORD { 58 | qint64 nOffset; 59 | qint64 nSize; 60 | XBinary::FT fileType; 61 | XBinary::HANDLE_METHOD handleMethod; 62 | QMap mapProperties; 63 | QString sString; 64 | QString sName; // For unpack mode 65 | QString sExt; 66 | quint32 nCRC; 67 | }; 68 | 69 | struct DATA { 70 | OPTIONS options; 71 | XBinary::_MEMORY_MAP memoryMap; 72 | EMODE emode; 73 | QVector listRecords; 74 | }; 75 | 76 | XExtractor(QObject *pParent = nullptr); 77 | 78 | void setData(QIODevice *pDevice, DATA *pData, XBinary::PDSTRUCT *pPdStruct); 79 | bool processFile(const QString &sFileName, DATA *pData, XBinary::PDSTRUCT *pPdStruct); 80 | 81 | static QList getAvailableFileTypes(EMODE emode); 82 | static XExtractor::OPTIONS getDefaultOptions(); 83 | static QVector scanDevice(QIODevice *pDevice, OPTIONS options, XBinary::PDSTRUCT *pPdStruct); 84 | 85 | static QAbstractItemModel *createModelFromRecords(DATA *pData); 86 | 87 | static QString extractorModeToString(EMODE mode); 88 | static EMODE ftStringToExtractorMode(QString sString); 89 | 90 | static bool isFormatModeAvailable(XBinary::FT fileType); 91 | static bool isUnpackModeAvailable(XBinary::FT fileType); 92 | 93 | private: 94 | void handleSearch(qint32 nGlobalIndex, XBinary *pBinary, DATA *pData, XBinary::FT fileType, const QString &sSignature, qint32 nDelta, XBinary::PDSTRUCT *pPdStruct); 95 | void handleRaw(); 96 | void handleFormat(XBinary::FT fileType); 97 | 98 | public slots: 99 | void process(); 100 | 101 | private: 102 | QIODevice *m_pDevice; 103 | DATA *m_pData; 104 | XBinary::PDSTRUCT *m_pPdStruct; 105 | }; 106 | 107 | #endif // XEXTRACTOR_H 108 | -------------------------------------------------------------------------------- /xmodel_extractor.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2025 hors 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in 11 | * all copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | */ 21 | #include "xmodel_extractor.h" 22 | 23 | XModel_Extractor::XModel_Extractor(XExtractor::DATA *pData, QObject *pParent) : XModel(pParent) 24 | { 25 | m_pData = pData; 26 | 27 | _setRowCount(pData->listRecords.count()); 28 | 29 | if (pData->emode == XExtractor::EMODE_FORMAT) { 30 | _setColumnCount(__COLUMN_FORMAT_SIZE); 31 | } else if (pData->emode == XExtractor::EMODE_RAW) { 32 | _setColumnCount(__COLUMN_RAW_SIZE); 33 | } else { 34 | _setColumnCount(__COLUMN_GENERIC_SIZE); 35 | } 36 | 37 | m_modeAddress = XBinary::getWidthModeFromSize_32_64(pData->memoryMap.nModuleAddress + pData->memoryMap.nImageSize); 38 | m_modeOffset = XBinary::getWidthModeFromSize_32_64(pData->memoryMap.nBinarySize); 39 | 40 | setColumnAlignment(COLUMN_GENERIC_NUMBER, Qt::AlignVCenter | Qt::AlignRight); 41 | setColumnAlignment(COLUMN_GENERIC_OFFSET, Qt::AlignVCenter | Qt::AlignRight); 42 | setColumnAlignment(COLUMN_GENERIC_ADDRESS, Qt::AlignVCenter | Qt::AlignRight); 43 | setColumnAlignment(COLUMN_GENERIC_REGION, Qt::AlignVCenter | Qt::AlignLeft); 44 | setColumnAlignment(COLUMN_GENERIC_SIZE, Qt::AlignVCenter | Qt::AlignRight); 45 | setColumnAlignment(COLUMN_GENERIC_METHOD, Qt::AlignVCenter | Qt::AlignLeft); 46 | 47 | if (pData->emode == XExtractor::EMODE_FORMAT) { 48 | setColumnAlignment(COLUMN_FORMAT_TYPE, Qt::AlignVCenter | Qt::AlignLeft); 49 | setColumnAlignment(COLUMN_FORMAT_INFO, Qt::AlignVCenter | Qt::AlignLeft); 50 | setColumnAlignment(COLUMN_FORMAT_NAME, Qt::AlignVCenter | Qt::AlignLeft); 51 | } else if (pData->emode == XExtractor::EMODE_RAW) { 52 | setColumnAlignment(COLUMN_RAW_TYPE, Qt::AlignVCenter | Qt::AlignLeft); 53 | setColumnAlignment(COLUMN_RAW_INFO, Qt::AlignVCenter | Qt::AlignLeft); 54 | } 55 | 56 | setColumnSymbolSize(COLUMN_GENERIC_NUMBER, QString::number(rowCount()).length()); 57 | setColumnSymbolSize(COLUMN_GENERIC_OFFSET, XBinary::getByteSizeFromWidthMode(m_modeOffset) * 2); 58 | setColumnSymbolSize(COLUMN_GENERIC_ADDRESS, XBinary::getByteSizeFromWidthMode(m_modeAddress) * 2); 59 | setColumnSymbolSize(COLUMN_GENERIC_REGION, 1); 60 | setColumnSymbolSize(COLUMN_GENERIC_SIZE, XBinary::getByteSizeFromWidthMode(m_modeOffset) * 2); 61 | setColumnSymbolSize(COLUMN_GENERIC_METHOD, 10); 62 | 63 | if (pData->emode == XExtractor::EMODE_FORMAT) { 64 | setColumnSymbolSize(COLUMN_FORMAT_TYPE, 10); 65 | setColumnSymbolSize(COLUMN_FORMAT_INFO, 10); 66 | setColumnSymbolSize(COLUMN_FORMAT_NAME, 10); 67 | } else if (pData->emode == XExtractor::EMODE_RAW) { 68 | setColumnSymbolSize(COLUMN_RAW_TYPE, 10); 69 | setColumnSymbolSize(COLUMN_RAW_INFO, 10); 70 | } 71 | 72 | qint32 nNumberOfRegions = pData->memoryMap.listRecords.count(); 73 | qint32 nMaxRegionNameLength = 4; 74 | 75 | for (qint32 i = 0; i < nNumberOfRegions; i++) { 76 | nMaxRegionNameLength = qMax(nMaxRegionNameLength, pData->memoryMap.listRecords.at(i).sName.length()); 77 | nMaxRegionNameLength = qMin(50, nMaxRegionNameLength); 78 | } 79 | 80 | setColumnSymbolSize(COLUMN_GENERIC_REGION, nMaxRegionNameLength); 81 | } 82 | 83 | QVariant XModel_Extractor::data(const QModelIndex &index, int nRole) const 84 | { 85 | QVariant result; 86 | 87 | if (index.isValid()) { 88 | qint32 nRow = index.row(); 89 | 90 | if ((nRow >= 0) && (m_pData->listRecords.count() > nRow)) { 91 | qint32 nColumn = index.column(); 92 | 93 | if (nRole == Qt::DisplayRole) { 94 | if (nColumn == COLUMN_GENERIC_NUMBER) { 95 | result = nRow; 96 | } else if (nColumn == COLUMN_GENERIC_OFFSET) { 97 | result = XBinary::valueToHex(m_modeOffset, m_pData->listRecords.at(nRow).nOffset); 98 | } else if (nColumn == COLUMN_GENERIC_ADDRESS) { 99 | XADDR nAddress = XBinary::offsetToAddress(&(m_pData->memoryMap), m_pData->listRecords.at(nRow).nOffset); 100 | if (nAddress != (XADDR)-1) { 101 | result = XBinary::valueToHex(m_modeAddress, nAddress); 102 | } 103 | } else if (nColumn == COLUMN_GENERIC_REGION) { 104 | result = XBinary::getMemoryRecordByOffset(&(m_pData->memoryMap), m_pData->listRecords.at(nRow).nOffset).sName; 105 | } else if (nColumn == COLUMN_GENERIC_SIZE) { 106 | result = QString::number(m_pData->listRecords.at(nRow).nSize, 16); 107 | } else if (nColumn == COLUMN_GENERIC_METHOD) { 108 | result = XBinary::compressMethodToString((XBinary::COMPRESS_METHOD)( 109 | m_pData->listRecords.at(nRow).mapProperties.value(XBinary::FPART_PROP_COMPRESSMETHOD, XBinary::COMPRESS_METHOD_STORE).toInt())); 110 | } else if (nColumn >= __COLUMN_GENERIC_SIZE) { 111 | if (m_pData->emode == XExtractor::EMODE_FORMAT) { 112 | if (nColumn == COLUMN_FORMAT_TYPE) { 113 | QString sFileType = XBinary::fileTypeIdToString(m_pData->listRecords.at(nRow).fileType); 114 | if (m_pData->listRecords.at(nRow).handleMethod != XBinary::HANDLE_METHOD_UNKNOWN) 115 | sFileType += " / " + XBinary::handleMethodToString(m_pData->listRecords.at(nRow).handleMethod); 116 | result = sFileType; 117 | } else if (nColumn == COLUMN_FORMAT_INFO) { 118 | result = m_pData->listRecords.at(nRow).sString; 119 | } else if (nColumn == COLUMN_FORMAT_NAME) { 120 | result = m_pData->listRecords.at(nRow).sName; 121 | } 122 | } else if (m_pData->emode == XExtractor::EMODE_RAW) { 123 | if (nColumn == COLUMN_RAW_TYPE) { 124 | QString sFileType = XBinary::fileTypeIdToString(m_pData->listRecords.at(nRow).fileType); 125 | if (m_pData->listRecords.at(nRow).handleMethod != XBinary::HANDLE_METHOD_UNKNOWN) 126 | sFileType += " / " + XBinary::handleMethodToString(m_pData->listRecords.at(nRow).handleMethod); 127 | result = sFileType; 128 | } else if (nColumn == COLUMN_RAW_INFO) { 129 | result = m_pData->listRecords.at(nRow).sString; 130 | } 131 | } 132 | } 133 | } else if (nRole == Qt::TextAlignmentRole) { 134 | result = getColumnAlignment(nColumn); 135 | } else if (nRole == Qt::UserRole + USERROLE_ORIGINDEX) { 136 | result = nRow; 137 | } else if (nRole == Qt::UserRole + USERROLE_ADDRESS) { 138 | result = XBinary::offsetToAddress(&(m_pData->memoryMap), m_pData->listRecords.at(nRow).nOffset); 139 | } else if (nRole == Qt::UserRole + USERROLE_OFFSET) { 140 | result = m_pData->listRecords.at(nRow).nOffset; 141 | } else if (nRole == Qt::UserRole + USERROLE_SIZE) { 142 | result = m_pData->listRecords.at(nRow).nSize; 143 | } else if (nRole == Qt::UserRole + USERROLE_STRING1) { 144 | result = m_pData->listRecords.at(nRow).sString; 145 | } else if (nRole == Qt::UserRole + USERROLE_STRING2) { 146 | result = m_pData->listRecords.at(nRow).sExt; 147 | } 148 | } 149 | } 150 | 151 | return result; 152 | } 153 | 154 | QVariant XModel_Extractor::headerData(int nSection, Qt::Orientation orientation, int nRole) const 155 | { 156 | QVariant result; 157 | 158 | if (orientation == Qt::Horizontal) { 159 | if (nRole == Qt::DisplayRole) { 160 | if (nSection == COLUMN_GENERIC_NUMBER) { 161 | result = "#"; 162 | } else if (nSection == COLUMN_GENERIC_OFFSET) { 163 | result = tr("Offset"); 164 | } else if (nSection == COLUMN_GENERIC_ADDRESS) { 165 | result = tr("Address"); 166 | } else if (nSection == COLUMN_GENERIC_REGION) { 167 | result = tr("Region"); 168 | } else if (nSection == COLUMN_GENERIC_SIZE) { 169 | result = tr("Size"); 170 | } else if (nSection == COLUMN_GENERIC_METHOD) { 171 | result = tr("Method"); 172 | } else if (nSection >= __COLUMN_GENERIC_SIZE) { 173 | if (m_pData->emode == XExtractor::EMODE_FORMAT) { 174 | if (nSection == COLUMN_FORMAT_TYPE) { 175 | result = tr("Type"); 176 | } else if (nSection == COLUMN_FORMAT_INFO) { 177 | result = tr("Info"); 178 | } else if (nSection == COLUMN_FORMAT_NAME) { 179 | result = tr("Name"); 180 | } 181 | } else if (m_pData->emode == XExtractor::EMODE_RAW) { 182 | if (nSection == COLUMN_RAW_TYPE) { 183 | result = tr("Type"); 184 | } else if (nSection == COLUMN_RAW_INFO) { 185 | result = tr("Info"); 186 | } 187 | } 188 | } 189 | } else if (nRole == Qt::TextAlignmentRole) { 190 | result = getColumnAlignment(nSection); 191 | } 192 | } 193 | 194 | return result; 195 | } 196 | 197 | XModel::SORT_METHOD XModel_Extractor::getSortMethod(qint32 nColumn) 198 | { 199 | SORT_METHOD result = SORT_METHOD_DEFAULT; 200 | 201 | if ((nColumn == COLUMN_GENERIC_OFFSET) || (nColumn == COLUMN_GENERIC_OFFSET) || (nColumn == COLUMN_GENERIC_SIZE)) { 202 | result = SORT_METHOD_HEX; 203 | } 204 | 205 | return result; 206 | } 207 | -------------------------------------------------------------------------------- /xextractor.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2022-2025 hors 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in 11 | * all copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | */ 21 | #include "xextractor.h" 22 | 23 | XBinary::XCONVERT _TABLE_XExtractor_EMODE[] = { 24 | {XExtractor::EMODE_UNKNOWN, "Unknown", QObject::tr("Unknown")}, 25 | {XExtractor::EMODE_RAW, "Raw", QObject::tr("Raw")}, 26 | {XExtractor::EMODE_FORMAT, "Format", QObject::tr("Format")}, 27 | {XExtractor::EMODE_HEURISTIC, "Heuristic", QObject::tr("Heuristic")}, 28 | }; 29 | 30 | bool compareXExtractor(const XExtractor::RECORD &a, const XExtractor::RECORD &b) 31 | { 32 | return a.nOffset < b.nOffset; 33 | } 34 | 35 | XExtractor::XExtractor(QObject *pParent) : XThreadObject(pParent) 36 | { 37 | m_pDevice = nullptr; 38 | m_pData = nullptr; 39 | m_pPdStruct = nullptr; 40 | } 41 | 42 | void XExtractor::setData(QIODevice *pDevice, DATA *pData, XBinary::PDSTRUCT *pPdStruct) 43 | { 44 | m_pDevice = pDevice; 45 | m_pData = pData; 46 | m_pPdStruct = pPdStruct; 47 | } 48 | 49 | bool XExtractor::processFile(const QString &sFileName, DATA *pData, XBinary::PDSTRUCT *pPdStruct) 50 | { 51 | bool bResult = false; 52 | 53 | QFile file(sFileName); 54 | 55 | if (file.open(QIODevice::ReadOnly)) { 56 | setData(&file, pData, pPdStruct); 57 | process(); 58 | 59 | bResult = true; 60 | 61 | file.close(); 62 | } 63 | 64 | return bResult; 65 | } 66 | 67 | QList XExtractor::getAvailableFileTypes(EMODE emode) 68 | { 69 | QList listResult; 70 | 71 | if ((emode == EMODE_RAW) || (emode == EMODE_FORMAT)) { 72 | listResult.append(XBinary::FT_PE); 73 | listResult.append(XBinary::FT_ELF); 74 | listResult.append(XBinary::FT_MACHOFAT); 75 | listResult.append(XBinary::FT_MACHO); 76 | listResult.append(XBinary::FT_PDF); 77 | listResult.append(XBinary::FT_PNG); 78 | listResult.append(XBinary::FT_JPEG); 79 | listResult.append(XBinary::FT_TIFF); 80 | listResult.append(XBinary::FT_BMP); 81 | listResult.append(XBinary::FT_GIF); 82 | listResult.append(XBinary::FT_ICO); 83 | listResult.append(XBinary::FT_DEX); 84 | listResult.append(XBinary::FT_ZIP); 85 | listResult.append(XBinary::FT_RAR); 86 | listResult.append(XBinary::FT_GZIP); 87 | listResult.append(XBinary::FT_ZLIB); 88 | listResult.append(XBinary::FT_7Z); 89 | listResult.append(XBinary::FT_CAB); 90 | listResult.append(XBinary::FT_MP3); 91 | listResult.append(XBinary::FT_MP4); 92 | listResult.append(XBinary::FT_RIFF); 93 | listResult.append(XBinary::FT_LE); 94 | listResult.append(XBinary::FT_NE); 95 | listResult.append(XBinary::FT_AMIGAHUNK); 96 | listResult.append(XBinary::FT_JAVACLASS); 97 | listResult.append(XBinary::FT_SZDD); 98 | listResult.append(XBinary::FT_BZIP2); 99 | listResult.append(XBinary::FT_LHA); 100 | listResult.append(XBinary::FT_DJVU); 101 | } 102 | 103 | if (emode == EMODE_FORMAT) { 104 | listResult.append(XBinary::FT_BINARY); 105 | } 106 | 107 | return listResult; 108 | } 109 | 110 | XExtractor::OPTIONS XExtractor::getDefaultOptions() 111 | { 112 | XExtractor::OPTIONS result = {}; 113 | 114 | result.listFileTypes.append(XBinary::FT_PE); 115 | result.listFileTypes.append(XBinary::FT_ELF); 116 | result.listFileTypes.append(XBinary::FT_MACHOFAT); 117 | result.listFileTypes.append(XBinary::FT_MACHO); 118 | result.listFileTypes.append(XBinary::FT_ZIP); 119 | result.listFileTypes.append(XBinary::FT_RAR); 120 | result.listFileTypes.append(XBinary::FT_GZIP); 121 | result.listFileTypes.append(XBinary::FT_ZLIB); 122 | result.listFileTypes.append(XBinary::FT_PDF); 123 | result.listFileTypes.append(XBinary::FT_7Z); 124 | result.listFileTypes.append(XBinary::FT_PNG); 125 | result.listFileTypes.append(XBinary::FT_JPEG); 126 | // result.listFileTypes.append(XBinary::FT_TIFF); 127 | result.listFileTypes.append(XBinary::FT_BMP); 128 | result.listFileTypes.append(XBinary::FT_GIF); 129 | result.listFileTypes.append(XBinary::FT_CAB); 130 | // result.listFileTypes.append(XBinary::FT_ICO); 131 | result.listFileTypes.append(XBinary::FT_DEX); 132 | result.listFileTypes.append(XBinary::FT_MP3); 133 | result.listFileTypes.append(XBinary::FT_MP4); 134 | result.listFileTypes.append(XBinary::FT_RIFF); 135 | // result.listFileTypes.append(XBinary::FT_LE); 136 | // result.listFileTypes.append(XBinary::FT_NE); 137 | // result.listFileTypes.append(XBinary::FT_AMIGAHUNK); 138 | // result.listFileTypes.append(XBinary::FT_JAVACLASS); 139 | // result.listFileTypes.append(XBinary::FT_SIGNATURE); 140 | // result.listFileTypes.append(XBinary::FT_OTHER); 141 | 142 | result.bDeepScan = true; 143 | result.bAnalyze = true; 144 | // result.bHeuristicScan = true; 145 | 146 | result.nBufferSize = 2 * 1024 * 1024; 147 | 148 | return result; 149 | } 150 | 151 | QAbstractItemModel *XExtractor::createModelFromRecords(DATA *pData) 152 | { 153 | return 0; 154 | } 155 | 156 | QString XExtractor::extractorModeToString(EMODE mode) 157 | { 158 | return XBinary::XCONVERT_idToTransString(mode, _TABLE_XExtractor_EMODE, sizeof(_TABLE_XExtractor_EMODE) / sizeof(XBinary::XCONVERT)); 159 | } 160 | 161 | bool XExtractor::isFormatModeAvailable(XBinary::FT fileType) 162 | { 163 | bool bResult = false; 164 | 165 | if ((fileType == XBinary::FT_ZIP) || (fileType == XBinary::FT_JAR) || (fileType == XBinary::FT_APK) || (fileType == XBinary::FT_APKS) || 166 | (fileType == XBinary::FT_PDF) || (fileType == XBinary::FT_TAR) || (fileType == XBinary::FT_PE32) || (fileType == XBinary::FT_PE64)) { 167 | bResult = true; 168 | } 169 | 170 | return bResult; 171 | } 172 | 173 | bool XExtractor::isUnpackModeAvailable(XBinary::FT fileType) 174 | { 175 | bool bResult = false; 176 | 177 | if ((fileType == XBinary::FT_ZIP) || (fileType == XBinary::FT_JAR) || (fileType == XBinary::FT_APK) || (fileType == XBinary::FT_APKS) || 178 | (fileType == XBinary::FT_PDF) || (fileType == XBinary::FT_TAR)) { 179 | bResult = true; 180 | } 181 | 182 | return bResult; 183 | } 184 | 185 | XExtractor::EMODE XExtractor::ftStringToExtractorMode(QString sString) 186 | { 187 | return (XExtractor::EMODE)XBinary::XCONVERT_ftStringToId(sString, _TABLE_XExtractor_EMODE, sizeof(_TABLE_XExtractor_EMODE) / sizeof(XBinary::XCONVERT)); 188 | } 189 | 190 | QVector XExtractor::scanDevice(QIODevice *pDevice, OPTIONS options, XBinary::PDSTRUCT *pPdStruct) 191 | { 192 | DATA _data = {}; 193 | _data.options = options; 194 | 195 | XExtractor _extractor; 196 | _extractor.setData(pDevice, &_data, pPdStruct); 197 | _extractor.process(); 198 | 199 | return _data.listRecords; 200 | } 201 | 202 | void XExtractor::handleSearch(qint32 nGlobalIndex, XBinary *pBinary, DATA *pData, XBinary::FT fileType, const QString &sSignature, qint32 nDelta, 203 | XBinary::PDSTRUCT *pPdStruct) 204 | { 205 | if (m_pData->options.listFileTypes.contains(fileType) || m_pData->options.bAllTypes) { 206 | XBinary::setPdStructStatus(pPdStruct, nGlobalIndex, XBinary::fileTypeIdToString(fileType)); 207 | 208 | bool bNextByte = true; 209 | // mb TODO all archives! 210 | if (fileType == XBinary::FT_LHA) { 211 | bNextByte = false; 212 | } 213 | 214 | qint64 nOffset = 0; 215 | 216 | qint32 _nFreeIndex = XBinary::getFreeIndex(pPdStruct); 217 | XBinary::setPdStructInit(pPdStruct, _nFreeIndex, pBinary->getSize()); 218 | 219 | qint32 nFound = 0; 220 | 221 | while (XBinary::isPdStructNotCanceled(pPdStruct)) { 222 | nOffset = pBinary->find_signature(&(pData->memoryMap), nOffset, -1, sSignature, nullptr, pPdStruct); 223 | 224 | if (nOffset != -1) { 225 | qint64 _nOffset = nOffset + nDelta; 226 | 227 | if (fileType == XBinary::FT_SIGNATURE) { 228 | // TODO 229 | /* 230 | CRC8 0x07 231 | CRC8_SAE_J1850 0x1D 232 | CRC8_SAE_J1850_ZERO 0x1D 233 | CRC8_8H2F 0x2F 234 | CRC8_CDMA2000 0x9B 235 | CRC8_DARC 0x39 236 | CRC8_DVB_S2 0xD5 237 | CRC8_EBU 0x1D 238 | CRC8_ICODE 0x1D 239 | CRC8_ITU 0x07 240 | CRC8_MAXIM 0x31 241 | CRC8_ROHC 0x07 242 | CRC8_WCDMA 0x9B 243 | 244 | CRC16_CCIT_ZERO 0x1021 245 | CRC16_ARC 0x8005 246 | CRC16_AUG_CCITT 0x1021 247 | CRC16_BUYPASS 0x8005 248 | CRC16_CCITT_FALSE 0x1021 249 | CRC16_CDMA2000 0xC867 250 | CRC16_DDS_110 0x8005 251 | CRC16_DECT_R 0x0589 252 | CRC16_DECT_X 0x0589 253 | CRC16_DNP 0x3D65 254 | CRC16_EN_13757 0x3D65 255 | CRC16_GENIBUS 0x1021 256 | CRC16_MAXIM 0x8005 257 | CRC16_MCRF4XX 0x1021 258 | CRC16_RIELLO 0x1021 259 | CRC16_T10_DIF 0x8BB7 260 | CRC16_TELEDISK 0xA097 261 | CRC16_TMS37157 0x1021 262 | CRC16_USB 0x8005 263 | CRC16_A 0x1021 264 | CRC16_KERMIT 0x1021 265 | CRC16_MODBUS 0x8005 266 | CRC16_X_25 0x1021 267 | CRC16_XMODEM 0x1021 268 | 269 | CRC32 0x04C11DB7 270 | CRC32_BZIP2 0x04C11DB7 271 | CRC32_C 0x1EDC6F41 272 | CRC32_D 0xA833982B 273 | CRC32_MPEG2 0x04C11DB7 274 | CRC32_POSIX 0x04C11DB7 275 | CRC32_Q 0x814141AB 276 | CRC32_JAMCRC 0x04C11DB7 277 | CRC32_XFER 0x000000AF 278 | 279 | CRC64_ECMA_182 0x42F0E1EBA9EA3693 280 | CRC64_GO_ISO 0x000000000000001B 281 | CRC64_WE 0x42F0E1EBA9EA3693 282 | CRC64_XZ 0x42F0E1EBA9EA3693 283 | 284 | */ 285 | 286 | nOffset += 1; 287 | } else { 288 | qint64 nResSize = 0; 289 | XBinary::FT _fileType = XBinary::FT_UNKNOWN; 290 | qint64 nFileFormatSize = 0; 291 | 292 | { 293 | SubDevice subdevice(m_pDevice, _nOffset, -1); 294 | 295 | if (subdevice.open(QIODevice::ReadOnly)) { 296 | if (XFormats::isValid(fileType, &subdevice, false, -1, pPdStruct)) { 297 | QSet stFT = XFormats::getFileTypes(&subdevice, true, pPdStruct); 298 | _fileType = XBinary::_getPrefFileType(&stFT); 299 | nFileFormatSize = XFormats::getFileFormatSize(_fileType, &subdevice, false, -1, pPdStruct); 300 | } 301 | 302 | subdevice.close(); 303 | } 304 | } 305 | 306 | if (nFileFormatSize) { 307 | SubDevice subdevice(m_pDevice, _nOffset, nFileFormatSize); 308 | 309 | if (subdevice.open(QIODevice::ReadOnly)) { 310 | XBinary::FILEFORMATINFO formatInfo = XFormats::getFileFormatInfo(_fileType, &subdevice, false, -1, pPdStruct); 311 | 312 | if (formatInfo.bIsValid) { 313 | RECORD record = {}; 314 | 315 | record.mapProperties.insert(XBinary::FPART_PROP_COMPRESSMETHOD, XArchive::COMPRESS_METHOD_STORE); 316 | record.nOffset = _nOffset; 317 | record.nSize = nFileFormatSize; 318 | 319 | if (record.nSize) { 320 | record.sString = XBinary::getFileFormatString(&formatInfo); 321 | record.sExt = formatInfo.sExt; 322 | record.fileType = formatInfo.fileType; 323 | 324 | // // Fix if more than the device size 325 | // if ((record.nOffset + record.nSize) > m_pDevice->size()) { 326 | // record.nSize = (m_pDevice->size() - record.nOffset); 327 | // } 328 | 329 | record.nCRC = XBinary::_getCRC32(&subdevice, pPdStruct); 330 | 331 | m_pData->listRecords.append(record); 332 | 333 | nFound++; 334 | } 335 | 336 | nResSize = record.nSize; 337 | } 338 | 339 | subdevice.close(); 340 | } 341 | } 342 | 343 | if (nResSize == 0) { 344 | nResSize = 1; 345 | } 346 | 347 | // if ((m_pData->options.bDeepScan) && (fileType != XBinary::FT_ZIP)) { 348 | // nResult = 1; 349 | // } 350 | 351 | if (m_pData->options.bDeepScan) { 352 | if (bNextByte) { 353 | nResSize = 1; 354 | } 355 | } 356 | 357 | nOffset += nResSize; 358 | } 359 | 360 | } else { 361 | break; 362 | } 363 | 364 | if ((m_pData->options.nLimit > 0) && (nFound >= m_pData->options.nLimit)) { 365 | break; 366 | } 367 | 368 | XBinary::setPdStructCurrent(pPdStruct, _nFreeIndex, nOffset); 369 | } 370 | 371 | XBinary::setPdStructFinished(pPdStruct, _nFreeIndex); 372 | XBinary::setPdStructCurrentIncrement(pPdStruct, nGlobalIndex); 373 | } 374 | } 375 | 376 | void XExtractor::handleRaw() 377 | { 378 | m_pData->emode = XExtractor::EMODE_RAW; 379 | m_pData->listRecords.clear(); 380 | 381 | qint32 nSearchCount = 0; 382 | 383 | if (m_pData->options.bAllTypes) { 384 | nSearchCount = getAvailableFileTypes(XExtractor::EMODE_RAW).count(); 385 | } else { 386 | nSearchCount = m_pData->options.listFileTypes.count(); 387 | } 388 | 389 | if (m_pData->options.listFileTypes.contains(XBinary::FT_ICO) || (m_pData->options.bAllTypes)) { 390 | nSearchCount++; 391 | } 392 | 393 | if (m_pData->options.listFileTypes.contains(XBinary::FT_MACHO) || (m_pData->options.bAllTypes)) { 394 | nSearchCount += 3; 395 | } 396 | 397 | if (m_pData->options.listFileTypes.contains(XBinary::FT_MACHOFAT) || (m_pData->options.bAllTypes)) { 398 | nSearchCount++; 399 | } 400 | 401 | if (m_pData->options.listFileTypes.contains(XBinary::FT_TIFF) || (m_pData->options.bAllTypes)) { 402 | nSearchCount++; 403 | } 404 | 405 | // if (m_pData->options.listFileTypes.contains(XBinary::FT_RIFF)) { 406 | // nSearchCount += 2; 407 | // } 408 | 409 | if (m_pData->options.listFileTypes.contains(XBinary::FT_AMIGAHUNK) || (m_pData->options.bAllTypes)) { 410 | nSearchCount++; 411 | } 412 | 413 | if (m_pData->options.listFileTypes.contains(XBinary::FT_DJVU) || (m_pData->options.bAllTypes)) { 414 | nSearchCount++; 415 | } 416 | 417 | if (m_pData->options.listFileTypes.contains(XBinary::FT_LHA) || (m_pData->options.bAllTypes)) { 418 | nSearchCount += 2; 419 | } 420 | 421 | if (m_pData->options.listFileTypes.contains(XBinary::FT_BZIP2) || (m_pData->options.bAllTypes)) { 422 | nSearchCount++; 423 | } 424 | 425 | qint32 nGlobalIndex = XBinary::getFreeIndex(m_pPdStruct); 426 | XBinary::setPdStructInit(m_pPdStruct, nGlobalIndex, nSearchCount); 427 | 428 | // TODO signatures 429 | XBinary binary(m_pDevice); 430 | 431 | connect(&binary, SIGNAL(errorMessage(QString)), this, SIGNAL(errorMessage(QString))); 432 | 433 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_PE, "'MZ'", 0, m_pPdStruct); 434 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_ELF, "7F'ELF'", 0, m_pPdStruct); 435 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_7Z, "'7z'BCAF271C", 0, m_pPdStruct); 436 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_ZIP, "'PK'0304", 0, m_pPdStruct); 437 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_RAR, "'Rar!'1A07", 0, m_pPdStruct); 438 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_GZIP, "1F8B08", 0, m_pPdStruct); 439 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_ZLIB, "785E", 0, m_pPdStruct); 440 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_ZLIB, "789C", 0, m_pPdStruct); 441 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_ZLIB, "78DA", 0, m_pPdStruct); 442 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_DEX, "'dex\n'", 0, m_pPdStruct); 443 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_PDF, "'%PDF'", 0, m_pPdStruct); 444 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_PNG, "89'PNG\r\n'1A0A", 0, m_pPdStruct); 445 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_JPEG, "FFD8FF", 0, m_pPdStruct); 446 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_CAB, "'MSCF'", 0, m_pPdStruct); 447 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_ICO, "00000100", 0, m_pPdStruct); 448 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_CUR, "00000200", 0, m_pPdStruct); // CUR 449 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_MACHO, "FEEDFACE", 0, m_pPdStruct); 450 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_MACHO, "CEFAEDFE", 0, m_pPdStruct); 451 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_MACHO, "FEEDFACF", 0, m_pPdStruct); 452 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_MACHO, "CFFAEDFE", 0, m_pPdStruct); 453 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_MACHOFAT, "CAFEBABE", 0, m_pPdStruct); 454 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_MACHOFAT, "BEBAFECA", 0, m_pPdStruct); 455 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_BMP, "'BM'", 0, m_pPdStruct); 456 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_GIF, "'GIF8'", 0, m_pPdStruct); 457 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_TIFF, "'MM'002A", 0, m_pPdStruct); 458 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_TIFF, "'II'2A00", 0, m_pPdStruct); 459 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_MP3, "'ID3'", 0, m_pPdStruct); 460 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_MP4, "'ftyp'", -4, m_pPdStruct); // 000000..'ftyp' 461 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_RIFF, "'RIFF'", 0, m_pPdStruct); 462 | // handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_RIFF, "'RIFX'", 0, m_pPdStruct); 463 | // handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_RIFF, "'AIFF'", 0, m_pPdStruct); 464 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_NE, "'MZ'", 0, m_pPdStruct); 465 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_LE, "'MZ'", 0, m_pPdStruct); 466 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_AMIGAHUNK, "000003F3", 0, m_pPdStruct); 467 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_AMIGAHUNK, "000003E7", 0, m_pPdStruct); 468 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_JAVACLASS, "CAFEBABE", 0, m_pPdStruct); 469 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_DJVU, "'AT&TFORM'", 0, m_pPdStruct); 470 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_DJVU, "'SDJVFORM'", 0, m_pPdStruct); 471 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_SZDD, "'SZDD'88F027'3A'", 0, m_pPdStruct); 472 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_LHA, "'-lh'..2d'", -2, m_pPdStruct); // "....'-lh'..2d" 473 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_LHA, "'-lz'..2d'", -2, m_pPdStruct); 474 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_LHA, "'-pm'..2d'", -2, m_pPdStruct); 475 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_BZIP2, "314159265359", -4, m_pPdStruct); 476 | handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_BZIP2, "17724538509000000000", -4, m_pPdStruct); // Empty 477 | 478 | // TODO LE/BE 479 | // handleSearch(nGlobalIndex, &binary, m_pData, XBinary::FT_SIGNATURE, "00000000", -4, 0, "CRC32", "Test"); 480 | // TODO more 481 | 482 | std::sort(m_pData->listRecords.begin(), m_pData->listRecords.end(), compareXExtractor); 483 | 484 | XBinary::setPdStructFinished(m_pPdStruct, nGlobalIndex); 485 | } 486 | 487 | void XExtractor::handleFormat(XBinary::FT fileType) 488 | { 489 | m_pData->emode = EMODE_FORMAT; 490 | m_pData->listRecords.clear(); 491 | 492 | QList listParts; 493 | 494 | if ((fileType == XBinary::FT_ZIP) || (fileType == XBinary::FT_JAR) || (fileType == XBinary::FT_APK) || (fileType == XBinary::FT_APKS) || 495 | (fileType == XBinary::FT_PDF) || (fileType == XBinary::FT_TAR)) { 496 | listParts = XFormats::getFileParts(fileType, m_pDevice, XBinary::FILEPART_STREAM, -1, false, -1, m_pPdStruct); 497 | } else if ((fileType == XBinary::FT_PE32) || (fileType == XBinary::FT_PE64)) { 498 | listParts = XFormats::getFileParts(fileType, m_pDevice, XBinary::FILEPART_RESOURCE, -1, false, -1, m_pPdStruct); 499 | } 500 | 501 | qint32 nNumberOfParts = listParts.count(); 502 | 503 | if (nNumberOfParts > 0) { 504 | qint32 nGlobalIndex = XBinary::getFreeIndex(m_pPdStruct); 505 | XBinary::setPdStructInit(m_pPdStruct, nGlobalIndex, nNumberOfParts); 506 | 507 | for (qint32 i = 0; (i < nNumberOfParts) && XBinary::isPdStructNotCanceled(m_pPdStruct); i++) { 508 | XBinary::FPART fpart = listParts.at(i); 509 | 510 | QString sPrefName = fpart.mapProperties.value(XBinary::FPART_PROP_ORIGINALNAME).toString(); 511 | 512 | if (sPrefName == "") { 513 | sPrefName = fpart.sName; 514 | } 515 | 516 | XBinary::setPdStructStatus(m_pPdStruct, nGlobalIndex, sPrefName); 517 | 518 | bool bAdd = false; 519 | 520 | if (fpart.nFileSize > 0) { 521 | RECORD record = {}; 522 | record.nOffset = fpart.nFileOffset; 523 | record.nSize = fpart.nFileSize; 524 | record.mapProperties = fpart.mapProperties; 525 | record.sName = sPrefName; 526 | 527 | { 528 | QSet stFileTypes; 529 | XBinary::FT fileTypePref = (XBinary::FT)(fpart.mapProperties.value(XBinary::FPART_PROP_FILETYPE, XBinary::FT_UNKNOWN).toUInt()); 530 | XBinary::HANDLE_METHOD handleMethod = 531 | (XBinary::HANDLE_METHOD)(fpart.mapProperties.value(XBinary::FPART_PROP_HANDLEMETHOD, XBinary::HANDLE_METHOD_UNKNOWN).toUInt()); 532 | 533 | if (handleMethod != XBinary::HANDLE_METHOD_UNKNOWN) { 534 | stFileTypes.insert(fileTypePref); 535 | 536 | record.sExt = fpart.mapProperties.value(XBinary::FPART_PROP_EXT, QString()).toString(); 537 | record.fileType = fileTypePref; 538 | record.handleMethod = handleMethod; 539 | record.sString = fpart.mapProperties.value(XBinary::FPART_PROP_INFO, false).toString(); 540 | } else { 541 | XCompressedDevice compressedDevice; 542 | compressedDevice.setData(m_pDevice, fpart, m_pPdStruct); 543 | 544 | if (compressedDevice.open(QIODevice::ReadOnly)) { 545 | stFileTypes = XFormats::getFileTypes(&compressedDevice, true, m_pPdStruct); 546 | fileTypePref = XBinary::_getPrefFileType(&stFileTypes); 547 | 548 | XBinary::FILEFORMATINFO formatInfo = XFormats::getFileFormatInfo(fileTypePref, &compressedDevice, false, -1, m_pPdStruct); 549 | 550 | record.sExt = formatInfo.sExt; 551 | record.fileType = formatInfo.fileType; 552 | record.sString = XBinary::getFileFormatString(&formatInfo); 553 | record.nCRC = XBinary::_getCRC32(&compressedDevice, m_pPdStruct); 554 | 555 | if ((fileType == XBinary::FT_APK) || (fileType == XBinary::FT_APKS)) { 556 | if ((record.fileType == XBinary::FT_ANDROIDASRC) || (record.fileType == XBinary::FT_ANDROIDXML)) { 557 | record.fileType = XBinary::FT_XML; 558 | record.handleMethod = XBinary::HANDLE_METHOD_ANDROID_XML; 559 | } 560 | } 561 | 562 | compressedDevice.close(); 563 | } 564 | } 565 | 566 | if (m_pData->options.bAllTypes) { 567 | bAdd = true; 568 | } else { 569 | qint32 nNumberOfFileTypes = m_pData->options.listFileTypes.count(); 570 | 571 | for (qint32 j = 0; j < nNumberOfFileTypes; j++) { 572 | XBinary::FT _fileType = m_pData->options.listFileTypes.at(j); 573 | 574 | if (stFileTypes.contains(_fileType)) { 575 | bAdd = true; 576 | break; 577 | } 578 | } 579 | } 580 | } 581 | 582 | if (bAdd) { 583 | // Fix if more than the device size 584 | if ((record.nOffset + record.nSize) > m_pDevice->size()) { 585 | record.nSize = (m_pDevice->size() - record.nOffset); 586 | } 587 | 588 | m_pData->listRecords.append(record); 589 | } 590 | } 591 | 592 | XBinary::setPdStructCurrentIncrement(m_pPdStruct, nGlobalIndex); 593 | } 594 | 595 | XBinary::setPdStructFinished(m_pPdStruct, nGlobalIndex); 596 | } 597 | } 598 | 599 | void XExtractor::process() 600 | { 601 | qint32 _nFreeIndex = XBinary::getFreeIndex(m_pPdStruct); 602 | XBinary::setPdStructInit(m_pPdStruct, _nFreeIndex, 1); 603 | 604 | bool bInvalidMode = false; 605 | 606 | XBinary::FT fileType = m_pData->options.fileType; 607 | 608 | if (fileType == XBinary::FT_UNKNOWN) { 609 | QSet stFileTypes = XFormats::getFileTypes(m_pDevice, true); 610 | fileType = XBinary::_getPrefFileType(&stFileTypes); 611 | } 612 | 613 | if (m_pData->options.bAnalyze) { 614 | if (m_pData->options.emode == EMODE_HEURISTIC) { 615 | if (isFormatModeAvailable(fileType)) { 616 | handleFormat(fileType); 617 | } else { 618 | handleRaw(); 619 | } 620 | } else if (m_pData->options.emode == EMODE_FORMAT) { 621 | if (isFormatModeAvailable(fileType)) { 622 | handleFormat(fileType); 623 | } else { 624 | bInvalidMode = true; 625 | } 626 | } else if (m_pData->options.emode == EMODE_RAW) { 627 | handleRaw(); 628 | } 629 | } 630 | 631 | if (bInvalidMode) { 632 | #ifdef QT_DEBUG 633 | qDebug() << "Invalid mode" << XBinary::fileTypeIdToString(fileType) << m_pData->options.emode; 634 | #endif 635 | emit errorMessage(tr("Mode is not available for this file type")); 636 | } 637 | 638 | if (m_pData->options.bExtract) { 639 | if ((m_pData->emode == EMODE_FORMAT) || (m_pData->emode == EMODE_RAW)) { 640 | QList listArchiveRecords; 641 | 642 | qint32 nFreeIndex = XBinary::getFreeIndex(m_pPdStruct); 643 | qint32 nNumberOfRecords = m_pData->listRecords.count(); 644 | XBinary::setPdStructInit(m_pPdStruct, nFreeIndex, nNumberOfRecords); 645 | 646 | for (qint32 i = 0; (i < nNumberOfRecords) && XBinary::isPdStructNotCanceled(m_pPdStruct); i++) { 647 | QString sName = XBinary::convertFileNameSymbols(m_pData->listRecords.at(i).sName); 648 | QString sExt = QFileInfo(sName).completeSuffix(); 649 | 650 | if (sExt == "") { 651 | sExt = m_pData->listRecords.at(i).sExt; 652 | } 653 | 654 | if (sName != "") { 655 | sName += "_"; 656 | } 657 | sName += XBinary::valueToHex(m_pData->listRecords.at(i).nCRC); 658 | 659 | if (sExt != "") { 660 | sName += "."; 661 | sName += sExt; 662 | } 663 | 664 | sName = XBinary::fileTypeIdToFtString(m_pData->listRecords.at(i).fileType) + QDir::separator() + sName; 665 | 666 | XBinary::ARCHIVERECORD archiveRecord = {}; 667 | archiveRecord.mapProperties = m_pData->listRecords.at(i).mapProperties; 668 | archiveRecord.nStreamOffset = m_pData->listRecords.at(i).nOffset; 669 | archiveRecord.nStreamSize = m_pData->listRecords.at(i).nSize; 670 | archiveRecord.mapProperties.insert(XBinary::FPART_PROP_ORIGINALNAME, m_pData->listRecords.at(i).sString); 671 | // part.sExt = m_pData->listRecords.at(i).sExt; 672 | // part.fileType = m_pData->listRecords.at(i).fileType; 673 | 674 | listArchiveRecords.append(archiveRecord); 675 | } 676 | 677 | if (listArchiveRecords.count()) { 678 | XFormats xformats; 679 | _connect(&xformats); 680 | 681 | xformats.extractArchiveRecordsToFolder(&listArchiveRecords, m_pDevice, m_pData->options.sOutputDirectory, m_pPdStruct); 682 | } 683 | 684 | XBinary::setPdStructFinished(m_pPdStruct, nFreeIndex); 685 | } 686 | } 687 | 688 | XBinary::setPdStructFinished(m_pPdStruct, _nFreeIndex); 689 | } 690 | --------------------------------------------------------------------------------