├── README.md ├── xdex.pri ├── xdex.cmake ├── LICENSE ├── xandroidbinary.h ├── xandroidbinary_def.h ├── xdex_def.h ├── xdex.h ├── xandroidbinary.cpp └── xdex.cpp /README.md: -------------------------------------------------------------------------------- 1 | # XDEX 2 | 3 | Programs for Android are commonly written in Java and compiled to bytecode for the Java virtual machine, 4 | which is then translated to **Dalvik bytecode** and stored in .dex (**Dalvik EXecutable**) 5 | and .odex (**Optimized Dalvik EXecutable**) files; 6 | related terms odex and de-odex are associated with respective bytecode conversions. 7 | The compact **Dalvik Executable** format is designed for systems that are constrained 8 | in terms of memory and processor speed. 9 | -------------------------------------------------------------------------------- /xdex.pri: -------------------------------------------------------------------------------- 1 | INCLUDEPATH += $$PWD 2 | DEPENDPATH += $$PWD 3 | 4 | HEADERS += \ 5 | $$PWD/xandroidbinary.h \ 6 | $$PWD/xandroidbinary_def.h \ 7 | $$PWD/xdex.h \ 8 | $$PWD/xdex_def.h 9 | 10 | SOURCES += \ 11 | $$PWD/xandroidbinary.cpp \ 12 | $$PWD/xdex.cpp 13 | 14 | !contains(XCONFIG, xbinary) { 15 | XCONFIG += xbinary 16 | include($$PWD/../Formats/xbinary.pri) 17 | } 18 | 19 | DISTFILES += \ 20 | $$PWD/LICENSE \ 21 | $$PWD/README.md \ 22 | $$PWD/xdex.cmake 23 | -------------------------------------------------------------------------------- /xdex.cmake: -------------------------------------------------------------------------------- 1 | include_directories(${CMAKE_CURRENT_LIST_DIR}) 2 | 3 | if (NOT DEFINED XBINARY_SOURCES) 4 | include(${CMAKE_CURRENT_LIST_DIR}/../Formats/xbinary.cmake) 5 | set(XDEX_SOURCES ${XDEX_SOURCES} ${XBINARY_SOURCES}) 6 | endif() 7 | 8 | set(XDEX_SOURCES 9 | ${XDEX_SOURCES} 10 | ${CMAKE_CURRENT_LIST_DIR}/xandroidbinary.cpp 11 | ${CMAKE_CURRENT_LIST_DIR}/xandroidbinary.h 12 | ${CMAKE_CURRENT_LIST_DIR}/xdex.cpp 13 | ${CMAKE_CURRENT_LIST_DIR}/xdex.h 14 | ${CMAKE_CURRENT_LIST_DIR}/xdex_def.h 15 | ) 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-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 | -------------------------------------------------------------------------------- /xandroidbinary.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2019-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 XANDROIDBINARY_H 22 | #define XANDROIDBINARY_H 23 | 24 | #include 25 | #include 26 | 27 | #include "xandroidbinary_def.h" 28 | #include "xbinary.h" 29 | 30 | class XAndroidBinary : public XBinary { 31 | Q_OBJECT 32 | 33 | public: 34 | struct RECORD { 35 | qint64 nOffset; 36 | XANDROIDBINARY_DEF::HEADER header; 37 | QList listChildren; 38 | }; 39 | 40 | XAndroidBinary(QIODevice *pDevice); 41 | virtual ~XAndroidBinary(); 42 | 43 | virtual bool isValid(PDSTRUCT *pPdStruct = nullptr) override; 44 | virtual ENDIAN getEndian() override; 45 | virtual QString getVersion() override; 46 | XANDROIDBINARY_DEF::HEADER readHeader(qint64 nOffset); 47 | XANDROIDBINARY_DEF::HEADER_STRING_POOL readHeaderStringPool(qint64 nOffset); 48 | XANDROIDBINARY_DEF::HEADER_NAMESPACE readHeaderNamespace(qint64 nOffset); 49 | XANDROIDBINARY_DEF::HEADER_XML_START readHeaderXmlStart(qint64 nOffset); 50 | XANDROIDBINARY_DEF::HEADER_XML_ATTRIBUTE readHeaderXmlAttribute(qint64 nOffset); 51 | XANDROIDBINARY_DEF::HEADER_XML_END readHeaderXmlEnd(qint64 nOffset); 52 | QList getHeaders(PDSTRUCT *pPdStruct); 53 | RECORD getRecord(qint64 nOffset, PDSTRUCT *pPdStruct); 54 | QString recordToString(RECORD *pRecord, PDSTRUCT *pPdStruct); 55 | static QString getDecoded(QIODevice *pDevice, PDSTRUCT *pPdStruct); 56 | static QString getDecoded(const QString &sFileName, PDSTRUCT *pPdStruct); 57 | static QString getDecoded(QByteArray *pbaData, PDSTRUCT *pPdStruct); 58 | virtual FT getFileType() override; 59 | virtual QString getFileFormatExt() override; 60 | virtual QString getMIMEString() override; 61 | }; 62 | 63 | #endif // XANDROIDBINARY_H 64 | -------------------------------------------------------------------------------- /xandroidbinary_def.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2019-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 XANDROIDBINARY_DEF_H 22 | #define XANDROIDBINARY_DEF_H 23 | 24 | #include 25 | 26 | namespace XANDROIDBINARY_DEF { 27 | struct HEADER { 28 | quint16 type; 29 | quint16 header_size; 30 | quint32 data_size; 31 | }; 32 | 33 | struct HEADER_STRING_POOL { 34 | HEADER header; 35 | quint32 stringCount; 36 | quint32 styleCount; 37 | quint32 flags; 38 | quint32 stringsStart; 39 | quint32 stylesStart; 40 | }; 41 | 42 | struct HEADER_NAMESPACE { 43 | HEADER header; 44 | quint32 lineNumber; 45 | quint32 comment; 46 | quint32 prefix; 47 | quint32 uri; 48 | }; 49 | 50 | struct HEADER_XML_ATTRIBUTE { 51 | quint32 ns; 52 | quint32 name; 53 | quint32 rawValue; 54 | quint16 size; 55 | quint8 reserved; // 0 56 | quint8 dataType; 57 | quint32 data; 58 | }; 59 | 60 | struct HEADER_XML_START { 61 | HEADER header; 62 | quint32 lineNumber; 63 | quint32 comment; 64 | quint32 ns; 65 | quint32 name; 66 | quint16 attributeStart; 67 | quint16 attributeSize; 68 | quint16 attributeCount; 69 | quint16 idIndex; 70 | quint16 classIndex; 71 | quint16 styleIndex; 72 | }; 73 | 74 | struct HEADER_XML_END { 75 | HEADER header; 76 | quint32 lineNumber; 77 | quint32 comment; 78 | quint32 ns; 79 | quint32 name; 80 | }; 81 | 82 | enum { 83 | RES_NULL_TYPE = 0x0000, 84 | RES_STRING_POOL_TYPE = 0x0001, 85 | RES_TABLE_TYPE = 0x0002, 86 | RES_XML_TYPE = 0x0003, 87 | // Chunk types in RES_XML_TYPE 88 | RES_XML_FIRST_CHUNK_TYPE = 0x0100, 89 | RES_XML_START_NAMESPACE_TYPE = 0x0100, 90 | RES_XML_END_NAMESPACE_TYPE = 0x0101, 91 | RES_XML_START_ELEMENT_TYPE = 0x0102, 92 | RES_XML_END_ELEMENT_TYPE = 0x0103, 93 | RES_XML_CDATA_TYPE = 0x0104, 94 | RES_XML_LAST_CHUNK_TYPE = 0x017F, 95 | // This contains a uint32_t array mapping strings in the string 96 | // pool back to resource identifiers. It is optional. 97 | RES_XML_RESOURCE_MAP_TYPE = 0x0180, 98 | // Chunk types in RES_TABLE_TYPE 99 | RES_TABLE_PACKAGE_TYPE = 0x0200, 100 | RES_TABLE_TYPE_TYPE = 0x0201, 101 | RES_TABLE_TYPE_SPEC_TYPE = 0x0202 102 | }; 103 | } // namespace XANDROIDBINARY_DEF 104 | 105 | #endif // XANDROIDBINARY_DEF_H 106 | -------------------------------------------------------------------------------- /xdex_def.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017-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 XDEX_DEF_H 22 | #define XDEX_DEF_H 23 | 24 | #include 25 | 26 | namespace XDEX_DEF { 27 | struct HEADER { 28 | quint32 magic; // always LE 29 | quint32 version; // always LE 30 | quint32 checksum; 31 | quint8 signature[20]; 32 | quint32 file_size; 33 | quint32 header_size; 34 | quint32 endian_tag; // always LE 35 | quint32 link_size; 36 | quint32 link_off; 37 | quint32 map_off; 38 | quint32 string_ids_size; 39 | quint32 string_ids_off; 40 | quint32 type_ids_size; 41 | quint32 type_ids_off; 42 | quint32 proto_ids_size; 43 | quint32 proto_ids_off; 44 | quint32 field_ids_size; 45 | quint32 field_ids_off; 46 | quint32 method_ids_size; 47 | quint32 method_ids_off; 48 | quint32 class_defs_size; 49 | quint32 class_defs_off; 50 | quint32 data_size; 51 | quint32 data_off; 52 | }; 53 | 54 | struct MAP_ITEM { 55 | quint16 nType; 56 | quint32 nCount; 57 | quint32 nOffset; 58 | }; 59 | 60 | struct STRING_ITEM_ID { 61 | quint32 string_data_off; 62 | }; 63 | 64 | struct TYPE_ITEM_ID { 65 | quint32 descriptor_idx; 66 | }; 67 | 68 | struct PROTO_ITEM_ID { 69 | quint32 shorty_idx; 70 | quint32 return_type_idx; 71 | quint32 parameters_off; 72 | }; 73 | 74 | struct FIELD_ITEM_ID { 75 | quint16 class_idx; 76 | quint16 type_idx; 77 | quint32 name_idx; 78 | }; 79 | 80 | struct METHOD_ITEM_ID { 81 | quint16 class_idx; 82 | quint16 proto_idx; 83 | quint32 name_idx; 84 | }; 85 | 86 | struct CLASS_ITEM_DEF { 87 | quint32 class_idx; 88 | quint32 access_flags; 89 | quint32 superclass_idx; 90 | quint32 interfaces_off; 91 | quint32 source_file_idx; 92 | quint32 annotations_off; 93 | quint32 class_data_off; 94 | quint32 static_values_off; 95 | }; 96 | 97 | const quint16 TYPE_HEADER_ITEM = 0x0000; 98 | const quint16 TYPE_STRING_ID_ITEM = 0x0001; 99 | const quint16 TYPE_TYPE_ID_ITEM = 0x0002; 100 | const quint16 TYPE_PROTO_ID_ITEM = 0x0003; 101 | const quint16 TYPE_FIELD_ID_ITEM = 0x0004; 102 | const quint16 TYPE_METHOD_ID_ITEM = 0x0005; 103 | const quint16 TYPE_CLASS_DEF_ITEM = 0x0006; 104 | const quint16 TYPE_CALL_SITE_ID_ITEM = 0x0007; 105 | const quint16 TYPE_METHOD_HANDLE_ITEM = 0x0008; 106 | const quint16 TYPE_MAP_LIST = 0x1000; 107 | const quint16 TYPE_TYPE_LIST = 0x1001; 108 | const quint16 TYPE_ANNOTATION_SET_REF_LIST = 0x1002; 109 | const quint16 TYPE_ANNOTATION_SET_ITEM = 0x1003; 110 | const quint16 TYPE_CLASS_DATA_ITEM = 0x2000; 111 | const quint16 TYPE_CODE_ITEM = 0x2001; 112 | const quint16 TYPE_STRING_DATA_ITEM = 0x2002; 113 | const quint16 TYPE_DEBUG_INFO_ITEM = 0x2003; 114 | const quint16 TYPE_ANNOTATION_ITEM = 0x2004; 115 | const quint16 TYPE_ENCODED_ARRAY_ITEM = 0x2005; 116 | const quint16 TYPE_ANNOTATIONS_DIRECTORY_ITEM = 0x2006; 117 | const quint16 TYPE_HIDDENAPI_CLASS_DATA_ITEM = 0xF000; 118 | } // namespace XDEX_DEF 119 | #endif // XDEX_DEF_H 120 | -------------------------------------------------------------------------------- /xdex.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2019-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 XDEX_H 22 | #define XDEX_H 23 | 24 | #include "xbinary.h" 25 | #include "xdex_def.h" 26 | 27 | class XDEX : public XBinary { 28 | Q_OBJECT 29 | 30 | public: 31 | enum TYPE { 32 | TYPE_UNKNOWN = 0, 33 | TYPE_MAINMODULE 34 | // TODO more 35 | // TODO main module !!! TODO Check 36 | // TODO the second module ... 37 | }; 38 | 39 | enum STRUCTID { 40 | STRUCTID_UNKNOWN = 0, 41 | STRUCTID_HEADER, 42 | STRUCTID_STRING_IDS_LIST, 43 | STRUCTID_TYPE_IDS_LIST, 44 | STRUCTID_PROTO_IDS_LIST, 45 | STRUCTID_FIELD_IDS_LIST, 46 | STRUCTID_METHOD_IDS_LIST, 47 | STRUCTID_CLASS_DEFS_LIST, 48 | STRUCTID_DATA_LIST, 49 | STRUCTID_LINK_LIST, 50 | STRUCTID_MAP_LIST, 51 | }; 52 | 53 | XDEX(QIODevice *pDevice); 54 | virtual ~XDEX(); 55 | 56 | static MODE getMode(QIODevice *pDevice); 57 | virtual bool isValid(PDSTRUCT *pPdStruct = nullptr) override; 58 | quint32 _getVersion(); 59 | virtual QString getVersion() override; 60 | virtual ENDIAN getEndian() override; 61 | virtual MODE getMode() override; 62 | virtual QString getArch() override; 63 | virtual OSNAME getOsName() override; 64 | virtual QString getOsVersion() override; 65 | virtual FT getFileType() override; 66 | virtual qint32 getType() override; 67 | virtual QString typeIdToString(qint32 nType) override; 68 | virtual QString getMIMEString() override; 69 | virtual QString getInfo(PDSTRUCT *pPdStruct = nullptr) override; 70 | 71 | virtual QList getMapModesList() override; 72 | virtual _MEMORY_MAP getMemoryMap(MAPMODE mapMode = MAPMODE_UNKNOWN, PDSTRUCT *pPdStruct = nullptr) override; 73 | virtual qint64 getFileFormatSize(PDSTRUCT *pPdStruct) override; 74 | 75 | quint32 getHeader_magic(); 76 | quint32 getHeader_version(); 77 | quint32 getHeader_checksum(); 78 | QByteArray getHeader_signature(); 79 | quint32 getHeader_file_size(); 80 | quint32 getHeader_header_size(); 81 | quint32 getHeader_endian_tag(); 82 | quint32 getHeader_link_size(); 83 | quint32 getHeader_link_off(); 84 | quint32 getHeader_map_off(); 85 | quint32 getHeader_string_ids_size(); 86 | quint32 getHeader_string_ids_off(); 87 | quint32 getHeader_type_ids_size(); 88 | quint32 getHeader_type_ids_off(); 89 | quint32 getHeader_proto_ids_size(); 90 | quint32 getHeader_proto_ids_off(); 91 | quint32 getHeader_field_ids_size(); 92 | quint32 getHeader_field_ids_off(); 93 | quint32 getHeader_method_ids_size(); 94 | quint32 getHeader_method_ids_off(); 95 | quint32 getHeader_class_defs_size(); 96 | quint32 getHeader_class_defs_off(); 97 | quint32 getHeader_data_size(); 98 | quint32 getHeader_data_off(); 99 | 100 | void setHeader_magic(quint32 value); 101 | void setHeader_version(quint32 value); 102 | void setHeader_checksum(quint32 value); 103 | void setHeader_file_size(quint32 value); 104 | void setHeader_header_size(quint32 value); 105 | void setHeader_endian_tag(quint32 value); 106 | void setHeader_link_size(quint32 value); 107 | void setHeader_link_off(quint32 value); 108 | void setHeader_map_off(quint32 value); 109 | void setHeader_string_ids_size(quint32 value); 110 | void setHeader_string_ids_off(quint32 value); 111 | void setHeader_type_ids_size(quint32 value); 112 | void setHeader_type_ids_off(quint32 value); 113 | void setHeader_proto_ids_size(quint32 value); 114 | void setHeader_proto_ids_off(quint32 value); 115 | void setHeader_field_ids_size(quint32 value); 116 | void setHeader_field_ids_off(quint32 value); 117 | void setHeader_method_ids_size(quint32 value); 118 | void setHeader_method_ids_off(quint32 value); 119 | void setHeader_class_defs_size(quint32 value); 120 | void setHeader_class_defs_off(quint32 value); 121 | void setHeader_data_size(quint32 value); 122 | void setHeader_data_off(quint32 value); 123 | 124 | XDEX_DEF::HEADER getHeader(); 125 | XDEX_DEF::HEADER _readHEADER(qint64 nOffset); 126 | quint32 getHeaderSize(); 127 | QList getMapItems(PDSTRUCT *pPdStruct = nullptr); 128 | 129 | static bool compareMapItems(QList *pListMaps, QList *pListIDs, PDSTRUCT *pPdStruct = nullptr); 130 | static quint32 getMapItemsHash(QList *pListMaps, PDSTRUCT *pPdStruct); 131 | static bool isMapItemPresent(quint16 nType, QList *pMapItems, PDSTRUCT *pPdStruct = nullptr); 132 | 133 | static QMap getTypes(); 134 | static QMap getTypesS(); 135 | static XDEX_DEF::MAP_ITEM getMapItem(quint16 nType, QList *pMapItems, PDSTRUCT *pPdStruct); 136 | 137 | QList getList_STRING_ITEM_ID(PDSTRUCT *pPdStruct); 138 | QList getList_STRING_ITEM_ID(QList *pListMapItems, PDSTRUCT *pPdStruct); 139 | QList getList_TYPE_ITEM_ID(PDSTRUCT *pPdStruct); 140 | QList getList_TYPE_ITEM_ID(QList *pListMapItems, PDSTRUCT *pPdStruct); 141 | QList getList_PROTO_ITEM_ID(QList *pListMapItems, PDSTRUCT *pPdStruct); 142 | QList getList_FIELD_ITEM_ID(QList *pListMapItems, PDSTRUCT *pPdStruct = nullptr); 143 | QList getList_METHOD_ITEM_ID(QList *pListMapItems, PDSTRUCT *pPdStruct = nullptr); 144 | QList getList_CLASS_ITEM_DEF(QList *pListMapItems, PDSTRUCT *pPdStruct = nullptr); 145 | 146 | QList getStrings(QList *pMapItems, PDSTRUCT *pPdStruct = nullptr); 147 | QString _getString(XDEX_DEF::MAP_ITEM map_stringIdItem, quint32 nIndex, bool bIsBigEndian); 148 | QString _getString(XDEX_DEF::MAP_ITEM map_stringIdItem, quint32 nIndex, bool bIsBigEndian, char *pData, qint32 nDataSize, qint32 nDataOffset); 149 | QString _getTypeItemtString(XDEX_DEF::MAP_ITEM map_stringIdItem, XDEX_DEF::MAP_ITEM map_typeItemId, quint32 nIndex, bool bIsBigEndian); 150 | QList _getTypeList(qint64 nOffset, bool bIsBigEndian, PDSTRUCT *pPdStruct); 151 | QList getTypeItemStrings(QList *pMapItems, QList *pListStrings, PDSTRUCT *pPdStruct = nullptr); 152 | void getProtoIdItems(QList *pMapItems, PDSTRUCT *pPdStruct); 153 | QString getStringItemIdString(XDEX_DEF::STRING_ITEM_ID stringItemId); 154 | QString getStringItemIdString(XDEX_DEF::STRING_ITEM_ID stringItemId, char *pData, qint32 nDataSize, qint32 nDataOffset); 155 | QString getStringItemIdString(QList *pList, qint32 nIndex, char *pData, qint32 nDataSize, qint32 nDataOffset); 156 | QString getTypeItemIdString(XDEX_DEF::TYPE_ITEM_ID typeItemId, XDEX_DEF::MAP_ITEM *pMapItemStrings); 157 | QString getTypeItemIdString(XDEX_DEF::TYPE_ITEM_ID typeItemId, XDEX_DEF::MAP_ITEM *pMapItemStrings, char *pData, qint32 nDataSize, qint32 nDataOffset); 158 | QString getTypeItemIdString(QList *pList, qint32 nIndex, XDEX_DEF::MAP_ITEM *pMapItemStrings, char *pData, qint32 nDataSize, 159 | qint32 nDataOffset); 160 | QString getProtoItemIdString(XDEX_DEF::PROTO_ITEM_ID protoItemId, XDEX_DEF::MAP_ITEM *pMapItemStrings); 161 | 162 | static QMap getHeaderMagics(); 163 | static QMap getHeaderVersions(); 164 | static QMap getHeaderEndianTags(); 165 | 166 | bool isStringPoolSorted(PDSTRUCT *pPdStruct); 167 | bool isStringPoolSorted(QList *pMapItems, PDSTRUCT *pPdStruct); 168 | bool isFieldNamesUnicode(QList *pListIDs, QList *pListStrings, PDSTRUCT *pPdStruct); 169 | bool isMethodNamesUnicode(QList *pListIDs, QList *pListStrings, PDSTRUCT *pPdStruct); 170 | 171 | qint64 getDataSizeByType(qint32 nType, qint64 nOffset, qint32 nCount, bool bIsBigEndian, PDSTRUCT *pPdStruct); 172 | 173 | virtual QString getFileFormatExt() override; 174 | virtual QString getFileFormatExtsString() override; 175 | 176 | virtual QString structIDToString(quint32 nID) override; 177 | virtual QList getDataHeaders(const DATA_HEADERS_OPTIONS &dataHeadersOptions, PDSTRUCT *pPdStruct) override; 178 | 179 | virtual QList getFileParts(quint32 nFileParts, qint32 nLimit = -1, PDSTRUCT *pPdStruct = nullptr) override; 180 | }; 181 | 182 | #endif // XDEX_H 183 | -------------------------------------------------------------------------------- /xandroidbinary.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2019-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 "xandroidbinary.h" 22 | 23 | XAndroidBinary::XAndroidBinary(QIODevice *pDevice) : XBinary(pDevice) 24 | { 25 | } 26 | 27 | XAndroidBinary::~XAndroidBinary() 28 | { 29 | } 30 | 31 | bool XAndroidBinary::isValid(PDSTRUCT *pPdStruct) 32 | { 33 | bool bIsValid = false; 34 | 35 | _MEMORY_MAP memoryMap = XBinary::getSimpleMemoryMap(); 36 | 37 | bIsValid = compareSignature(&memoryMap, "00000800........0100", 0, pPdStruct) || compareSignature(&memoryMap, "03000800........0100", 0, pPdStruct) || 38 | compareSignature(&memoryMap, "02000C00........0100", 0, pPdStruct); 39 | 40 | return bIsValid; 41 | } 42 | 43 | XBinary::ENDIAN XAndroidBinary::getEndian() 44 | { 45 | return ENDIAN_LITTLE; 46 | } 47 | 48 | QString XAndroidBinary::getVersion() 49 | { 50 | return ""; // TODO Check !!! 51 | } 52 | 53 | XANDROIDBINARY_DEF::HEADER XAndroidBinary::readHeader(qint64 nOffset) 54 | { 55 | XANDROIDBINARY_DEF::HEADER result = {}; 56 | 57 | result.type = read_uint32(nOffset + offsetof(XANDROIDBINARY_DEF::HEADER, type)); 58 | result.header_size = read_uint32(nOffset + offsetof(XANDROIDBINARY_DEF::HEADER, header_size)); 59 | result.data_size = read_uint32(nOffset + offsetof(XANDROIDBINARY_DEF::HEADER, data_size)); 60 | 61 | return result; 62 | } 63 | 64 | XANDROIDBINARY_DEF::HEADER_STRING_POOL XAndroidBinary::readHeaderStringPool(qint64 nOffset) 65 | { 66 | XANDROIDBINARY_DEF::HEADER_STRING_POOL result = {}; 67 | 68 | result.header = readHeader(nOffset); 69 | result.stringCount = read_uint32(nOffset + offsetof(XANDROIDBINARY_DEF::HEADER_STRING_POOL, stringCount)); 70 | result.styleCount = read_uint32(nOffset + offsetof(XANDROIDBINARY_DEF::HEADER_STRING_POOL, styleCount)); 71 | result.flags = read_uint32(nOffset + offsetof(XANDROIDBINARY_DEF::HEADER_STRING_POOL, flags)); 72 | result.stringsStart = read_uint32(nOffset + offsetof(XANDROIDBINARY_DEF::HEADER_STRING_POOL, stringsStart)); 73 | result.stylesStart = read_uint32(nOffset + offsetof(XANDROIDBINARY_DEF::HEADER_STRING_POOL, stylesStart)); 74 | 75 | return result; 76 | } 77 | 78 | XANDROIDBINARY_DEF::HEADER_NAMESPACE XAndroidBinary::readHeaderNamespace(qint64 nOffset) 79 | { 80 | XANDROIDBINARY_DEF::HEADER_NAMESPACE result = {}; 81 | 82 | result.header = readHeader(nOffset); 83 | result.lineNumber = read_uint32(nOffset + offsetof(XANDROIDBINARY_DEF::HEADER_NAMESPACE, lineNumber)); 84 | result.comment = read_uint32(nOffset + offsetof(XANDROIDBINARY_DEF::HEADER_NAMESPACE, comment)); 85 | result.prefix = read_uint32(nOffset + offsetof(XANDROIDBINARY_DEF::HEADER_NAMESPACE, prefix)); 86 | result.uri = read_uint32(nOffset + offsetof(XANDROIDBINARY_DEF::HEADER_NAMESPACE, uri)); 87 | 88 | return result; 89 | } 90 | 91 | XANDROIDBINARY_DEF::HEADER_XML_START XAndroidBinary::readHeaderXmlStart(qint64 nOffset) 92 | { 93 | XANDROIDBINARY_DEF::HEADER_XML_START result = {}; 94 | 95 | result.header = readHeader(nOffset); 96 | result.lineNumber = read_uint32(nOffset + offsetof(XANDROIDBINARY_DEF::HEADER_XML_START, lineNumber)); 97 | result.comment = read_uint32(nOffset + offsetof(XANDROIDBINARY_DEF::HEADER_XML_START, comment)); 98 | result.ns = read_uint32(nOffset + offsetof(XANDROIDBINARY_DEF::HEADER_XML_START, ns)); 99 | result.name = read_uint32(nOffset + offsetof(XANDROIDBINARY_DEF::HEADER_XML_START, name)); 100 | result.attributeStart = read_uint16(nOffset + offsetof(XANDROIDBINARY_DEF::HEADER_XML_START, attributeStart)); 101 | result.attributeSize = read_uint16(nOffset + offsetof(XANDROIDBINARY_DEF::HEADER_XML_START, attributeSize)); 102 | result.attributeCount = read_uint16(nOffset + offsetof(XANDROIDBINARY_DEF::HEADER_XML_START, attributeCount)); 103 | result.idIndex = read_uint16(nOffset + offsetof(XANDROIDBINARY_DEF::HEADER_XML_START, idIndex)); 104 | result.classIndex = read_uint16(nOffset + offsetof(XANDROIDBINARY_DEF::HEADER_XML_START, classIndex)); 105 | result.styleIndex = read_uint16(nOffset + offsetof(XANDROIDBINARY_DEF::HEADER_XML_START, styleIndex)); 106 | 107 | return result; 108 | } 109 | 110 | XANDROIDBINARY_DEF::HEADER_XML_ATTRIBUTE XAndroidBinary::readHeaderXmlAttribute(qint64 nOffset) 111 | { 112 | XANDROIDBINARY_DEF::HEADER_XML_ATTRIBUTE result = {}; 113 | 114 | result.ns = read_uint32(nOffset + offsetof(XANDROIDBINARY_DEF::HEADER_XML_ATTRIBUTE, ns)); 115 | result.name = read_uint32(nOffset + offsetof(XANDROIDBINARY_DEF::HEADER_XML_ATTRIBUTE, name)); 116 | result.rawValue = read_uint32(nOffset + offsetof(XANDROIDBINARY_DEF::HEADER_XML_ATTRIBUTE, rawValue)); 117 | result.size = read_uint16(nOffset + offsetof(XANDROIDBINARY_DEF::HEADER_XML_ATTRIBUTE, size)); 118 | result.reserved = read_uint8(nOffset + offsetof(XANDROIDBINARY_DEF::HEADER_XML_ATTRIBUTE, reserved)); 119 | result.dataType = read_uint8(nOffset + offsetof(XANDROIDBINARY_DEF::HEADER_XML_ATTRIBUTE, dataType)); 120 | result.data = read_uint32(nOffset + offsetof(XANDROIDBINARY_DEF::HEADER_XML_ATTRIBUTE, data)); 121 | 122 | return result; 123 | } 124 | 125 | XANDROIDBINARY_DEF::HEADER_XML_END XAndroidBinary::readHeaderXmlEnd(qint64 nOffset) 126 | { 127 | XANDROIDBINARY_DEF::HEADER_XML_END result = {}; 128 | 129 | result.header = readHeader(nOffset); 130 | result.lineNumber = read_uint32(nOffset + offsetof(XANDROIDBINARY_DEF::HEADER_XML_END, lineNumber)); 131 | result.comment = read_uint32(nOffset + offsetof(XANDROIDBINARY_DEF::HEADER_XML_END, comment)); 132 | result.ns = read_uint32(nOffset + offsetof(XANDROIDBINARY_DEF::HEADER_XML_END, ns)); 133 | result.name = read_uint32(nOffset + offsetof(XANDROIDBINARY_DEF::HEADER_XML_END, name)); 134 | 135 | return result; 136 | } 137 | 138 | QList XAndroidBinary::getHeaders(PDSTRUCT *pPdStruct) 139 | { 140 | QList listHeaders; 141 | 142 | qint64 nTotalSize = getSize(); 143 | qint64 nCurrentOffset = 0; 144 | 145 | while ((nCurrentOffset < nTotalSize) && XBinary::isPdStructNotCanceled(pPdStruct)) { 146 | XANDROIDBINARY_DEF::HEADER record = readHeader(nCurrentOffset); 147 | listHeaders.append(record); 148 | 149 | nCurrentOffset += record.data_size; 150 | } 151 | 152 | return listHeaders; 153 | } 154 | 155 | XAndroidBinary::RECORD XAndroidBinary::getRecord(qint64 nOffset, PDSTRUCT *pPdStruct) 156 | { 157 | RECORD result = {}; 158 | 159 | result.header = readHeader(nOffset); 160 | result.nOffset = nOffset; 161 | 162 | if ((result.header.type == XANDROIDBINARY_DEF::RES_NULL_TYPE) || (result.header.type == XANDROIDBINARY_DEF::RES_XML_TYPE) || 163 | (result.header.type == XANDROIDBINARY_DEF::RES_TABLE_TYPE) || (result.header.type == XANDROIDBINARY_DEF::RES_TABLE_PACKAGE_TYPE)) { 164 | qint64 nCurrentOffset = nOffset + result.header.header_size; 165 | 166 | while ((nCurrentOffset < result.header.data_size) && XBinary::isPdStructNotCanceled(pPdStruct)) { 167 | RECORD record = getRecord(nCurrentOffset, pPdStruct); 168 | 169 | if (record.header.data_size == 0) { 170 | break; 171 | } 172 | 173 | result.listChildren.append(record); 174 | 175 | nCurrentOffset += record.header.data_size; 176 | } 177 | } 178 | 179 | return result; 180 | } 181 | 182 | QString XAndroidBinary::recordToString(XAndroidBinary::RECORD *pRecord, PDSTRUCT *pPdStruct) 183 | { 184 | QString sResult; 185 | 186 | if ((pRecord->header.type == XANDROIDBINARY_DEF::RES_NULL_TYPE) || (pRecord->header.type == XANDROIDBINARY_DEF::RES_XML_TYPE)) { 187 | QXmlStreamWriter xml(&sResult); 188 | 189 | xml.setAutoFormatting(true); 190 | xml.writeStartDocument("1.0", false); 191 | 192 | qint32 nNumberOfChildren = pRecord->listChildren.count(); 193 | QList listStrings; 194 | QList listResources; 195 | QStack stackPrefix; 196 | QStack stackURI; 197 | 198 | for (qint32 i = 0; (i < nNumberOfChildren) && XBinary::isPdStructNotCanceled(pPdStruct); i++) { 199 | if (pRecord->listChildren.at(i).header.type == XANDROIDBINARY_DEF::RES_STRING_POOL_TYPE) { 200 | XANDROIDBINARY_DEF::HEADER_STRING_POOL headerStringPool = readHeaderStringPool(pRecord->listChildren.at(i).nOffset); 201 | 202 | qint64 nCurrentOffset = pRecord->listChildren.at(i).nOffset + headerStringPool.header.header_size; 203 | qint64 nStringsDataOffset = pRecord->listChildren.at(i).nOffset + headerStringPool.stringsStart; 204 | 205 | for (quint32 j = 0; (j < headerStringPool.stringCount) && XBinary::isPdStructNotCanceled(pPdStruct); j++) { 206 | qint64 nStringOffset = nStringsDataOffset + read_int32(nCurrentOffset + j * sizeof(quint32)); 207 | 208 | QString sString; 209 | quint16 nStringSize = read_uint16(nStringOffset); 210 | 211 | if (headerStringPool.flags) { 212 | sString = read_ansiString(nStringOffset + sizeof(quint16), nStringSize); 213 | } else { 214 | sString = read_unicodeString(nStringOffset + sizeof(quint16), nStringSize); 215 | } 216 | 217 | listStrings.append(sString); 218 | } 219 | } else if (pRecord->listChildren.at(i).header.type == XANDROIDBINARY_DEF::RES_XML_RESOURCE_MAP_TYPE) { 220 | qint32 nNumberOfResources = (pRecord->listChildren.at(i).header.data_size - sizeof(XANDROIDBINARY_DEF::HEADER)) / 4; 221 | 222 | qint64 nCurrentOffset = pRecord->listChildren.at(i).nOffset + sizeof(XANDROIDBINARY_DEF::HEADER); 223 | 224 | for (qint32 j = 0; (j < nNumberOfResources) && XBinary::isPdStructNotCanceled(pPdStruct); j++) { 225 | quint32 nID = read_uint32(nCurrentOffset + j * sizeof(quint32)); 226 | 227 | // qDebug("Resource ID %x",nID); 228 | 229 | listResources.append(nID); 230 | } 231 | } else if (pRecord->listChildren.at(i).header.type == XANDROIDBINARY_DEF::RES_XML_START_NAMESPACE_TYPE) { 232 | XANDROIDBINARY_DEF::HEADER_NAMESPACE headerNamespace = readHeaderNamespace(pRecord->listChildren.at(i).nOffset); 233 | 234 | stackPrefix.push(getStringByIndex(&listStrings, headerNamespace.prefix)); 235 | stackURI.push(getStringByIndex(&listStrings, headerNamespace.uri)); 236 | 237 | xml.writeNamespace(stackURI.top(), stackPrefix.top()); 238 | } else if (pRecord->listChildren.at(i).header.type == XANDROIDBINARY_DEF::RES_XML_END_NAMESPACE_TYPE) { 239 | stackPrefix.pop(); 240 | stackURI.pop(); 241 | } else if (pRecord->listChildren.at(i).header.type == XANDROIDBINARY_DEF::RES_XML_START_ELEMENT_TYPE) { 242 | XANDROIDBINARY_DEF::HEADER_XML_START headerXmlStart = readHeaderXmlStart(pRecord->listChildren.at(i).nOffset); 243 | 244 | // qDebug("idIndex %d",headerXmlStart.idIndex); 245 | // qDebug("classIndex 246 | // %d",headerXmlStart.classIndex); 247 | // qDebug("styleIndex 248 | // %d",headerXmlStart.styleIndex); 249 | 250 | QString sNS = getStringByIndex(&listStrings, headerXmlStart.ns); 251 | QString sName = getStringByIndex(&listStrings, headerXmlStart.name); 252 | 253 | xml.writeStartElement(sNS, sName); 254 | 255 | qint64 nCurrentOffset = pRecord->listChildren.at(i).nOffset + sizeof(XANDROIDBINARY_DEF::HEADER_XML_START); 256 | 257 | for (qint32 j = 0; (j < headerXmlStart.attributeCount) && XBinary::isPdStructNotCanceled(pPdStruct); j++) { 258 | XANDROIDBINARY_DEF::HEADER_XML_ATTRIBUTE headerXmlAttribute = readHeaderXmlAttribute(nCurrentOffset); 259 | 260 | QString sValue; 261 | 262 | if (headerXmlAttribute.dataType == 1) // TODO Const 263 | { 264 | sValue = "@" + QString::number(headerXmlAttribute.data, 16); 265 | } else if (headerXmlAttribute.dataType == 3) // TODO Const 266 | { 267 | sValue = getStringByIndex(&listStrings, headerXmlAttribute.data); 268 | } else if (headerXmlAttribute.dataType == 16) // TODO Const 269 | { 270 | sValue = QString::number(headerXmlAttribute.data); 271 | } else if (headerXmlAttribute.dataType == 17) // TODO Const // Flags 272 | { 273 | sValue = "0x" + QString::number(headerXmlAttribute.data, 16); 274 | } else if (headerXmlAttribute.dataType == 18) // TODO Const 275 | { 276 | sValue = (headerXmlAttribute.data == 0xFFFFFFFF) ? "true" : "false"; 277 | } 278 | // else 279 | // { 280 | // sValue="0x"+QString::number(headerXmlAttribute.data,16); 281 | // } 282 | // else 283 | // { 284 | // qDebug("headerXmlAttribute.dataType 285 | // %d %s: 286 | // %x",headerXmlAttribute.dataType,getStringByIndex(&listStrings,headerXmlAttribute.name).toLatin1().data(),headerXmlAttribute.data); 287 | // } 288 | // TODO More types check 289 | 290 | QString sNS_Attribute = getStringByIndex(&listStrings, headerXmlAttribute.ns); 291 | QString sName_Attribute = getStringByIndex(&listStrings, headerXmlAttribute.name); 292 | 293 | if (sName_Attribute == ":") { 294 | sName_Attribute = ""; 295 | } 296 | 297 | xml.writeAttribute(sNS_Attribute, sName_Attribute, sValue); 298 | 299 | nCurrentOffset += sizeof(XANDROIDBINARY_DEF::HEADER_XML_ATTRIBUTE); 300 | } 301 | } else if (pRecord->listChildren.at(i).header.type == XANDROIDBINARY_DEF::RES_XML_END_ELEMENT_TYPE) { 302 | // XANDROIDBINARY_DEF::HEADER_XML_END 303 | // headerXmlEnd=readHeaderXmlEnd(pRecord->listChildren.at(i).nOffset); 304 | 305 | xml.writeEndElement(); 306 | } 307 | // else 308 | // { 309 | // qDebug("Record 310 | // %x",pRecord->listChildren.at(i).header.type); 311 | // } 312 | } 313 | 314 | xml.writeEndDocument(); 315 | } 316 | 317 | return sResult; 318 | } 319 | 320 | QString XAndroidBinary::getDecoded(QIODevice *pDevice, PDSTRUCT *pPdStruct) 321 | { 322 | QString sResult; 323 | 324 | XAndroidBinary xab(pDevice); 325 | RECORD record = xab.getRecord(0, pPdStruct); 326 | sResult = xab.recordToString(&record, pPdStruct); 327 | 328 | return sResult; 329 | } 330 | 331 | QString XAndroidBinary::getDecoded(const QString &sFileName, PDSTRUCT *pPdStruct) 332 | { 333 | QString sResult; 334 | 335 | QFile file; 336 | file.setFileName(sFileName); 337 | 338 | if (file.open(QIODevice::ReadOnly)) { 339 | sResult = getDecoded(&file, pPdStruct); 340 | file.close(); 341 | } 342 | 343 | return sResult; 344 | } 345 | 346 | QString XAndroidBinary::getDecoded(QByteArray *pbaData, PDSTRUCT *pPdStruct) 347 | { 348 | QString sResult; 349 | 350 | QBuffer buffer; 351 | buffer.setBuffer(pbaData); 352 | 353 | if (buffer.open(QIODevice::ReadOnly)) { 354 | sResult = getDecoded(&buffer, pPdStruct); 355 | 356 | buffer.close(); 357 | } 358 | 359 | return sResult; 360 | } 361 | 362 | QString XAndroidBinary::getFileFormatExt() 363 | { 364 | QString sResult = "xml"; 365 | 366 | if (read_uint32(0, true) == 0x02000C00) { 367 | sResult = "arsrc"; 368 | } 369 | 370 | return sResult; 371 | } 372 | 373 | QString XAndroidBinary::getMIMEString() 374 | { 375 | QString sResult = "application/xml"; 376 | 377 | if (read_uint32(0, true) == 0x02000C00) { 378 | sResult = "application/octet-stream"; 379 | } 380 | 381 | return sResult; 382 | } 383 | 384 | XBinary::FT XAndroidBinary::getFileType() 385 | { 386 | XBinary::FT result = FT_ANDROIDXML; 387 | 388 | if (read_uint32(0, true) == 0x02000C00) { 389 | result = FT_ANDROIDASRC; 390 | } 391 | 392 | return result; 393 | } 394 | -------------------------------------------------------------------------------- /xdex.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2019-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 "xdex.h" 22 | 23 | XBinary::XCONVERT _TABLE_DEX_STRUCTID[] = {{XDEX::STRUCTID_UNKNOWN, "Unknown", QObject::tr("Unknown")}, 24 | {XDEX::STRUCTID_HEADER, "HEADER", QString("HEADER")}, 25 | {XDEX::STRUCTID_STRING_IDS_LIST, "STRING_IDS_LIST", QString("STRING_IDS_LIST")}, 26 | {XDEX::STRUCTID_TYPE_IDS_LIST, "TYPE_IDS_LIST", QString("TYPE_IDS_LIST")}, 27 | {XDEX::STRUCTID_PROTO_IDS_LIST, "PROTO_IDS_LIST", QString("PROTO_IDS_LIST")}, 28 | {XDEX::STRUCTID_FIELD_IDS_LIST, "FIELD_IDS_LIST", QString("FIELD_IDS_LIST")}, 29 | {XDEX::STRUCTID_METHOD_IDS_LIST, "METHOD_IDS_LIST", QString("METHOD_IDS_LIST")}, 30 | {XDEX::STRUCTID_CLASS_DEFS_LIST, "CLASS_DEFS_LIST", QString("CLASS_DEFS_LIST")}, 31 | {XDEX::STRUCTID_DATA_LIST, "DATA_LIST", QString("DATA_LIST")}, 32 | {XDEX::STRUCTID_LINK_LIST, "LINK_LIST", QString("LINK_LIST")}, 33 | {XDEX::STRUCTID_MAP_LIST, "MAP_LIST", QString("MAP_LIST")}}; 34 | 35 | XDEX::XDEX(QIODevice *pDevice) : XBinary(pDevice) 36 | { 37 | } 38 | 39 | XDEX::~XDEX() 40 | { 41 | } 42 | 43 | XBinary::MODE XDEX::getMode(QIODevice *pDevice) 44 | { 45 | XDEX xdex(pDevice); 46 | 47 | return xdex.getMode(); 48 | } 49 | 50 | bool XDEX::isValid(PDSTRUCT *pPdStruct) 51 | { 52 | bool bIsValid = false; 53 | 54 | // TODO More checks(sizes,mb hashes) 55 | 56 | _MEMORY_MAP memoryMap = XBinary::getSimpleMemoryMap(); 57 | bIsValid = compareSignature(&memoryMap, "'dex\n'......00", 0, pPdStruct); 58 | 59 | if (bIsValid) { 60 | bIsValid = (_getVersion() >= 35); 61 | } 62 | 63 | return bIsValid; 64 | } 65 | 66 | quint32 XDEX::_getVersion() 67 | { 68 | quint32 nVersion = 0; 69 | 70 | QString sVersion = read_ansiString(4); 71 | 72 | nVersion = sVersion.toUInt(); 73 | 74 | return nVersion; 75 | } 76 | 77 | QString XDEX::getVersion() 78 | { 79 | return read_ansiString(4); // TODO Check 80 | } 81 | 82 | XBinary::ENDIAN XDEX::getEndian() 83 | { 84 | ENDIAN result = ENDIAN_UNKNOWN; 85 | 86 | quint32 nData = read_uint32(offsetof(XDEX_DEF::HEADER, endian_tag)); 87 | 88 | if (nData == 0x12345678) { 89 | result = ENDIAN_LITTLE; 90 | } else if (nData == 0x78563412) { 91 | result = ENDIAN_BIG; 92 | } 93 | 94 | return result; 95 | } 96 | 97 | XBinary::MODE XDEX::getMode() 98 | { 99 | return MODE_32; 100 | } 101 | 102 | QString XDEX::getArch() 103 | { 104 | return QString("Dalvik"); // TODO Check 105 | } 106 | 107 | QString XDEX::getOsVersion() 108 | { 109 | QString sVersion; 110 | 111 | QString sDDEXVersion = getVersion(); 112 | 113 | // https://source.android.com/devices/tech/dalvik/dex-format 114 | if (sDDEXVersion == "035") { 115 | sVersion = XBinary::getAndroidVersionFromApi(14); // TODO move the function here 116 | } 117 | // else if (sDDEXVersion=="036") 118 | // { 119 | // // Due to a Dalvik bug present in older versions of Android, Dex version 036 has been skipped. 120 | // // Dex version 036 is not valid for any version of Android and never will be. 121 | // } 122 | else if (sDDEXVersion == "037") { 123 | sVersion = XBinary::getAndroidVersionFromApi(24); // TODO move the function here 124 | } else if (sDDEXVersion == "038") { 125 | sVersion = XBinary::getAndroidVersionFromApi(26); // TODO move the function here 126 | } else if (sDDEXVersion == "039") { 127 | sVersion = XBinary::getAndroidVersionFromApi(28); // TODO move the function here 128 | } else if (sDDEXVersion == "040") { 129 | sVersion = XBinary::getAndroidVersionFromApi(29); // TODO move the function here 130 | } else { 131 | sVersion = sDDEXVersion; 132 | } 133 | 134 | return sVersion; 135 | } 136 | 137 | XBinary::OSNAME XDEX::getOsName() 138 | { 139 | return OSNAME_ANDROID; 140 | } 141 | 142 | XBinary::FT XDEX::getFileType() 143 | { 144 | return FT_DEX; 145 | } 146 | 147 | qint32 XDEX::getType() 148 | { 149 | // TODO more (main module,second module etc) 150 | return TYPE_MAINMODULE; 151 | } 152 | 153 | QString XDEX::typeIdToString(qint32 nType) 154 | { 155 | QString sResult = tr("Unknown"); 156 | 157 | switch (nType) { 158 | case TYPE_UNKNOWN: sResult = tr("Unknown"); break; 159 | case TYPE_MAINMODULE: sResult = tr("Main module"); break; 160 | } 161 | 162 | return sResult; 163 | } 164 | 165 | QString XDEX::getInfo(PDSTRUCT *pPdStruct) 166 | { 167 | // Provide a compact info string; include mapHash computed from MAP_ITEMs 168 | QString sResult; 169 | 170 | QList listMapItems = getMapItems(pPdStruct); 171 | if (!listMapItems.isEmpty() && XBinary::isPdStructNotCanceled(pPdStruct)) { 172 | quint32 nHash = getMapItemsHash(&listMapItems, pPdStruct); 173 | sResult = QString("%1").arg(XBinary::valueToHex(nHash, false)); 174 | } 175 | 176 | return sResult; 177 | } 178 | 179 | QList XDEX::getMapModesList() 180 | { 181 | QList listResult; 182 | 183 | listResult.append(MAPMODE_REGIONS); 184 | listResult.append(MAPMODE_SECTIONS); 185 | 186 | return listResult; 187 | } 188 | 189 | XBinary::_MEMORY_MAP XDEX::getMemoryMap(MAPMODE mapMode, PDSTRUCT *pPdStruct) 190 | { 191 | XBinary::_MEMORY_MAP result = {}; 192 | 193 | if (mapMode == MAPMODE_UNKNOWN) { 194 | mapMode = MAPMODE_REGIONS; // Default mode 195 | } 196 | 197 | if (mapMode == MAPMODE_REGIONS) { 198 | result = _getMemoryMap(FILEPART_HEADER | FILEPART_REGION | FILEPART_OVERLAY, pPdStruct); 199 | } else if (mapMode == MAPMODE_SECTIONS) { 200 | result = _getMemoryMap(FILEPART_HEADER | FILEPART_SECTION | FILEPART_OVERLAY, pPdStruct); 201 | } 202 | 203 | return result; 204 | } 205 | 206 | qint64 XDEX::getFileFormatSize(PDSTRUCT *pPdStruct) 207 | { 208 | qint64 nResult = 0; 209 | 210 | // Validate basic structure first 211 | if (!isValid(pPdStruct)) { 212 | return 0; 213 | } 214 | 215 | const qint64 nActualSize = getSize(); 216 | const quint32 nHeaderSize = getHeader_header_size(); 217 | const quint32 nFileSizeField = getHeader_file_size(); 218 | 219 | // Sanity: header must not exceed actual file and must be at least the header struct 220 | if ((nHeaderSize < sizeof(XDEX_DEF::HEADER)) || ((qint64)nHeaderSize > nActualSize)) { 221 | // Fallback: unknown header, return clamped field or actual size 222 | return qMin(nActualSize, (qint64)nFileSizeField); 223 | } 224 | 225 | // DEX format size should be the header's file_size; clamp to actual size and enforce header_size lower bound 226 | if ((nFileSizeField == 0) || (nFileSizeField < nHeaderSize)) { 227 | nResult = nActualSize; // invalid field, fallback to actual 228 | } else { 229 | nResult = qMin(nActualSize, (qint64)nFileSizeField); 230 | } 231 | 232 | return nResult; 233 | } 234 | 235 | quint32 XDEX::getHeader_magic() 236 | { 237 | return read_uint32(offsetof(XDEX_DEF::HEADER, magic), false); 238 | } 239 | 240 | quint32 XDEX::getHeader_version() 241 | { 242 | return read_uint32(offsetof(XDEX_DEF::HEADER, version), false); 243 | } 244 | 245 | quint32 XDEX::getHeader_checksum() 246 | { 247 | return read_uint32(offsetof(XDEX_DEF::HEADER, checksum), isBigEndian()); 248 | } 249 | 250 | QByteArray XDEX::getHeader_signature() 251 | { 252 | return read_array(offsetof(XDEX_DEF::HEADER, signature), 20); 253 | } 254 | 255 | quint32 XDEX::getHeader_file_size() 256 | { 257 | return read_uint32(offsetof(XDEX_DEF::HEADER, file_size), isBigEndian()); 258 | } 259 | 260 | quint32 XDEX::getHeader_header_size() 261 | { 262 | return read_uint32(offsetof(XDEX_DEF::HEADER, header_size), isBigEndian()); 263 | } 264 | 265 | quint32 XDEX::getHeader_endian_tag() 266 | { 267 | return read_uint32(offsetof(XDEX_DEF::HEADER, endian_tag)); 268 | } 269 | 270 | quint32 XDEX::getHeader_link_size() 271 | { 272 | return read_uint32(offsetof(XDEX_DEF::HEADER, link_size), isBigEndian()); 273 | } 274 | 275 | quint32 XDEX::getHeader_link_off() 276 | { 277 | return read_uint32(offsetof(XDEX_DEF::HEADER, link_off), isBigEndian()); 278 | } 279 | 280 | quint32 XDEX::getHeader_map_off() 281 | { 282 | return read_uint32(offsetof(XDEX_DEF::HEADER, map_off), isBigEndian()); 283 | } 284 | 285 | quint32 XDEX::getHeader_string_ids_size() 286 | { 287 | return read_uint32(offsetof(XDEX_DEF::HEADER, string_ids_size), isBigEndian()); 288 | } 289 | 290 | quint32 XDEX::getHeader_string_ids_off() 291 | { 292 | return read_uint32(offsetof(XDEX_DEF::HEADER, string_ids_off), isBigEndian()); 293 | } 294 | 295 | quint32 XDEX::getHeader_type_ids_size() 296 | { 297 | return read_uint32(offsetof(XDEX_DEF::HEADER, type_ids_size), isBigEndian()); 298 | } 299 | 300 | quint32 XDEX::getHeader_type_ids_off() 301 | { 302 | return read_uint32(offsetof(XDEX_DEF::HEADER, type_ids_off), isBigEndian()); 303 | } 304 | 305 | quint32 XDEX::getHeader_proto_ids_size() 306 | { 307 | return read_uint32(offsetof(XDEX_DEF::HEADER, proto_ids_size), isBigEndian()); 308 | } 309 | 310 | quint32 XDEX::getHeader_proto_ids_off() 311 | { 312 | return read_uint32(offsetof(XDEX_DEF::HEADER, proto_ids_off), isBigEndian()); 313 | } 314 | 315 | quint32 XDEX::getHeader_field_ids_size() 316 | { 317 | return read_uint32(offsetof(XDEX_DEF::HEADER, field_ids_size), isBigEndian()); 318 | } 319 | 320 | quint32 XDEX::getHeader_field_ids_off() 321 | { 322 | return read_uint32(offsetof(XDEX_DEF::HEADER, field_ids_off), isBigEndian()); 323 | } 324 | 325 | quint32 XDEX::getHeader_method_ids_size() 326 | { 327 | return read_uint32(offsetof(XDEX_DEF::HEADER, method_ids_size), isBigEndian()); 328 | } 329 | 330 | quint32 XDEX::getHeader_method_ids_off() 331 | { 332 | return read_uint32(offsetof(XDEX_DEF::HEADER, method_ids_off), isBigEndian()); 333 | } 334 | 335 | quint32 XDEX::getHeader_class_defs_size() 336 | { 337 | return read_uint32(offsetof(XDEX_DEF::HEADER, class_defs_size), isBigEndian()); 338 | } 339 | 340 | quint32 XDEX::getHeader_class_defs_off() 341 | { 342 | return read_uint32(offsetof(XDEX_DEF::HEADER, class_defs_off), isBigEndian()); 343 | } 344 | 345 | quint32 XDEX::getHeader_data_size() 346 | { 347 | return read_uint32(offsetof(XDEX_DEF::HEADER, data_size), isBigEndian()); 348 | } 349 | 350 | quint32 XDEX::getHeader_data_off() 351 | { 352 | return read_uint32(offsetof(XDEX_DEF::HEADER, data_off), isBigEndian()); 353 | } 354 | 355 | void XDEX::setHeader_magic(quint32 value) 356 | { 357 | write_uint32(offsetof(XDEX_DEF::HEADER, magic), value, false); 358 | } 359 | 360 | void XDEX::setHeader_version(quint32 value) 361 | { 362 | write_uint32(offsetof(XDEX_DEF::HEADER, version), value, false); 363 | } 364 | 365 | void XDEX::setHeader_checksum(quint32 value) 366 | { 367 | write_uint32(offsetof(XDEX_DEF::HEADER, checksum), value, isBigEndian()); 368 | } 369 | 370 | void XDEX::setHeader_file_size(quint32 value) 371 | { 372 | write_uint32(offsetof(XDEX_DEF::HEADER, file_size), value, isBigEndian()); 373 | } 374 | 375 | void XDEX::setHeader_header_size(quint32 value) 376 | { 377 | write_uint32(offsetof(XDEX_DEF::HEADER, header_size), value, isBigEndian()); 378 | } 379 | 380 | void XDEX::setHeader_endian_tag(quint32 value) 381 | { 382 | write_uint32(offsetof(XDEX_DEF::HEADER, endian_tag), value); 383 | } 384 | 385 | void XDEX::setHeader_link_size(quint32 value) 386 | { 387 | write_uint32(offsetof(XDEX_DEF::HEADER, link_size), value, isBigEndian()); 388 | } 389 | 390 | void XDEX::setHeader_link_off(quint32 value) 391 | { 392 | write_uint32(offsetof(XDEX_DEF::HEADER, link_off), value, isBigEndian()); 393 | } 394 | 395 | void XDEX::setHeader_map_off(quint32 value) 396 | { 397 | write_uint32(offsetof(XDEX_DEF::HEADER, map_off), value, isBigEndian()); 398 | } 399 | 400 | void XDEX::setHeader_string_ids_size(quint32 value) 401 | { 402 | write_uint32(offsetof(XDEX_DEF::HEADER, string_ids_size), value, isBigEndian()); 403 | } 404 | 405 | void XDEX::setHeader_string_ids_off(quint32 value) 406 | { 407 | write_uint32(offsetof(XDEX_DEF::HEADER, string_ids_off), value, isBigEndian()); 408 | } 409 | 410 | void XDEX::setHeader_type_ids_size(quint32 value) 411 | { 412 | write_uint32(offsetof(XDEX_DEF::HEADER, type_ids_size), value, isBigEndian()); 413 | } 414 | 415 | void XDEX::setHeader_type_ids_off(quint32 value) 416 | { 417 | write_uint32(offsetof(XDEX_DEF::HEADER, type_ids_off), value, isBigEndian()); 418 | } 419 | 420 | void XDEX::setHeader_proto_ids_size(quint32 value) 421 | { 422 | write_uint32(offsetof(XDEX_DEF::HEADER, proto_ids_size), value, isBigEndian()); 423 | } 424 | 425 | void XDEX::setHeader_proto_ids_off(quint32 value) 426 | { 427 | write_uint32(offsetof(XDEX_DEF::HEADER, proto_ids_off), value, isBigEndian()); 428 | } 429 | 430 | void XDEX::setHeader_field_ids_size(quint32 value) 431 | { 432 | write_uint32(offsetof(XDEX_DEF::HEADER, field_ids_size), value, isBigEndian()); 433 | } 434 | 435 | void XDEX::setHeader_field_ids_off(quint32 value) 436 | { 437 | write_uint32(offsetof(XDEX_DEF::HEADER, field_ids_off), value, isBigEndian()); 438 | } 439 | 440 | void XDEX::setHeader_method_ids_size(quint32 value) 441 | { 442 | write_uint32(offsetof(XDEX_DEF::HEADER, method_ids_size), value, isBigEndian()); 443 | } 444 | 445 | void XDEX::setHeader_method_ids_off(quint32 value) 446 | { 447 | write_uint32(offsetof(XDEX_DEF::HEADER, method_ids_off), value, isBigEndian()); 448 | } 449 | 450 | void XDEX::setHeader_class_defs_size(quint32 value) 451 | { 452 | write_uint32(offsetof(XDEX_DEF::HEADER, class_defs_size), value, isBigEndian()); 453 | } 454 | 455 | void XDEX::setHeader_class_defs_off(quint32 value) 456 | { 457 | write_uint32(offsetof(XDEX_DEF::HEADER, class_defs_off), value, isBigEndian()); 458 | } 459 | 460 | void XDEX::setHeader_data_size(quint32 value) 461 | { 462 | write_uint32(offsetof(XDEX_DEF::HEADER, data_size), value, isBigEndian()); 463 | } 464 | 465 | void XDEX::setHeader_data_off(quint32 value) 466 | { 467 | write_uint32(offsetof(XDEX_DEF::HEADER, data_off), value, isBigEndian()); 468 | } 469 | 470 | XDEX_DEF::HEADER XDEX::getHeader() 471 | { 472 | return _readHEADER(0); 473 | } 474 | 475 | XDEX_DEF::HEADER XDEX::_readHEADER(qint64 nOffset) 476 | { 477 | XDEX_DEF::HEADER result = {}; 478 | 479 | bool bIsBigEndian = (read_uint32(nOffset + offsetof(XDEX_DEF::HEADER, endian_tag)) == 0x78563412); 480 | 481 | result.magic = read_uint32(nOffset + offsetof(XDEX_DEF::HEADER, magic), false); 482 | result.version = read_uint32(nOffset + offsetof(XDEX_DEF::HEADER, version), false); 483 | result.checksum = read_uint32(nOffset + offsetof(XDEX_DEF::HEADER, checksum), bIsBigEndian); 484 | // result.signature=getHeader_signature(); 485 | result.file_size = read_uint32(nOffset + offsetof(XDEX_DEF::HEADER, file_size), bIsBigEndian); 486 | result.header_size = read_uint32(nOffset + offsetof(XDEX_DEF::HEADER, header_size), bIsBigEndian); 487 | result.endian_tag = read_uint32(nOffset + offsetof(XDEX_DEF::HEADER, endian_tag), false); 488 | result.link_size = read_uint32(nOffset + offsetof(XDEX_DEF::HEADER, link_size), bIsBigEndian); 489 | result.link_off = read_uint32(nOffset + offsetof(XDEX_DEF::HEADER, link_off), bIsBigEndian); 490 | result.map_off = read_uint32(nOffset + offsetof(XDEX_DEF::HEADER, map_off), bIsBigEndian); 491 | result.string_ids_size = read_uint32(nOffset + offsetof(XDEX_DEF::HEADER, string_ids_size), bIsBigEndian); 492 | result.string_ids_off = read_uint32(nOffset + offsetof(XDEX_DEF::HEADER, string_ids_off), bIsBigEndian); 493 | result.type_ids_size = read_uint32(nOffset + offsetof(XDEX_DEF::HEADER, type_ids_size), bIsBigEndian); 494 | result.type_ids_off = read_uint32(nOffset + offsetof(XDEX_DEF::HEADER, type_ids_off), bIsBigEndian); 495 | result.proto_ids_size = read_uint32(nOffset + offsetof(XDEX_DEF::HEADER, proto_ids_size), bIsBigEndian); 496 | result.proto_ids_off = read_uint32(nOffset + offsetof(XDEX_DEF::HEADER, proto_ids_off), bIsBigEndian); 497 | result.field_ids_size = read_uint32(nOffset + offsetof(XDEX_DEF::HEADER, field_ids_size), bIsBigEndian); 498 | result.field_ids_off = read_uint32(nOffset + offsetof(XDEX_DEF::HEADER, field_ids_off), bIsBigEndian); 499 | result.method_ids_size = read_uint32(nOffset + offsetof(XDEX_DEF::HEADER, method_ids_size), bIsBigEndian); 500 | result.method_ids_off = read_uint32(nOffset + offsetof(XDEX_DEF::HEADER, method_ids_off), bIsBigEndian); 501 | result.class_defs_size = read_uint32(nOffset + offsetof(XDEX_DEF::HEADER, class_defs_size), bIsBigEndian); 502 | result.class_defs_off = read_uint32(offsetof(XDEX_DEF::HEADER, class_defs_off), bIsBigEndian); 503 | result.data_size = read_uint32(offsetof(XDEX_DEF::HEADER, data_size), bIsBigEndian); 504 | result.data_off = read_uint32(offsetof(XDEX_DEF::HEADER, data_off), bIsBigEndian); 505 | 506 | return result; 507 | } 508 | 509 | quint32 XDEX::getHeaderSize() 510 | { 511 | return sizeof(XDEX_DEF::HEADER); 512 | } 513 | 514 | QList XDEX::getMapItems(PDSTRUCT *pPdStruct) 515 | { 516 | QList listResult; 517 | 518 | qint64 nMapOff = getHeader_map_off(); 519 | if (nMapOff == 0) { 520 | return listResult; 521 | } 522 | 523 | const qint64 nFileSize = getSize(); 524 | if ((nMapOff < 0) || (nMapOff > (nFileSize - 4))) { // need at least 4 bytes for size 525 | return listResult; 526 | } 527 | 528 | bool bIsBigEndian = isBigEndian(); 529 | 530 | quint32 nDeclaredItems = read_uint32(nMapOff, bIsBigEndian); 531 | qint64 nOffset = nMapOff + 4; 532 | 533 | // Compute maximum possible entries given file size to avoid OOB 534 | qint64 nAvail = nFileSize - nOffset; 535 | qint64 nMaxItemsBySize = (nAvail >= 0) ? (nAvail / 12) : 0; 536 | quint32 nItems = static_cast(qMin(nDeclaredItems, qMin(nMaxItemsBySize, 0x10000))); 537 | 538 | qint32 _nFreeIndex = XBinary::getFreeIndex(pPdStruct); 539 | XBinary::setPdStructInit(pPdStruct, _nFreeIndex, nItems); 540 | 541 | for (quint32 i = 0; (i < nItems) && XBinary::isPdStructNotCanceled(pPdStruct); i++) { 542 | XDEX_DEF::MAP_ITEM map_item = {}; 543 | 544 | map_item.nType = read_uint16(nOffset, bIsBigEndian); 545 | // skip 2 bytes reserved/unused at +2 546 | map_item.nCount = read_uint32(nOffset + 4, bIsBigEndian); 547 | map_item.nOffset = read_uint32(nOffset + 8, bIsBigEndian); 548 | 549 | listResult.append(map_item); 550 | 551 | nOffset += 12; 552 | 553 | XBinary::setPdStructCurrentIncrement(pPdStruct, _nFreeIndex); 554 | } 555 | 556 | XBinary::setPdStructFinished(pPdStruct, _nFreeIndex); 557 | 558 | return listResult; 559 | } 560 | 561 | bool XDEX::compareMapItems(QList *pListMaps, QList *pListIDs, PDSTRUCT *pPdStruct) 562 | { 563 | bool bResult = false; 564 | 565 | qint32 nNumberOfMapItems = pListMaps->count(); 566 | qint32 nNumberOfIDs = pListIDs->count(); 567 | 568 | qint32 nCurrentMapItem = 0; 569 | qint32 nCurrentID = 0; 570 | 571 | while ((nCurrentMapItem < nNumberOfMapItems) && (nCurrentID < nNumberOfIDs) && XBinary::isPdStructNotCanceled(pPdStruct)) { 572 | bResult = false; 573 | 574 | if (pListMaps->at(nCurrentMapItem).nType == pListIDs->at(nCurrentID)) { 575 | bResult = true; 576 | nCurrentMapItem++; 577 | nCurrentID++; 578 | } else { 579 | nCurrentID++; 580 | } 581 | } 582 | 583 | bResult = (bResult) && (nCurrentMapItem == qMin(nNumberOfMapItems, nNumberOfIDs)); 584 | 585 | return bResult; 586 | } 587 | 588 | quint32 XDEX::getMapItemsHash(QList *pListMaps, PDSTRUCT *pPdStruct) 589 | { 590 | quint32 nResult = 0; 591 | 592 | if (!pListMaps) { 593 | return 0; 594 | } 595 | 596 | const qint32 nCount = pListMaps->count(); 597 | 598 | // Initialize CRC32 (EDB88320) with standard init value 599 | quint32 nCrc = 0xFFFFFFFF; 600 | quint32 *pTable = XBinary::_getCRC32Table_EDB88320(); 601 | 602 | qint32 _nFreeIndex = XBinary::getFreeIndex(pPdStruct); 603 | XBinary::setPdStructInit(pPdStruct, _nFreeIndex, nCount); 604 | 605 | for (qint32 i = 0; (i < nCount) && XBinary::isPdStructNotCanceled(pPdStruct); i++) { 606 | const XDEX_DEF::MAP_ITEM &mi = pListMaps->at(i); 607 | 608 | // Serialize only the type (sequence of types) in little-endian order 609 | char b16[2] = {static_cast(mi.nType & 0xFF), static_cast((mi.nType >> 8) & 0xFF)}; 610 | 611 | nCrc = XBinary::_getCRC32(b16, 2, nCrc, pTable); 612 | 613 | XBinary::setPdStructCurrentIncrement(pPdStruct, _nFreeIndex); 614 | } 615 | 616 | XBinary::setPdStructFinished(pPdStruct, _nFreeIndex); 617 | 618 | if (XBinary::isPdStructStopped(pPdStruct)) { 619 | return 0; 620 | } 621 | 622 | // Finalize CRC 623 | nResult = nCrc ^ 0xFFFFFFFF; 624 | 625 | return nResult; 626 | } 627 | 628 | bool XDEX::isMapItemPresent(quint16 nType, QList *pMapItems, PDSTRUCT *pPdStruct) 629 | { 630 | bool bResult = false; 631 | 632 | qint32 nNumberOfItems = pMapItems->count(); 633 | 634 | for (qint32 i = 0; (i < nNumberOfItems) && XBinary::isPdStructNotCanceled(pPdStruct); i++) { 635 | if (pMapItems->at(i).nType == nType) { 636 | bResult = true; 637 | 638 | break; 639 | } 640 | } 641 | 642 | return bResult; 643 | } 644 | 645 | QMap XDEX::getTypes() 646 | { 647 | QMap mapResult; 648 | 649 | mapResult.insert(0x0000, "TYPE_HEADER_ITEM"); 650 | mapResult.insert(0x0001, "TYPE_STRING_ID_ITEM"); 651 | mapResult.insert(0x0002, "TYPE_TYPE_ID_ITEM"); 652 | mapResult.insert(0x0003, "TYPE_PROTO_ID_ITEM"); 653 | mapResult.insert(0x0004, "TYPE_FIELD_ID_ITEM"); 654 | mapResult.insert(0x0005, "TYPE_METHOD_ID_ITEM"); 655 | mapResult.insert(0x0006, "TYPE_CLASS_DEF_ITEM"); 656 | mapResult.insert(0x0007, "TYPE_CALL_SITE_ID_ITEM"); 657 | mapResult.insert(0x0008, "TYPE_METHOD_HANDLE_ITEM"); 658 | mapResult.insert(0x1000, "TYPE_MAP_LIST"); 659 | mapResult.insert(0x1001, "TYPE_TYPE_LIST"); 660 | mapResult.insert(0x1002, "TYPE_ANNOTATION_SET_REF_LIST"); 661 | mapResult.insert(0x1003, "TYPE_ANNOTATION_SET_ITEM"); 662 | mapResult.insert(0x2000, "TYPE_CLASS_DATA_ITEM"); 663 | mapResult.insert(0x2001, "TYPE_CODE_ITEM"); 664 | mapResult.insert(0x2002, "TYPE_STRING_DATA_ITEM"); 665 | mapResult.insert(0x2003, "TYPE_DEBUG_INFO_ITEM"); 666 | mapResult.insert(0x2004, "TYPE_ANNOTATION_ITEM"); 667 | mapResult.insert(0x2005, "TYPE_ENCODED_ARRAY_ITEM"); 668 | mapResult.insert(0x2006, "TYPE_ANNOTATIONS_DIRECTORY_ITEM"); 669 | mapResult.insert(0xF000, "TYPE_HIDDENAPI_CLASS_DATA_ITEM"); 670 | 671 | return mapResult; 672 | } 673 | 674 | QMap XDEX::getTypesS() 675 | { 676 | QMap mapResult; 677 | 678 | mapResult.insert(0x0000, "HEADER_ITEM"); 679 | mapResult.insert(0x0001, "STRING_ID_ITEM"); 680 | mapResult.insert(0x0002, "TYPE_ID_ITEM"); 681 | mapResult.insert(0x0003, "PROTO_ID_ITEM"); 682 | mapResult.insert(0x0004, "FIELD_ID_ITEM"); 683 | mapResult.insert(0x0005, "METHOD_ID_ITEM"); 684 | mapResult.insert(0x0006, "CLASS_DEF_ITEM"); 685 | mapResult.insert(0x0007, "CALL_SITE_ID_ITEM"); 686 | mapResult.insert(0x0008, "METHOD_HANDLE_ITEM"); 687 | mapResult.insert(0x1000, "MAP_LIST"); 688 | mapResult.insert(0x1001, "TYPE_LIST"); 689 | mapResult.insert(0x1002, "ANNOTATION_SET_REF_LIST"); 690 | mapResult.insert(0x1003, "ANNOTATION_SET_ITEM"); 691 | mapResult.insert(0x2000, "CLASS_DATA_ITEM"); 692 | mapResult.insert(0x2001, "CODE_ITEM"); 693 | mapResult.insert(0x2002, "STRING_DATA_ITEM"); 694 | mapResult.insert(0x2003, "DEBUG_INFO_ITEM"); 695 | mapResult.insert(0x2004, "ANNOTATION_ITEM"); 696 | mapResult.insert(0x2005, "ENCODED_ARRAY_ITEM"); 697 | mapResult.insert(0x2006, "ANNOTATIONS_DIRECTORY_ITEM"); 698 | mapResult.insert(0xF000, "HIDDENAPI_CLASS_DATA_ITEM"); 699 | 700 | return mapResult; 701 | } 702 | 703 | XDEX_DEF::MAP_ITEM XDEX::getMapItem(quint16 nType, QList *pMapItems, PDSTRUCT *pPdStruct) 704 | { 705 | XDEX_DEF::MAP_ITEM result = {}; 706 | 707 | qint32 nCount = pMapItems->count(); 708 | 709 | for (qint32 i = 0; (i < nCount) && XBinary::isPdStructNotCanceled(pPdStruct); i++) { 710 | if (pMapItems->at(i).nType == nType) { 711 | result = pMapItems->at(i); 712 | 713 | break; 714 | } 715 | } 716 | 717 | return result; 718 | } 719 | 720 | QList XDEX::getList_STRING_ITEM_ID(PDSTRUCT *pPdStruct) 721 | { 722 | QList listMapItems = getMapItems(pPdStruct); 723 | 724 | return getList_STRING_ITEM_ID(&listMapItems, pPdStruct); 725 | } 726 | 727 | QList XDEX::getList_STRING_ITEM_ID(QList *pListMapItems, PDSTRUCT *pPdStruct) 728 | { 729 | QList listResult; 730 | 731 | bool bIsBigEndian = isBigEndian(); 732 | 733 | XDEX_DEF::MAP_ITEM mapItem = getMapItem(XDEX_DEF::TYPE_STRING_ID_ITEM, pListMapItems, pPdStruct); 734 | 735 | QByteArray baData = read_array_process(mapItem.nOffset, mapItem.nCount * sizeof(XDEX_DEF::STRING_ITEM_ID), pPdStruct); 736 | char *pData = baData.data(); 737 | qint32 nSize = baData.size() / (qint32)sizeof(XDEX_DEF::STRING_ITEM_ID); 738 | 739 | for (qint32 i = 0; (i < nSize) && XBinary::isPdStructNotCanceled(pPdStruct); i++) { 740 | qint64 nOffset = sizeof(XDEX_DEF::STRING_ITEM_ID) * i; 741 | 742 | XDEX_DEF::STRING_ITEM_ID record = {}; 743 | 744 | record.string_data_off = _read_int32(pData + nOffset + offsetof(XDEX_DEF::STRING_ITEM_ID, string_data_off), bIsBigEndian); 745 | 746 | listResult.append(record); 747 | } 748 | 749 | return listResult; 750 | } 751 | 752 | QList XDEX::getList_TYPE_ITEM_ID(PDSTRUCT *pPdStruct) 753 | { 754 | QList listMapItems = getMapItems(pPdStruct); 755 | 756 | return getList_TYPE_ITEM_ID(&listMapItems, pPdStruct); 757 | } 758 | 759 | QList XDEX::getList_TYPE_ITEM_ID(QList *pListMapItems, PDSTRUCT *pPdStruct) 760 | { 761 | QList listResult; 762 | 763 | XDEX_DEF::MAP_ITEM mapItem = getMapItem(XDEX_DEF::TYPE_TYPE_ID_ITEM, pListMapItems, pPdStruct); 764 | bool bIsBigEndian = isBigEndian(); 765 | 766 | QByteArray baData = read_array_process(mapItem.nOffset, mapItem.nCount * sizeof(XDEX_DEF::TYPE_ITEM_ID), pPdStruct); 767 | char *pData = baData.data(); 768 | qint32 nSize = baData.size() / (qint32)sizeof(XDEX_DEF::TYPE_ITEM_ID); 769 | 770 | for (qint32 i = 0; (i < nSize) && XBinary::isPdStructNotCanceled(pPdStruct); i++) { 771 | qint64 nOffset = sizeof(XDEX_DEF::TYPE_ITEM_ID) * i; 772 | 773 | XDEX_DEF::TYPE_ITEM_ID record = {}; 774 | 775 | record.descriptor_idx = _read_int32(pData + nOffset + offsetof(XDEX_DEF::TYPE_ITEM_ID, descriptor_idx), bIsBigEndian); 776 | 777 | listResult.append(record); 778 | } 779 | 780 | return listResult; 781 | } 782 | 783 | QList XDEX::getList_PROTO_ITEM_ID(QList *pListMapItems, PDSTRUCT *pPdStruct) 784 | { 785 | QList listResult; 786 | 787 | XDEX_DEF::MAP_ITEM mapItem = getMapItem(XDEX_DEF::TYPE_PROTO_ID_ITEM, pListMapItems, pPdStruct); 788 | bool bIsBigEndian = isBigEndian(); 789 | 790 | QByteArray baData = read_array_process(mapItem.nOffset, mapItem.nCount * sizeof(XDEX_DEF::PROTO_ITEM_ID), pPdStruct); 791 | char *pData = baData.data(); 792 | qint32 nSize = baData.size() / (qint32)sizeof(XDEX_DEF::PROTO_ITEM_ID); 793 | 794 | for (qint32 i = 0; (i < nSize) && XBinary::isPdStructNotCanceled(pPdStruct); i++) { 795 | qint64 nOffset = sizeof(XDEX_DEF::PROTO_ITEM_ID) * i; 796 | 797 | XDEX_DEF::PROTO_ITEM_ID record = {}; 798 | 799 | record.shorty_idx = _read_int32(pData + nOffset + offsetof(XDEX_DEF::PROTO_ITEM_ID, shorty_idx), bIsBigEndian); 800 | record.return_type_idx = _read_int32(pData + nOffset + offsetof(XDEX_DEF::PROTO_ITEM_ID, return_type_idx), bIsBigEndian); 801 | record.parameters_off = _read_int32(pData + nOffset + offsetof(XDEX_DEF::PROTO_ITEM_ID, parameters_off), bIsBigEndian); 802 | 803 | listResult.append(record); 804 | } 805 | 806 | return listResult; 807 | } 808 | 809 | QList XDEX::getList_FIELD_ITEM_ID(QList *pListMapItems, PDSTRUCT *pPdStruct) 810 | { 811 | QList listResult; 812 | 813 | XDEX_DEF::MAP_ITEM mapItem = getMapItem(XDEX_DEF::TYPE_FIELD_ID_ITEM, pListMapItems, pPdStruct); 814 | bool bIsBigEndian = isBigEndian(); 815 | 816 | QByteArray baData = read_array_process(mapItem.nOffset, mapItem.nCount * sizeof(XDEX_DEF::FIELD_ITEM_ID), pPdStruct); 817 | char *pData = baData.data(); 818 | qint32 nSize = baData.size() / (qint32)sizeof(XDEX_DEF::FIELD_ITEM_ID); 819 | 820 | qint32 _nFreeIndex = XBinary::getFreeIndex(pPdStruct); 821 | XBinary::setPdStructInit(pPdStruct, _nFreeIndex, nSize); 822 | 823 | for (qint32 i = 0; (i < nSize) && XBinary::isPdStructNotCanceled(pPdStruct); i++) { 824 | qint64 nOffset = sizeof(XDEX_DEF::FIELD_ITEM_ID) * i; 825 | 826 | XDEX_DEF::FIELD_ITEM_ID record = {}; 827 | 828 | record.class_idx = _read_int16(pData + nOffset + offsetof(XDEX_DEF::FIELD_ITEM_ID, class_idx), bIsBigEndian); 829 | record.type_idx = _read_int16(pData + nOffset + offsetof(XDEX_DEF::FIELD_ITEM_ID, type_idx), bIsBigEndian); 830 | record.name_idx = _read_int32(pData + nOffset + offsetof(XDEX_DEF::FIELD_ITEM_ID, name_idx), bIsBigEndian); 831 | 832 | listResult.append(record); 833 | 834 | XBinary::setPdStructCurrentIncrement(pPdStruct, _nFreeIndex); 835 | } 836 | 837 | XBinary::setPdStructFinished(pPdStruct, _nFreeIndex); 838 | 839 | return listResult; 840 | } 841 | 842 | QList XDEX::getList_METHOD_ITEM_ID(QList *pListMapItems, PDSTRUCT *pPdStruct) 843 | { 844 | QList listResult; 845 | 846 | XDEX_DEF::MAP_ITEM mapItem = getMapItem(XDEX_DEF::TYPE_METHOD_ID_ITEM, pListMapItems, pPdStruct); 847 | bool bIsBigEndian = isBigEndian(); 848 | 849 | QByteArray baData = read_array_process(mapItem.nOffset, mapItem.nCount * sizeof(XDEX_DEF::METHOD_ITEM_ID), pPdStruct); 850 | char *pData = baData.data(); 851 | qint32 nSize = baData.size() / (qint32)sizeof(XDEX_DEF::METHOD_ITEM_ID); 852 | 853 | qint32 _nFreeIndex = XBinary::getFreeIndex(pPdStruct); 854 | XBinary::setPdStructInit(pPdStruct, _nFreeIndex, nSize); 855 | 856 | for (qint32 i = 0; (i < nSize) && XBinary::isPdStructNotCanceled(pPdStruct); i++) { 857 | qint64 nOffset = sizeof(XDEX_DEF::METHOD_ITEM_ID) * i; 858 | 859 | XDEX_DEF::METHOD_ITEM_ID record = {}; 860 | 861 | record.class_idx = _read_int16(pData + nOffset + offsetof(XDEX_DEF::METHOD_ITEM_ID, class_idx), bIsBigEndian); 862 | record.proto_idx = _read_int16(pData + nOffset + offsetof(XDEX_DEF::METHOD_ITEM_ID, proto_idx), bIsBigEndian); 863 | record.name_idx = _read_int32(pData + nOffset + offsetof(XDEX_DEF::METHOD_ITEM_ID, name_idx), bIsBigEndian); 864 | 865 | listResult.append(record); 866 | 867 | XBinary::setPdStructCurrentIncrement(pPdStruct, _nFreeIndex); 868 | } 869 | 870 | XBinary::setPdStructFinished(pPdStruct, _nFreeIndex); 871 | 872 | return listResult; 873 | } 874 | 875 | QList XDEX::getList_CLASS_ITEM_DEF(QList *pListMapItems, PDSTRUCT *pPdStruct) 876 | { 877 | QList listResult; 878 | 879 | XDEX_DEF::MAP_ITEM mapItem = getMapItem(XDEX_DEF::TYPE_CLASS_DEF_ITEM, pListMapItems, pPdStruct); 880 | bool bIsBigEndian = isBigEndian(); 881 | 882 | QByteArray baData = read_array_process(mapItem.nOffset, mapItem.nCount * sizeof(XDEX_DEF::CLASS_ITEM_DEF), pPdStruct); 883 | char *pData = baData.data(); 884 | qint32 nSize = baData.size() / (qint32)sizeof(XDEX_DEF::CLASS_ITEM_DEF); 885 | 886 | for (qint32 i = 0; (i < nSize) && XBinary::isPdStructNotCanceled(pPdStruct); i++) { 887 | qint64 nOffset = sizeof(XDEX_DEF::CLASS_ITEM_DEF) * i; 888 | 889 | XDEX_DEF::CLASS_ITEM_DEF record = {}; 890 | 891 | record.class_idx = _read_int32(pData + nOffset + offsetof(XDEX_DEF::CLASS_ITEM_DEF, class_idx), bIsBigEndian); 892 | record.access_flags = _read_int32(pData + nOffset + offsetof(XDEX_DEF::CLASS_ITEM_DEF, access_flags), bIsBigEndian); 893 | record.superclass_idx = _read_int32(pData + nOffset + offsetof(XDEX_DEF::CLASS_ITEM_DEF, superclass_idx), bIsBigEndian); 894 | record.interfaces_off = _read_int32(pData + nOffset + offsetof(XDEX_DEF::CLASS_ITEM_DEF, interfaces_off), bIsBigEndian); 895 | record.source_file_idx = _read_int32(pData + nOffset + offsetof(XDEX_DEF::CLASS_ITEM_DEF, source_file_idx), bIsBigEndian); 896 | record.annotations_off = _read_int32(pData + nOffset + offsetof(XDEX_DEF::CLASS_ITEM_DEF, annotations_off), bIsBigEndian); 897 | record.class_data_off = _read_int32(pData + nOffset + offsetof(XDEX_DEF::CLASS_ITEM_DEF, class_data_off), bIsBigEndian); 898 | record.static_values_off = _read_int32(pData + nOffset + offsetof(XDEX_DEF::CLASS_ITEM_DEF, static_values_off), bIsBigEndian); 899 | 900 | listResult.append(record); 901 | } 902 | 903 | return listResult; 904 | } 905 | 906 | QList XDEX::getStrings(QList *pMapItems, PDSTRUCT *pPdStruct) 907 | { 908 | QList listResult; 909 | 910 | bool bIsBigEndian = isBigEndian(); 911 | 912 | XDEX_DEF::MAP_ITEM map_strings = getMapItem(XDEX_DEF::TYPE_STRING_ID_ITEM, pMapItems, pPdStruct); 913 | 914 | QByteArray baData = read_array_process(getHeader_data_off(), getHeader_data_size(), pPdStruct); 915 | 916 | qint32 _nFreeIndex = XBinary::getFreeIndex(pPdStruct); 917 | XBinary::setPdStructInit(pPdStruct, _nFreeIndex, map_strings.nCount); 918 | 919 | for (quint32 i = 0; (i < map_strings.nCount) && XBinary::isPdStructNotCanceled(pPdStruct); i++) { 920 | QString sString = _getString(map_strings, i, bIsBigEndian, baData.data(), baData.size(), getHeader_data_off()); 921 | 922 | listResult.append(sString); 923 | XBinary::setPdStructCurrentIncrement(pPdStruct, _nFreeIndex); 924 | } 925 | 926 | XBinary::setPdStructFinished(pPdStruct, _nFreeIndex); 927 | 928 | return listResult; 929 | } 930 | 931 | QString XDEX::_getString(XDEX_DEF::MAP_ITEM map_stringIdItem, quint32 nIndex, bool bIsBigEndian) 932 | { 933 | QString sResult; 934 | 935 | if (nIndex < map_stringIdItem.nCount) { 936 | qint64 nOffset = map_stringIdItem.nOffset + sizeof(quint32) * nIndex; 937 | 938 | quint32 nStringsOffset = read_uint32(nOffset, bIsBigEndian); 939 | 940 | sResult = XBinary::_read_utf8String(nStringsOffset); 941 | } 942 | 943 | return sResult; 944 | } 945 | 946 | QString XDEX::_getString(XDEX_DEF::MAP_ITEM map_stringIdItem, quint32 nIndex, bool bIsBigEndian, char *pData, qint32 nDataSize, qint32 nDataOffset) 947 | { 948 | QString sResult; 949 | 950 | if (nIndex < map_stringIdItem.nCount) { 951 | qint64 nOffset = map_stringIdItem.nOffset + sizeof(quint32) * nIndex; 952 | 953 | qint32 nStringsOffset = (qint32)read_uint32(nOffset, bIsBigEndian); 954 | 955 | sResult = XBinary::_read_utf8String(nStringsOffset, pData, nDataSize, nDataOffset); 956 | } 957 | 958 | return sResult; 959 | } 960 | 961 | QString XDEX::_getTypeItemtString(XDEX_DEF::MAP_ITEM map_stringIdItem, XDEX_DEF::MAP_ITEM map_typeItemId, quint32 nIndex, bool bIsBigEndian) 962 | { 963 | QString sResult; 964 | 965 | if (nIndex < map_typeItemId.nCount) { 966 | quint32 nID = read_uint32(map_typeItemId.nOffset + sizeof(quint32) * nIndex, bIsBigEndian); 967 | 968 | sResult = _getString(map_stringIdItem, nID, bIsBigEndian); 969 | } 970 | 971 | return sResult; 972 | } 973 | 974 | QList XDEX::_getTypeList(qint64 nOffset, bool bIsBigEndian, PDSTRUCT *pPdStruct) 975 | { 976 | QList listResult; 977 | 978 | if (nOffset) { 979 | quint32 nCount = read_uint32(nOffset, bIsBigEndian); 980 | 981 | for (quint32 i = 0; (i < nCount) && XBinary::isPdStructNotCanceled(pPdStruct); i++) { 982 | quint32 nType = read_uint32(nOffset + sizeof(quint32) * (1 + i), bIsBigEndian); 983 | listResult.append(nType); 984 | } 985 | } 986 | 987 | return listResult; 988 | } 989 | 990 | QList XDEX::getTypeItemStrings(QList *pMapItems, QList *pListStrings, PDSTRUCT *pPdStruct) 991 | { 992 | QList listResult; 993 | 994 | bool bIsBigEndian = isBigEndian(); 995 | 996 | qint32 nStringsCount = pListStrings->count(); 997 | 998 | XDEX_DEF::MAP_ITEM map_items = getMapItem(XDEX_DEF::TYPE_TYPE_ID_ITEM, pMapItems, pPdStruct); 999 | 1000 | qint32 _nFreeIndex = XBinary::getFreeIndex(pPdStruct); 1001 | XBinary::setPdStructInit(pPdStruct, _nFreeIndex, map_items.nCount); 1002 | 1003 | for (quint32 i = 0; (i < map_items.nCount) && XBinary::isPdStructNotCanceled(pPdStruct); i++) { 1004 | quint32 nOffset = map_items.nOffset + sizeof(quint32) * i; 1005 | 1006 | quint32 nItem = read_uint32(nOffset, bIsBigEndian); 1007 | 1008 | if (((qint32)nItem > 0) && ((qint32)nItem < nStringsCount)) { 1009 | QString sString = pListStrings->at(nItem); 1010 | 1011 | listResult.append(sString); 1012 | } 1013 | 1014 | XBinary::setPdStructCurrentIncrement(pPdStruct, _nFreeIndex); 1015 | } 1016 | 1017 | XBinary::setPdStructFinished(pPdStruct, _nFreeIndex); 1018 | 1019 | return listResult; 1020 | } 1021 | 1022 | void XDEX::getProtoIdItems(QList *pMapItems, PDSTRUCT *pPdStruct) 1023 | { 1024 | bool bIsBigEndian = isBigEndian(); 1025 | 1026 | XDEX_DEF::MAP_ITEM map_protoIdItem = getMapItem(XDEX_DEF::TYPE_PROTO_ID_ITEM, pMapItems, pPdStruct); 1027 | XDEX_DEF::MAP_ITEM map_typeIdItem = getMapItem(XDEX_DEF::TYPE_TYPE_ID_ITEM, pMapItems, pPdStruct); 1028 | XDEX_DEF::MAP_ITEM map_stringIdItem = getMapItem(XDEX_DEF::TYPE_STRING_ID_ITEM, pMapItems, pPdStruct); 1029 | 1030 | for (quint32 i = 0; (i < map_protoIdItem.nCount) && XBinary::isPdStructNotCanceled(pPdStruct); i++) { 1031 | quint32 nOffset = map_protoIdItem.nOffset + sizeof(XDEX_DEF::PROTO_ITEM_ID) * i; 1032 | 1033 | XDEX_DEF::PROTO_ITEM_ID record = {}; 1034 | 1035 | record.shorty_idx = read_uint32(nOffset + offsetof(XDEX_DEF::PROTO_ITEM_ID, shorty_idx), bIsBigEndian); 1036 | record.return_type_idx = read_uint32(nOffset + offsetof(XDEX_DEF::PROTO_ITEM_ID, return_type_idx), bIsBigEndian); 1037 | record.parameters_off = read_uint32(nOffset + offsetof(XDEX_DEF::PROTO_ITEM_ID, parameters_off), bIsBigEndian); 1038 | 1039 | QString sProto = _getString(map_stringIdItem, record.shorty_idx, bIsBigEndian); 1040 | QString sRet = _getTypeItemtString(map_stringIdItem, map_typeIdItem, record.return_type_idx, bIsBigEndian); 1041 | 1042 | QList listParams = _getTypeList(record.parameters_off, bIsBigEndian, pPdStruct); 1043 | 1044 | // QString sDebugString=QString("%1 %2").arg(sRet,sProto); 1045 | 1046 | // qDebug("%s",sDebugString.toLatin1().data()); 1047 | } 1048 | } 1049 | 1050 | QString XDEX::getStringItemIdString(XDEX_DEF::STRING_ITEM_ID stringItemId) 1051 | { 1052 | QString sResult; 1053 | 1054 | sResult = _read_utf8String(stringItemId.string_data_off); 1055 | 1056 | return sResult; 1057 | } 1058 | 1059 | QString XDEX::getStringItemIdString(XDEX_DEF::STRING_ITEM_ID stringItemId, char *pData, qint32 nDataSize, qint32 nDataOffset) 1060 | { 1061 | QString sResult; 1062 | 1063 | sResult = XBinary::_read_utf8String(stringItemId.string_data_off, pData, nDataSize, nDataOffset); 1064 | 1065 | return sResult; 1066 | } 1067 | 1068 | QString XDEX::getStringItemIdString(QList *pList, qint32 nIndex, char *pData, qint32 nDataSize, qint32 nDataOffset) 1069 | { 1070 | QString sResult; 1071 | 1072 | if ((nIndex > 0) && (nIndex < pList->count())) { 1073 | sResult = getStringItemIdString(pList->at(nIndex), pData, nDataSize, nDataOffset); 1074 | } 1075 | 1076 | return sResult; 1077 | } 1078 | 1079 | QString XDEX::getTypeItemIdString(XDEX_DEF::TYPE_ITEM_ID typeItemId, XDEX_DEF::MAP_ITEM *pMapItemStrings) 1080 | { 1081 | QString sResult; 1082 | 1083 | bool bIsBigEndian = isBigEndian(); 1084 | 1085 | sResult = _read_utf8String(read_uint32(pMapItemStrings->nOffset + sizeof(quint32) * typeItemId.descriptor_idx, bIsBigEndian)); 1086 | 1087 | return sResult; 1088 | } 1089 | 1090 | QString XDEX::getTypeItemIdString(XDEX_DEF::TYPE_ITEM_ID typeItemId, XDEX_DEF::MAP_ITEM *pMapItemStrings, char *pData, qint32 nDataSize, qint32 nDataOffset) 1091 | { 1092 | QString sResult; 1093 | 1094 | bool bIsBigEndian = isBigEndian(); 1095 | 1096 | sResult = XBinary::_read_utf8String(read_uint32(pMapItemStrings->nOffset + sizeof(quint32) * typeItemId.descriptor_idx, bIsBigEndian), pData, nDataSize, nDataOffset); 1097 | 1098 | return sResult; 1099 | } 1100 | 1101 | QString XDEX::getTypeItemIdString(QList *pList, qint32 nIndex, XDEX_DEF::MAP_ITEM *pMapItemStrings, char *pData, qint32 nDataSize, 1102 | qint32 nDataOffset) 1103 | { 1104 | QString sResult; 1105 | 1106 | if ((nIndex > 0) && (nIndex < pList->count())) { 1107 | sResult = getTypeItemIdString(pList->at(nIndex), pMapItemStrings, pData, nDataSize, nDataOffset); 1108 | } 1109 | 1110 | return sResult; 1111 | } 1112 | 1113 | QString XDEX::getProtoItemIdString(XDEX_DEF::PROTO_ITEM_ID protoItemId, XDEX_DEF::MAP_ITEM *pMapItemStrings) 1114 | { 1115 | QString sResult; 1116 | 1117 | bool bIsBigEndian = isBigEndian(); 1118 | 1119 | QString sPrototype = _read_utf8String(read_uint32(pMapItemStrings->nOffset + sizeof(quint32) * protoItemId.shorty_idx, bIsBigEndian)); 1120 | QString sReturn = _read_utf8String(read_uint32(pMapItemStrings->nOffset + sizeof(quint32) * protoItemId.return_type_idx, bIsBigEndian)); 1121 | sResult = QString("%1 %2()").arg(sReturn, sPrototype); 1122 | 1123 | return sResult; 1124 | } 1125 | 1126 | QMap XDEX::getHeaderMagics() 1127 | { 1128 | QMap mapResult; 1129 | 1130 | mapResult.insert(0x0A786564, "Magic"); 1131 | 1132 | return mapResult; 1133 | } 1134 | 1135 | QMap XDEX::getHeaderVersions() 1136 | { 1137 | QMap mapResult; 1138 | 1139 | mapResult.insert(0x00353330, "035"); 1140 | // 036 invalid 1141 | mapResult.insert(0x00373330, "037"); 1142 | mapResult.insert(0x00383330, "038"); 1143 | mapResult.insert(0x00393330, "039"); 1144 | 1145 | return mapResult; 1146 | } 1147 | 1148 | QMap XDEX::getHeaderEndianTags() 1149 | { 1150 | QMap mapResult; 1151 | 1152 | mapResult.insert(0x12345678, "Little endian"); 1153 | mapResult.insert(0x78563412, "Big endian"); 1154 | 1155 | return mapResult; 1156 | } 1157 | 1158 | bool XDEX::isStringPoolSorted(QList *pMapItems, PDSTRUCT *pPdStruct) 1159 | { 1160 | bool bResult = true; 1161 | 1162 | bool bIsBigEndian = isBigEndian(); 1163 | 1164 | XDEX_DEF::MAP_ITEM map_strings = getMapItem(XDEX_DEF::TYPE_STRING_ID_ITEM, pMapItems, pPdStruct); 1165 | 1166 | qint32 nPrevStringOffset = 0; 1167 | 1168 | for (quint32 i = 0; (i < map_strings.nCount) && XBinary::isPdStructNotCanceled(pPdStruct); i++) { 1169 | qint64 nOffset = map_strings.nOffset + sizeof(quint32) * i; 1170 | 1171 | qint32 nStringOffset = (qint32)read_uint32(nOffset, bIsBigEndian); 1172 | 1173 | if (nStringOffset < nPrevStringOffset) { 1174 | bResult = false; 1175 | 1176 | break; 1177 | } 1178 | 1179 | nPrevStringOffset = nStringOffset; 1180 | } 1181 | 1182 | return bResult; 1183 | } 1184 | 1185 | bool XDEX::isFieldNamesUnicode(QList *pListIDs, QList *pListStrings, PDSTRUCT *pPdStruct) 1186 | { 1187 | bool bResult = false; 1188 | 1189 | qint32 nNumberOfIds = pListIDs->count(); 1190 | qint32 nNumberOfStrings = pListStrings->count(); 1191 | 1192 | for (qint32 i = 0; (i < nNumberOfIds) && XBinary::isPdStructNotCanceled(pPdStruct); i++) { 1193 | QString sString = getStringByIndex(pListStrings, pListIDs->at(i).name_idx, nNumberOfStrings); 1194 | 1195 | if (XBinary::isStringUnicode(sString)) { 1196 | bResult = true; 1197 | break; 1198 | } 1199 | } 1200 | 1201 | return bResult; 1202 | } 1203 | 1204 | bool XDEX::isMethodNamesUnicode(QList *pListIDs, QList *pListStrings, PDSTRUCT *pPdStruct) 1205 | { 1206 | bool bResult = false; 1207 | 1208 | qint32 nNumberOfIds = pListIDs->count(); 1209 | qint32 nNumberOfStrings = pListStrings->count(); 1210 | 1211 | for (qint32 i = 0; (i < nNumberOfIds) && XBinary::isPdStructNotCanceled(pPdStruct); i++) { 1212 | QString sString = getStringByIndex(pListStrings, pListIDs->at(i).name_idx, nNumberOfStrings); 1213 | 1214 | if (XBinary::isStringUnicode(sString)) { 1215 | bResult = true; 1216 | break; 1217 | } 1218 | } 1219 | 1220 | return bResult; 1221 | } 1222 | 1223 | qint64 XDEX::getDataSizeByType(qint32 nType, qint64 nOffset, qint32 nCount, bool bIsBigEndian, PDSTRUCT *pPdStruct) 1224 | { 1225 | Q_UNUSED(pPdStruct) 1226 | 1227 | qint64 nResult = 0; 1228 | 1229 | if (nType == XDEX_DEF::TYPE_HEADER_ITEM) { 1230 | nResult = 0x70; 1231 | } else if ((nType == XDEX_DEF::TYPE_STRING_ID_ITEM) || (nType == XDEX_DEF::TYPE_TYPE_ID_ITEM) || (nType == XDEX_DEF::TYPE_CALL_SITE_ID_ITEM)) { 1232 | nResult = nCount * 4; 1233 | } else if (nType == XDEX_DEF::TYPE_PROTO_ID_ITEM) { 1234 | nResult = nCount * 12; 1235 | } else if ((nType == XDEX_DEF::TYPE_FIELD_ID_ITEM) || (nType == XDEX_DEF::TYPE_METHOD_ID_ITEM) || (nType == XDEX_DEF::TYPE_METHOD_HANDLE_ITEM)) { 1236 | nResult = nCount * 8; 1237 | } else if (nType == XDEX_DEF::TYPE_CLASS_DEF_ITEM) { 1238 | nResult = nCount * 32; 1239 | } else if (nType == XDEX_DEF::TYPE_MAP_LIST) { 1240 | nCount = read_uint32(nOffset, bIsBigEndian); 1241 | nResult = 4 + (nCount * 12); 1242 | } else if (nType == XDEX_DEF::TYPE_TYPE_LIST) { 1243 | nResult = 4 + (nCount * 2); 1244 | } else if ((nType == XDEX_DEF::TYPE_ANNOTATION_SET_REF_LIST) || (nType == XDEX_DEF::TYPE_ANNOTATION_SET_ITEM)) { 1245 | nResult = 4 + (nCount * 4); 1246 | } else if ((nType == XDEX_DEF::TYPE_CLASS_DATA_ITEM) || (nType == XDEX_DEF::TYPE_CODE_ITEM) || (nType == XDEX_DEF::TYPE_STRING_DATA_ITEM) || 1247 | (nType == XDEX_DEF::TYPE_DEBUG_INFO_ITEM) || (nType == XDEX_DEF::TYPE_ANNOTATION_ITEM) || (nType == XDEX_DEF::TYPE_ENCODED_ARRAY_ITEM) || 1248 | (nType == XDEX_DEF::TYPE_ANNOTATIONS_DIRECTORY_ITEM) || (nType == XDEX_DEF::TYPE_HIDDENAPI_CLASS_DATA_ITEM)) { 1249 | nResult = 1; // TODO 1250 | } 1251 | 1252 | return nResult; 1253 | } 1254 | 1255 | QString XDEX::getFileFormatExt() 1256 | { 1257 | return "dex"; 1258 | } 1259 | 1260 | QString XDEX::getFileFormatExtsString() 1261 | { 1262 | return "DEX(dex)"; 1263 | } 1264 | 1265 | QString XDEX::getMIMEString() 1266 | { 1267 | return "application/vnd.android.dex"; 1268 | } 1269 | 1270 | QString XDEX::structIDToString(quint32 nID) 1271 | { 1272 | return XBinary::XCONVERT_idToTransString(nID, _TABLE_DEX_STRUCTID, sizeof(_TABLE_DEX_STRUCTID) / sizeof(XBinary::XCONVERT)); 1273 | } 1274 | 1275 | QList XDEX::getFileParts(quint32 nFileParts, qint32 nLimit, PDSTRUCT *pPdStruct) 1276 | { 1277 | QList listResult; 1278 | 1279 | XDEX_DEF::HEADER header = getHeader(); 1280 | 1281 | if (nFileParts & FILEPART_HEADER) { 1282 | listResult.append(getFPART(FILEPART_HEADER, tr("Header"), 0, header.header_size, -1, 0)); 1283 | } 1284 | 1285 | qint64 nMaxOffset = header.data_off + header.data_size; 1286 | 1287 | if (nFileParts & FILEPART_REGION) { 1288 | if (header.link_size) listResult.append(getFPART(FILEPART_REGION, "link", header.link_off, header.link_size, -1, 0)); 1289 | if (header.string_ids_size) listResult.append(getFPART(FILEPART_REGION, "string_ids", header.string_ids_off, header.string_ids_size * 4, -1, 0)); 1290 | if (header.type_ids_size) listResult.append(getFPART(FILEPART_REGION, "type_ids", header.type_ids_off, header.type_ids_size * 4, -1, 0)); 1291 | if (header.proto_ids_size) listResult.append(getFPART(FILEPART_REGION, "proto_ids", header.proto_ids_off, header.proto_ids_size * 12, -1, 0)); 1292 | if (header.field_ids_size) listResult.append(getFPART(FILEPART_REGION, "field_ids", header.field_ids_off, header.field_ids_size * 8, -1, 0)); 1293 | if (header.method_ids_size) listResult.append(getFPART(FILEPART_REGION, "method_ids", header.method_ids_off, header.method_ids_size * 8, -1, 0)); 1294 | if (header.class_defs_size) listResult.append(getFPART(FILEPART_REGION, "class_defs", header.class_defs_off, header.class_defs_size * 32, -1, 0)); 1295 | if (header.data_size) listResult.append(getFPART(FILEPART_REGION, "data", header.data_off, header.data_size, -1, 0)); 1296 | } 1297 | 1298 | if ((nFileParts & FILEPART_SECTION) || (nFileParts & FILEPART_OVERLAY)) { 1299 | QMap mapTypes = getTypes(); 1300 | bool bIsBigEndian = isBigEndian(); 1301 | 1302 | QList listMapItems = getMapItems(pPdStruct); 1303 | 1304 | qint32 nNumberOfRecords = listMapItems.count(); 1305 | 1306 | for (qint32 i = 0; (i < nNumberOfRecords) && XBinary::isPdStructNotCanceled(pPdStruct); i++) { 1307 | XDEX_DEF::MAP_ITEM mapItem = listMapItems.at(i); 1308 | 1309 | FPART record = {}; 1310 | record.nFileOffset = mapItem.nOffset; 1311 | record.nFileSize = getDataSizeByType(mapItem.nType, mapItem.nOffset, mapItem.nCount, bIsBigEndian, pPdStruct); 1312 | 1313 | if (nFileParts & FILEPART_SECTION) { 1314 | record.nVirtualAddress = -1; 1315 | record.filePart = FILEPART_SECTION; 1316 | record.sName = mapTypes.value(mapItem.nType); 1317 | listResult.append(record); 1318 | } 1319 | 1320 | if (record.nFileOffset + record.nFileSize > nMaxOffset) { 1321 | nMaxOffset = record.nFileOffset + record.nFileSize; 1322 | } 1323 | } 1324 | } 1325 | 1326 | if (nFileParts & FILEPART_OVERLAY) { 1327 | if (nMaxOffset < getSize()) { 1328 | listResult.append(getFPART(FILEPART_OVERLAY, tr("Overlay"), nMaxOffset, getSize() - nMaxOffset, -1, 0)); 1329 | } 1330 | } 1331 | 1332 | return listResult; 1333 | } 1334 | 1335 | QList XDEX::getDataHeaders(const DATA_HEADERS_OPTIONS &dataHeadersOptions, PDSTRUCT *pPdStruct) 1336 | { 1337 | QList listResult; 1338 | 1339 | if (dataHeadersOptions.nID == STRUCTID_UNKNOWN) { 1340 | DATA_HEADERS_OPTIONS _dataHeadersOptions = dataHeadersOptions; 1341 | _dataHeadersOptions.bChildren = true; 1342 | _dataHeadersOptions.dsID_parent = _addDefaultHeaders(&listResult, pPdStruct); 1343 | _dataHeadersOptions.dhMode = XBinary::DHMODE_HEADER; 1344 | _dataHeadersOptions.fileType = dataHeadersOptions.pMemoryMap->fileType; 1345 | _dataHeadersOptions.nID = STRUCTID_HEADER; 1346 | _dataHeadersOptions.nLocation = 0; 1347 | _dataHeadersOptions.locType = XBinary::LT_OFFSET; 1348 | 1349 | listResult.append(getDataHeaders(_dataHeadersOptions, pPdStruct)); 1350 | } else { 1351 | qint64 nStartOffset = locationToOffset(dataHeadersOptions.pMemoryMap, dataHeadersOptions.locType, dataHeadersOptions.nLocation); 1352 | 1353 | if (nStartOffset != -1) { 1354 | if (dataHeadersOptions.nID == STRUCTID_HEADER) { 1355 | XBinary::DATA_HEADER dataHeader = _initDataHeader(dataHeadersOptions, XDEX::structIDToString(dataHeadersOptions.nID)); 1356 | dataHeader.nSize = sizeof(XDEX_DEF::HEADER); 1357 | 1358 | dataHeader.listRecords.append( 1359 | getDataRecordDV(offsetof(XDEX_DEF::HEADER, magic), 4, "magic", VT_UINT32, DRF_UNKNOWN, ENDIAN_LITTLE, XDEX::getHeaderMagics(), VL_TYPE_LIST)); 1360 | dataHeader.listRecords.append( 1361 | getDataRecordDV(offsetof(XDEX_DEF::HEADER, version), 4, "version", VT_UINT32, DRF_UNKNOWN, ENDIAN_LITTLE, XDEX::getHeaderVersions(), VL_TYPE_LIST)); 1362 | dataHeader.listRecords.append( 1363 | getDataRecord(offsetof(XDEX_DEF::HEADER, checksum), 4, "checksum", VT_UINT32, DRF_UNKNOWN, dataHeadersOptions.pMemoryMap->endian)); 1364 | dataHeader.listRecords.append( 1365 | getDataRecord(offsetof(XDEX_DEF::HEADER, signature), 20, "signature", VT_BYTE_ARRAY, DRF_UNKNOWN, dataHeadersOptions.pMemoryMap->endian)); 1366 | dataHeader.listRecords.append( 1367 | getDataRecord(offsetof(XDEX_DEF::HEADER, file_size), 4, "file_size", VT_UINT32, DRF_SIZE, dataHeadersOptions.pMemoryMap->endian)); 1368 | dataHeader.listRecords.append( 1369 | getDataRecord(offsetof(XDEX_DEF::HEADER, header_size), 4, "header_size", VT_UINT32, DRF_SIZE, dataHeadersOptions.pMemoryMap->endian)); 1370 | dataHeader.listRecords.append(getDataRecordDV(offsetof(XDEX_DEF::HEADER, endian_tag), 4, "endian_tag", VT_UINT32, DRF_UNKNOWN, ENDIAN_LITTLE, 1371 | XDEX::getHeaderEndianTags(), VL_TYPE_LIST)); 1372 | dataHeader.listRecords.append( 1373 | getDataRecord(offsetof(XDEX_DEF::HEADER, link_size), 4, "link_size", VT_UINT32, DRF_SIZE, dataHeadersOptions.pMemoryMap->endian)); 1374 | dataHeader.listRecords.append( 1375 | getDataRecord(offsetof(XDEX_DEF::HEADER, link_off), 4, "link_off", VT_UINT32, DRF_OFFSET, dataHeadersOptions.pMemoryMap->endian)); 1376 | dataHeader.listRecords.append( 1377 | getDataRecord(offsetof(XDEX_DEF::HEADER, map_off), 4, "map_off", VT_UINT32, DRF_OFFSET, dataHeadersOptions.pMemoryMap->endian)); 1378 | dataHeader.listRecords.append( 1379 | getDataRecord(offsetof(XDEX_DEF::HEADER, string_ids_size), 4, "string_ids_size", VT_UINT32, DRF_SIZE, dataHeadersOptions.pMemoryMap->endian)); 1380 | dataHeader.listRecords.append( 1381 | getDataRecord(offsetof(XDEX_DEF::HEADER, string_ids_off), 4, "string_ids_off", VT_UINT32, DRF_OFFSET, dataHeadersOptions.pMemoryMap->endian)); 1382 | dataHeader.listRecords.append( 1383 | getDataRecord(offsetof(XDEX_DEF::HEADER, type_ids_size), 4, "type_ids_size", VT_UINT32, DRF_SIZE, dataHeadersOptions.pMemoryMap->endian)); 1384 | dataHeader.listRecords.append( 1385 | getDataRecord(offsetof(XDEX_DEF::HEADER, type_ids_off), 4, "type_ids_off", VT_UINT32, DRF_OFFSET, dataHeadersOptions.pMemoryMap->endian)); 1386 | dataHeader.listRecords.append( 1387 | getDataRecord(offsetof(XDEX_DEF::HEADER, proto_ids_size), 4, "proto_ids_size", VT_UINT32, DRF_SIZE, dataHeadersOptions.pMemoryMap->endian)); 1388 | dataHeader.listRecords.append( 1389 | getDataRecord(offsetof(XDEX_DEF::HEADER, proto_ids_off), 4, "proto_ids_off", VT_UINT32, DRF_OFFSET, dataHeadersOptions.pMemoryMap->endian)); 1390 | dataHeader.listRecords.append( 1391 | getDataRecord(offsetof(XDEX_DEF::HEADER, field_ids_size), 4, "field_ids_size", VT_UINT32, DRF_SIZE, dataHeadersOptions.pMemoryMap->endian)); 1392 | dataHeader.listRecords.append( 1393 | getDataRecord(offsetof(XDEX_DEF::HEADER, field_ids_off), 4, "field_ids_off", VT_UINT32, DRF_OFFSET, dataHeadersOptions.pMemoryMap->endian)); 1394 | dataHeader.listRecords.append( 1395 | getDataRecord(offsetof(XDEX_DEF::HEADER, method_ids_size), 4, "method_ids_size", VT_UINT32, DRF_SIZE, dataHeadersOptions.pMemoryMap->endian)); 1396 | dataHeader.listRecords.append( 1397 | getDataRecord(offsetof(XDEX_DEF::HEADER, method_ids_off), 4, "method_ids_off", VT_UINT32, DRF_OFFSET, dataHeadersOptions.pMemoryMap->endian)); 1398 | dataHeader.listRecords.append( 1399 | getDataRecord(offsetof(XDEX_DEF::HEADER, class_defs_size), 4, "class_defs_size", VT_UINT32, DRF_SIZE, dataHeadersOptions.pMemoryMap->endian)); 1400 | dataHeader.listRecords.append( 1401 | getDataRecord(offsetof(XDEX_DEF::HEADER, class_defs_off), 4, "class_defs_off", VT_UINT32, DRF_OFFSET, dataHeadersOptions.pMemoryMap->endian)); 1402 | dataHeader.listRecords.append( 1403 | getDataRecord(offsetof(XDEX_DEF::HEADER, data_size), 4, "data_size", VT_UINT32, DRF_SIZE, dataHeadersOptions.pMemoryMap->endian)); 1404 | dataHeader.listRecords.append( 1405 | getDataRecord(offsetof(XDEX_DEF::HEADER, data_off), 4, "data_off", VT_UINT32, DRF_OFFSET, dataHeadersOptions.pMemoryMap->endian)); 1406 | 1407 | listResult.append(dataHeader); 1408 | 1409 | if (dataHeadersOptions.bChildren && isPdStructNotCanceled(pPdStruct)) { 1410 | if (dataHeadersOptions.nID == STRUCTID_HEADER) { 1411 | XDEX_DEF::HEADER header = _readHEADER(nStartOffset); 1412 | 1413 | if (header.string_ids_off && header.string_ids_size) { 1414 | DATA_HEADERS_OPTIONS _dataHeadersOptions = dataHeadersOptions; 1415 | _dataHeadersOptions.bChildren = true; 1416 | _dataHeadersOptions.dsID_parent = dataHeader.dsID; 1417 | _dataHeadersOptions.dhMode = XBinary::DHMODE_TABLE; 1418 | _dataHeadersOptions.nID = STRUCTID_STRING_IDS_LIST; 1419 | _dataHeadersOptions.nLocation = dataHeader.nLocation + header.string_ids_off; 1420 | _dataHeadersOptions.locType = dataHeader.locType; 1421 | _dataHeadersOptions.nCount = header.string_ids_size / 4; 1422 | _dataHeadersOptions.nSize = header.string_ids_size; 1423 | 1424 | listResult.append(getDataHeaders(_dataHeadersOptions, pPdStruct)); 1425 | } 1426 | if (header.type_ids_off && header.type_ids_size) { 1427 | DATA_HEADERS_OPTIONS _dataHeadersOptions = dataHeadersOptions; 1428 | _dataHeadersOptions.bChildren = true; 1429 | _dataHeadersOptions.dsID_parent = dataHeader.dsID; 1430 | _dataHeadersOptions.dhMode = XBinary::DHMODE_TABLE; 1431 | _dataHeadersOptions.nID = STRUCTID_TYPE_IDS_LIST; 1432 | _dataHeadersOptions.nLocation = dataHeader.nLocation + header.type_ids_off; 1433 | _dataHeadersOptions.locType = dataHeader.locType; 1434 | _dataHeadersOptions.nCount = header.type_ids_size / 4; 1435 | _dataHeadersOptions.nSize = header.type_ids_size; 1436 | 1437 | listResult.append(getDataHeaders(_dataHeadersOptions, pPdStruct)); 1438 | } 1439 | if (header.proto_ids_off && header.proto_ids_size) { 1440 | DATA_HEADERS_OPTIONS _dataHeadersOptions = dataHeadersOptions; 1441 | _dataHeadersOptions.bChildren = true; 1442 | _dataHeadersOptions.dsID_parent = dataHeader.dsID; 1443 | _dataHeadersOptions.dhMode = XBinary::DHMODE_TABLE; 1444 | _dataHeadersOptions.nID = STRUCTID_PROTO_IDS_LIST; 1445 | _dataHeadersOptions.nLocation = dataHeader.nLocation + header.proto_ids_off; 1446 | _dataHeadersOptions.locType = dataHeader.locType; 1447 | _dataHeadersOptions.nCount = header.proto_ids_size / 12; 1448 | _dataHeadersOptions.nSize = header.proto_ids_size; 1449 | 1450 | listResult.append(getDataHeaders(_dataHeadersOptions, pPdStruct)); 1451 | } 1452 | if (header.field_ids_off && header.field_ids_size) { 1453 | DATA_HEADERS_OPTIONS _dataHeadersOptions = dataHeadersOptions; 1454 | _dataHeadersOptions.bChildren = true; 1455 | _dataHeadersOptions.dsID_parent = dataHeader.dsID; 1456 | _dataHeadersOptions.dhMode = XBinary::DHMODE_TABLE; 1457 | _dataHeadersOptions.nID = STRUCTID_FIELD_IDS_LIST; 1458 | _dataHeadersOptions.nLocation = dataHeader.nLocation + header.field_ids_off; 1459 | _dataHeadersOptions.locType = dataHeader.locType; 1460 | _dataHeadersOptions.nCount = header.field_ids_size / 8; 1461 | _dataHeadersOptions.nSize = header.field_ids_size; 1462 | 1463 | listResult.append(getDataHeaders(_dataHeadersOptions, pPdStruct)); 1464 | } 1465 | if (header.method_ids_off && header.method_ids_size) { 1466 | DATA_HEADERS_OPTIONS _dataHeadersOptions = dataHeadersOptions; 1467 | _dataHeadersOptions.bChildren = true; 1468 | _dataHeadersOptions.dsID_parent = dataHeader.dsID; 1469 | _dataHeadersOptions.dhMode = XBinary::DHMODE_TABLE; 1470 | _dataHeadersOptions.nID = STRUCTID_METHOD_IDS_LIST; 1471 | _dataHeadersOptions.nLocation = dataHeader.nLocation + header.method_ids_off; 1472 | _dataHeadersOptions.locType = dataHeader.locType; 1473 | _dataHeadersOptions.nCount = header.method_ids_size / 8; 1474 | _dataHeadersOptions.nSize = header.method_ids_size; 1475 | 1476 | listResult.append(getDataHeaders(_dataHeadersOptions, pPdStruct)); 1477 | } 1478 | if (header.class_defs_off && header.class_defs_size) { 1479 | DATA_HEADERS_OPTIONS _dataHeadersOptions = dataHeadersOptions; 1480 | _dataHeadersOptions.bChildren = true; 1481 | _dataHeadersOptions.dsID_parent = dataHeader.dsID; 1482 | _dataHeadersOptions.dhMode = XBinary::DHMODE_TABLE; 1483 | _dataHeadersOptions.nID = STRUCTID_CLASS_DEFS_LIST; 1484 | _dataHeadersOptions.nLocation = dataHeader.nLocation + header.class_defs_off; 1485 | _dataHeadersOptions.locType = dataHeader.locType; 1486 | _dataHeadersOptions.nCount = header.class_defs_size / 32; 1487 | _dataHeadersOptions.nSize = header.class_defs_size; 1488 | 1489 | listResult.append(getDataHeaders(_dataHeadersOptions, pPdStruct)); 1490 | } 1491 | if (header.data_off && header.data_size) { 1492 | DATA_HEADERS_OPTIONS _dataHeadersOptions = dataHeadersOptions; 1493 | _dataHeadersOptions.bChildren = true; 1494 | _dataHeadersOptions.dsID_parent = dataHeader.dsID; 1495 | _dataHeadersOptions.dhMode = XBinary::DHMODE_HEX; 1496 | _dataHeadersOptions.nID = STRUCTID_DATA_LIST; 1497 | _dataHeadersOptions.nLocation = dataHeader.nLocation + header.data_off; 1498 | _dataHeadersOptions.locType = dataHeader.locType; 1499 | _dataHeadersOptions.nCount = header.data_size; 1500 | _dataHeadersOptions.nSize = header.data_size; 1501 | 1502 | listResult.append(getDataHeaders(_dataHeadersOptions, pPdStruct)); 1503 | } 1504 | if (header.link_off && header.link_size) { 1505 | DATA_HEADERS_OPTIONS _dataHeadersOptions = dataHeadersOptions; 1506 | _dataHeadersOptions.bChildren = true; 1507 | _dataHeadersOptions.dsID_parent = dataHeader.dsID; 1508 | _dataHeadersOptions.dhMode = XBinary::DHMODE_HEX; 1509 | _dataHeadersOptions.nID = STRUCTID_LINK_LIST; 1510 | _dataHeadersOptions.nLocation = dataHeader.nLocation + header.link_off; 1511 | _dataHeadersOptions.locType = dataHeader.locType; 1512 | _dataHeadersOptions.nCount = header.link_size; 1513 | _dataHeadersOptions.nSize = header.link_size; 1514 | 1515 | listResult.append(getDataHeaders(_dataHeadersOptions, pPdStruct)); 1516 | } 1517 | if (header.map_off) { 1518 | DATA_HEADERS_OPTIONS _dataHeadersOptions = dataHeadersOptions; 1519 | _dataHeadersOptions.bChildren = true; 1520 | _dataHeadersOptions.dsID_parent = dataHeader.dsID; 1521 | _dataHeadersOptions.dhMode = XBinary::DHMODE_TABLE; 1522 | _dataHeadersOptions.nID = STRUCTID_MAP_LIST; 1523 | _dataHeadersOptions.nLocation = dataHeader.nLocation + header.map_off + 4; 1524 | _dataHeadersOptions.locType = dataHeader.locType; 1525 | 1526 | _dataHeadersOptions.nCount = read_uint32(nStartOffset + header.map_off, (dataHeadersOptions.pMemoryMap->endian == ENDIAN_BIG)); 1527 | _dataHeadersOptions.nCount = qMin(_dataHeadersOptions.nCount, (qint32)1000); // to avoid crazy values 1528 | 1529 | listResult.append(getDataHeaders(_dataHeadersOptions, pPdStruct)); 1530 | } 1531 | } 1532 | } 1533 | } else if (dataHeadersOptions.nID == STRUCTID_STRING_IDS_LIST) { 1534 | XBinary::DATA_HEADER dataHeader = _initDataHeader(dataHeadersOptions, XDEX::structIDToString(dataHeadersOptions.nID)); 1535 | dataHeader.nSize = dataHeadersOptions.nCount * 4; 1536 | 1537 | dataHeader.listRecords.append(getDataRecord(0, 4, "string_id", VT_UINT32, DRF_UNKNOWN, dataHeadersOptions.pMemoryMap->endian)); 1538 | 1539 | listResult.append(dataHeader); 1540 | } else if (dataHeadersOptions.nID == STRUCTID_TYPE_IDS_LIST) { 1541 | XBinary::DATA_HEADER dataHeader = _initDataHeader(dataHeadersOptions, XDEX::structIDToString(dataHeadersOptions.nID)); 1542 | dataHeader.nSize = dataHeadersOptions.nCount * 4; 1543 | 1544 | dataHeader.listRecords.append(getDataRecord(0, 4, "type_id", VT_UINT32, DRF_UNKNOWN, dataHeadersOptions.pMemoryMap->endian)); 1545 | 1546 | listResult.append(dataHeader); 1547 | } else if (dataHeadersOptions.nID == STRUCTID_PROTO_IDS_LIST) { 1548 | XBinary::DATA_HEADER dataHeader = _initDataHeader(dataHeadersOptions, XDEX::structIDToString(dataHeadersOptions.nID)); 1549 | dataHeader.nSize = dataHeadersOptions.nCount * 12; 1550 | 1551 | dataHeader.listRecords.append(getDataRecord(0, 4, "shorty_idx", VT_UINT32, DRF_UNKNOWN, dataHeadersOptions.pMemoryMap->endian)); 1552 | dataHeader.listRecords.append(getDataRecord(4, 4, "return_type_idx", VT_UINT32, DRF_UNKNOWN, dataHeadersOptions.pMemoryMap->endian)); 1553 | dataHeader.listRecords.append(getDataRecord(8, 4, "parameters_off", VT_UINT32, DRF_UNKNOWN, dataHeadersOptions.pMemoryMap->endian)); 1554 | 1555 | listResult.append(dataHeader); 1556 | } else if (dataHeadersOptions.nID == STRUCTID_FIELD_IDS_LIST) { 1557 | XBinary::DATA_HEADER dataHeader = _initDataHeader(dataHeadersOptions, XDEX::structIDToString(dataHeadersOptions.nID)); 1558 | dataHeader.nSize = dataHeadersOptions.nCount * 8; 1559 | 1560 | dataHeader.listRecords.append(getDataRecord(0, 2, "class_idx", VT_UINT16, DRF_UNKNOWN, dataHeadersOptions.pMemoryMap->endian)); 1561 | dataHeader.listRecords.append(getDataRecord(2, 2, "type_idx", VT_UINT16, DRF_UNKNOWN, dataHeadersOptions.pMemoryMap->endian)); 1562 | dataHeader.listRecords.append(getDataRecord(4, 4, "name_idx", VT_UINT32, DRF_UNKNOWN, dataHeadersOptions.pMemoryMap->endian)); 1563 | 1564 | listResult.append(dataHeader); 1565 | } else if (dataHeadersOptions.nID == STRUCTID_METHOD_IDS_LIST) { 1566 | XBinary::DATA_HEADER dataHeader = _initDataHeader(dataHeadersOptions, XDEX::structIDToString(dataHeadersOptions.nID)); 1567 | dataHeader.nSize = dataHeadersOptions.nCount * 8; 1568 | 1569 | dataHeader.listRecords.append(getDataRecord(0, 2, "class_idx", VT_UINT16, DRF_UNKNOWN, dataHeadersOptions.pMemoryMap->endian)); 1570 | dataHeader.listRecords.append(getDataRecord(2, 2, "proto_idx", VT_UINT16, DRF_UNKNOWN, dataHeadersOptions.pMemoryMap->endian)); 1571 | dataHeader.listRecords.append(getDataRecord(4, 4, "name_idx", VT_UINT32, DRF_UNKNOWN, dataHeadersOptions.pMemoryMap->endian)); 1572 | 1573 | listResult.append(dataHeader); 1574 | } else if (dataHeadersOptions.nID == STRUCTID_MAP_LIST) { 1575 | XBinary::DATA_HEADER dataHeader = _initDataHeader(dataHeadersOptions, XDEX::structIDToString(dataHeadersOptions.nID)); 1576 | 1577 | dataHeader.listRecords.append(getDataRecord(0, 2, "type", VT_USHORT, DRF_UNKNOWN, dataHeadersOptions.pMemoryMap->endian)); 1578 | dataHeader.listRecords.append(getDataRecord(2, 2, "unused", VT_USHORT, DRF_UNKNOWN, dataHeadersOptions.pMemoryMap->endian)); 1579 | dataHeader.listRecords.append(getDataRecord(4, 4, "size", VT_UINT, DRF_SIZE, dataHeadersOptions.pMemoryMap->endian)); 1580 | dataHeader.listRecords.append(getDataRecord(8, 4, "offset", VT_UINT, DRF_OFFSET, dataHeadersOptions.pMemoryMap->endian)); 1581 | 1582 | listResult.append(dataHeader); 1583 | } 1584 | } 1585 | } 1586 | 1587 | return listResult; 1588 | } 1589 | 1590 | bool XDEX::isStringPoolSorted(PDSTRUCT *pPdStruct) 1591 | { 1592 | QList mapItems = getMapItems(pPdStruct); 1593 | 1594 | return isStringPoolSorted(&mapItems, pPdStruct); 1595 | } 1596 | --------------------------------------------------------------------------------