From a90f1017f7e48a2d4e017ab26e3ef91d482d1f58 Mon Sep 17 00:00:00 2001 From: = Date: Sat, 17 May 2025 22:56:57 -0400 Subject: [PATCH] add fastfile and zonefile support for all cods --- libs/encryption/encryption.cpp | 68 +- libs/encryption/encryption.h | 3 +- libs/encryption/encryption.pro | 12 + libs/fastfile/360/fastfile_cod10_360.cpp | 115 ++ libs/fastfile/360/fastfile_cod10_360.h | 20 + libs/fastfile/360/fastfile_cod11_360.cpp | 107 ++ libs/fastfile/360/fastfile_cod11_360.h | 20 + libs/fastfile/360/fastfile_cod12_360.cpp | 107 ++ libs/fastfile/360/fastfile_cod12_360.h | 20 + libs/fastfile/360/fastfile_cod2_360.cpp | 89 ++ libs/fastfile/360/fastfile_cod2_360.h | 20 + libs/fastfile/360/fastfile_cod4_360.cpp | 93 ++ libs/fastfile/360/fastfile_cod4_360.h | 20 + libs/fastfile/360/fastfile_cod5_360.cpp | 89 ++ libs/fastfile/360/fastfile_cod5_360.h | 20 + libs/fastfile/360/fastfile_cod6_360.cpp | 151 +++ libs/fastfile/360/fastfile_cod6_360.h | 20 + libs/fastfile/360/fastfile_cod7_360.cpp | 151 +++ libs/fastfile/360/fastfile_cod7_360.h | 20 + libs/fastfile/360/fastfile_cod8_360.cpp | 115 ++ libs/fastfile/360/fastfile_cod8_360.h | 20 + libs/fastfile/360/fastfile_cod9_360.cpp | 115 ++ libs/fastfile/360/fastfile_cod9_360.h | 20 + libs/fastfile/PC/fastfile_cod10_pc.cpp | 137 +++ libs/fastfile/PC/fastfile_cod10_pc.h | 20 + libs/fastfile/PC/fastfile_cod11_pc.cpp | 137 +++ libs/fastfile/PC/fastfile_cod11_pc.h | 20 + libs/fastfile/PC/fastfile_cod12_pc.cpp | 151 +++ libs/fastfile/PC/fastfile_cod12_pc.h | 20 + libs/fastfile/PC/fastfile_cod4_pc.cpp | 93 ++ libs/fastfile/PC/fastfile_cod4_pc.h | 20 + libs/fastfile/PC/fastfile_cod5_pc.cpp | 93 ++ libs/fastfile/PC/fastfile_cod5_pc.h | 20 + libs/fastfile/PC/fastfile_cod6_pc.cpp | 93 ++ libs/fastfile/PC/fastfile_cod6_pc.h | 20 + libs/fastfile/PC/fastfile_cod7_pc.cpp | 170 +++ libs/fastfile/PC/fastfile_cod7_pc.h | 20 + libs/fastfile/PC/fastfile_cod8_pc.cpp | 170 +++ libs/fastfile/PC/fastfile_cod8_pc.h | 20 + libs/fastfile/PC/fastfile_cod9_pc.cpp | 137 +++ libs/fastfile/PC/fastfile_cod9_pc.h | 20 + libs/fastfile/PS3/fastfile_cod10_ps3.cpp | 137 +++ libs/fastfile/PS3/fastfile_cod10_ps3.h | 20 + libs/fastfile/PS3/fastfile_cod11_ps3.cpp | 137 +++ libs/fastfile/PS3/fastfile_cod11_ps3.h | 20 + libs/fastfile/PS3/fastfile_cod12_ps3.cpp | 137 +++ libs/fastfile/PS3/fastfile_cod12_ps3.h | 20 + libs/fastfile/PS3/fastfile_cod4_ps3.cpp | 120 ++ libs/fastfile/PS3/fastfile_cod4_ps3.h | 20 + libs/fastfile/PS3/fastfile_cod5_ps3.cpp | 120 ++ libs/fastfile/PS3/fastfile_cod5_ps3.h | 20 + libs/fastfile/PS3/fastfile_cod6_ps3.cpp | 104 ++ libs/fastfile/PS3/fastfile_cod6_ps3.h | 20 + libs/fastfile/PS3/fastfile_cod7_ps3.cpp | 173 +++ libs/fastfile/PS3/fastfile_cod7_ps3.h | 20 + libs/fastfile/PS3/fastfile_cod8_ps3.cpp | 173 +++ libs/fastfile/PS3/fastfile_cod8_ps3.h | 20 + libs/fastfile/PS3/fastfile_cod9_ps3.cpp | 137 +++ libs/fastfile/PS3/fastfile_cod9_ps3.h | 20 + libs/fastfile/Wii/fastfile_cod4_wii.cpp | 114 ++ libs/fastfile/Wii/fastfile_cod4_wii.h | 20 + libs/fastfile/Wii/fastfile_cod7_wii.cpp | 114 ++ libs/fastfile/Wii/fastfile_cod7_wii.h | 20 + libs/fastfile/Wii/fastfile_cod8_wii.cpp | 114 ++ libs/fastfile/Wii/fastfile_cod8_wii.h | 20 + libs/fastfile/WiiU/fastfile_cod10_wiiu.cpp | 135 +++ libs/fastfile/WiiU/fastfile_cod10_wiiu.h | 20 + libs/fastfile/WiiU/fastfile_cod9_wiiu.cpp | 135 +++ libs/fastfile/WiiU/fastfile_cod9_wiiu.h | 20 + libs/fastfile/fastfile.pro | 56 +- libs/fastfile/fastfile_factory.h | 373 +++--- libs/zonefile/360/zonefile_cod10_360.cpp | 1072 +++++++++++++++++ libs/zonefile/360/zonefile_cod10_360.h | 52 + libs/zonefile/360/zonefile_cod11_360.cpp | 1072 +++++++++++++++++ libs/zonefile/360/zonefile_cod11_360.h | 52 + libs/zonefile/360/zonefile_cod12_360.cpp | 1207 ++++++++++++++++++++ libs/zonefile/360/zonefile_cod12_360.h | 53 + libs/zonefile/360/zonefile_cod2_360.cpp | 1112 ++++++++++++++++++ libs/zonefile/360/zonefile_cod2_360.h | 52 + libs/zonefile/360/zonefile_cod4_360.cpp | 1151 +++++++++++++++++++ libs/zonefile/360/zonefile_cod4_360.h | 54 + libs/zonefile/360/zonefile_cod5_360.cpp | 1151 +++++++++++++++++++ libs/zonefile/360/zonefile_cod5_360.h | 54 + libs/zonefile/360/zonefile_cod6_360.cpp | 1151 +++++++++++++++++++ libs/zonefile/360/zonefile_cod6_360.h | 54 + libs/zonefile/360/zonefile_cod7_360.cpp | 1077 +++++++++++++++++ libs/zonefile/360/zonefile_cod7_360.h | 52 + libs/zonefile/360/zonefile_cod8_360.cpp | 1077 +++++++++++++++++ libs/zonefile/360/zonefile_cod8_360.h | 52 + libs/zonefile/360/zonefile_cod9_360.cpp | 1072 +++++++++++++++++ libs/zonefile/360/zonefile_cod9_360.h | 52 + libs/zonefile/PC/zonefile_cod10_pc.cpp | 1072 +++++++++++++++++ libs/zonefile/PC/zonefile_cod10_pc.h | 52 + libs/zonefile/PC/zonefile_cod11_pc.cpp | 1072 +++++++++++++++++ libs/zonefile/PC/zonefile_cod11_pc.h | 52 + libs/zonefile/PC/zonefile_cod12_pc.cpp | 1207 ++++++++++++++++++++ libs/zonefile/PC/zonefile_cod12_pc.h | 53 + libs/zonefile/PC/zonefile_cod4_pc.cpp | 1140 ++++++++++++++++++ libs/zonefile/PC/zonefile_cod4_pc.h | 54 + libs/zonefile/PC/zonefile_cod5_pc.cpp | 1140 ++++++++++++++++++ libs/zonefile/PC/zonefile_cod5_pc.h | 54 + libs/zonefile/PC/zonefile_cod6_pc.cpp | 1140 ++++++++++++++++++ libs/zonefile/PC/zonefile_cod6_pc.h | 54 + libs/zonefile/PC/zonefile_cod7_pc.cpp | 1077 +++++++++++++++++ libs/zonefile/PC/zonefile_cod7_pc.h | 52 + libs/zonefile/PC/zonefile_cod8_pc.cpp | 1077 +++++++++++++++++ libs/zonefile/PC/zonefile_cod8_pc.h | 52 + libs/zonefile/PC/zonefile_cod9_pc.cpp | 1072 +++++++++++++++++ libs/zonefile/PC/zonefile_cod9_pc.h | 52 + libs/zonefile/PS3/zonefile_cod10_ps3.cpp | 1072 +++++++++++++++++ libs/zonefile/PS3/zonefile_cod10_ps3.h | 52 + libs/zonefile/PS3/zonefile_cod11_ps3.cpp | 1072 +++++++++++++++++ libs/zonefile/PS3/zonefile_cod11_ps3.h | 52 + libs/zonefile/PS3/zonefile_cod12_ps3.cpp | 1072 +++++++++++++++++ libs/zonefile/PS3/zonefile_cod12_ps3.h | 52 + libs/zonefile/PS3/zonefile_cod4_ps3.cpp | 1139 ++++++++++++++++++ libs/zonefile/PS3/zonefile_cod4_ps3.h | 54 + libs/zonefile/PS3/zonefile_cod5_ps3.cpp | 1139 ++++++++++++++++++ libs/zonefile/PS3/zonefile_cod5_ps3.h | 54 + libs/zonefile/PS3/zonefile_cod6_ps3.cpp | 1139 ++++++++++++++++++ libs/zonefile/PS3/zonefile_cod6_ps3.h | 54 + libs/zonefile/PS3/zonefile_cod7_ps3.cpp | 1077 +++++++++++++++++ libs/zonefile/PS3/zonefile_cod7_ps3.h | 52 + libs/zonefile/PS3/zonefile_cod8_ps3.cpp | 1077 +++++++++++++++++ libs/zonefile/PS3/zonefile_cod8_ps3.h | 52 + libs/zonefile/PS3/zonefile_cod9_ps3.cpp | 1072 +++++++++++++++++ libs/zonefile/PS3/zonefile_cod9_ps3.h | 52 + libs/zonefile/Wii/zonefile_cod4_wii.cpp | 1077 +++++++++++++++++ libs/zonefile/Wii/zonefile_cod4_wii.h | 52 + libs/zonefile/Wii/zonefile_cod7_wii.cpp | 1077 +++++++++++++++++ libs/zonefile/Wii/zonefile_cod7_wii.h | 52 + libs/zonefile/Wii/zonefile_cod8_wii.cpp | 1077 +++++++++++++++++ libs/zonefile/Wii/zonefile_cod8_wii.h | 52 + libs/zonefile/WiiU/zonefile_cod10_wiiu.cpp | 1072 +++++++++++++++++ libs/zonefile/WiiU/zonefile_cod10_wiiu.h | 52 + libs/zonefile/WiiU/zonefile_cod9_wiiu.cpp | 1072 +++++++++++++++++ libs/zonefile/WiiU/zonefile_cod9_wiiu.h | 52 + libs/zonefile/zonefile.pro | 55 +- 138 files changed, 43319 insertions(+), 180 deletions(-) create mode 100644 libs/fastfile/360/fastfile_cod10_360.cpp create mode 100644 libs/fastfile/360/fastfile_cod10_360.h create mode 100644 libs/fastfile/360/fastfile_cod11_360.cpp create mode 100644 libs/fastfile/360/fastfile_cod11_360.h create mode 100644 libs/fastfile/360/fastfile_cod12_360.cpp create mode 100644 libs/fastfile/360/fastfile_cod12_360.h create mode 100644 libs/fastfile/360/fastfile_cod2_360.cpp create mode 100644 libs/fastfile/360/fastfile_cod2_360.h create mode 100644 libs/fastfile/360/fastfile_cod4_360.cpp create mode 100644 libs/fastfile/360/fastfile_cod4_360.h create mode 100644 libs/fastfile/360/fastfile_cod5_360.cpp create mode 100644 libs/fastfile/360/fastfile_cod5_360.h create mode 100644 libs/fastfile/360/fastfile_cod6_360.cpp create mode 100644 libs/fastfile/360/fastfile_cod6_360.h create mode 100644 libs/fastfile/360/fastfile_cod7_360.cpp create mode 100644 libs/fastfile/360/fastfile_cod7_360.h create mode 100644 libs/fastfile/360/fastfile_cod8_360.cpp create mode 100644 libs/fastfile/360/fastfile_cod8_360.h create mode 100644 libs/fastfile/360/fastfile_cod9_360.cpp create mode 100644 libs/fastfile/360/fastfile_cod9_360.h create mode 100644 libs/fastfile/PC/fastfile_cod10_pc.cpp create mode 100644 libs/fastfile/PC/fastfile_cod10_pc.h create mode 100644 libs/fastfile/PC/fastfile_cod11_pc.cpp create mode 100644 libs/fastfile/PC/fastfile_cod11_pc.h create mode 100644 libs/fastfile/PC/fastfile_cod12_pc.cpp create mode 100644 libs/fastfile/PC/fastfile_cod12_pc.h create mode 100644 libs/fastfile/PC/fastfile_cod4_pc.cpp create mode 100644 libs/fastfile/PC/fastfile_cod4_pc.h create mode 100644 libs/fastfile/PC/fastfile_cod5_pc.cpp create mode 100644 libs/fastfile/PC/fastfile_cod5_pc.h create mode 100644 libs/fastfile/PC/fastfile_cod6_pc.cpp create mode 100644 libs/fastfile/PC/fastfile_cod6_pc.h create mode 100644 libs/fastfile/PC/fastfile_cod7_pc.cpp create mode 100644 libs/fastfile/PC/fastfile_cod7_pc.h create mode 100644 libs/fastfile/PC/fastfile_cod8_pc.cpp create mode 100644 libs/fastfile/PC/fastfile_cod8_pc.h create mode 100644 libs/fastfile/PC/fastfile_cod9_pc.cpp create mode 100644 libs/fastfile/PC/fastfile_cod9_pc.h create mode 100644 libs/fastfile/PS3/fastfile_cod10_ps3.cpp create mode 100644 libs/fastfile/PS3/fastfile_cod10_ps3.h create mode 100644 libs/fastfile/PS3/fastfile_cod11_ps3.cpp create mode 100644 libs/fastfile/PS3/fastfile_cod11_ps3.h create mode 100644 libs/fastfile/PS3/fastfile_cod12_ps3.cpp create mode 100644 libs/fastfile/PS3/fastfile_cod12_ps3.h create mode 100644 libs/fastfile/PS3/fastfile_cod4_ps3.cpp create mode 100644 libs/fastfile/PS3/fastfile_cod4_ps3.h create mode 100644 libs/fastfile/PS3/fastfile_cod5_ps3.cpp create mode 100644 libs/fastfile/PS3/fastfile_cod5_ps3.h create mode 100644 libs/fastfile/PS3/fastfile_cod6_ps3.cpp create mode 100644 libs/fastfile/PS3/fastfile_cod6_ps3.h create mode 100644 libs/fastfile/PS3/fastfile_cod7_ps3.cpp create mode 100644 libs/fastfile/PS3/fastfile_cod7_ps3.h create mode 100644 libs/fastfile/PS3/fastfile_cod8_ps3.cpp create mode 100644 libs/fastfile/PS3/fastfile_cod8_ps3.h create mode 100644 libs/fastfile/PS3/fastfile_cod9_ps3.cpp create mode 100644 libs/fastfile/PS3/fastfile_cod9_ps3.h create mode 100644 libs/fastfile/Wii/fastfile_cod4_wii.cpp create mode 100644 libs/fastfile/Wii/fastfile_cod4_wii.h create mode 100644 libs/fastfile/Wii/fastfile_cod7_wii.cpp create mode 100644 libs/fastfile/Wii/fastfile_cod7_wii.h create mode 100644 libs/fastfile/Wii/fastfile_cod8_wii.cpp create mode 100644 libs/fastfile/Wii/fastfile_cod8_wii.h create mode 100644 libs/fastfile/WiiU/fastfile_cod10_wiiu.cpp create mode 100644 libs/fastfile/WiiU/fastfile_cod10_wiiu.h create mode 100644 libs/fastfile/WiiU/fastfile_cod9_wiiu.cpp create mode 100644 libs/fastfile/WiiU/fastfile_cod9_wiiu.h create mode 100644 libs/zonefile/360/zonefile_cod10_360.cpp create mode 100644 libs/zonefile/360/zonefile_cod10_360.h create mode 100644 libs/zonefile/360/zonefile_cod11_360.cpp create mode 100644 libs/zonefile/360/zonefile_cod11_360.h create mode 100644 libs/zonefile/360/zonefile_cod12_360.cpp create mode 100644 libs/zonefile/360/zonefile_cod12_360.h create mode 100644 libs/zonefile/360/zonefile_cod2_360.cpp create mode 100644 libs/zonefile/360/zonefile_cod2_360.h create mode 100644 libs/zonefile/360/zonefile_cod4_360.cpp create mode 100644 libs/zonefile/360/zonefile_cod4_360.h create mode 100644 libs/zonefile/360/zonefile_cod5_360.cpp create mode 100644 libs/zonefile/360/zonefile_cod5_360.h create mode 100644 libs/zonefile/360/zonefile_cod6_360.cpp create mode 100644 libs/zonefile/360/zonefile_cod6_360.h create mode 100644 libs/zonefile/360/zonefile_cod7_360.cpp create mode 100644 libs/zonefile/360/zonefile_cod7_360.h create mode 100644 libs/zonefile/360/zonefile_cod8_360.cpp create mode 100644 libs/zonefile/360/zonefile_cod8_360.h create mode 100644 libs/zonefile/360/zonefile_cod9_360.cpp create mode 100644 libs/zonefile/360/zonefile_cod9_360.h create mode 100644 libs/zonefile/PC/zonefile_cod10_pc.cpp create mode 100644 libs/zonefile/PC/zonefile_cod10_pc.h create mode 100644 libs/zonefile/PC/zonefile_cod11_pc.cpp create mode 100644 libs/zonefile/PC/zonefile_cod11_pc.h create mode 100644 libs/zonefile/PC/zonefile_cod12_pc.cpp create mode 100644 libs/zonefile/PC/zonefile_cod12_pc.h create mode 100644 libs/zonefile/PC/zonefile_cod4_pc.cpp create mode 100644 libs/zonefile/PC/zonefile_cod4_pc.h create mode 100644 libs/zonefile/PC/zonefile_cod5_pc.cpp create mode 100644 libs/zonefile/PC/zonefile_cod5_pc.h create mode 100644 libs/zonefile/PC/zonefile_cod6_pc.cpp create mode 100644 libs/zonefile/PC/zonefile_cod6_pc.h create mode 100644 libs/zonefile/PC/zonefile_cod7_pc.cpp create mode 100644 libs/zonefile/PC/zonefile_cod7_pc.h create mode 100644 libs/zonefile/PC/zonefile_cod8_pc.cpp create mode 100644 libs/zonefile/PC/zonefile_cod8_pc.h create mode 100644 libs/zonefile/PC/zonefile_cod9_pc.cpp create mode 100644 libs/zonefile/PC/zonefile_cod9_pc.h create mode 100644 libs/zonefile/PS3/zonefile_cod10_ps3.cpp create mode 100644 libs/zonefile/PS3/zonefile_cod10_ps3.h create mode 100644 libs/zonefile/PS3/zonefile_cod11_ps3.cpp create mode 100644 libs/zonefile/PS3/zonefile_cod11_ps3.h create mode 100644 libs/zonefile/PS3/zonefile_cod12_ps3.cpp create mode 100644 libs/zonefile/PS3/zonefile_cod12_ps3.h create mode 100644 libs/zonefile/PS3/zonefile_cod4_ps3.cpp create mode 100644 libs/zonefile/PS3/zonefile_cod4_ps3.h create mode 100644 libs/zonefile/PS3/zonefile_cod5_ps3.cpp create mode 100644 libs/zonefile/PS3/zonefile_cod5_ps3.h create mode 100644 libs/zonefile/PS3/zonefile_cod6_ps3.cpp create mode 100644 libs/zonefile/PS3/zonefile_cod6_ps3.h create mode 100644 libs/zonefile/PS3/zonefile_cod7_ps3.cpp create mode 100644 libs/zonefile/PS3/zonefile_cod7_ps3.h create mode 100644 libs/zonefile/PS3/zonefile_cod8_ps3.cpp create mode 100644 libs/zonefile/PS3/zonefile_cod8_ps3.h create mode 100644 libs/zonefile/PS3/zonefile_cod9_ps3.cpp create mode 100644 libs/zonefile/PS3/zonefile_cod9_ps3.h create mode 100644 libs/zonefile/Wii/zonefile_cod4_wii.cpp create mode 100644 libs/zonefile/Wii/zonefile_cod4_wii.h create mode 100644 libs/zonefile/Wii/zonefile_cod7_wii.cpp create mode 100644 libs/zonefile/Wii/zonefile_cod7_wii.h create mode 100644 libs/zonefile/Wii/zonefile_cod8_wii.cpp create mode 100644 libs/zonefile/Wii/zonefile_cod8_wii.h create mode 100644 libs/zonefile/WiiU/zonefile_cod10_wiiu.cpp create mode 100644 libs/zonefile/WiiU/zonefile_cod10_wiiu.h create mode 100644 libs/zonefile/WiiU/zonefile_cod9_wiiu.cpp create mode 100644 libs/zonefile/WiiU/zonefile_cod9_wiiu.h diff --git a/libs/encryption/encryption.cpp b/libs/encryption/encryption.cpp index 613ea2e..81e2abe 100644 --- a/libs/encryption/encryption.cpp +++ b/libs/encryption/encryption.cpp @@ -1,6 +1,7 @@ #include "encryption.h" #include "QtZlib/zlib.h" #include "ecrypt-sync.h" +#include "compression.h" void Encryption::Convert32BitTo8Bit(quint32 value, quint8 *array) { array[0] = static_cast(value >> 0); @@ -350,7 +351,7 @@ void Encryption::generateNewIV(int index, const QByteArray &hash, QByteArray &iv ivCounter[index]++; } -QByteArray Encryption::decryptFastFile(const QByteArray &fastFileData) +QByteArray Encryption::decryptFastFile_BO2(const QByteArray &fastFileData) { const QByteArray bo2_salsa20_key = QByteArray::fromHex("641D8A2FE31D3AA63622BBC9CE8587229D42B0F8ED9B924130BF88B65EDC50BE"); @@ -438,3 +439,68 @@ QByteArray Encryption::decryptFastFile(const QByteArray &fastFileData) return finalFastFile; } + +QByteArray Encryption::decryptFastFile_BO3(const QByteArray &fastFileData) { + const QByteArray salsaKey = QByteArray::fromHex("0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3"); + + QByteArray ivTable(0xFB0, 0); + fillIVTable(fastFileData, ivTable, 0xFB0 - 1); + + QVector ivCounter(4, 1); + QDataStream stream(fastFileData); + stream.setByteOrder(QDataStream::LittleEndian); + + QByteArray finalFastFile; + QByteArray sha1Hash(20, 0); + QByteArray ivPtr(8, 0); + int chunkIndex = 0; + + while (!stream.atEnd()) { + if (stream.device()->bytesAvailable() < 4) { + qWarning() << "No sufficient data for chunk size at offset:" << stream.device()->pos(); + break; + } + + quint32 dataLength; + stream >> dataLength; + + if (dataLength == 0 || dataLength > fastFileData.size() - stream.device()->pos()) { + qWarning() << "Invalid data length at offset:" << stream.device()->pos(); + break; + } + + fillIV(chunkIndex % 4, ivPtr, ivTable, ivCounter); + + ECRYPT_ctx x; + ECRYPT_keysetup(&x, reinterpret_cast(salsaKey.constData()), 256, 0); + ECRYPT_ivsetup(&x, reinterpret_cast(ivPtr.constData())); + + QByteArray encryptedBlock = fastFileData.mid(stream.device()->pos(), dataLength); + QByteArray decryptedBlock(dataLength, Qt::Uninitialized); + + ECRYPT_decrypt_bytes(&x, + reinterpret_cast(encryptedBlock.constData()), + reinterpret_cast(decryptedBlock.data()), + dataLength); + + // SHA1 hash update + sha1Hash = QCryptographicHash::hash(decryptedBlock, QCryptographicHash::Sha1); + + // Decompress (ZLIB raw DEFLATE) + QByteArray decompressedData = Compression::DecompressDeflate(decryptedBlock); + if (decompressedData.isEmpty()) { + qWarning() << "Failed decompression at chunk index:" << chunkIndex; + return QByteArray(); + } + + finalFastFile.append(decompressedData); + + // Update IV table using SHA1 + generateNewIV(chunkIndex % 4, sha1Hash, ivTable, ivCounter); + + stream.skipRawData(dataLength); + chunkIndex++; + } + + return finalFastFile; +} diff --git a/libs/encryption/encryption.h b/libs/encryption/encryption.h index 6b36041..f03d85e 100644 --- a/libs/encryption/encryption.h +++ b/libs/encryption/encryption.h @@ -46,7 +46,8 @@ public: static void generateNewIV(int index, const QByteArray& hash, QByteArray& ivTable, QVector& ivCounter); - static QByteArray decryptFastFile(const QByteArray& fastFileData); + static QByteArray decryptFastFile_BO2(const QByteArray& fastFileData); + static QByteArray decryptFastFile_BO3(const QByteArray& fastFileData); }; #endif // ENCRYPTION_H diff --git a/libs/encryption/encryption.pro b/libs/encryption/encryption.pro index 28d2cfb..d923b34 100644 --- a/libs/encryption/encryption.pro +++ b/libs/encryption/encryption.pro @@ -17,4 +17,16 @@ HEADERS += \ config_win32.h \ sha1.h +app.depends += \ + compression + +LIBS += \ + -L$$OUT_PWD/../ -lcompression + +INCLUDEPATH += \ + $$PWD/../compression + +DEPENDPATH += \ + $$PWD/../compression + DESTDIR = $$OUT_PWD/../ diff --git a/libs/fastfile/360/fastfile_cod10_360.cpp b/libs/fastfile/360/fastfile_cod10_360.cpp new file mode 100644 index 0000000..8ab1f72 --- /dev/null +++ b/libs/fastfile/360/fastfile_cod10_360.cpp @@ -0,0 +1,115 @@ +#include "fastfile_cod10_360.h" +#include "zonefile_cod10_360.h" +#include "encryption.h" + +#include +#include + +FastFile_COD10_360::FastFile_COD10_360() + : FastFile() { + SetCompany(COMPANY_INFINITY_WARD); + SetType(FILETYPE_FAST_FILE); + SetSignage(SIGNAGE_UNSIGNED); + SetMagic(0); + SetVersion(0); + SetPlatform("360"); + SetGame("COD10"); +} + +FastFile_COD10_360::FastFile_COD10_360(const QByteArray& aData) + : FastFile_COD10_360() { + + if (!aData.isEmpty()) { + Load(aData); + } +} + +FastFile_COD10_360::FastFile_COD10_360(const QString aFilePath) + : FastFile_COD10_360() { + + if (!aFilePath.isEmpty()) { + Load(aFilePath); + } +} + +FastFile_COD10_360::~FastFile_COD10_360() { + +} + +QByteArray FastFile_COD10_360::GetBinaryData() { + return QByteArray(); +} + +bool FastFile_COD10_360::Load(const QString aFilePath) { + if (aFilePath.isEmpty()) { + return false; + } + + // Check fastfile can be read + QFile *file = new QFile(aFilePath); + if (!file->open(QIODevice::ReadOnly)) { + qDebug() << QString("Error: Failed to open FastFile: %1!").arg(aFilePath); + return false; + } + + // Decompress fastfile and close + const QString fastFileStem = aFilePath.section("/", -1, -1).section(".", 0, 0); + SetStem(fastFileStem); + if (!Load(file->readAll())) { + qDebug() << "Error: Failed to load fastfile: " << fastFileStem + ".ff"; + return false; + } + + file->close(); + + // Open zone file after decompressing ff and writing + return true; +} + +bool FastFile_COD10_360::Load(const QByteArray aData) { + QByteArray decompressedData; + + // Create a QDataStream on the input data. + QDataStream fastFileStream(aData); + fastFileStream.setByteOrder(QDataStream::LittleEndian); + + // For COD7/COD9, use BigEndian. + fastFileStream.setByteOrder(QDataStream::BigEndian); + + // Select key based on game. + QByteArray key = QByteArray::fromHex("0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3"); + + // Read the 8-byte magic. + QByteArray fileMagic(8, Qt::Uninitialized); + fastFileStream.readRawData(fileMagic.data(), 8); + if (fileMagic != "PHEEBs71") { + qWarning() << "Invalid fast file magic!"; + return false; + } + fastFileStream.skipRawData(4); + + // Read IV table name (32 bytes). + QByteArray fileName(32, Qt::Uninitialized); + fastFileStream.readRawData(fileName.data(), 32); + + // Skip the RSA signature (256 bytes). + QByteArray rsaSignature(256, Qt::Uninitialized); + fastFileStream.readRawData(rsaSignature.data(), 256); + + decompressedData = Encryption::decryptFastFile_BO2(aData); + + // For COD9, write out the complete decompressed zone for testing. + QFile testFile("exports/" + GetStem() + ".zone"); + if(testFile.open(QIODevice::WriteOnly)) { + testFile.write(decompressedData); + testFile.close(); + } + + // Load the zone file with the decompressed data (using an Xbox platform flag). + ZoneFile_COD10_360 zoneFile; + zoneFile.SetStem(GetStem()); + zoneFile.Load(decompressedData); + SetZoneFile(std::make_shared(zoneFile)); + + return true; +} diff --git a/libs/fastfile/360/fastfile_cod10_360.h b/libs/fastfile/360/fastfile_cod10_360.h new file mode 100644 index 0000000..b0574a1 --- /dev/null +++ b/libs/fastfile/360/fastfile_cod10_360.h @@ -0,0 +1,20 @@ +#ifndef FASTFILE_COD10_360_H +#define FASTFILE_COD10_360_H + +#include "fastfile.h" + +class FastFile_COD10_360 : public FastFile +{ +public: + FastFile_COD10_360(); + FastFile_COD10_360(const QByteArray& aData); + FastFile_COD10_360(const QString aFilePath); + ~FastFile_COD10_360(); + + QByteArray GetBinaryData() override; + + bool Load(const QString aFilePath) override; + bool Load(const QByteArray aData) override; +}; + +#endif // FASTFILE_COD10_360_H diff --git a/libs/fastfile/360/fastfile_cod11_360.cpp b/libs/fastfile/360/fastfile_cod11_360.cpp new file mode 100644 index 0000000..990373f --- /dev/null +++ b/libs/fastfile/360/fastfile_cod11_360.cpp @@ -0,0 +1,107 @@ +#include "fastfile_cod11_360.h" +#include "zonefile_cod11_360.h" + +#include "utils.h" +#include "compression.h" +#include "encryption.h" + +#include +#include + +FastFile_COD11_360::FastFile_COD11_360() + : FastFile() { + SetCompany(COMPANY_INFINITY_WARD); + SetType(FILETYPE_FAST_FILE); + SetSignage(SIGNAGE_UNSIGNED); + SetMagic(0); + SetVersion(0); + SetGame("COD11"); + SetPlatform("PC"); +} + +FastFile_COD11_360::FastFile_COD11_360(const QByteArray& aData) + : FastFile_COD11_360() { + + if (!aData.isEmpty()) { + Load(aData); + } +} + +FastFile_COD11_360::FastFile_COD11_360(const QString aFilePath) + : FastFile_COD11_360() { + if (!aFilePath.isEmpty()) { + Load(aFilePath); + } +} + +FastFile_COD11_360::~FastFile_COD11_360() { + +} + +QByteArray FastFile_COD11_360::GetBinaryData() { + return QByteArray(); +} + +bool FastFile_COD11_360::Load(const QString aFilePath) { + if (aFilePath.isEmpty()) { + return false; + } + + // Check fastfile can be read + QFile *file = new QFile(aFilePath); + if (!file->open(QIODevice::ReadOnly)) { + qDebug() << QString("Error: Failed to open FastFile: %1!").arg(aFilePath); + return false; + } + + // Decompress fastfile and close + const QString fastFileStem = aFilePath.section("/", -1, -1).split('.').first(); + SetStem(fastFileStem); + if (!Load(file->readAll())) { + qDebug() << "Error: Failed to load fastfile: " << fastFileStem; + return false; + } + + file->close(); + + // Open zone file after decompressing ff and writing + return true; +} + +bool FastFile_COD11_360::Load(const QByteArray aData) { + QByteArray decompressedData; + + // Prepare data stream for parsing + QDataStream fastFileStream(aData); + fastFileStream.setByteOrder(QDataStream::LittleEndian); + + // Verify magic header + QByteArray fileMagic(8, Qt::Uninitialized); + fastFileStream.readRawData(fileMagic.data(), 8); + if (fileMagic != "TAff0000") { + qWarning() << "Invalid fast file magic for COD12!"; + return false; + } + + // Skip: File size (4 bytes), flags/version (4 bytes), unknown (8 bytes), build tag (32 bytes), RSA signature (256 bytes) + fastFileStream.skipRawData(4 + 4 + 8 + 32 + 256); // total 304 bytes skipped so far + 8 bytes magic = 312 bytes at correct position. + + // Correctly positioned at 0x138 + QByteArray encryptedData = aData.mid(0x138); + decompressedData = Encryption::decryptFastFile_BO3(encryptedData); + + // Output for verification/testing + Utils::ExportData(GetStem() + ".zone", decompressedData); + + // Load the zone file with decompressed data + ZoneFile_COD11_360 zoneFile; + zoneFile.SetStem(GetStem()); + if (!zoneFile.Load(decompressedData)) { + qWarning() << "Failed to load ZoneFile!"; + return false; + } + + SetZoneFile(std::make_shared(zoneFile)); + + return true; +} diff --git a/libs/fastfile/360/fastfile_cod11_360.h b/libs/fastfile/360/fastfile_cod11_360.h new file mode 100644 index 0000000..a14c43c --- /dev/null +++ b/libs/fastfile/360/fastfile_cod11_360.h @@ -0,0 +1,20 @@ +#ifndef FASTFILE_COD11_360_H +#define FASTFILE_COD11_360_H + +#include "fastfile.h" + +class FastFile_COD11_360 : public FastFile +{ +public: + FastFile_COD11_360(); + FastFile_COD11_360(const QByteArray &aData); + FastFile_COD11_360(const QString aFilePath); + ~FastFile_COD11_360(); + + QByteArray GetBinaryData() override; + + bool Load(const QString aFilePath) override; + bool Load(const QByteArray aData) override; +}; + +#endif // FASTFILE_COD11_360_H diff --git a/libs/fastfile/360/fastfile_cod12_360.cpp b/libs/fastfile/360/fastfile_cod12_360.cpp new file mode 100644 index 0000000..f0581a4 --- /dev/null +++ b/libs/fastfile/360/fastfile_cod12_360.cpp @@ -0,0 +1,107 @@ +#include "fastfile_cod12_360.h" +#include "zonefile_cod12_360.h" + +#include "utils.h" +#include "compression.h" +#include "encryption.h" + +#include +#include + +FastFile_COD12_360::FastFile_COD12_360() + : FastFile() { + SetCompany(COMPANY_INFINITY_WARD); + SetType(FILETYPE_FAST_FILE); + SetSignage(SIGNAGE_UNSIGNED); + SetMagic(0); + SetVersion(0); + SetGame("COD12"); + SetPlatform("PC"); +} + +FastFile_COD12_360::FastFile_COD12_360(const QByteArray& aData) + : FastFile_COD12_360() { + + if (!aData.isEmpty()) { + Load(aData); + } +} + +FastFile_COD12_360::FastFile_COD12_360(const QString aFilePath) + : FastFile_COD12_360() { + if (!aFilePath.isEmpty()) { + Load(aFilePath); + } +} + +FastFile_COD12_360::~FastFile_COD12_360() { + +} + +QByteArray FastFile_COD12_360::GetBinaryData() { + return QByteArray(); +} + +bool FastFile_COD12_360::Load(const QString aFilePath) { + if (aFilePath.isEmpty()) { + return false; + } + + // Check fastfile can be read + QFile *file = new QFile(aFilePath); + if (!file->open(QIODevice::ReadOnly)) { + qDebug() << QString("Error: Failed to open FastFile: %1!").arg(aFilePath); + return false; + } + + // Decompress fastfile and close + const QString fastFileStem = aFilePath.section("/", -1, -1).split('.').first(); + SetStem(fastFileStem); + if (!Load(file->readAll())) { + qDebug() << "Error: Failed to load fastfile: " << fastFileStem; + return false; + } + + file->close(); + + // Open zone file after decompressing ff and writing + return true; +} + +bool FastFile_COD12_360::Load(const QByteArray aData) { + QByteArray decompressedData; + + // Prepare data stream for parsing + QDataStream fastFileStream(aData); + fastFileStream.setByteOrder(QDataStream::LittleEndian); + + // Verify magic header + QByteArray fileMagic(8, Qt::Uninitialized); + fastFileStream.readRawData(fileMagic.data(), 8); + if (fileMagic != "TAff0000") { + qWarning() << "Invalid fast file magic for COD12!"; + return false; + } + + // Skip: File size (4 bytes), flags/version (4 bytes), unknown (8 bytes), build tag (32 bytes), RSA signature (256 bytes) + fastFileStream.skipRawData(4 + 4 + 8 + 32 + 256); // total 304 bytes skipped so far + 8 bytes magic = 312 bytes at correct position. + + // Correctly positioned at 0x138 + QByteArray encryptedData = aData.mid(0x138); + decompressedData = Encryption::decryptFastFile_BO3(encryptedData); + + // Output for verification/testing + Utils::ExportData(GetStem() + ".zone", decompressedData); + + // Load the zone file with decompressed data + ZoneFile_COD12_360 zoneFile; + zoneFile.SetStem(GetStem()); + if (!zoneFile.Load(decompressedData)) { + qWarning() << "Failed to load ZoneFile!"; + return false; + } + + SetZoneFile(std::make_shared(zoneFile)); + + return true; +} diff --git a/libs/fastfile/360/fastfile_cod12_360.h b/libs/fastfile/360/fastfile_cod12_360.h new file mode 100644 index 0000000..082d89a --- /dev/null +++ b/libs/fastfile/360/fastfile_cod12_360.h @@ -0,0 +1,20 @@ +#ifndef FASTFILE_COD12_360_H +#define FASTFILE_COD12_360_H + +#include "fastfile.h" + +class FastFile_COD12_360 : public FastFile +{ +public: + FastFile_COD12_360(); + FastFile_COD12_360(const QByteArray &aData); + FastFile_COD12_360(const QString aFilePath); + ~FastFile_COD12_360(); + + QByteArray GetBinaryData() override; + + bool Load(const QString aFilePath) override; + bool Load(const QByteArray aData) override; +}; + +#endif // FASTFILE_COD12_360_H diff --git a/libs/fastfile/360/fastfile_cod2_360.cpp b/libs/fastfile/360/fastfile_cod2_360.cpp new file mode 100644 index 0000000..e61690b --- /dev/null +++ b/libs/fastfile/360/fastfile_cod2_360.cpp @@ -0,0 +1,89 @@ +#include "fastfile_cod2_360.h" + +#include "utils.h" +#include "compression.h" +#include "zonefile_cod2_360.h" + +#include +#include + +FastFile_COD2_360::FastFile_COD2_360() + : FastFile() { + SetCompany(COMPANY_INFINITY_WARD); + SetType(FILETYPE_FAST_FILE); + SetSignage(SIGNAGE_UNSIGNED); + SetMagic(0); + SetVersion(0); + SetPlatform("360"); + SetGame("COD2"); +} + +FastFile_COD2_360::FastFile_COD2_360(const QByteArray& aData) + : FastFile_COD2_360() { + + if (!aData.isEmpty()) { + Load(aData); + } +} + +FastFile_COD2_360::FastFile_COD2_360(const QString aFilePath) + : FastFile_COD2_360() { + + if (!aFilePath.isEmpty()) { + Load(aFilePath); + } +} + +FastFile_COD2_360::~FastFile_COD2_360() { + +} + +QByteArray FastFile_COD2_360::GetBinaryData() { + return QByteArray(); +} + +bool FastFile_COD2_360::Load(const QString aFilePath) { + if (aFilePath.isEmpty()) { + return false; + } + + // Check fastfile can be read + QFile *file = new QFile(aFilePath); + if (!file->open(QIODevice::ReadOnly)) { + qDebug() << QString("Error: Failed to open FastFile: %1!").arg(aFilePath); + return false; + } + + // Decompress fastfile and close + const QString fastFileStem = aFilePath.section("/", -1, -1).section(".", 0, 0); + SetStem(fastFileStem); + if (!Load(file->readAll())) { + qDebug() << "Error: Failed to load fastfile: " << fastFileStem; + return false; + } + + file->close(); + + // Open zone file after decompressing ff and writing + return true; +} + +bool FastFile_COD2_360::Load(const QByteArray aData) { + // Create a QDataStream on the input data. + QDataStream fastFileStream(aData); + fastFileStream.setByteOrder(QDataStream::LittleEndian); + + Utils::ReadUntilHex(&fastFileStream, "78"); + QByteArray compressedData = aData.mid(fastFileStream.device()->pos()); + QByteArray decompressedData = Compression::DecompressZLIB(compressedData); + + Utils::ExportData(GetStem() + ".zone", decompressedData); + + // Load the zone file with the decompressed data (using an Xbox platform flag). + ZoneFile_COD2_360 zoneFile; + zoneFile.SetStem(GetStem()); + zoneFile.Load(decompressedData); + SetZoneFile(std::make_shared(zoneFile)); + + return true; +} diff --git a/libs/fastfile/360/fastfile_cod2_360.h b/libs/fastfile/360/fastfile_cod2_360.h new file mode 100644 index 0000000..d1fe760 --- /dev/null +++ b/libs/fastfile/360/fastfile_cod2_360.h @@ -0,0 +1,20 @@ +#ifndef FASTFILE_COD2_360_H +#define FASTFILE_COD2_360_H + +#include "fastfile.h" + +class FastFile_COD2_360 : public FastFile +{ +public: + FastFile_COD2_360(); + FastFile_COD2_360(const QByteArray& aData); + FastFile_COD2_360(const QString aFilePath); + ~FastFile_COD2_360(); + + QByteArray GetBinaryData() override; + + bool Load(const QString aFilePath) override; + bool Load(const QByteArray aData) override; +}; + +#endif // FASTFILE_COD2_360_H diff --git a/libs/fastfile/360/fastfile_cod4_360.cpp b/libs/fastfile/360/fastfile_cod4_360.cpp new file mode 100644 index 0000000..5ac6889 --- /dev/null +++ b/libs/fastfile/360/fastfile_cod4_360.cpp @@ -0,0 +1,93 @@ +#include "fastfile_cod4_360.h" +#include "zonefile_cod4_360.h" + +#include "utils.h" +#include "compression.h" +#include "statusbarmanager.h" + +#include +#include + +FastFile_COD4_360::FastFile_COD4_360() + : FastFile() { + SetCompany(COMPANY_INFINITY_WARD); + SetType(FILETYPE_FAST_FILE); + SetSignage(SIGNAGE_UNSIGNED); + SetMagic(0); + SetVersion(0); + SetPlatform("360"); + SetGame("COD4"); +} + +FastFile_COD4_360::FastFile_COD4_360(const QByteArray& aData) + : FastFile_COD4_360() { + + if (!aData.isEmpty()) { + Load(aData); + } +} + +FastFile_COD4_360::FastFile_COD4_360(const QString aFilePath) + : FastFile_COD4_360() { + + if (!aFilePath.isEmpty()) { + Load(aFilePath); + } +} + +FastFile_COD4_360::~FastFile_COD4_360() { + +} + +QByteArray FastFile_COD4_360::GetBinaryData() { + return QByteArray(); +} + +bool FastFile_COD4_360::Load(const QString aFilePath) { + StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/path", 1000); + + if (aFilePath.isEmpty()) { + return false; + } + + // Check fastfile can be read + QFile *file = new QFile(aFilePath); + if (!file->open(QIODevice::ReadOnly)) { + qDebug() << QString("Error: Failed to open FastFile: %1!").arg(aFilePath); + return false; + } + + // Decompress fastfile and close + QString fastFileStem = aFilePath.split('/').last().replace(".ff", ""); + SetStem(fastFileStem); + if (!Load(file->readAll())) { + qDebug() << "Error: Failed to load fastfile: " << fastFileStem; + return false; + } + + file->close(); + + // Open zone file after decompressing ff and writing + return true; +} + +bool FastFile_COD4_360::Load(const QByteArray aData) { + StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/data", 1000); + QByteArray decompressedData; + + // Create a QDataStream on the input data. + QDataStream fastFileStream(aData); + fastFileStream.setByteOrder(QDataStream::LittleEndian); + + // For COD5, simply decompress from offset 12. + decompressedData = Compression::DecompressZLIB(aData.mid(12)); + + Utils::ExportData(GetStem() + ".zone", decompressedData); + + ZoneFile_COD4_360 zoneFile; + zoneFile.SetStem(GetStem()); + zoneFile.Load(decompressedData); + SetZoneFile(std::make_shared(zoneFile)); + + return true; +} diff --git a/libs/fastfile/360/fastfile_cod4_360.h b/libs/fastfile/360/fastfile_cod4_360.h new file mode 100644 index 0000000..5f8cdb2 --- /dev/null +++ b/libs/fastfile/360/fastfile_cod4_360.h @@ -0,0 +1,20 @@ +#ifndef FASTFILE_COD4_360_H +#define FASTFILE_COD4_360_H + +#include "fastfile.h" + +class FastFile_COD4_360 : public FastFile +{ +public: + FastFile_COD4_360(); + FastFile_COD4_360(const QByteArray &aData); + FastFile_COD4_360(const QString aFilePath); + ~FastFile_COD4_360(); + + QByteArray GetBinaryData() override; + + bool Load(const QString aFilePath) override; + bool Load(const QByteArray aData) override; +}; + +#endif // FASTFILE_COD4_360_H diff --git a/libs/fastfile/360/fastfile_cod5_360.cpp b/libs/fastfile/360/fastfile_cod5_360.cpp new file mode 100644 index 0000000..8608958 --- /dev/null +++ b/libs/fastfile/360/fastfile_cod5_360.cpp @@ -0,0 +1,89 @@ +#include "fastfile_cod5_360.h" +#include "zonefile_cod5_360.h" + +#include "utils.h" +#include "compression.h" +#include "statusbarmanager.h" + +#include +#include + +FastFile_COD5_360::FastFile_COD5_360() + : FastFile() { + SetCompany(COMPANY_INFINITY_WARD); + SetType(FILETYPE_FAST_FILE); + SetSignage(SIGNAGE_UNSIGNED); + SetMagic(0); + SetVersion(0); + SetPlatform("360"); + SetGame("COD5"); +} + +FastFile_COD5_360::FastFile_COD5_360(const QByteArray& aData) + : FastFile_COD5_360() { + + if (!aData.isEmpty()) { + Load(aData); + } +} + +FastFile_COD5_360::FastFile_COD5_360(const QString aFilePath) + : FastFile_COD5_360() { + + if (!aFilePath.isEmpty()) { + Load(aFilePath); + } +} + +FastFile_COD5_360::~FastFile_COD5_360() { + +} + +QByteArray FastFile_COD5_360::GetBinaryData() { + return QByteArray(); +} + +bool FastFile_COD5_360::Load(const QString aFilePath) { + StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/path", 1000); + + if (aFilePath.isEmpty()) { + return false; + } + + // Check fastfile can be read + QFile *file = new QFile(aFilePath); + if (!file->open(QIODevice::ReadOnly)) { + qDebug() << QString("Error: Failed to open FastFile: %1!").arg(aFilePath); + return false; + } + + // Decompress fastfile and close + QString fastFileStem = aFilePath.split('/').last().replace(".ff", ""); + SetStem(fastFileStem); + if (!Load(file->readAll())) { + qDebug() << "Error: Failed to load fastfile: " << fastFileStem; + return false; + } + + file->close(); + + // Open zone file after decompressing ff and writing + return true; +} + +bool FastFile_COD5_360::Load(const QByteArray aData) { + StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/data", 1000); + QByteArray decompressedData; + + // For COD5, simply decompress from offset 12. + decompressedData = Compression::DecompressZLIB(aData.mid(12)); + + Utils::ExportData(GetStem() + ".zone", decompressedData); + + ZoneFile_COD5_360 zoneFile; + zoneFile.SetStem(GetStem()); + zoneFile.Load(decompressedData); + SetZoneFile(std::make_shared(zoneFile)); + + return true; +} diff --git a/libs/fastfile/360/fastfile_cod5_360.h b/libs/fastfile/360/fastfile_cod5_360.h new file mode 100644 index 0000000..80ba475 --- /dev/null +++ b/libs/fastfile/360/fastfile_cod5_360.h @@ -0,0 +1,20 @@ +#ifndef FASTFILE_COD5_360_H +#define FASTFILE_COD5_360_H + +#include "fastfile.h" + +class FastFile_COD5_360 : public FastFile +{ +public: + FastFile_COD5_360(); + FastFile_COD5_360(const QByteArray &aData); + FastFile_COD5_360(const QString aFilePath); + ~FastFile_COD5_360(); + + QByteArray GetBinaryData() override; + + bool Load(const QString aFilePath) override; + bool Load(const QByteArray aData) override; +}; + +#endif // FASTFILE_COD5_360_H diff --git a/libs/fastfile/360/fastfile_cod6_360.cpp b/libs/fastfile/360/fastfile_cod6_360.cpp new file mode 100644 index 0000000..34ada0f --- /dev/null +++ b/libs/fastfile/360/fastfile_cod6_360.cpp @@ -0,0 +1,151 @@ +#include "fastfile_cod6_360.h" +#include "zonefile_cod6_360.h" + +#include "compression.h" +#include "encryption.h" + +#include +#include + +FastFile_COD6_360::FastFile_COD6_360() + : FastFile() { + SetCompany(COMPANY_INFINITY_WARD); + SetType(FILETYPE_FAST_FILE); + SetSignage(SIGNAGE_UNSIGNED); + SetMagic(0); + SetVersion(0); + SetPlatform("360"); + SetGame("COD6"); +} + +FastFile_COD6_360::FastFile_COD6_360(const QByteArray& aData) + : FastFile_COD6_360() { + + if (!aData.isEmpty()) { + Load(aData); + } +} + +FastFile_COD6_360::FastFile_COD6_360(const QString aFilePath) + : FastFile_COD6_360() { + + if (!aFilePath.isEmpty()) { + Load(aFilePath); + } +} + +FastFile_COD6_360::~FastFile_COD6_360() { + +} + +QByteArray FastFile_COD6_360::GetBinaryData() { + return QByteArray(); +} + +bool FastFile_COD6_360::Load(const QString aFilePath) { + if (aFilePath.isEmpty()) { + return false; + } + + // Check fastfile can be read + QFile *file = new QFile(aFilePath); + if (!file->open(QIODevice::ReadOnly)) { + qDebug() << QString("Error: Failed to open FastFile: %1!").arg(aFilePath); + return false; + } + + // Decompress fastfile and close + const QString fastFileStem = aFilePath.section("/", -1, -1); + SetStem(fastFileStem); + if (!Load(file->readAll())) { + qDebug() << "Error: Failed to load fastfile: " << fastFileStem; + return false; + } + + file->close(); + + // Open zone file after decompressing ff and writing + return true; +} + +bool FastFile_COD6_360::Load(const QByteArray aData) { + QByteArray decompressedData; + + // Create a QDataStream on the input data. + QDataStream fastFileStream(aData); + + // Load the zone file with the decompressed data (using an Xbox platform flag). + ZoneFile_COD6_360 zoneFile; + zoneFile.SetStem(GetStem()); + + // For COD7/COD9, use BigEndian. + fastFileStream.setByteOrder(QDataStream::BigEndian); + + // Select key based on game. + QByteArray key = QByteArray::fromHex("1ac1d12d527c59b40eca619120ff8217ccff09cd16896f81b829c7f52793405d"); + fastFileStream.skipRawData(4); + + // Read the 8-byte magic. + QByteArray fileMagic(8, Qt::Uninitialized); + fastFileStream.readRawData(fileMagic.data(), 8); + if (fileMagic != "PHEEBs71") { + qWarning() << "Invalid fast file magic!"; + return false; + } + fastFileStream.skipRawData(4); + + // Read IV table name (32 bytes). + QByteArray fileName(32, Qt::Uninitialized); + fastFileStream.readRawData(fileName.data(), 32); + + // Build the IV table from the fileName. + QByteArray ivTable = Encryption::InitIVTable(fileName); + + // Skip the RSA signature (256 bytes). + QByteArray rsaSignature(256, Qt::Uninitialized); + fastFileStream.readRawData(rsaSignature.data(), 256); + + // Now the stream should be positioned at 0x13C, where sections begin. + int sectionIndex = 0; + while (true) { + qint32 sectionSize = 0; + fastFileStream >> sectionSize; + qDebug() << "Section index:" << sectionIndex << "Size:" << sectionSize + << "Pos:" << fastFileStream.device()->pos(); + if (sectionSize == 0) + break; + + // Read the section data. + QByteArray sectionData; + sectionData.resize(sectionSize); + fastFileStream.readRawData(sectionData.data(), sectionSize); + + // Compute the IV for this section. + QByteArray iv = Encryption::GetIV(ivTable, sectionIndex); + + // Decrypt the section using Salsa20. + QByteArray decData = Encryption::salsa20DecryptSection(sectionData, key, iv); + + // Compute SHA1 hash of the decrypted data. + QByteArray sectionHash = QCryptographicHash::hash(decData, QCryptographicHash::Sha1); + + // Update the IV table based on the section hash. + Encryption::UpdateIVTable(ivTable, sectionIndex, sectionHash); + + // Build a compressed data buffer by prepending the two-byte zlib header. + QByteArray compressedData; + compressedData.append(char(0x78)); + compressedData.append(char(0x01)); + compressedData.append(decData); + + decompressedData.append(Compression::DecompressZLIB(compressedData)); + + sectionIndex++; + } + + zoneFile.Load(decompressedData); + + SetZoneFile(std::make_shared(zoneFile)); + + return true; +} diff --git a/libs/fastfile/360/fastfile_cod6_360.h b/libs/fastfile/360/fastfile_cod6_360.h new file mode 100644 index 0000000..8a7f430 --- /dev/null +++ b/libs/fastfile/360/fastfile_cod6_360.h @@ -0,0 +1,20 @@ +#ifndef FASTFILE_COD6_360_H +#define FASTFILE_COD6_360_H + +#include "fastfile.h" + +class FastFile_COD6_360 : public FastFile +{ +public: + FastFile_COD6_360(); + FastFile_COD6_360(const QByteArray& aData); + FastFile_COD6_360(const QString aFilePath); + ~FastFile_COD6_360(); + + QByteArray GetBinaryData() override; + + bool Load(const QString aFilePath) override; + bool Load(const QByteArray aData) override; +}; + +#endif // FASTFILE_COD6_360_H diff --git a/libs/fastfile/360/fastfile_cod7_360.cpp b/libs/fastfile/360/fastfile_cod7_360.cpp new file mode 100644 index 0000000..7da1f6e --- /dev/null +++ b/libs/fastfile/360/fastfile_cod7_360.cpp @@ -0,0 +1,151 @@ +#include "fastfile_cod7_360.h" +#include "zonefile_cod7_360.h" + +#include "compression.h" +#include "encryption.h" + +#include +#include + +FastFile_COD7_360::FastFile_COD7_360() + : FastFile() { + SetCompany(COMPANY_INFINITY_WARD); + SetType(FILETYPE_FAST_FILE); + SetSignage(SIGNAGE_UNSIGNED); + SetMagic(0); + SetVersion(0); + SetPlatform("360"); + SetGame("COD7"); +} + +FastFile_COD7_360::FastFile_COD7_360(const QByteArray& aData) + : FastFile_COD7_360() { + + if (!aData.isEmpty()) { + Load(aData); + } +} + +FastFile_COD7_360::FastFile_COD7_360(const QString aFilePath) + : FastFile_COD7_360() { + + if (!aFilePath.isEmpty()) { + Load(aFilePath); + } +} + +FastFile_COD7_360::~FastFile_COD7_360() { + +} + +QByteArray FastFile_COD7_360::GetBinaryData() { + return QByteArray(); +} + +bool FastFile_COD7_360::Load(const QString aFilePath) { + if (aFilePath.isEmpty()) { + return false; + } + + // Check fastfile can be read + QFile *file = new QFile(aFilePath); + if (!file->open(QIODevice::ReadOnly)) { + qDebug() << QString("Error: Failed to open FastFile: %1!").arg(aFilePath); + return false; + } + + // Decompress fastfile and close + const QString fastFileStem = aFilePath.section("/", -1, -1); + SetStem(fastFileStem); + if (!Load(file->readAll())) { + qDebug() << "Error: Failed to load fastfile: " << fastFileStem; + return false; + } + + file->close(); + + // Open zone file after decompressing ff and writing + return true; +} + +bool FastFile_COD7_360::Load(const QByteArray aData) { + QByteArray decompressedData; + + // Create a QDataStream on the input data. + QDataStream fastFileStream(aData); + + // Load the zone file with the decompressed data (using an Xbox platform flag). + ZoneFile_COD7_360 zoneFile; + zoneFile.SetStem(GetStem()); + + // For COD7/COD9, use BigEndian. + fastFileStream.setByteOrder(QDataStream::BigEndian); + + // Select key based on game. + QByteArray key = QByteArray::fromHex("1ac1d12d527c59b40eca619120ff8217ccff09cd16896f81b829c7f52793405d"); + fastFileStream.skipRawData(4); + + // Read the 8-byte magic. + QByteArray fileMagic(8, Qt::Uninitialized); + fastFileStream.readRawData(fileMagic.data(), 8); + if (fileMagic != "PHEEBs71") { + qWarning() << "Invalid fast file magic!"; + return false; + } + fastFileStream.skipRawData(4); + + // Read IV table name (32 bytes). + QByteArray fileName(32, Qt::Uninitialized); + fastFileStream.readRawData(fileName.data(), 32); + + // Build the IV table from the fileName. + QByteArray ivTable = Encryption::InitIVTable(fileName); + + // Skip the RSA signature (256 bytes). + QByteArray rsaSignature(256, Qt::Uninitialized); + fastFileStream.readRawData(rsaSignature.data(), 256); + + // Now the stream should be positioned at 0x13C, where sections begin. + int sectionIndex = 0; + while (true) { + qint32 sectionSize = 0; + fastFileStream >> sectionSize; + qDebug() << "Section index:" << sectionIndex << "Size:" << sectionSize + << "Pos:" << fastFileStream.device()->pos(); + if (sectionSize == 0) + break; + + // Read the section data. + QByteArray sectionData; + sectionData.resize(sectionSize); + fastFileStream.readRawData(sectionData.data(), sectionSize); + + // Compute the IV for this section. + QByteArray iv = Encryption::GetIV(ivTable, sectionIndex); + + // Decrypt the section using Salsa20. + QByteArray decData = Encryption::salsa20DecryptSection(sectionData, key, iv); + + // Compute SHA1 hash of the decrypted data. + QByteArray sectionHash = QCryptographicHash::hash(decData, QCryptographicHash::Sha1); + + // Update the IV table based on the section hash. + Encryption::UpdateIVTable(ivTable, sectionIndex, sectionHash); + + // Build a compressed data buffer by prepending the two-byte zlib header. + QByteArray compressedData; + compressedData.append(char(0x78)); + compressedData.append(char(0x01)); + compressedData.append(decData); + + decompressedData.append(Compression::DecompressZLIB(compressedData)); + + sectionIndex++; + } + + zoneFile.Load(decompressedData); + + SetZoneFile(std::make_shared(zoneFile)); + + return true; +} diff --git a/libs/fastfile/360/fastfile_cod7_360.h b/libs/fastfile/360/fastfile_cod7_360.h new file mode 100644 index 0000000..a30972c --- /dev/null +++ b/libs/fastfile/360/fastfile_cod7_360.h @@ -0,0 +1,20 @@ +#ifndef FASTFILE_COD7_360_H +#define FASTFILE_COD7_360_H + +#include "fastfile.h" + +class FastFile_COD7_360 : public FastFile +{ +public: + FastFile_COD7_360(); + FastFile_COD7_360(const QByteArray& aData); + FastFile_COD7_360(const QString aFilePath); + ~FastFile_COD7_360(); + + QByteArray GetBinaryData() override; + + bool Load(const QString aFilePath) override; + bool Load(const QByteArray aData) override; +}; + +#endif // FASTFILE_COD7_360_H diff --git a/libs/fastfile/360/fastfile_cod8_360.cpp b/libs/fastfile/360/fastfile_cod8_360.cpp new file mode 100644 index 0000000..afdb404 --- /dev/null +++ b/libs/fastfile/360/fastfile_cod8_360.cpp @@ -0,0 +1,115 @@ +#include "fastfile_cod8_360.h" +#include "zonefile_cod8_360.h" +#include "encryption.h" + +#include +#include + +FastFile_COD8_360::FastFile_COD8_360() + : FastFile() { + SetCompany(COMPANY_INFINITY_WARD); + SetType(FILETYPE_FAST_FILE); + SetSignage(SIGNAGE_UNSIGNED); + SetMagic(0); + SetVersion(0); + SetPlatform("360"); + SetGame("COD8"); +} + +FastFile_COD8_360::FastFile_COD8_360(const QByteArray& aData) + : FastFile_COD8_360() { + + if (!aData.isEmpty()) { + Load(aData); + } +} + +FastFile_COD8_360::FastFile_COD8_360(const QString aFilePath) + : FastFile_COD8_360() { + + if (!aFilePath.isEmpty()) { + Load(aFilePath); + } +} + +FastFile_COD8_360::~FastFile_COD8_360() { + +} + +QByteArray FastFile_COD8_360::GetBinaryData() { + return QByteArray(); +} + +bool FastFile_COD8_360::Load(const QString aFilePath) { + if (aFilePath.isEmpty()) { + return false; + } + + // Check fastfile can be read + QFile *file = new QFile(aFilePath); + if (!file->open(QIODevice::ReadOnly)) { + qDebug() << QString("Error: Failed to open FastFile: %1!").arg(aFilePath); + return false; + } + + // Decompress fastfile and close + const QString fastFileStem = aFilePath.section("/", -1, -1).section(".", 0, 0); + SetStem(fastFileStem); + if (!Load(file->readAll())) { + qDebug() << "Error: Failed to load fastfile: " << fastFileStem + ".ff"; + return false; + } + + file->close(); + + // Open zone file after decompressing ff and writing + return true; +} + +bool FastFile_COD8_360::Load(const QByteArray aData) { + QByteArray decompressedData; + + // Create a QDataStream on the input data. + QDataStream fastFileStream(aData); + fastFileStream.setByteOrder(QDataStream::LittleEndian); + + // For COD7/COD9, use BigEndian. + fastFileStream.setByteOrder(QDataStream::BigEndian); + + // Select key based on game. + QByteArray key = QByteArray::fromHex("0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3"); + + // Read the 8-byte magic. + QByteArray fileMagic(8, Qt::Uninitialized); + fastFileStream.readRawData(fileMagic.data(), 8); + if (fileMagic != "PHEEBs71") { + qWarning() << "Invalid fast file magic!"; + return false; + } + fastFileStream.skipRawData(4); + + // Read IV table name (32 bytes). + QByteArray fileName(32, Qt::Uninitialized); + fastFileStream.readRawData(fileName.data(), 32); + + // Skip the RSA signature (256 bytes). + QByteArray rsaSignature(256, Qt::Uninitialized); + fastFileStream.readRawData(rsaSignature.data(), 256); + + decompressedData = Encryption::decryptFastFile_BO2(aData); + + // For COD9, write out the complete decompressed zone for testing. + QFile testFile("exports/" + GetStem() + ".zone"); + if(testFile.open(QIODevice::WriteOnly)) { + testFile.write(decompressedData); + testFile.close(); + } + + // Load the zone file with the decompressed data (using an Xbox platform flag). + ZoneFile_COD8_360 zoneFile; + zoneFile.SetStem(GetStem()); + zoneFile.Load(decompressedData); + SetZoneFile(std::make_shared(zoneFile)); + + return true; +} diff --git a/libs/fastfile/360/fastfile_cod8_360.h b/libs/fastfile/360/fastfile_cod8_360.h new file mode 100644 index 0000000..793cc5a --- /dev/null +++ b/libs/fastfile/360/fastfile_cod8_360.h @@ -0,0 +1,20 @@ +#ifndef FASTFILE_COD8_360_H +#define FASTFILE_COD8_360_H + +#include "fastfile.h" + +class FastFile_COD8_360 : public FastFile +{ +public: + FastFile_COD8_360(); + FastFile_COD8_360(const QByteArray& aData); + FastFile_COD8_360(const QString aFilePath); + ~FastFile_COD8_360(); + + QByteArray GetBinaryData() override; + + bool Load(const QString aFilePath) override; + bool Load(const QByteArray aData) override; +}; + +#endif // FASTFILE_COD8_360_H diff --git a/libs/fastfile/360/fastfile_cod9_360.cpp b/libs/fastfile/360/fastfile_cod9_360.cpp new file mode 100644 index 0000000..04205f3 --- /dev/null +++ b/libs/fastfile/360/fastfile_cod9_360.cpp @@ -0,0 +1,115 @@ +#include "fastfile_cod9_360.h" +#include "zonefile_cod9_360.h" +#include "encryption.h" + +#include +#include + +FastFile_COD9_360::FastFile_COD9_360() + : FastFile() { + SetCompany(COMPANY_INFINITY_WARD); + SetType(FILETYPE_FAST_FILE); + SetSignage(SIGNAGE_UNSIGNED); + SetMagic(0); + SetVersion(0); + SetPlatform("360"); + SetGame("COD9"); +} + +FastFile_COD9_360::FastFile_COD9_360(const QByteArray& aData) + : FastFile_COD9_360() { + + if (!aData.isEmpty()) { + Load(aData); + } +} + +FastFile_COD9_360::FastFile_COD9_360(const QString aFilePath) + : FastFile_COD9_360() { + + if (!aFilePath.isEmpty()) { + Load(aFilePath); + } +} + +FastFile_COD9_360::~FastFile_COD9_360() { + +} + +QByteArray FastFile_COD9_360::GetBinaryData() { + return QByteArray(); +} + +bool FastFile_COD9_360::Load(const QString aFilePath) { + if (aFilePath.isEmpty()) { + return false; + } + + // Check fastfile can be read + QFile *file = new QFile(aFilePath); + if (!file->open(QIODevice::ReadOnly)) { + qDebug() << QString("Error: Failed to open FastFile: %1!").arg(aFilePath); + return false; + } + + // Decompress fastfile and close + const QString fastFileStem = aFilePath.section("/", -1, -1).section(".", 0, 0); + SetStem(fastFileStem); + if (!Load(file->readAll())) { + qDebug() << "Error: Failed to load fastfile: " << fastFileStem + ".ff"; + return false; + } + + file->close(); + + // Open zone file after decompressing ff and writing + return true; +} + +bool FastFile_COD9_360::Load(const QByteArray aData) { + QByteArray decompressedData; + + // Create a QDataStream on the input data. + QDataStream fastFileStream(aData); + fastFileStream.setByteOrder(QDataStream::LittleEndian); + + // For COD7/COD9, use BigEndian. + fastFileStream.setByteOrder(QDataStream::BigEndian); + + // Select key based on game. + QByteArray key = QByteArray::fromHex("0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3"); + + // Read the 8-byte magic. + QByteArray fileMagic(8, Qt::Uninitialized); + fastFileStream.readRawData(fileMagic.data(), 8); + if (fileMagic != "PHEEBs71") { + qWarning() << "Invalid fast file magic!"; + return false; + } + fastFileStream.skipRawData(4); + + // Read IV table name (32 bytes). + QByteArray fileName(32, Qt::Uninitialized); + fastFileStream.readRawData(fileName.data(), 32); + + // Skip the RSA signature (256 bytes). + QByteArray rsaSignature(256, Qt::Uninitialized); + fastFileStream.readRawData(rsaSignature.data(), 256); + + decompressedData = Encryption::decryptFastFile_BO2(aData); + + // For COD9, write out the complete decompressed zone for testing. + QFile testFile("exports/" + GetStem() + ".zone"); + if(testFile.open(QIODevice::WriteOnly)) { + testFile.write(decompressedData); + testFile.close(); + } + + // Load the zone file with the decompressed data (using an Xbox platform flag). + ZoneFile_COD9_360 zoneFile; + zoneFile.SetStem(GetStem()); + zoneFile.Load(decompressedData); + SetZoneFile(std::make_shared(zoneFile)); + + return true; +} diff --git a/libs/fastfile/360/fastfile_cod9_360.h b/libs/fastfile/360/fastfile_cod9_360.h new file mode 100644 index 0000000..84fa4a8 --- /dev/null +++ b/libs/fastfile/360/fastfile_cod9_360.h @@ -0,0 +1,20 @@ +#ifndef FASTFILE_COD9_360_H +#define FASTFILE_COD9_360_H + +#include "fastfile.h" + +class FastFile_COD9_360 : public FastFile +{ +public: + FastFile_COD9_360(); + FastFile_COD9_360(const QByteArray& aData); + FastFile_COD9_360(const QString aFilePath); + ~FastFile_COD9_360(); + + QByteArray GetBinaryData() override; + + bool Load(const QString aFilePath) override; + bool Load(const QByteArray aData) override; +}; + +#endif // FASTFILE_COD9_360_H diff --git a/libs/fastfile/PC/fastfile_cod10_pc.cpp b/libs/fastfile/PC/fastfile_cod10_pc.cpp new file mode 100644 index 0000000..34ef0b8 --- /dev/null +++ b/libs/fastfile/PC/fastfile_cod10_pc.cpp @@ -0,0 +1,137 @@ +#include "fastfile_cod10_pc.h" +#include "zonefile_cod10_pc.h" +#include "encryption.h" + +#include +#include + +FastFile_COD10_PC::FastFile_COD10_PC() + : FastFile() { + SetCompany(COMPANY_INFINITY_WARD); + SetType(FILETYPE_FAST_FILE); + SetSignage(SIGNAGE_UNSIGNED); + SetMagic(0); + SetVersion(0); + SetGame("COD10"); + SetPlatform("PC"); +} + +FastFile_COD10_PC::FastFile_COD10_PC(const QByteArray& aData) + : FastFile_COD10_PC() { + + if (!aData.isEmpty()) { + Load(aData); + } +} + +FastFile_COD10_PC::FastFile_COD10_PC(const QString aFilePath) + : FastFile_COD10_PC() { + + if (!aFilePath.isEmpty()) { + Load(aFilePath); + } +} + +FastFile_COD10_PC::~FastFile_COD10_PC() { + +} + +QByteArray FastFile_COD10_PC::GetBinaryData() { + return QByteArray(); +} + +bool FastFile_COD10_PC::Load(const QString aFilePath) { + if (aFilePath.isEmpty()) { + return false; + } + + // Check fastfile can be read + QFile *file = new QFile(aFilePath); + if (!file->open(QIODevice::ReadOnly)) { + qDebug() << QString("Error: Failed to open FastFile: %1!").arg(aFilePath); + return false; + } + + // Decompress fastfile and close + const QString fastFileStem = aFilePath.section("/", -1, -1).section(".", 0, 0); + SetStem(fastFileStem); + if (!Load(file->readAll())) { + qDebug() << "Error: Failed to load fastfile: " << fastFileStem + ".ff"; + return false; + } + + file->close(); + + // Open zone file after decompressing ff and writing + return true; +} + +bool FastFile_COD10_PC::Load(const QByteArray aData) { + QByteArray decompressedData; + + // Create a QDataStream on the input data. + QDataStream fastFileStream(aData); + fastFileStream.setByteOrder(QDataStream::LittleEndian); + + // Parse header values. + SetCompany(pParseFFCompany(&fastFileStream)); + SetType(pParseFFFileType(&fastFileStream)); + SetSignage(pParseFFSignage(&fastFileStream)); + SetMagic(pParseFFMagic(&fastFileStream)); + quint32 version = pParseFFVersion(&fastFileStream); + SetVersion(version); + SetPlatform(pCalculateFFPlatform(version)); + SetGame("COD9"); + + // For COD7/COD9, use BigEndian. + fastFileStream.setByteOrder(QDataStream::BigEndian); + if (GetPlatform() == "PC") { + fastFileStream.setByteOrder(QDataStream::LittleEndian); + } + + // Select key based on game. + QByteArray key; + if (GetPlatform() == "360") { + key = QByteArray::fromHex("0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3"); + } else if (GetPlatform() == "PC") { + key = QByteArray::fromHex("641D8A2FE31D3AA63622BBC9CE8587229D42B0F8ED9B924130BF88B65EDC50BE"); + } + + // Read the 8-byte magic. + QByteArray fileMagic(8, Qt::Uninitialized); + fastFileStream.readRawData(fileMagic.data(), 8); + if (fileMagic != "PHEEBs71") { + qWarning() << "Invalid fast file magic!"; + return false; + } + fastFileStream.skipRawData(4); + + // Read IV table name (32 bytes). + QByteArray fileName(32, Qt::Uninitialized); + fastFileStream.readRawData(fileName.data(), 32); + + // Skip the RSA signature (256 bytes). + QByteArray rsaSignature(256, Qt::Uninitialized); + fastFileStream.readRawData(rsaSignature.data(), 256); + + if (GetPlatform() == "360") { + //decompressedData = Compressor::cod9_decryptFastFile(aData); + } else if (GetPlatform() == "PC") { + decompressedData = Encryption::decryptFastFile_BO2(aData); + } + + // For COD9, write out the complete decompressed zone for testing. + QFile testFile("exports/" + GetStem() + ".zone"); + if(testFile.open(QIODevice::WriteOnly)) { + testFile.write(decompressedData); + testFile.close(); + } + + // Load the zone file with the decompressed data (using an Xbox platform flag). + ZoneFile_COD10_PC zoneFile; + zoneFile.SetStem(GetStem()); + zoneFile.Load(decompressedData); + SetZoneFile(std::make_shared(zoneFile)); + + return true; +} diff --git a/libs/fastfile/PC/fastfile_cod10_pc.h b/libs/fastfile/PC/fastfile_cod10_pc.h new file mode 100644 index 0000000..c4041d4 --- /dev/null +++ b/libs/fastfile/PC/fastfile_cod10_pc.h @@ -0,0 +1,20 @@ +#ifndef FASTFILE_COD10_PC_H +#define FASTFILE_COD10_PC_H + +#include "fastfile.h" + +class FastFile_COD10_PC : public FastFile +{ +public: + FastFile_COD10_PC(); + FastFile_COD10_PC(const QByteArray &aData); + FastFile_COD10_PC(const QString aFilePath); + ~FastFile_COD10_PC(); + + QByteArray GetBinaryData() override; + + bool Load(const QString aFilePath) override; + bool Load(const QByteArray aData) override; +}; + +#endif // FASTFILE_COD10_PC_H diff --git a/libs/fastfile/PC/fastfile_cod11_pc.cpp b/libs/fastfile/PC/fastfile_cod11_pc.cpp new file mode 100644 index 0000000..dafaf47 --- /dev/null +++ b/libs/fastfile/PC/fastfile_cod11_pc.cpp @@ -0,0 +1,137 @@ +#include "fastfile_cod11_pc.h" +#include "zonefile_cod11_pc.h" +#include "encryption.h" + +#include +#include + +FastFile_COD11_PC::FastFile_COD11_PC() + : FastFile() { + SetCompany(COMPANY_INFINITY_WARD); + SetType(FILETYPE_FAST_FILE); + SetSignage(SIGNAGE_UNSIGNED); + SetMagic(0); + SetVersion(0); + SetGame("COD11"); + SetPlatform("PC"); +} + +FastFile_COD11_PC::FastFile_COD11_PC(const QByteArray& aData) + : FastFile_COD11_PC() { + + if (!aData.isEmpty()) { + Load(aData); + } +} + +FastFile_COD11_PC::FastFile_COD11_PC(const QString aFilePath) + : FastFile_COD11_PC() { + + if (!aFilePath.isEmpty()) { + Load(aFilePath); + } +} + +FastFile_COD11_PC::~FastFile_COD11_PC() { + +} + +QByteArray FastFile_COD11_PC::GetBinaryData() { + return QByteArray(); +} + +bool FastFile_COD11_PC::Load(const QString aFilePath) { + if (aFilePath.isEmpty()) { + return false; + } + + // Check fastfile can be read + QFile *file = new QFile(aFilePath); + if (!file->open(QIODevice::ReadOnly)) { + qDebug() << QString("Error: Failed to open FastFile: %1!").arg(aFilePath); + return false; + } + + // Decompress fastfile and close + const QString fastFileStem = aFilePath.section("/", -1, -1).section(".", 0, 0); + SetStem(fastFileStem); + if (!Load(file->readAll())) { + qDebug() << "Error: Failed to load fastfile: " << fastFileStem + ".ff"; + return false; + } + + file->close(); + + // Open zone file after decompressing ff and writing + return true; +} + +bool FastFile_COD11_PC::Load(const QByteArray aData) { + QByteArray decompressedData; + + // Create a QDataStream on the input data. + QDataStream fastFileStream(aData); + fastFileStream.setByteOrder(QDataStream::LittleEndian); + + // Parse header values. + SetCompany(pParseFFCompany(&fastFileStream)); + SetType(pParseFFFileType(&fastFileStream)); + SetSignage(pParseFFSignage(&fastFileStream)); + SetMagic(pParseFFMagic(&fastFileStream)); + quint32 version = pParseFFVersion(&fastFileStream); + SetVersion(version); + SetPlatform(pCalculateFFPlatform(version)); + SetGame("COD9"); + + // For COD7/COD9, use BigEndian. + fastFileStream.setByteOrder(QDataStream::BigEndian); + if (GetPlatform() == "PC") { + fastFileStream.setByteOrder(QDataStream::LittleEndian); + } + + // Select key based on game. + QByteArray key; + if (GetPlatform() == "360") { + key = QByteArray::fromHex("0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3"); + } else if (GetPlatform() == "PC") { + key = QByteArray::fromHex("641D8A2FE31D3AA63622BBC9CE8587229D42B0F8ED9B924130BF88B65EDC50BE"); + } + + // Read the 8-byte magic. + QByteArray fileMagic(8, Qt::Uninitialized); + fastFileStream.readRawData(fileMagic.data(), 8); + if (fileMagic != "PHEEBs71") { + qWarning() << "Invalid fast file magic!"; + return false; + } + fastFileStream.skipRawData(4); + + // Read IV table name (32 bytes). + QByteArray fileName(32, Qt::Uninitialized); + fastFileStream.readRawData(fileName.data(), 32); + + // Skip the RSA signature (256 bytes). + QByteArray rsaSignature(256, Qt::Uninitialized); + fastFileStream.readRawData(rsaSignature.data(), 256); + + if (GetPlatform() == "360") { + //decompressedData = Compressor::cod9_decryptFastFile(aData); + } else if (GetPlatform() == "PC") { + decompressedData = Encryption::decryptFastFile_BO2(aData); + } + + // For COD9, write out the complete decompressed zone for testing. + QFile testFile("exports/" + GetStem() + ".zone"); + if(testFile.open(QIODevice::WriteOnly)) { + testFile.write(decompressedData); + testFile.close(); + } + + // Load the zone file with the decompressed data (using an Xbox platform flag). + ZoneFile_COD11_PC zoneFile; + zoneFile.SetStem(GetStem()); + zoneFile.Load(decompressedData); + SetZoneFile(std::make_shared(zoneFile)); + + return true; +} diff --git a/libs/fastfile/PC/fastfile_cod11_pc.h b/libs/fastfile/PC/fastfile_cod11_pc.h new file mode 100644 index 0000000..cf493d5 --- /dev/null +++ b/libs/fastfile/PC/fastfile_cod11_pc.h @@ -0,0 +1,20 @@ +#ifndef FASTFILE_COD11_PC_H +#define FASTFILE_COD11_PC_H + +#include "fastfile.h" + +class FastFile_COD11_PC : public FastFile +{ +public: + FastFile_COD11_PC(); + FastFile_COD11_PC(const QByteArray &aData); + FastFile_COD11_PC(const QString aFilePath); + ~FastFile_COD11_PC(); + + QByteArray GetBinaryData() override; + + bool Load(const QString aFilePath) override; + bool Load(const QByteArray aData) override; +}; + +#endif // FASTFILE_COD11_PC_H diff --git a/libs/fastfile/PC/fastfile_cod12_pc.cpp b/libs/fastfile/PC/fastfile_cod12_pc.cpp new file mode 100644 index 0000000..5541223 --- /dev/null +++ b/libs/fastfile/PC/fastfile_cod12_pc.cpp @@ -0,0 +1,151 @@ +#include "fastfile_cod12_pc.h" +#include "zonefile_cod12_pc.h" + +#include "utils.h" +#include "compression.h" +#include "encryption.h" + +#include +#include + +FastFile_COD12_PC::FastFile_COD12_PC() + : FastFile() { + SetCompany(COMPANY_INFINITY_WARD); + SetType(FILETYPE_FAST_FILE); + SetSignage(SIGNAGE_UNSIGNED); + SetMagic(0); + SetVersion(0); + SetGame("COD12"); + SetPlatform("PC"); +} + +FastFile_COD12_PC::FastFile_COD12_PC(const QByteArray& aData) + : FastFile_COD12_PC() { + + if (!aData.isEmpty()) { + Load(aData); + } +} + +FastFile_COD12_PC::FastFile_COD12_PC(const QString aFilePath) + : FastFile_COD12_PC() { + + if (!aFilePath.isEmpty()) { + Load(aFilePath); + } +} + +FastFile_COD12_PC::~FastFile_COD12_PC() { + +} + +QByteArray FastFile_COD12_PC::GetBinaryData() { + return QByteArray(); +} + +bool FastFile_COD12_PC::Load(const QString aFilePath) { + if (aFilePath.isEmpty()) { + return false; + } + + // Check fastfile can be read + QFile *file = new QFile(aFilePath); + if (!file->open(QIODevice::ReadOnly)) { + qDebug() << QString("Error: Failed to open FastFile: %1!").arg(aFilePath); + return false; + } + + // Decompress fastfile and close + const QString fastFileStem = aFilePath.section("/", -1, -1).split('.').first(); + SetStem(fastFileStem); + if (!Load(file->readAll())) { + qDebug() << "Error: Failed to load fastfile: " << fastFileStem; + return false; + } + + file->close(); + + // Open zone file after decompressing ff and writing + return true; +} + +bool FastFile_COD12_PC::Load(const QByteArray aData) { + QByteArray decompressedData; + + // Create a QDataStream on the input data. + QDataStream fastFileStream(aData); + fastFileStream.setByteOrder(QDataStream::LittleEndian); + + // Load the zone file with the decompressed data (using an Xbox platform flag). + ZoneFile_COD12_PC zoneFile; + zoneFile.SetStem(GetStem()); + + // Skip header magic + fastFileStream.skipRawData(8); + + quint32 version; + fastFileStream >> version; + + quint8 unknownFlag, compressionFlag, platformFlag, encryptionFlag; + fastFileStream >> unknownFlag >> compressionFlag >> platformFlag >> encryptionFlag; + + if (compressionFlag != 1) { + qDebug() << "Invalid fastfile compression: " << compressionFlag; + return false; + } else if (platformFlag != 0) { + qDebug() << "Invalid platform: " << platformFlag; + return false; + } else if (encryptionFlag != 0) { + qDebug() << "Decryption not supported yet!"; + return false; + } + + fastFileStream.skipRawData(128); + + quint64 size; + fastFileStream >> size; + + fastFileStream.skipRawData(432); + + int consumed = 0; + while(consumed < size) + { + // Read Block Header + quint32 compressedSize, decompressedSize, blockSize, blockPosition; + fastFileStream >> compressedSize >> decompressedSize >> blockSize >> blockPosition; + + // Validate the block position, it should match + if(blockPosition != fastFileStream.device()->pos() - 16) + { + qDebug() << "Block Position does not match Stream Position."; + return false; + } + + // Check for padding blocks + if(decompressedSize == 0) + { + fastFileStream.device()->read((((fastFileStream.device()->pos()) + ((0x800000) - 1)) & ~((0x800000) - 1)) - fastFileStream.device()->pos()); + continue; + } + + fastFileStream.device()->read(2); + + QByteArray compressedData(compressedSize - 2, Qt::Uninitialized); + qDebug() << "Data position: " << fastFileStream.device()->pos() << " - Size: " << compressedSize; + fastFileStream.readRawData(compressedData.data(), compressedSize - 2); + decompressedData.append(Compression::DecompressDeflate(compressedData)); + + consumed += decompressedSize; + + // Sinze Fast Files are aligns, we must skip the full block + fastFileStream.device()->seek(blockPosition + 16 + blockSize); + } + + Utils::ExportData(GetStem() + ".zone", decompressedData); + + zoneFile.Load(decompressedData); + + SetZoneFile(std::make_shared(zoneFile)); + + return true; +} diff --git a/libs/fastfile/PC/fastfile_cod12_pc.h b/libs/fastfile/PC/fastfile_cod12_pc.h new file mode 100644 index 0000000..5613275 --- /dev/null +++ b/libs/fastfile/PC/fastfile_cod12_pc.h @@ -0,0 +1,20 @@ +#ifndef FASTFILE_COD12_PC_H +#define FASTFILE_COD12_PC_H + +#include "fastfile.h" + +class FastFile_COD12_PC : public FastFile +{ +public: + FastFile_COD12_PC(); + FastFile_COD12_PC(const QByteArray &aData); + FastFile_COD12_PC(const QString aFilePath); + ~FastFile_COD12_PC(); + + QByteArray GetBinaryData() override; + + bool Load(const QString aFilePath) override; + bool Load(const QByteArray aData) override; +}; + +#endif // FASTFILE_COD12_PC_H diff --git a/libs/fastfile/PC/fastfile_cod4_pc.cpp b/libs/fastfile/PC/fastfile_cod4_pc.cpp new file mode 100644 index 0000000..c457d97 --- /dev/null +++ b/libs/fastfile/PC/fastfile_cod4_pc.cpp @@ -0,0 +1,93 @@ +#include "fastfile_cod4_pc.h" +#include "zonefile_cod4_pc.h" + +#include "utils.h" +#include "compression.h" +#include "statusbarmanager.h" + +#include +#include + +FastFile_COD4_PC::FastFile_COD4_PC() + : FastFile() { + SetCompany(COMPANY_INFINITY_WARD); + SetType(FILETYPE_FAST_FILE); + SetSignage(SIGNAGE_UNSIGNED); + SetMagic(0); + SetVersion(0); + SetPlatform("PC"); + SetGame("COD4"); +} + +FastFile_COD4_PC::FastFile_COD4_PC(const QByteArray& aData) + : FastFile_COD4_PC() { + + if (!aData.isEmpty()) { + Load(aData); + } +} + +FastFile_COD4_PC::FastFile_COD4_PC(const QString aFilePath) + : FastFile_COD4_PC() { + + if (!aFilePath.isEmpty()) { + Load(aFilePath); + } +} + +FastFile_COD4_PC::~FastFile_COD4_PC() { + +} + +QByteArray FastFile_COD4_PC::GetBinaryData() { + return QByteArray(); +} + +bool FastFile_COD4_PC::Load(const QString aFilePath) { + StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/path", 1000); + + if (aFilePath.isEmpty()) { + return false; + } + + // Check fastfile can be read + QFile *file = new QFile(aFilePath); + if (!file->open(QIODevice::ReadOnly)) { + qDebug() << QString("Error: Failed to open FastFile: %1!").arg(aFilePath); + return false; + } + + // Decompress fastfile and close + const QString fastFileStem = aFilePath.section("/", -1, -1); + SetStem(fastFileStem); + if (!Load(file->readAll())) { + qDebug() << "Error: Failed to load fastfile: " << fastFileStem; + return false; + } + + file->close(); + + // Open zone file after decompressing ff and writing + return true; +} + +bool FastFile_COD4_PC::Load(const QByteArray aData) { + StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/data", 1000); + QByteArray decompressedData; + + // Create a QDataStream on the input data. + QDataStream fastFileStream(aData); + fastFileStream.setByteOrder(QDataStream::LittleEndian); + + // For COD5, simply decompress from offset 12. + decompressedData = Compression::DecompressZLIB(aData.mid(12)); + + Utils::ExportData(GetStem() + ".zone", decompressedData); + + ZoneFile_COD4_PC zoneFile; + zoneFile.SetStem(GetStem()); + zoneFile.Load(decompressedData); + SetZoneFile(std::make_shared(zoneFile)); + + return true; +} diff --git a/libs/fastfile/PC/fastfile_cod4_pc.h b/libs/fastfile/PC/fastfile_cod4_pc.h new file mode 100644 index 0000000..3b5e3d0 --- /dev/null +++ b/libs/fastfile/PC/fastfile_cod4_pc.h @@ -0,0 +1,20 @@ +#ifndef FASTFILE_COD4_PC_H +#define FASTFILE_COD4_PC_H + +#include "fastfile.h" + +class FastFile_COD4_PC : public FastFile +{ +public: + FastFile_COD4_PC(); + FastFile_COD4_PC(const QByteArray &aData); + FastFile_COD4_PC(const QString aFilePath); + ~FastFile_COD4_PC(); + + QByteArray GetBinaryData() override; + + bool Load(const QString aFilePath) override; + bool Load(const QByteArray aData) override; +}; + +#endif // FASTFILE_COD4_PC_H diff --git a/libs/fastfile/PC/fastfile_cod5_pc.cpp b/libs/fastfile/PC/fastfile_cod5_pc.cpp new file mode 100644 index 0000000..a277a56 --- /dev/null +++ b/libs/fastfile/PC/fastfile_cod5_pc.cpp @@ -0,0 +1,93 @@ +#include "fastfile_cod5_pc.h" +#include "zonefile_cod5_pc.h" + +#include "utils.h" +#include "compression.h" +#include "statusbarmanager.h" + +#include +#include + +FastFile_COD5_PC::FastFile_COD5_PC() + : FastFile() { + SetCompany(COMPANY_INFINITY_WARD); + SetType(FILETYPE_FAST_FILE); + SetSignage(SIGNAGE_UNSIGNED); + SetMagic(0); + SetVersion(0); + SetPlatform("PC"); + SetGame("COD5"); +} + +FastFile_COD5_PC::FastFile_COD5_PC(const QByteArray& aData) + : FastFile_COD5_PC() { + + if (!aData.isEmpty()) { + Load(aData); + } +} + +FastFile_COD5_PC::FastFile_COD5_PC(const QString aFilePath) + : FastFile_COD5_PC() { + + if (!aFilePath.isEmpty()) { + Load(aFilePath); + } +} + +FastFile_COD5_PC::~FastFile_COD5_PC() { + +} + +QByteArray FastFile_COD5_PC::GetBinaryData() { + return QByteArray(); +} + +bool FastFile_COD5_PC::Load(const QString aFilePath) { + StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/path", 1000); + + if (aFilePath.isEmpty()) { + return false; + } + + // Check fastfile can be read + QFile *file = new QFile(aFilePath); + if (!file->open(QIODevice::ReadOnly)) { + qDebug() << QString("Error: Failed to open FastFile: %1!").arg(aFilePath); + return false; + } + + // Decompress fastfile and close + const QString fastFileStem = aFilePath.section("/", -1, -1); + SetStem(fastFileStem); + if (!Load(file->readAll())) { + qDebug() << "Error: Failed to load fastfile: " << fastFileStem; + return false; + } + + file->close(); + + // Open zone file after decompressing ff and writing + return true; +} + +bool FastFile_COD5_PC::Load(const QByteArray aData) { + StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/data", 1000); + QByteArray decompressedData; + + // Create a QDataStream on the input data. + QDataStream fastFileStream(aData); + fastFileStream.setByteOrder(QDataStream::LittleEndian); + + // For COD5, simply decompress from offset 12. + decompressedData = Compression::DecompressZLIB(aData.mid(12)); + + Utils::ExportData(GetStem() + ".zone", decompressedData); + + ZoneFile_COD5_PC zoneFile; + zoneFile.SetStem(GetStem()); + zoneFile.Load(decompressedData); + SetZoneFile(std::make_shared(zoneFile)); + + return true; +} diff --git a/libs/fastfile/PC/fastfile_cod5_pc.h b/libs/fastfile/PC/fastfile_cod5_pc.h new file mode 100644 index 0000000..7251203 --- /dev/null +++ b/libs/fastfile/PC/fastfile_cod5_pc.h @@ -0,0 +1,20 @@ +#ifndef FASTFILE_COD5_PC_H +#define FASTFILE_COD5_PC_H + +#include "fastfile.h" + +class FastFile_COD5_PC : public FastFile +{ +public: + FastFile_COD5_PC(); + FastFile_COD5_PC(const QByteArray &aData); + FastFile_COD5_PC(const QString aFilePath); + ~FastFile_COD5_PC(); + + QByteArray GetBinaryData() override; + + bool Load(const QString aFilePath) override; + bool Load(const QByteArray aData) override; +}; + +#endif // FASTFILE_COD5_PC_H diff --git a/libs/fastfile/PC/fastfile_cod6_pc.cpp b/libs/fastfile/PC/fastfile_cod6_pc.cpp new file mode 100644 index 0000000..df8c444 --- /dev/null +++ b/libs/fastfile/PC/fastfile_cod6_pc.cpp @@ -0,0 +1,93 @@ +#include "fastfile_cod6_pc.h" +#include "zonefile_cod6_pc.h" + +#include "utils.h" +#include "compression.h" +#include "statusbarmanager.h" + +#include +#include + +FastFile_COD6_PC::FastFile_COD6_PC() + : FastFile() { + SetCompany(COMPANY_INFINITY_WARD); + SetType(FILETYPE_FAST_FILE); + SetSignage(SIGNAGE_UNSIGNED); + SetMagic(0); + SetVersion(0); + SetPlatform("PC"); + SetGame("COD6"); +} + +FastFile_COD6_PC::FastFile_COD6_PC(const QByteArray& aData) + : FastFile_COD6_PC() { + + if (!aData.isEmpty()) { + Load(aData); + } +} + +FastFile_COD6_PC::FastFile_COD6_PC(const QString aFilePath) + : FastFile_COD6_PC() { + + if (!aFilePath.isEmpty()) { + Load(aFilePath); + } +} + +FastFile_COD6_PC::~FastFile_COD6_PC() { + +} + +QByteArray FastFile_COD6_PC::GetBinaryData() { + return QByteArray(); +} + +bool FastFile_COD6_PC::Load(const QString aFilePath) { + StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/path", 1000); + + if (aFilePath.isEmpty()) { + return false; + } + + // Check fastfile can be read + QFile *file = new QFile(aFilePath); + if (!file->open(QIODevice::ReadOnly)) { + qDebug() << QString("Error: Failed to open FastFile: %1!").arg(aFilePath); + return false; + } + + // Decompress fastfile and close + const QString fastFileStem = aFilePath.section("/", -1, -1); + SetStem(fastFileStem); + if (!Load(file->readAll())) { + qDebug() << "Error: Failed to load fastfile: " << fastFileStem; + return false; + } + + file->close(); + + // Open zone file after decompressing ff and writing + return true; +} + +bool FastFile_COD6_PC::Load(const QByteArray aData) { + StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/data", 1000); + QByteArray decompressedData; + + // Create a QDataStream on the input data. + QDataStream fastFileStream(aData); + fastFileStream.setByteOrder(QDataStream::LittleEndian); + + // For COD5, simply decompress from offset 12. + decompressedData = Compression::DecompressZLIB(aData.mid(12)); + + Utils::ExportData(GetStem() + ".zone", decompressedData); + + ZoneFile_COD6_PC zoneFile; + zoneFile.SetStem(GetStem()); + zoneFile.Load(decompressedData); + SetZoneFile(std::make_shared(zoneFile)); + + return true; +} diff --git a/libs/fastfile/PC/fastfile_cod6_pc.h b/libs/fastfile/PC/fastfile_cod6_pc.h new file mode 100644 index 0000000..8670c99 --- /dev/null +++ b/libs/fastfile/PC/fastfile_cod6_pc.h @@ -0,0 +1,20 @@ +#ifndef FASTFILE_COD6_PC_H +#define FASTFILE_COD6_PC_H + +#include "fastfile.h" + +class FastFile_COD6_PC : public FastFile +{ +public: + FastFile_COD6_PC(); + FastFile_COD6_PC(const QByteArray &aData); + FastFile_COD6_PC(const QString aFilePath); + ~FastFile_COD6_PC(); + + QByteArray GetBinaryData() override; + + bool Load(const QString aFilePath) override; + bool Load(const QByteArray aData) override; +}; + +#endif // FASTFILE_COD6_PC_H diff --git a/libs/fastfile/PC/fastfile_cod7_pc.cpp b/libs/fastfile/PC/fastfile_cod7_pc.cpp new file mode 100644 index 0000000..787688c --- /dev/null +++ b/libs/fastfile/PC/fastfile_cod7_pc.cpp @@ -0,0 +1,170 @@ +#include "fastfile_cod7_pc.h" +#include "zonefile_cod7_pc.h" + +#include "utils.h" +#include "compression.h" +#include "encryption.h" + +#include +#include + +FastFile_COD7_PC::FastFile_COD7_PC() + : FastFile() { + SetCompany(COMPANY_INFINITY_WARD); + SetType(FILETYPE_FAST_FILE); + SetSignage(SIGNAGE_UNSIGNED); + SetMagic(0); + SetVersion(0); + SetGame("COD7"); + SetPlatform("PC"); +} + +FastFile_COD7_PC::FastFile_COD7_PC(const QByteArray& aData) + : FastFile_COD7_PC() { + + if (!aData.isEmpty()) { + Load(aData); + } +} + +FastFile_COD7_PC::FastFile_COD7_PC(const QString aFilePath) + : FastFile_COD7_PC() { + + if (!aFilePath.isEmpty()) { + Load(aFilePath); + } +} + +FastFile_COD7_PC::~FastFile_COD7_PC() { + +} + +QByteArray FastFile_COD7_PC::GetBinaryData() { + return QByteArray(); +} + +bool FastFile_COD7_PC::Load(const QString aFilePath) { + if (aFilePath.isEmpty()) { + return false; + } + + // Check fastfile can be read + QFile *file = new QFile(aFilePath); + if (!file->open(QIODevice::ReadOnly)) { + qDebug() << QString("Error: Failed to open FastFile: %1!").arg(aFilePath); + return false; + } + + // Decompress fastfile and close + const QString fastFileStem = aFilePath.section("/", -1, -1); + SetStem(fastFileStem); + if (!Load(file->readAll())) { + qDebug() << "Error: Failed to load fastfile: " << fastFileStem; + return false; + } + + file->close(); + + // Open zone file after decompressing ff and writing + return true; +} + +bool FastFile_COD7_PC::Load(const QByteArray aData) { + QByteArray decompressedData; + + // Create a QDataStream on the input data. + QDataStream fastFileStream(aData); + fastFileStream.setByteOrder(QDataStream::LittleEndian); + + // Parse header values. + SetCompany(pParseFFCompany(&fastFileStream)); + SetType(pParseFFFileType(&fastFileStream)); + SetSignage(pParseFFSignage(&fastFileStream)); + SetMagic(pParseFFMagic(&fastFileStream)); + quint32 version = pParseFFVersion(&fastFileStream); + SetVersion(version); + SetPlatform(pCalculateFFPlatform(version)); + SetGame("COD7"); + + // Load the zone file with the decompressed data (using an Xbox platform flag). + ZoneFile_COD7_PC zoneFile; + zoneFile.SetStem(GetStem()); + + // For COD7/COD9, use BigEndian. + fastFileStream.setByteOrder(QDataStream::LittleEndian); + + // Select key based on game. + QByteArray key; + fastFileStream.skipRawData(4); + if (GetPlatform() == "360") { + key = QByteArray::fromHex("1ac1d12d527c59b40eca619120ff8217ccff09cd16896f81b829c7f52793405d"); + } else if (GetPlatform() == "PS3") { + key = QByteArray::fromHex("46D3F997F29C9ACE175B0DAE3AB8C0C1B8E423E2E3BF7E3C311EA35245BF193A"); + // or + // key = QByteArray::fromHex("0C99B3DDB8D6D0845D1147E470F28A8BF2AE69A8A9F534767B54E9180FF55370"); + } + + // Read the 8-byte magic. + QByteArray fileMagic(8, Qt::Uninitialized); + fastFileStream.readRawData(fileMagic.data(), 8); + if (fileMagic != "PHEEBs71") { + qWarning() << "Invalid fast file magic!"; + return false; + } + fastFileStream.skipRawData(4); + + // Read IV table name (32 bytes). + QByteArray fileName(32, Qt::Uninitialized); + fastFileStream.readRawData(fileName.data(), 32); + + // Build the IV table from the fileName. + QByteArray ivTable = Encryption::InitIVTable(fileName); + + // Skip the RSA signature (256 bytes). + QByteArray rsaSignature(256, Qt::Uninitialized); + fastFileStream.readRawData(rsaSignature.data(), 256); + + // Now the stream should be positioned at 0x13C, where sections begin. + int sectionIndex = 0; + while (true) { + qint32 sectionSize = 0; + fastFileStream >> sectionSize; + qDebug() << "Section index:" << sectionIndex << "Size:" << sectionSize + << "Pos:" << fastFileStream.device()->pos(); + if (sectionSize == 0) + break; + + // Read the section data. + QByteArray sectionData; + sectionData.resize(sectionSize); + fastFileStream.readRawData(sectionData.data(), sectionSize); + + // Compute the IV for this section. + QByteArray iv = Encryption::GetIV(ivTable, sectionIndex); + + // Decrypt the section using Salsa20. + QByteArray decData = Encryption::salsa20DecryptSection(sectionData, key, iv); + + // Compute SHA1 hash of the decrypted data. + QByteArray sectionHash = QCryptographicHash::hash(decData, QCryptographicHash::Sha1); + + // Update the IV table based on the section hash. + Encryption::UpdateIVTable(ivTable, sectionIndex, sectionHash); + + // Build a compressed data buffer by prepending the two-byte zlib header. + QByteArray compressedData; + compressedData.append(char(0x78)); + compressedData.append(char(0x01)); + compressedData.append(decData); + + decompressedData.append(Compression::DecompressZLIB(compressedData)); + + sectionIndex++; + } + + zoneFile.Load(decompressedData); + + SetZoneFile(std::make_shared(zoneFile)); + + return true; +} diff --git a/libs/fastfile/PC/fastfile_cod7_pc.h b/libs/fastfile/PC/fastfile_cod7_pc.h new file mode 100644 index 0000000..5372582 --- /dev/null +++ b/libs/fastfile/PC/fastfile_cod7_pc.h @@ -0,0 +1,20 @@ +#ifndef FASTFILE_COD7_PC_H +#define FASTFILE_COD7_PC_H + +#include "fastfile.h" + +class FastFile_COD7_PC : public FastFile +{ +public: + FastFile_COD7_PC(); + FastFile_COD7_PC(const QByteArray &aData); + FastFile_COD7_PC(const QString aFilePath); + ~FastFile_COD7_PC(); + + QByteArray GetBinaryData() override; + + bool Load(const QString aFilePath) override; + bool Load(const QByteArray aData) override; +}; + +#endif // FASTFILE_COD7_PC_H diff --git a/libs/fastfile/PC/fastfile_cod8_pc.cpp b/libs/fastfile/PC/fastfile_cod8_pc.cpp new file mode 100644 index 0000000..472098f --- /dev/null +++ b/libs/fastfile/PC/fastfile_cod8_pc.cpp @@ -0,0 +1,170 @@ +#include "fastfile_cod8_pc.h" +#include "zonefile_cod8_pc.h" + +#include "utils.h" +#include "compression.h" +#include "encryption.h" + +#include +#include + +FastFile_COD8_PC::FastFile_COD8_PC() + : FastFile() { + SetCompany(COMPANY_INFINITY_WARD); + SetType(FILETYPE_FAST_FILE); + SetSignage(SIGNAGE_UNSIGNED); + SetMagic(0); + SetVersion(0); + SetGame("COD8"); + SetPlatform("PC"); +} + +FastFile_COD8_PC::FastFile_COD8_PC(const QByteArray& aData) + : FastFile_COD8_PC() { + + if (!aData.isEmpty()) { + Load(aData); + } +} + +FastFile_COD8_PC::FastFile_COD8_PC(const QString aFilePath) + : FastFile_COD8_PC() { + + if (!aFilePath.isEmpty()) { + Load(aFilePath); + } +} + +FastFile_COD8_PC::~FastFile_COD8_PC() { + +} + +QByteArray FastFile_COD8_PC::GetBinaryData() { + return QByteArray(); +} + +bool FastFile_COD8_PC::Load(const QString aFilePath) { + if (aFilePath.isEmpty()) { + return false; + } + + // Check fastfile can be read + QFile *file = new QFile(aFilePath); + if (!file->open(QIODevice::ReadOnly)) { + qDebug() << QString("Error: Failed to open FastFile: %1!").arg(aFilePath); + return false; + } + + // Decompress fastfile and close + const QString fastFileStem = aFilePath.section("/", -1, -1); + SetStem(fastFileStem); + if (!Load(file->readAll())) { + qDebug() << "Error: Failed to load fastfile: " << fastFileStem; + return false; + } + + file->close(); + + // Open zone file after decompressing ff and writing + return true; +} + +bool FastFile_COD8_PC::Load(const QByteArray aData) { + QByteArray decompressedData; + + // Create a QDataStream on the input data. + QDataStream fastFileStream(aData); + fastFileStream.setByteOrder(QDataStream::LittleEndian); + + // Parse header values. + SetCompany(pParseFFCompany(&fastFileStream)); + SetType(pParseFFFileType(&fastFileStream)); + SetSignage(pParseFFSignage(&fastFileStream)); + SetMagic(pParseFFMagic(&fastFileStream)); + quint32 version = pParseFFVersion(&fastFileStream); + SetVersion(version); + SetPlatform(pCalculateFFPlatform(version)); + SetGame("COD7"); + + // Load the zone file with the decompressed data (using an Xbox platform flag). + ZoneFile_COD8_PC zoneFile; + zoneFile.SetStem(GetStem()); + + // For COD7/COD9, use BigEndian. + fastFileStream.setByteOrder(QDataStream::LittleEndian); + + // Select key based on game. + QByteArray key; + fastFileStream.skipRawData(4); + if (GetPlatform() == "360") { + key = QByteArray::fromHex("1ac1d12d527c59b40eca619120ff8217ccff09cd16896f81b829c7f52793405d"); + } else if (GetPlatform() == "PS3") { + key = QByteArray::fromHex("46D3F997F29C9ACE175B0DAE3AB8C0C1B8E423E2E3BF7E3C311EA35245BF193A"); + // or + // key = QByteArray::fromHex("0C99B3DDB8D6D0845D1147E470F28A8BF2AE69A8A9F534767B54E9180FF55370"); + } + + // Read the 8-byte magic. + QByteArray fileMagic(8, Qt::Uninitialized); + fastFileStream.readRawData(fileMagic.data(), 8); + if (fileMagic != "PHEEBs71") { + qWarning() << "Invalid fast file magic!"; + return false; + } + fastFileStream.skipRawData(4); + + // Read IV table name (32 bytes). + QByteArray fileName(32, Qt::Uninitialized); + fastFileStream.readRawData(fileName.data(), 32); + + // Build the IV table from the fileName. + QByteArray ivTable = Encryption::InitIVTable(fileName); + + // Skip the RSA signature (256 bytes). + QByteArray rsaSignature(256, Qt::Uninitialized); + fastFileStream.readRawData(rsaSignature.data(), 256); + + // Now the stream should be positioned at 0x13C, where sections begin. + int sectionIndex = 0; + while (true) { + qint32 sectionSize = 0; + fastFileStream >> sectionSize; + qDebug() << "Section index:" << sectionIndex << "Size:" << sectionSize + << "Pos:" << fastFileStream.device()->pos(); + if (sectionSize == 0) + break; + + // Read the section data. + QByteArray sectionData; + sectionData.resize(sectionSize); + fastFileStream.readRawData(sectionData.data(), sectionSize); + + // Compute the IV for this section. + QByteArray iv = Encryption::GetIV(ivTable, sectionIndex); + + // Decrypt the section using Salsa20. + QByteArray decData = Encryption::salsa20DecryptSection(sectionData, key, iv); + + // Compute SHA1 hash of the decrypted data. + QByteArray sectionHash = QCryptographicHash::hash(decData, QCryptographicHash::Sha1); + + // Update the IV table based on the section hash. + Encryption::UpdateIVTable(ivTable, sectionIndex, sectionHash); + + // Build a compressed data buffer by prepending the two-byte zlib header. + QByteArray compressedData; + compressedData.append(char(0x78)); + compressedData.append(char(0x01)); + compressedData.append(decData); + + decompressedData.append(Compression::DecompressZLIB(compressedData)); + + sectionIndex++; + } + + zoneFile.Load(decompressedData); + + SetZoneFile(std::make_shared(zoneFile)); + + return true; +} diff --git a/libs/fastfile/PC/fastfile_cod8_pc.h b/libs/fastfile/PC/fastfile_cod8_pc.h new file mode 100644 index 0000000..2476836 --- /dev/null +++ b/libs/fastfile/PC/fastfile_cod8_pc.h @@ -0,0 +1,20 @@ +#ifndef FASTFILE_COD8_PC_H +#define FASTFILE_COD8_PC_H + +#include "fastfile.h" + +class FastFile_COD8_PC : public FastFile +{ +public: + FastFile_COD8_PC(); + FastFile_COD8_PC(const QByteArray &aData); + FastFile_COD8_PC(const QString aFilePath); + ~FastFile_COD8_PC(); + + QByteArray GetBinaryData() override; + + bool Load(const QString aFilePath) override; + bool Load(const QByteArray aData) override; +}; + +#endif // FASTFILE_COD8_PC_H diff --git a/libs/fastfile/PC/fastfile_cod9_pc.cpp b/libs/fastfile/PC/fastfile_cod9_pc.cpp new file mode 100644 index 0000000..2b920c9 --- /dev/null +++ b/libs/fastfile/PC/fastfile_cod9_pc.cpp @@ -0,0 +1,137 @@ +#include "fastfile_cod9_pc.h" +#include "zonefile_cod9_pc.h" +#include "encryption.h" + +#include +#include + +FastFile_COD9_PC::FastFile_COD9_PC() + : FastFile() { + SetCompany(COMPANY_INFINITY_WARD); + SetType(FILETYPE_FAST_FILE); + SetSignage(SIGNAGE_UNSIGNED); + SetMagic(0); + SetVersion(0); + SetGame("COD9"); + SetPlatform("PC"); +} + +FastFile_COD9_PC::FastFile_COD9_PC(const QByteArray& aData) + : FastFile_COD9_PC() { + + if (!aData.isEmpty()) { + Load(aData); + } +} + +FastFile_COD9_PC::FastFile_COD9_PC(const QString aFilePath) + : FastFile_COD9_PC() { + + if (!aFilePath.isEmpty()) { + Load(aFilePath); + } +} + +FastFile_COD9_PC::~FastFile_COD9_PC() { + +} + +QByteArray FastFile_COD9_PC::GetBinaryData() { + return QByteArray(); +} + +bool FastFile_COD9_PC::Load(const QString aFilePath) { + if (aFilePath.isEmpty()) { + return false; + } + + // Check fastfile can be read + QFile *file = new QFile(aFilePath); + if (!file->open(QIODevice::ReadOnly)) { + qDebug() << QString("Error: Failed to open FastFile: %1!").arg(aFilePath); + return false; + } + + // Decompress fastfile and close + const QString fastFileStem = aFilePath.section("/", -1, -1).section(".", 0, 0); + SetStem(fastFileStem); + if (!Load(file->readAll())) { + qDebug() << "Error: Failed to load fastfile: " << fastFileStem + ".ff"; + return false; + } + + file->close(); + + // Open zone file after decompressing ff and writing + return true; +} + +bool FastFile_COD9_PC::Load(const QByteArray aData) { + QByteArray decompressedData; + + // Create a QDataStream on the input data. + QDataStream fastFileStream(aData); + fastFileStream.setByteOrder(QDataStream::LittleEndian); + + // Parse header values. + SetCompany(pParseFFCompany(&fastFileStream)); + SetType(pParseFFFileType(&fastFileStream)); + SetSignage(pParseFFSignage(&fastFileStream)); + SetMagic(pParseFFMagic(&fastFileStream)); + quint32 version = pParseFFVersion(&fastFileStream); + SetVersion(version); + SetPlatform(pCalculateFFPlatform(version)); + SetGame("COD9"); + + // For COD7/COD9, use BigEndian. + fastFileStream.setByteOrder(QDataStream::BigEndian); + if (GetPlatform() == "PC") { + fastFileStream.setByteOrder(QDataStream::LittleEndian); + } + + // Select key based on game. + QByteArray key; + if (GetPlatform() == "360") { + key = QByteArray::fromHex("0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3"); + } else if (GetPlatform() == "PC") { + key = QByteArray::fromHex("641D8A2FE31D3AA63622BBC9CE8587229D42B0F8ED9B924130BF88B65EDC50BE"); + } + + // Read the 8-byte magic. + QByteArray fileMagic(8, Qt::Uninitialized); + fastFileStream.readRawData(fileMagic.data(), 8); + if (fileMagic != "PHEEBs71") { + qWarning() << "Invalid fast file magic!"; + return false; + } + fastFileStream.skipRawData(4); + + // Read IV table name (32 bytes). + QByteArray fileName(32, Qt::Uninitialized); + fastFileStream.readRawData(fileName.data(), 32); + + // Skip the RSA signature (256 bytes). + QByteArray rsaSignature(256, Qt::Uninitialized); + fastFileStream.readRawData(rsaSignature.data(), 256); + + if (GetPlatform() == "360") { + //decompressedData = Compressor::cod9_decryptFastFile(aData); + } else if (GetPlatform() == "PC") { + decompressedData = Encryption::decryptFastFile_BO2(aData); + } + + // For COD9, write out the complete decompressed zone for testing. + QFile testFile("exports/" + GetStem() + ".zone"); + if(testFile.open(QIODevice::WriteOnly)) { + testFile.write(decompressedData); + testFile.close(); + } + + // Load the zone file with the decompressed data (using an Xbox platform flag). + ZoneFile_COD9_PC zoneFile; + zoneFile.SetStem(GetStem()); + zoneFile.Load(decompressedData); + SetZoneFile(std::make_shared(zoneFile)); + + return true; +} diff --git a/libs/fastfile/PC/fastfile_cod9_pc.h b/libs/fastfile/PC/fastfile_cod9_pc.h new file mode 100644 index 0000000..144e680 --- /dev/null +++ b/libs/fastfile/PC/fastfile_cod9_pc.h @@ -0,0 +1,20 @@ +#ifndef FASTFILE_COD9_PC_H +#define FASTFILE_COD9_PC_H + +#include "fastfile.h" + +class FastFile_COD9_PC : public FastFile +{ +public: + FastFile_COD9_PC(); + FastFile_COD9_PC(const QByteArray &aData); + FastFile_COD9_PC(const QString aFilePath); + ~FastFile_COD9_PC(); + + QByteArray GetBinaryData() override; + + bool Load(const QString aFilePath) override; + bool Load(const QByteArray aData) override; +}; + +#endif // FASTFILE_COD9_PC_H diff --git a/libs/fastfile/PS3/fastfile_cod10_ps3.cpp b/libs/fastfile/PS3/fastfile_cod10_ps3.cpp new file mode 100644 index 0000000..e0f1bca --- /dev/null +++ b/libs/fastfile/PS3/fastfile_cod10_ps3.cpp @@ -0,0 +1,137 @@ +#include "fastfile_cod10_ps3.h" +#include "zonefile_cod10_ps3.h" +#include "encryption.h" + +#include +#include + +FastFile_COD10_PS3::FastFile_COD10_PS3() + : FastFile() { + SetCompany(COMPANY_INFINITY_WARD); + SetType(FILETYPE_FAST_FILE); + SetSignage(SIGNAGE_UNSIGNED); + SetMagic(0); + SetVersion(0); + SetGame("COD10"); + SetPlatform("PS3"); +} + +FastFile_COD10_PS3::FastFile_COD10_PS3(const QByteArray& aData) + : FastFile_COD10_PS3() { + + if (!aData.isEmpty()) { + Load(aData); + } +} + +FastFile_COD10_PS3::FastFile_COD10_PS3(const QString aFilePath) + : FastFile_COD10_PS3() { + + if (!aFilePath.isEmpty()) { + Load(aFilePath); + } +} + +FastFile_COD10_PS3::~FastFile_COD10_PS3() { + +} + +QByteArray FastFile_COD10_PS3::GetBinaryData() { + return QByteArray(); +} + +bool FastFile_COD10_PS3::Load(const QString aFilePath) { + if (aFilePath.isEmpty()) { + return false; + } + + // Check fastfile can be read + QFile *file = new QFile(aFilePath); + if (!file->open(QIODevice::ReadOnly)) { + qDebug() << QString("Error: Failed to open FastFile: %1!").arg(aFilePath); + return false; + } + + // Decompress fastfile and close + const QString fastFileStem = aFilePath.section("/", -1, -1).section(".", 0, 0); + SetStem(fastFileStem); + if (!Load(file->readAll())) { + qDebug() << "Error: Failed to load fastfile: " << fastFileStem + ".ff"; + return false; + } + + file->close(); + + // Open zone file after decompressing ff and writing + return true; +} + +bool FastFile_COD10_PS3::Load(const QByteArray aData) { + QByteArray decompressedData; + + // Create a QDataStream on the input data. + QDataStream fastFileStream(aData); + fastFileStream.setByteOrder(QDataStream::LittleEndian); + + // Parse header values. + SetCompany(pParseFFCompany(&fastFileStream)); + SetType(pParseFFFileType(&fastFileStream)); + SetSignage(pParseFFSignage(&fastFileStream)); + SetMagic(pParseFFMagic(&fastFileStream)); + quint32 version = pParseFFVersion(&fastFileStream); + SetVersion(version); + SetPlatform(pCalculateFFPlatform(version)); + SetGame("COD9"); + + // For COD7/COD9, use BigEndian. + fastFileStream.setByteOrder(QDataStream::BigEndian); + if (GetPlatform() == "PC") { + fastFileStream.setByteOrder(QDataStream::LittleEndian); + } + + // Select key based on game. + QByteArray key; + if (GetPlatform() == "360") { + key = QByteArray::fromHex("0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3"); + } else if (GetPlatform() == "PC") { + key = QByteArray::fromHex("641D8A2FE31D3AA63622BBC9CE8587229D42B0F8ED9B924130BF88B65EDC50BE"); + } + + // Read the 8-byte magic. + QByteArray fileMagic(8, Qt::Uninitialized); + fastFileStream.readRawData(fileMagic.data(), 8); + if (fileMagic != "PHEEBs71") { + qWarning() << "Invalid fast file magic!"; + return false; + } + fastFileStream.skipRawData(4); + + // Read IV table name (32 bytes). + QByteArray fileName(32, Qt::Uninitialized); + fastFileStream.readRawData(fileName.data(), 32); + + // Skip the RSA signature (256 bytes). + QByteArray rsaSignature(256, Qt::Uninitialized); + fastFileStream.readRawData(rsaSignature.data(), 256); + + if (GetPlatform() == "360") { + //decompressedData = Compressor::cod9_decryptFastFile(aData); + } else if (GetPlatform() == "PC") { + decompressedData = Encryption::decryptFastFile_BO2(aData); + } + + // For COD9, write out the complete decompressed zone for testing. + QFile testFile("exports/" + GetStem() + ".zone"); + if(testFile.open(QIODevice::WriteOnly)) { + testFile.write(decompressedData); + testFile.close(); + } + + // Load the zone file with the decompressed data (using an Xbox platform flag). + ZoneFile_COD10_PS3 zoneFile; + zoneFile.SetStem(GetStem()); + zoneFile.Load(decompressedData); + SetZoneFile(std::make_shared(zoneFile)); + + return true; +} diff --git a/libs/fastfile/PS3/fastfile_cod10_ps3.h b/libs/fastfile/PS3/fastfile_cod10_ps3.h new file mode 100644 index 0000000..885d4cc --- /dev/null +++ b/libs/fastfile/PS3/fastfile_cod10_ps3.h @@ -0,0 +1,20 @@ +#ifndef FASTFILE_COD10_PS3_H +#define FASTFILE_COD10_PS3_H + +#include "fastfile.h" + +class FastFile_COD10_PS3 : public FastFile +{ +public: + FastFile_COD10_PS3(); + FastFile_COD10_PS3(const QByteArray &aData); + FastFile_COD10_PS3(const QString aFilePath); + ~FastFile_COD10_PS3(); + + QByteArray GetBinaryData() override; + + bool Load(const QString aFilePath) override; + bool Load(const QByteArray aData) override; +}; + +#endif // FASTFILE_COD10_PS3_H diff --git a/libs/fastfile/PS3/fastfile_cod11_ps3.cpp b/libs/fastfile/PS3/fastfile_cod11_ps3.cpp new file mode 100644 index 0000000..34c7e91 --- /dev/null +++ b/libs/fastfile/PS3/fastfile_cod11_ps3.cpp @@ -0,0 +1,137 @@ +#include "fastfile_cod11_ps3.h" +#include "zonefile_cod11_ps3.h" +#include "encryption.h" + +#include +#include + +FastFile_COD11_PS3::FastFile_COD11_PS3() + : FastFile() { + SetCompany(COMPANY_INFINITY_WARD); + SetType(FILETYPE_FAST_FILE); + SetSignage(SIGNAGE_UNSIGNED); + SetMagic(0); + SetVersion(0); + SetGame("COD11"); + SetPlatform("PS3"); +} + +FastFile_COD11_PS3::FastFile_COD11_PS3(const QByteArray& aData) + : FastFile_COD11_PS3() { + + if (!aData.isEmpty()) { + Load(aData); + } +} + +FastFile_COD11_PS3::FastFile_COD11_PS3(const QString aFilePath) + : FastFile_COD11_PS3() { + + if (!aFilePath.isEmpty()) { + Load(aFilePath); + } +} + +FastFile_COD11_PS3::~FastFile_COD11_PS3() { + +} + +QByteArray FastFile_COD11_PS3::GetBinaryData() { + return QByteArray(); +} + +bool FastFile_COD11_PS3::Load(const QString aFilePath) { + if (aFilePath.isEmpty()) { + return false; + } + + // Check fastfile can be read + QFile *file = new QFile(aFilePath); + if (!file->open(QIODevice::ReadOnly)) { + qDebug() << QString("Error: Failed to open FastFile: %1!").arg(aFilePath); + return false; + } + + // Decompress fastfile and close + const QString fastFileStem = aFilePath.section("/", -1, -1).section(".", 0, 0); + SetStem(fastFileStem); + if (!Load(file->readAll())) { + qDebug() << "Error: Failed to load fastfile: " << fastFileStem + ".ff"; + return false; + } + + file->close(); + + // Open zone file after decompressing ff and writing + return true; +} + +bool FastFile_COD11_PS3::Load(const QByteArray aData) { + QByteArray decompressedData; + + // Create a QDataStream on the input data. + QDataStream fastFileStream(aData); + fastFileStream.setByteOrder(QDataStream::LittleEndian); + + // Parse header values. + SetCompany(pParseFFCompany(&fastFileStream)); + SetType(pParseFFFileType(&fastFileStream)); + SetSignage(pParseFFSignage(&fastFileStream)); + SetMagic(pParseFFMagic(&fastFileStream)); + quint32 version = pParseFFVersion(&fastFileStream); + SetVersion(version); + SetPlatform(pCalculateFFPlatform(version)); + SetGame("COD9"); + + // For COD7/COD9, use BigEndian. + fastFileStream.setByteOrder(QDataStream::BigEndian); + if (GetPlatform() == "PC") { + fastFileStream.setByteOrder(QDataStream::LittleEndian); + } + + // Select key based on game. + QByteArray key; + if (GetPlatform() == "360") { + key = QByteArray::fromHex("0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3"); + } else if (GetPlatform() == "PC") { + key = QByteArray::fromHex("641D8A2FE31D3AA63622BBC9CE8587229D42B0F8ED9B924130BF88B65EDC50BE"); + } + + // Read the 8-byte magic. + QByteArray fileMagic(8, Qt::Uninitialized); + fastFileStream.readRawData(fileMagic.data(), 8); + if (fileMagic != "PHEEBs71") { + qWarning() << "Invalid fast file magic!"; + return false; + } + fastFileStream.skipRawData(4); + + // Read IV table name (32 bytes). + QByteArray fileName(32, Qt::Uninitialized); + fastFileStream.readRawData(fileName.data(), 32); + + // Skip the RSA signature (256 bytes). + QByteArray rsaSignature(256, Qt::Uninitialized); + fastFileStream.readRawData(rsaSignature.data(), 256); + + if (GetPlatform() == "360") { + //decompressedData = Compressor::cod9_decryptFastFile(aData); + } else if (GetPlatform() == "PC") { + decompressedData = Encryption::decryptFastFile_BO2(aData); + } + + // For COD9, write out the complete decompressed zone for testing. + QFile testFile("exports/" + GetStem() + ".zone"); + if(testFile.open(QIODevice::WriteOnly)) { + testFile.write(decompressedData); + testFile.close(); + } + + // Load the zone file with the decompressed data (using an Xbox platform flag). + ZoneFile_COD11_PS3 zoneFile; + zoneFile.SetStem(GetStem()); + zoneFile.Load(decompressedData); + SetZoneFile(std::make_shared(zoneFile)); + + return true; +} diff --git a/libs/fastfile/PS3/fastfile_cod11_ps3.h b/libs/fastfile/PS3/fastfile_cod11_ps3.h new file mode 100644 index 0000000..3424fb5 --- /dev/null +++ b/libs/fastfile/PS3/fastfile_cod11_ps3.h @@ -0,0 +1,20 @@ +#ifndef FASTFILE_COD11_PS3_H +#define FASTFILE_COD11_PS3_H + +#include "fastfile.h" + +class FastFile_COD11_PS3 : public FastFile +{ +public: + FastFile_COD11_PS3(); + FastFile_COD11_PS3(const QByteArray &aData); + FastFile_COD11_PS3(const QString aFilePath); + ~FastFile_COD11_PS3(); + + QByteArray GetBinaryData() override; + + bool Load(const QString aFilePath) override; + bool Load(const QByteArray aData) override; +}; + +#endif // FASTFILE_COD11_PS3_H diff --git a/libs/fastfile/PS3/fastfile_cod12_ps3.cpp b/libs/fastfile/PS3/fastfile_cod12_ps3.cpp new file mode 100644 index 0000000..b3768e1 --- /dev/null +++ b/libs/fastfile/PS3/fastfile_cod12_ps3.cpp @@ -0,0 +1,137 @@ +#include "fastfile_cod12_ps3.h" +#include "zonefile_cod12_ps3.h" +#include "encryption.h" + +#include +#include + +FastFile_COD12_PS3::FastFile_COD12_PS3() + : FastFile() { + SetCompany(COMPANY_INFINITY_WARD); + SetType(FILETYPE_FAST_FILE); + SetSignage(SIGNAGE_UNSIGNED); + SetMagic(0); + SetVersion(0); + SetGame("COD12"); + SetPlatform("PS3"); +} + +FastFile_COD12_PS3::FastFile_COD12_PS3(const QByteArray& aData) + : FastFile_COD12_PS3() { + + if (!aData.isEmpty()) { + Load(aData); + } +} + +FastFile_COD12_PS3::FastFile_COD12_PS3(const QString aFilePath) + : FastFile_COD12_PS3() { + + if (!aFilePath.isEmpty()) { + Load(aFilePath); + } +} + +FastFile_COD12_PS3::~FastFile_COD12_PS3() { + +} + +QByteArray FastFile_COD12_PS3::GetBinaryData() { + return QByteArray(); +} + +bool FastFile_COD12_PS3::Load(const QString aFilePath) { + if (aFilePath.isEmpty()) { + return false; + } + + // Check fastfile can be read + QFile *file = new QFile(aFilePath); + if (!file->open(QIODevice::ReadOnly)) { + qDebug() << QString("Error: Failed to open FastFile: %1!").arg(aFilePath); + return false; + } + + // Decompress fastfile and close + const QString fastFileStem = aFilePath.section("/", -1, -1).section(".", 0, 0); + SetStem(fastFileStem); + if (!Load(file->readAll())) { + qDebug() << "Error: Failed to load fastfile: " << fastFileStem + ".ff"; + return false; + } + + file->close(); + + // Open zone file after decompressing ff and writing + return true; +} + +bool FastFile_COD12_PS3::Load(const QByteArray aData) { + QByteArray decompressedData; + + // Create a QDataStream on the input data. + QDataStream fastFileStream(aData); + fastFileStream.setByteOrder(QDataStream::LittleEndian); + + // Parse header values. + SetCompany(pParseFFCompany(&fastFileStream)); + SetType(pParseFFFileType(&fastFileStream)); + SetSignage(pParseFFSignage(&fastFileStream)); + SetMagic(pParseFFMagic(&fastFileStream)); + quint32 version = pParseFFVersion(&fastFileStream); + SetVersion(version); + SetPlatform(pCalculateFFPlatform(version)); + SetGame("COD9"); + + // For COD7/COD9, use BigEndian. + fastFileStream.setByteOrder(QDataStream::BigEndian); + if (GetPlatform() == "PC") { + fastFileStream.setByteOrder(QDataStream::LittleEndian); + } + + // Select key based on game. + QByteArray key; + if (GetPlatform() == "360") { + key = QByteArray::fromHex("0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3"); + } else if (GetPlatform() == "PC") { + key = QByteArray::fromHex("641D8A2FE31D3AA63622BBC9CE8587229D42B0F8ED9B924130BF88B65EDC50BE"); + } + + // Read the 8-byte magic. + QByteArray fileMagic(8, Qt::Uninitialized); + fastFileStream.readRawData(fileMagic.data(), 8); + if (fileMagic != "PHEEBs71") { + qWarning() << "Invalid fast file magic!"; + return false; + } + fastFileStream.skipRawData(4); + + // Read IV table name (32 bytes). + QByteArray fileName(32, Qt::Uninitialized); + fastFileStream.readRawData(fileName.data(), 32); + + // Skip the RSA signature (256 bytes). + QByteArray rsaSignature(256, Qt::Uninitialized); + fastFileStream.readRawData(rsaSignature.data(), 256); + + if (GetPlatform() == "360") { + //decompressedData = Compressor::cod9_decryptFastFile(aData); + } else if (GetPlatform() == "PC") { + decompressedData = Encryption::decryptFastFile_BO2(aData); + } + + // For COD9, write out the complete decompressed zone for testing. + QFile testFile("exports/" + GetStem() + ".zone"); + if(testFile.open(QIODevice::WriteOnly)) { + testFile.write(decompressedData); + testFile.close(); + } + + // Load the zone file with the decompressed data (using an Xbox platform flag). + ZoneFile_COD12_PS3 zoneFile; + zoneFile.SetStem(GetStem()); + zoneFile.Load(decompressedData); + SetZoneFile(std::make_shared(zoneFile)); + + return true; +} diff --git a/libs/fastfile/PS3/fastfile_cod12_ps3.h b/libs/fastfile/PS3/fastfile_cod12_ps3.h new file mode 100644 index 0000000..9f66318 --- /dev/null +++ b/libs/fastfile/PS3/fastfile_cod12_ps3.h @@ -0,0 +1,20 @@ +#ifndef FASTFILE_COD12_PS3_H +#define FASTFILE_COD12_PS3_H + +#include "fastfile.h" + +class FastFile_COD12_PS3 : public FastFile +{ +public: + FastFile_COD12_PS3(); + FastFile_COD12_PS3(const QByteArray &aData); + FastFile_COD12_PS3(const QString aFilePath); + ~FastFile_COD12_PS3(); + + QByteArray GetBinaryData() override; + + bool Load(const QString aFilePath) override; + bool Load(const QByteArray aData) override; +}; + +#endif // FASTFILE_COD12_PS3_H diff --git a/libs/fastfile/PS3/fastfile_cod4_ps3.cpp b/libs/fastfile/PS3/fastfile_cod4_ps3.cpp new file mode 100644 index 0000000..d6ccbe3 --- /dev/null +++ b/libs/fastfile/PS3/fastfile_cod4_ps3.cpp @@ -0,0 +1,120 @@ +#include "fastfile_cod4_ps3.h" +#include "zonefile_cod4_ps3.h" + +#include "utils.h" +#include "compression.h" +#include "statusbarmanager.h" + +#include +#include + +FastFile_COD4_PS3::FastFile_COD4_PS3() + : FastFile() { + SetCompany(COMPANY_INFINITY_WARD); + SetType(FILETYPE_FAST_FILE); + SetSignage(SIGNAGE_UNSIGNED); + SetMagic(0); + SetVersion(0); + SetGame("COD4"); + SetPlatform("PS3"); +} + +FastFile_COD4_PS3::FastFile_COD4_PS3(const QByteArray& aData) + : FastFile_COD4_PS3() { + + if (!aData.isEmpty()) { + Load(aData); + } +} + +FastFile_COD4_PS3::FastFile_COD4_PS3(const QString aFilePath) + : FastFile_COD4_PS3() { + + if (!aFilePath.isEmpty()) { + Load(aFilePath); + } +} + +FastFile_COD4_PS3::~FastFile_COD4_PS3() { + +} + +QByteArray FastFile_COD4_PS3::GetBinaryData() { + return QByteArray(); +} + +bool FastFile_COD4_PS3::Load(const QString aFilePath) { + StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/path", 1000); + + if (aFilePath.isEmpty()) { + return false; + } + + // Check fastfile can be read + QFile *file = new QFile(aFilePath); + if (!file->open(QIODevice::ReadOnly)) { + qDebug() << QString("Error: Failed to open FastFile: %1!").arg(aFilePath); + return false; + } + + // Decompress fastfile and close + const QString fastFileStem = aFilePath.section("/", -1, -1); + SetStem(fastFileStem); + if (!Load(file->readAll())) { + qDebug() << "Error: Failed to load fastfile: " << fastFileStem; + return false; + } + + file->close(); + + // Open zone file after decompressing ff and writing + return true; +} + +bool FastFile_COD4_PS3::Load(const QByteArray aData) { + StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/data", 1000); + QByteArray decompressedData; + + // Create a QDataStream on the input data. + QDataStream fastFileStream(aData); + fastFileStream.setByteOrder(QDataStream::LittleEndian); + + // Parse header values. + SetCompany(pParseFFCompany(&fastFileStream)); + SetType(pParseFFFileType(&fastFileStream)); + SetSignage(pParseFFSignage(&fastFileStream)); + SetMagic(pParseFFMagic(&fastFileStream)); + SetVersion(pParseFFVersion(&fastFileStream)); + + int pos = 12; + // Loop until EOF or invalid chunk + while (pos <= aData.size()) { + // Read 2-byte BIG-ENDIAN chunk size + quint16 chunkSize; + QDataStream chunkStream(aData.mid(pos, 2)); + chunkStream.setByteOrder(QDataStream::BigEndian); + chunkStream >> chunkSize; + + pos += 2; + + if (chunkSize == 0 || pos + chunkSize > aData.size()) { + qWarning() << "Invalid or incomplete chunk detected, stopping."; + break; + } + + const QByteArray compressedChunk = aData.mid(pos, chunkSize); + + decompressedData.append(Compression::DecompressDeflate(compressedChunk)); + + pos += chunkSize; + } + + Utils::ExportData(GetStem() + ".zone", decompressedData); + + ZoneFile_COD4_PS3 zoneFile; + zoneFile.SetStem(GetStem()); + zoneFile.Load(decompressedData); + SetZoneFile(std::make_shared(zoneFile)); + + return true; +} diff --git a/libs/fastfile/PS3/fastfile_cod4_ps3.h b/libs/fastfile/PS3/fastfile_cod4_ps3.h new file mode 100644 index 0000000..78cc865 --- /dev/null +++ b/libs/fastfile/PS3/fastfile_cod4_ps3.h @@ -0,0 +1,20 @@ +#ifndef FASTFILE_COD4_PS3_H +#define FASTFILE_COD4_PS3_H + +#include "fastfile.h" + +class FastFile_COD4_PS3 : public FastFile +{ +public: + FastFile_COD4_PS3(); + FastFile_COD4_PS3(const QByteArray &aData); + FastFile_COD4_PS3(const QString aFilePath); + ~FastFile_COD4_PS3(); + + QByteArray GetBinaryData() override; + + bool Load(const QString aFilePath) override; + bool Load(const QByteArray aData) override; +}; + +#endif // FASTFILE_COD4_PS3_H diff --git a/libs/fastfile/PS3/fastfile_cod5_ps3.cpp b/libs/fastfile/PS3/fastfile_cod5_ps3.cpp new file mode 100644 index 0000000..4c84099 --- /dev/null +++ b/libs/fastfile/PS3/fastfile_cod5_ps3.cpp @@ -0,0 +1,120 @@ +#include "fastfile_cod5_ps3.h" +#include "zonefile_cod5_ps3.h" + +#include "utils.h" +#include "compression.h" +#include "statusbarmanager.h" + +#include +#include + +FastFile_COD5_PS3::FastFile_COD5_PS3() + : FastFile() { + SetCompany(COMPANY_INFINITY_WARD); + SetType(FILETYPE_FAST_FILE); + SetSignage(SIGNAGE_UNSIGNED); + SetMagic(0); + SetVersion(0); + SetGame("COD5"); + SetPlatform("PS3"); +} + +FastFile_COD5_PS3::FastFile_COD5_PS3(const QByteArray& aData) + : FastFile_COD5_PS3() { + + if (!aData.isEmpty()) { + Load(aData); + } +} + +FastFile_COD5_PS3::FastFile_COD5_PS3(const QString aFilePath) + : FastFile_COD5_PS3() { + + if (!aFilePath.isEmpty()) { + Load(aFilePath); + } +} + +FastFile_COD5_PS3::~FastFile_COD5_PS3() { + +} + +QByteArray FastFile_COD5_PS3::GetBinaryData() { + return QByteArray(); +} + +bool FastFile_COD5_PS3::Load(const QString aFilePath) { + StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/path", 1000); + + if (aFilePath.isEmpty()) { + return false; + } + + // Check fastfile can be read + QFile *file = new QFile(aFilePath); + if (!file->open(QIODevice::ReadOnly)) { + qDebug() << QString("Error: Failed to open FastFile: %1!").arg(aFilePath); + return false; + } + + // Decompress fastfile and close + const QString fastFileStem = aFilePath.section("/", -1, -1); + SetStem(fastFileStem); + if (!Load(file->readAll())) { + qDebug() << "Error: Failed to load fastfile: " << fastFileStem; + return false; + } + + file->close(); + + // Open zone file after decompressing ff and writing + return true; +} + +bool FastFile_COD5_PS3::Load(const QByteArray aData) { + StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/data", 1000); + QByteArray decompressedData; + + // Create a QDataStream on the input data. + QDataStream fastFileStream(aData); + fastFileStream.setByteOrder(QDataStream::LittleEndian); + + // Parse header values. + SetCompany(pParseFFCompany(&fastFileStream)); + SetType(pParseFFFileType(&fastFileStream)); + SetSignage(pParseFFSignage(&fastFileStream)); + SetMagic(pParseFFMagic(&fastFileStream)); + SetVersion(pParseFFVersion(&fastFileStream)); + + int pos = 12; + // Loop until EOF or invalid chunk + while (pos <= aData.size()) { + // Read 2-byte BIG-ENDIAN chunk size + quint16 chunkSize; + QDataStream chunkStream(aData.mid(pos, 2)); + chunkStream.setByteOrder(QDataStream::BigEndian); + chunkStream >> chunkSize; + + pos += 2; + + if (chunkSize == 0 || pos + chunkSize > aData.size()) { + qWarning() << "Invalid or incomplete chunk detected, stopping."; + break; + } + + const QByteArray compressedChunk = aData.mid(pos, chunkSize); + + decompressedData.append(Compression::DecompressDeflate(compressedChunk)); + + pos += chunkSize; + } + + Utils::ExportData(GetStem() + ".zone", decompressedData); + + ZoneFile_COD5_PS3 zoneFile; + zoneFile.SetStem(GetStem()); + zoneFile.Load(decompressedData); + SetZoneFile(std::make_shared(zoneFile)); + + return true; +} diff --git a/libs/fastfile/PS3/fastfile_cod5_ps3.h b/libs/fastfile/PS3/fastfile_cod5_ps3.h new file mode 100644 index 0000000..2714960 --- /dev/null +++ b/libs/fastfile/PS3/fastfile_cod5_ps3.h @@ -0,0 +1,20 @@ +#ifndef FASTFILE_COD5_PS3_H +#define FASTFILE_COD5_PS3_H + +#include "fastfile.h" + +class FastFile_COD5_PS3 : public FastFile +{ +public: + FastFile_COD5_PS3(); + FastFile_COD5_PS3(const QByteArray &aData); + FastFile_COD5_PS3(const QString aFilePath); + ~FastFile_COD5_PS3(); + + QByteArray GetBinaryData() override; + + bool Load(const QString aFilePath) override; + bool Load(const QByteArray aData) override; +}; + +#endif // FASTFILE_COD5_PS3_H diff --git a/libs/fastfile/PS3/fastfile_cod6_ps3.cpp b/libs/fastfile/PS3/fastfile_cod6_ps3.cpp new file mode 100644 index 0000000..f0d0929 --- /dev/null +++ b/libs/fastfile/PS3/fastfile_cod6_ps3.cpp @@ -0,0 +1,104 @@ +#include "fastfile_cod6_ps3.h" +#include "zonefile_cod6_ps3.h" + +#include "utils.h" +#include "compression.h" +#include "statusbarmanager.h" + +#include +#include + +FastFile_COD6_PS3::FastFile_COD6_PS3() + : FastFile() { + SetCompany(COMPANY_INFINITY_WARD); + SetType(FILETYPE_FAST_FILE); + SetSignage(SIGNAGE_UNSIGNED); + SetMagic(0); + SetVersion(0); + SetGame("COD6"); + SetPlatform("PS3"); +} + +FastFile_COD6_PS3::FastFile_COD6_PS3(const QByteArray& aData) + : FastFile_COD6_PS3() { + + if (!aData.isEmpty()) { + Load(aData); + } +} + +FastFile_COD6_PS3::FastFile_COD6_PS3(const QString aFilePath) + : FastFile_COD6_PS3() { + + if (!aFilePath.isEmpty()) { + Load(aFilePath); + } +} + +FastFile_COD6_PS3::~FastFile_COD6_PS3() { + +} + +QByteArray FastFile_COD6_PS3::GetBinaryData() { + return QByteArray(); +} + +bool FastFile_COD6_PS3::Load(const QString aFilePath) { + StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/path", 1000); + + if (aFilePath.isEmpty()) { + return false; + } + + // Check fastfile can be read + QFile *file = new QFile(aFilePath); + if (!file->open(QIODevice::ReadOnly)) { + qDebug() << QString("Error: Failed to open FastFile: %1!").arg(aFilePath); + return false; + } + + // Decompress fastfile and close + const QString fastFileStem = aFilePath.section("/", -1, -1); + SetStem(fastFileStem); + if (!Load(file->readAll())) { + qDebug() << "Error: Failed to load fastfile: " << fastFileStem; + return false; + } + + file->close(); + + // Open zone file after decompressing ff and writing + return true; +} + +bool FastFile_COD6_PS3::Load(const QByteArray aData) { + StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/data", 1000); + QByteArray decompressedData; + + // Create a QDataStream on the input data. + QDataStream fastFileStream(aData); + fastFileStream.setByteOrder(QDataStream::LittleEndian); + + // Parse header values. + SetCompany(pParseFFCompany(&fastFileStream)); + SetType(pParseFFFileType(&fastFileStream)); + SetSignage(pParseFFSignage(&fastFileStream)); + SetMagic(pParseFFMagic(&fastFileStream)); + quint32 version = pParseFFVersion(&fastFileStream); + SetVersion(version); + const QString platformStr = pCalculateFFPlatform(version); + SetPlatform(platformStr); + SetGame("COD5"); + + // For COD5, simply decompress from offset 12. + decompressedData = Compression::DecompressZLIB(aData.mid(12)); + + Utils::ExportData(GetStem() + ".zone", decompressedData); + + ZoneFile_COD6_PS3 zoneFile; + zoneFile.SetStem(GetStem()); + zoneFile.Load(decompressedData); + SetZoneFile(std::make_shared(zoneFile)); + + return true; +} diff --git a/libs/fastfile/PS3/fastfile_cod6_ps3.h b/libs/fastfile/PS3/fastfile_cod6_ps3.h new file mode 100644 index 0000000..aecd2b0 --- /dev/null +++ b/libs/fastfile/PS3/fastfile_cod6_ps3.h @@ -0,0 +1,20 @@ +#ifndef FASTFILE_COD6_PS3_H +#define FASTFILE_COD6_PS3_H + +#include "fastfile.h" + +class FastFile_COD6_PS3 : public FastFile +{ +public: + FastFile_COD6_PS3(); + FastFile_COD6_PS3(const QByteArray &aData); + FastFile_COD6_PS3(const QString aFilePath); + ~FastFile_COD6_PS3(); + + QByteArray GetBinaryData() override; + + bool Load(const QString aFilePath) override; + bool Load(const QByteArray aData) override; +}; + +#endif // FASTFILE_COD6_PS3_H diff --git a/libs/fastfile/PS3/fastfile_cod7_ps3.cpp b/libs/fastfile/PS3/fastfile_cod7_ps3.cpp new file mode 100644 index 0000000..8bc980a --- /dev/null +++ b/libs/fastfile/PS3/fastfile_cod7_ps3.cpp @@ -0,0 +1,173 @@ +#include "fastfile_cod7_ps3.h" +#include "zonefile_cod7_ps3.h" + +#include "utils.h" +#include "compression.h" +#include "encryption.h" + +#include +#include + +FastFile_COD7_PS3::FastFile_COD7_PS3() + : FastFile() { + SetCompany(COMPANY_INFINITY_WARD); + SetType(FILETYPE_FAST_FILE); + SetSignage(SIGNAGE_UNSIGNED); + SetMagic(0); + SetVersion(0); + SetGame("COD7"); + SetPlatform("PS3"); +} + +FastFile_COD7_PS3::FastFile_COD7_PS3(const QByteArray& aData) + : FastFile_COD7_PS3() { + + if (!aData.isEmpty()) { + Load(aData); + } +} + +FastFile_COD7_PS3::FastFile_COD7_PS3(const QString aFilePath) + : FastFile_COD7_PS3() { + + if (!aFilePath.isEmpty()) { + Load(aFilePath); + } +} + +FastFile_COD7_PS3::~FastFile_COD7_PS3() { + +} + +QByteArray FastFile_COD7_PS3::GetBinaryData() { + return QByteArray(); +} + +bool FastFile_COD7_PS3::Load(const QString aFilePath) { + if (aFilePath.isEmpty()) { + return false; + } + + // Check fastfile can be read + QFile *file = new QFile(aFilePath); + if (!file->open(QIODevice::ReadOnly)) { + qDebug() << QString("Error: Failed to open FastFile: %1!").arg(aFilePath); + return false; + } + + // Decompress fastfile and close + const QString fastFileStem = aFilePath.section("/", -1, -1); + SetStem(fastFileStem); + if (!Load(file->readAll())) { + qDebug() << "Error: Failed to load fastfile: " << fastFileStem; + return false; + } + + file->close(); + + // Open zone file after decompressing ff and writing + return true; +} + +bool FastFile_COD7_PS3::Load(const QByteArray aData) { + QByteArray decompressedData; + + // Create a QDataStream on the input data. + QDataStream fastFileStream(aData); + fastFileStream.setByteOrder(QDataStream::LittleEndian); + + // Parse header values. + SetCompany(pParseFFCompany(&fastFileStream)); + SetType(pParseFFFileType(&fastFileStream)); + SetSignage(pParseFFSignage(&fastFileStream)); + SetMagic(pParseFFMagic(&fastFileStream)); + quint32 version = pParseFFVersion(&fastFileStream); + SetVersion(version); + SetPlatform(pCalculateFFPlatform(version)); + SetGame("COD7"); + + // Load the zone file with the decompressed data (using an Xbox platform flag). + ZoneFile_COD7_PS3 zoneFile; + zoneFile.SetStem(GetStem()); + + // For COD7/COD9, use BigEndian. + fastFileStream.setByteOrder(QDataStream::BigEndian); + if (GetPlatform() == "PC") { + fastFileStream.setByteOrder(QDataStream::LittleEndian); + + // Select key based on game. + QByteArray key; + fastFileStream.skipRawData(4); + if (GetPlatform() == "360") { + key = QByteArray::fromHex("1ac1d12d527c59b40eca619120ff8217ccff09cd16896f81b829c7f52793405d"); + } else if (GetPlatform() == "PS3") { + key = QByteArray::fromHex("46D3F997F29C9ACE175B0DAE3AB8C0C1B8E423E2E3BF7E3C311EA35245BF193A"); + // or + // key = QByteArray::fromHex("0C99B3DDB8D6D0845D1147E470F28A8BF2AE69A8A9F534767B54E9180FF55370"); + } + + // Read the 8-byte magic. + QByteArray fileMagic(8, Qt::Uninitialized); + fastFileStream.readRawData(fileMagic.data(), 8); + if (fileMagic != "PHEEBs71") { + qWarning() << "Invalid fast file magic!"; + return false; + } + fastFileStream.skipRawData(4); + + // Read IV table name (32 bytes). + QByteArray fileName(32, Qt::Uninitialized); + fastFileStream.readRawData(fileName.data(), 32); + + // Build the IV table from the fileName. + QByteArray ivTable = Encryption::InitIVTable(fileName); + + // Skip the RSA signature (256 bytes). + QByteArray rsaSignature(256, Qt::Uninitialized); + fastFileStream.readRawData(rsaSignature.data(), 256); + + // Now the stream should be positioned at 0x13C, where sections begin. + int sectionIndex = 0; + while (true) { + qint32 sectionSize = 0; + fastFileStream >> sectionSize; + qDebug() << "Section index:" << sectionIndex << "Size:" << sectionSize + << "Pos:" << fastFileStream.device()->pos(); + if (sectionSize == 0) + break; + + // Read the section data. + QByteArray sectionData; + sectionData.resize(sectionSize); + fastFileStream.readRawData(sectionData.data(), sectionSize); + + // Compute the IV for this section. + QByteArray iv = Encryption::GetIV(ivTable, sectionIndex); + + // Decrypt the section using Salsa20. + QByteArray decData = Encryption::salsa20DecryptSection(sectionData, key, iv); + + // Compute SHA1 hash of the decrypted data. + QByteArray sectionHash = QCryptographicHash::hash(decData, QCryptographicHash::Sha1); + + // Update the IV table based on the section hash. + Encryption::UpdateIVTable(ivTable, sectionIndex, sectionHash); + + // Build a compressed data buffer by prepending the two-byte zlib header. + QByteArray compressedData; + compressedData.append(char(0x78)); + compressedData.append(char(0x01)); + compressedData.append(decData); + + decompressedData.append(Compression::DecompressZLIB(compressedData)); + + sectionIndex++; + } + + zoneFile.Load(decompressedData); + } + + SetZoneFile(std::make_shared(zoneFile)); + + return true; +} diff --git a/libs/fastfile/PS3/fastfile_cod7_ps3.h b/libs/fastfile/PS3/fastfile_cod7_ps3.h new file mode 100644 index 0000000..3d1482d --- /dev/null +++ b/libs/fastfile/PS3/fastfile_cod7_ps3.h @@ -0,0 +1,20 @@ +#ifndef FASTFILE_COD7_PS3_H +#define FASTFILE_COD7_PS3_H + +#include "fastfile.h" + +class FastFile_COD7_PS3 : public FastFile +{ +public: + FastFile_COD7_PS3(); + FastFile_COD7_PS3(const QByteArray &aData); + FastFile_COD7_PS3(const QString aFilePath); + ~FastFile_COD7_PS3(); + + QByteArray GetBinaryData() override; + + bool Load(const QString aFilePath) override; + bool Load(const QByteArray aData) override; +}; + +#endif // FASTFILE_COD7_PS3_H diff --git a/libs/fastfile/PS3/fastfile_cod8_ps3.cpp b/libs/fastfile/PS3/fastfile_cod8_ps3.cpp new file mode 100644 index 0000000..fef9e69 --- /dev/null +++ b/libs/fastfile/PS3/fastfile_cod8_ps3.cpp @@ -0,0 +1,173 @@ +#include "fastfile_cod8_ps3.h" +#include "zonefile_cod8_ps3.h" + +#include "utils.h" +#include "compression.h" +#include "encryption.h" + +#include +#include + +FastFile_COD8_PS3::FastFile_COD8_PS3() + : FastFile() { + SetCompany(COMPANY_INFINITY_WARD); + SetType(FILETYPE_FAST_FILE); + SetSignage(SIGNAGE_UNSIGNED); + SetMagic(0); + SetVersion(0); + SetGame("COD8"); + SetPlatform("PS3"); +} + +FastFile_COD8_PS3::FastFile_COD8_PS3(const QByteArray& aData) + : FastFile_COD8_PS3() { + + if (!aData.isEmpty()) { + Load(aData); + } +} + +FastFile_COD8_PS3::FastFile_COD8_PS3(const QString aFilePath) + : FastFile_COD8_PS3() { + + if (!aFilePath.isEmpty()) { + Load(aFilePath); + } +} + +FastFile_COD8_PS3::~FastFile_COD8_PS3() { + +} + +QByteArray FastFile_COD8_PS3::GetBinaryData() { + return QByteArray(); +} + +bool FastFile_COD8_PS3::Load(const QString aFilePath) { + if (aFilePath.isEmpty()) { + return false; + } + + // Check fastfile can be read + QFile *file = new QFile(aFilePath); + if (!file->open(QIODevice::ReadOnly)) { + qDebug() << QString("Error: Failed to open FastFile: %1!").arg(aFilePath); + return false; + } + + // Decompress fastfile and close + const QString fastFileStem = aFilePath.section("/", -1, -1); + SetStem(fastFileStem); + if (!Load(file->readAll())) { + qDebug() << "Error: Failed to load fastfile: " << fastFileStem; + return false; + } + + file->close(); + + // Open zone file after decompressing ff and writing + return true; +} + +bool FastFile_COD8_PS3::Load(const QByteArray aData) { + QByteArray decompressedData; + + // Create a QDataStream on the input data. + QDataStream fastFileStream(aData); + fastFileStream.setByteOrder(QDataStream::LittleEndian); + + // Parse header values. + SetCompany(pParseFFCompany(&fastFileStream)); + SetType(pParseFFFileType(&fastFileStream)); + SetSignage(pParseFFSignage(&fastFileStream)); + SetMagic(pParseFFMagic(&fastFileStream)); + quint32 version = pParseFFVersion(&fastFileStream); + SetVersion(version); + SetPlatform(pCalculateFFPlatform(version)); + SetGame("COD7"); + + // Load the zone file with the decompressed data (using an Xbox platform flag). + ZoneFile_COD8_PS3 zoneFile; + zoneFile.SetStem(GetStem()); + + // For COD7/COD9, use BigEndian. + fastFileStream.setByteOrder(QDataStream::BigEndian); + if (GetPlatform() == "PC") { + fastFileStream.setByteOrder(QDataStream::LittleEndian); + + // Select key based on game. + QByteArray key; + fastFileStream.skipRawData(4); + if (GetPlatform() == "360") { + key = QByteArray::fromHex("1ac1d12d527c59b40eca619120ff8217ccff09cd16896f81b829c7f52793405d"); + } else if (GetPlatform() == "PS3") { + key = QByteArray::fromHex("46D3F997F29C9ACE175B0DAE3AB8C0C1B8E423E2E3BF7E3C311EA35245BF193A"); + // or + // key = QByteArray::fromHex("0C99B3DDB8D6D0845D1147E470F28A8BF2AE69A8A9F534767B54E9180FF55370"); + } + + // Read the 8-byte magic. + QByteArray fileMagic(8, Qt::Uninitialized); + fastFileStream.readRawData(fileMagic.data(), 8); + if (fileMagic != "PHEEBs71") { + qWarning() << "Invalid fast file magic!"; + return false; + } + fastFileStream.skipRawData(4); + + // Read IV table name (32 bytes). + QByteArray fileName(32, Qt::Uninitialized); + fastFileStream.readRawData(fileName.data(), 32); + + // Build the IV table from the fileName. + QByteArray ivTable = Encryption::InitIVTable(fileName); + + // Skip the RSA signature (256 bytes). + QByteArray rsaSignature(256, Qt::Uninitialized); + fastFileStream.readRawData(rsaSignature.data(), 256); + + // Now the stream should be positioned at 0x13C, where sections begin. + int sectionIndex = 0; + while (true) { + qint32 sectionSize = 0; + fastFileStream >> sectionSize; + qDebug() << "Section index:" << sectionIndex << "Size:" << sectionSize + << "Pos:" << fastFileStream.device()->pos(); + if (sectionSize == 0) + break; + + // Read the section data. + QByteArray sectionData; + sectionData.resize(sectionSize); + fastFileStream.readRawData(sectionData.data(), sectionSize); + + // Compute the IV for this section. + QByteArray iv = Encryption::GetIV(ivTable, sectionIndex); + + // Decrypt the section using Salsa20. + QByteArray decData = Encryption::salsa20DecryptSection(sectionData, key, iv); + + // Compute SHA1 hash of the decrypted data. + QByteArray sectionHash = QCryptographicHash::hash(decData, QCryptographicHash::Sha1); + + // Update the IV table based on the section hash. + Encryption::UpdateIVTable(ivTable, sectionIndex, sectionHash); + + // Build a compressed data buffer by prepending the two-byte zlib header. + QByteArray compressedData; + compressedData.append(char(0x78)); + compressedData.append(char(0x01)); + compressedData.append(decData); + + decompressedData.append(Compression::DecompressZLIB(compressedData)); + + sectionIndex++; + } + + zoneFile.Load(decompressedData); + } + + SetZoneFile(std::make_shared(zoneFile)); + + return true; +} diff --git a/libs/fastfile/PS3/fastfile_cod8_ps3.h b/libs/fastfile/PS3/fastfile_cod8_ps3.h new file mode 100644 index 0000000..02570b0 --- /dev/null +++ b/libs/fastfile/PS3/fastfile_cod8_ps3.h @@ -0,0 +1,20 @@ +#ifndef FASTFILE_COD8_PS3_H +#define FASTFILE_COD8_PS3_H + +#include "fastfile.h" + +class FastFile_COD8_PS3 : public FastFile +{ +public: + FastFile_COD8_PS3(); + FastFile_COD8_PS3(const QByteArray &aData); + FastFile_COD8_PS3(const QString aFilePath); + ~FastFile_COD8_PS3(); + + QByteArray GetBinaryData() override; + + bool Load(const QString aFilePath) override; + bool Load(const QByteArray aData) override; +}; + +#endif // FASTFILE_COD8_PS3_H diff --git a/libs/fastfile/PS3/fastfile_cod9_ps3.cpp b/libs/fastfile/PS3/fastfile_cod9_ps3.cpp new file mode 100644 index 0000000..787c08d --- /dev/null +++ b/libs/fastfile/PS3/fastfile_cod9_ps3.cpp @@ -0,0 +1,137 @@ +#include "fastfile_cod9_ps3.h" +#include "zonefile_cod9_ps3.h" +#include "encryption.h" + +#include +#include + +FastFile_COD9_PS3::FastFile_COD9_PS3() + : FastFile() { + SetCompany(COMPANY_INFINITY_WARD); + SetType(FILETYPE_FAST_FILE); + SetSignage(SIGNAGE_UNSIGNED); + SetMagic(0); + SetVersion(0); + SetGame("COD9"); + SetPlatform("PS3"); +} + +FastFile_COD9_PS3::FastFile_COD9_PS3(const QByteArray& aData) + : FastFile_COD9_PS3() { + + if (!aData.isEmpty()) { + Load(aData); + } +} + +FastFile_COD9_PS3::FastFile_COD9_PS3(const QString aFilePath) + : FastFile_COD9_PS3() { + + if (!aFilePath.isEmpty()) { + Load(aFilePath); + } +} + +FastFile_COD9_PS3::~FastFile_COD9_PS3() { + +} + +QByteArray FastFile_COD9_PS3::GetBinaryData() { + return QByteArray(); +} + +bool FastFile_COD9_PS3::Load(const QString aFilePath) { + if (aFilePath.isEmpty()) { + return false; + } + + // Check fastfile can be read + QFile *file = new QFile(aFilePath); + if (!file->open(QIODevice::ReadOnly)) { + qDebug() << QString("Error: Failed to open FastFile: %1!").arg(aFilePath); + return false; + } + + // Decompress fastfile and close + const QString fastFileStem = aFilePath.section("/", -1, -1).section(".", 0, 0); + SetStem(fastFileStem); + if (!Load(file->readAll())) { + qDebug() << "Error: Failed to load fastfile: " << fastFileStem + ".ff"; + return false; + } + + file->close(); + + // Open zone file after decompressing ff and writing + return true; +} + +bool FastFile_COD9_PS3::Load(const QByteArray aData) { + QByteArray decompressedData; + + // Create a QDataStream on the input data. + QDataStream fastFileStream(aData); + fastFileStream.setByteOrder(QDataStream::LittleEndian); + + // Parse header values. + SetCompany(pParseFFCompany(&fastFileStream)); + SetType(pParseFFFileType(&fastFileStream)); + SetSignage(pParseFFSignage(&fastFileStream)); + SetMagic(pParseFFMagic(&fastFileStream)); + quint32 version = pParseFFVersion(&fastFileStream); + SetVersion(version); + SetPlatform(pCalculateFFPlatform(version)); + SetGame("COD9"); + + // For COD7/COD9, use BigEndian. + fastFileStream.setByteOrder(QDataStream::BigEndian); + if (GetPlatform() == "PC") { + fastFileStream.setByteOrder(QDataStream::LittleEndian); + } + + // Select key based on game. + QByteArray key; + if (GetPlatform() == "360") { + key = QByteArray::fromHex("0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3"); + } else if (GetPlatform() == "PC") { + key = QByteArray::fromHex("641D8A2FE31D3AA63622BBC9CE8587229D42B0F8ED9B924130BF88B65EDC50BE"); + } + + // Read the 8-byte magic. + QByteArray fileMagic(8, Qt::Uninitialized); + fastFileStream.readRawData(fileMagic.data(), 8); + if (fileMagic != "PHEEBs71") { + qWarning() << "Invalid fast file magic!"; + return false; + } + fastFileStream.skipRawData(4); + + // Read IV table name (32 bytes). + QByteArray fileName(32, Qt::Uninitialized); + fastFileStream.readRawData(fileName.data(), 32); + + // Skip the RSA signature (256 bytes). + QByteArray rsaSignature(256, Qt::Uninitialized); + fastFileStream.readRawData(rsaSignature.data(), 256); + + if (GetPlatform() == "360") { + //decompressedData = Compressor::cod9_decryptFastFile(aData); + } else if (GetPlatform() == "PC") { + decompressedData = Encryption::decryptFastFile_BO2(aData); + } + + // For COD9, write out the complete decompressed zone for testing. + QFile testFile("exports/" + GetStem() + ".zone"); + if(testFile.open(QIODevice::WriteOnly)) { + testFile.write(decompressedData); + testFile.close(); + } + + // Load the zone file with the decompressed data (using an Xbox platform flag). + ZoneFile_COD9_PS3 zoneFile; + zoneFile.SetStem(GetStem()); + zoneFile.Load(decompressedData); + SetZoneFile(std::make_shared(zoneFile)); + + return true; +} diff --git a/libs/fastfile/PS3/fastfile_cod9_ps3.h b/libs/fastfile/PS3/fastfile_cod9_ps3.h new file mode 100644 index 0000000..145f69f --- /dev/null +++ b/libs/fastfile/PS3/fastfile_cod9_ps3.h @@ -0,0 +1,20 @@ +#ifndef FASTFILE_COD9_PS3_H +#define FASTFILE_COD9_PS3_H + +#include "fastfile.h" + +class FastFile_COD9_PS3 : public FastFile +{ +public: + FastFile_COD9_PS3(); + FastFile_COD9_PS3(const QByteArray &aData); + FastFile_COD9_PS3(const QString aFilePath); + ~FastFile_COD9_PS3(); + + QByteArray GetBinaryData() override; + + bool Load(const QString aFilePath) override; + bool Load(const QByteArray aData) override; +}; + +#endif // FASTFILE_COD9_PS3_H diff --git a/libs/fastfile/Wii/fastfile_cod4_wii.cpp b/libs/fastfile/Wii/fastfile_cod4_wii.cpp new file mode 100644 index 0000000..b661fc3 --- /dev/null +++ b/libs/fastfile/Wii/fastfile_cod4_wii.cpp @@ -0,0 +1,114 @@ +#include "fastfile_cod4_wii.h" +#include "zonefile_cod4_wii.h" + +#include "utils.h" +#include "compression.h" + +#include +#include + +FastFile_COD4_Wii::FastFile_COD4_Wii() + : FastFile() { + SetCompany(COMPANY_INFINITY_WARD); + SetType(FILETYPE_FAST_FILE); + SetSignage(SIGNAGE_UNSIGNED); + SetMagic(0); + SetVersion(0); + SetGame("COD4"); + SetPlatform("Wii"); +} + +FastFile_COD4_Wii::FastFile_COD4_Wii(const QByteArray& aData) + : FastFile_COD4_Wii() { + if (!aData.isEmpty()) { + Load(aData); + } +} + +FastFile_COD4_Wii::FastFile_COD4_Wii(const QString aFilePath) + : FastFile_COD4_Wii() { + if (!aFilePath.isEmpty()) { + Load(aFilePath); + } +} + +FastFile_COD4_Wii::~FastFile_COD4_Wii() { + +} + +QByteArray FastFile_COD4_Wii::GetBinaryData() { + return QByteArray(); +} + +bool FastFile_COD4_Wii::Load(const QString aFilePath) { + if (aFilePath.isEmpty()) { + return false; + } + + // Check fastfile can be read + QFile *file = new QFile(aFilePath); + if (!file->open(QIODevice::ReadOnly)) { + qDebug() << QString("Error: Failed to open FastFile: %1!").arg(aFilePath); + return false; + } + + // Decompress fastfile and close + const QString fastFileStem = aFilePath.section("/", -1, -1); + SetStem(fastFileStem); + if (!Load(file->readAll())) { + qDebug() << "Error: Failed to load fastfile: " << fastFileStem; + return false; + } + + file->close(); + + // Open zone file after decompressing ff and writing + return true; +} + +bool FastFile_COD4_Wii::Load(const QByteArray aData) { + QByteArray decompressedData; + + // Create a QDataStream on the input data. + QDataStream fastFileStream(aData); + fastFileStream.setByteOrder(QDataStream::LittleEndian); + + // Parse header values. + SetCompany(pParseFFCompany(&fastFileStream)); + SetType(pParseFFFileType(&fastFileStream)); + SetSignage(pParseFFSignage(&fastFileStream)); + SetMagic(pParseFFMagic(&fastFileStream)); + quint32 version = pParseFFVersion(&fastFileStream); + SetVersion(version); + SetPlatform(pCalculateFFPlatform(version)); + SetGame("COD7"); + + // Load the zone file with the decompressed data (using an Xbox platform flag). + ZoneFile_COD7_Wii zoneFile; + zoneFile.SetStem(GetStem()); + + // For COD7/COD9, use BigEndian. + fastFileStream.setByteOrder(QDataStream::BigEndian); + + // For COD7, simply decompress from offset 12. + decompressedData = Compression::DecompressZLIB(aData.mid(12)); + + Utils::ExportData(GetStem() + ".zone", decompressedData); + + QDir workingDir = QDir::currentPath(); + workingDir.mkdir("exports"); + + QFile outputFile("exports/" + GetStem() + ".zone"); + if (!outputFile.open(QIODevice::WriteOnly)) { + qDebug() << "Failed to extract IPAK file."; + } + qDebug() << " - File Name: " << outputFile.fileName(); + outputFile.write(decompressedData); + outputFile.close(); + + zoneFile.Load(decompressedData); + + SetZoneFile(std::make_shared(zoneFile)); + + return true; +} diff --git a/libs/fastfile/Wii/fastfile_cod4_wii.h b/libs/fastfile/Wii/fastfile_cod4_wii.h new file mode 100644 index 0000000..d971c55 --- /dev/null +++ b/libs/fastfile/Wii/fastfile_cod4_wii.h @@ -0,0 +1,20 @@ +#ifndef FASTFILE_COD4_WII_H +#define FASTFILE_COD4_WII_H + +#include "fastfile.h" + +class FastFile_COD4_Wii : public FastFile +{ +public: + FastFile_COD4_Wii(); + FastFile_COD4_Wii(const QByteArray &aData); + FastFile_COD4_Wii(const QString aFilePath); + ~FastFile_COD4_Wii(); + + QByteArray GetBinaryData() override; + + bool Load(const QString aFilePath) override; + bool Load(const QByteArray aData) override; +}; + +#endif // FASTFILE_COD4_WII_H diff --git a/libs/fastfile/Wii/fastfile_cod7_wii.cpp b/libs/fastfile/Wii/fastfile_cod7_wii.cpp new file mode 100644 index 0000000..26735d2 --- /dev/null +++ b/libs/fastfile/Wii/fastfile_cod7_wii.cpp @@ -0,0 +1,114 @@ +#include "fastfile_cod7_wii.h" +#include "zonefile_cod7_wii.h" + +#include "utils.h" +#include "compression.h" + +#include +#include + +FastFile_COD7_Wii::FastFile_COD7_Wii() + : FastFile() { + SetCompany(COMPANY_INFINITY_WARD); + SetType(FILETYPE_FAST_FILE); + SetSignage(SIGNAGE_UNSIGNED); + SetMagic(0); + SetVersion(0); + SetGame("COD7"); + SetPlatform("Wii"); +} + +FastFile_COD7_Wii::FastFile_COD7_Wii(const QByteArray& aData) + : FastFile_COD7_Wii() { + if (!aData.isEmpty()) { + Load(aData); + } +} + +FastFile_COD7_Wii::FastFile_COD7_Wii(const QString aFilePath) + : FastFile_COD7_Wii() { + if (!aFilePath.isEmpty()) { + Load(aFilePath); + } +} + +FastFile_COD7_Wii::~FastFile_COD7_Wii() { + +} + +QByteArray FastFile_COD7_Wii::GetBinaryData() { + return QByteArray(); +} + +bool FastFile_COD7_Wii::Load(const QString aFilePath) { + if (aFilePath.isEmpty()) { + return false; + } + + // Check fastfile can be read + QFile *file = new QFile(aFilePath); + if (!file->open(QIODevice::ReadOnly)) { + qDebug() << QString("Error: Failed to open FastFile: %1!").arg(aFilePath); + return false; + } + + // Decompress fastfile and close + const QString fastFileStem = aFilePath.section("/", -1, -1); + SetStem(fastFileStem); + if (!Load(file->readAll())) { + qDebug() << "Error: Failed to load fastfile: " << fastFileStem; + return false; + } + + file->close(); + + // Open zone file after decompressing ff and writing + return true; +} + +bool FastFile_COD7_Wii::Load(const QByteArray aData) { + QByteArray decompressedData; + + // Create a QDataStream on the input data. + QDataStream fastFileStream(aData); + fastFileStream.setByteOrder(QDataStream::LittleEndian); + + // Parse header values. + SetCompany(pParseFFCompany(&fastFileStream)); + SetType(pParseFFFileType(&fastFileStream)); + SetSignage(pParseFFSignage(&fastFileStream)); + SetMagic(pParseFFMagic(&fastFileStream)); + quint32 version = pParseFFVersion(&fastFileStream); + SetVersion(version); + SetPlatform(pCalculateFFPlatform(version)); + SetGame("COD7"); + + // Load the zone file with the decompressed data (using an Xbox platform flag). + ZoneFile_COD7_Wii zoneFile; + zoneFile.SetStem(GetStem()); + + // For COD7/COD9, use BigEndian. + fastFileStream.setByteOrder(QDataStream::BigEndian); + + // For COD7, simply decompress from offset 12. + decompressedData = Compression::DecompressZLIB(aData.mid(12)); + + Utils::ExportData(GetStem() + ".zone", decompressedData); + + QDir workingDir = QDir::currentPath(); + workingDir.mkdir("exports"); + + QFile outputFile("exports/" + GetStem() + ".zone"); + if (!outputFile.open(QIODevice::WriteOnly)) { + qDebug() << "Failed to extract IPAK file."; + } + qDebug() << " - File Name: " << outputFile.fileName(); + outputFile.write(decompressedData); + outputFile.close(); + + zoneFile.Load(decompressedData); + + SetZoneFile(std::make_shared(zoneFile)); + + return true; +} diff --git a/libs/fastfile/Wii/fastfile_cod7_wii.h b/libs/fastfile/Wii/fastfile_cod7_wii.h new file mode 100644 index 0000000..7577422 --- /dev/null +++ b/libs/fastfile/Wii/fastfile_cod7_wii.h @@ -0,0 +1,20 @@ +#ifndef FASTFILE_COD7_WII_H +#define FASTFILE_COD7_WII_H + +#include "fastfile.h" + +class FastFile_COD7_Wii : public FastFile +{ +public: + FastFile_COD7_Wii(); + FastFile_COD7_Wii(const QByteArray &aData); + FastFile_COD7_Wii(const QString aFilePath); + ~FastFile_COD7_Wii(); + + QByteArray GetBinaryData() override; + + bool Load(const QString aFilePath) override; + bool Load(const QByteArray aData) override; +}; + +#endif // FASTFILE_COD7_WII_H diff --git a/libs/fastfile/Wii/fastfile_cod8_wii.cpp b/libs/fastfile/Wii/fastfile_cod8_wii.cpp new file mode 100644 index 0000000..8252db3 --- /dev/null +++ b/libs/fastfile/Wii/fastfile_cod8_wii.cpp @@ -0,0 +1,114 @@ +#include "fastfile_cod8_wii.h" +#include "zonefile_cod8_wii.h" + +#include "utils.h" +#include "compression.h" + +#include +#include + +FastFile_COD8_Wii::FastFile_COD8_Wii() + : FastFile() { + SetCompany(COMPANY_INFINITY_WARD); + SetType(FILETYPE_FAST_FILE); + SetSignage(SIGNAGE_UNSIGNED); + SetMagic(0); + SetVersion(0); + SetGame("COD7"); + SetPlatform("Wii"); +} + +FastFile_COD8_Wii::FastFile_COD8_Wii(const QByteArray& aData) + : FastFile_COD8_Wii() { + if (!aData.isEmpty()) { + Load(aData); + } +} + +FastFile_COD8_Wii::FastFile_COD8_Wii(const QString aFilePath) + : FastFile_COD8_Wii() { + if (!aFilePath.isEmpty()) { + Load(aFilePath); + } +} + +FastFile_COD8_Wii::~FastFile_COD8_Wii() { + +} + +QByteArray FastFile_COD8_Wii::GetBinaryData() { + return QByteArray(); +} + +bool FastFile_COD8_Wii::Load(const QString aFilePath) { + if (aFilePath.isEmpty()) { + return false; + } + + // Check fastfile can be read + QFile *file = new QFile(aFilePath); + if (!file->open(QIODevice::ReadOnly)) { + qDebug() << QString("Error: Failed to open FastFile: %1!").arg(aFilePath); + return false; + } + + // Decompress fastfile and close + const QString fastFileStem = aFilePath.section("/", -1, -1); + SetStem(fastFileStem); + if (!Load(file->readAll())) { + qDebug() << "Error: Failed to load fastfile: " << fastFileStem; + return false; + } + + file->close(); + + // Open zone file after decompressing ff and writing + return true; +} + +bool FastFile_COD8_Wii::Load(const QByteArray aData) { + QByteArray decompressedData; + + // Create a QDataStream on the input data. + QDataStream fastFileStream(aData); + fastFileStream.setByteOrder(QDataStream::LittleEndian); + + // Parse header values. + SetCompany(pParseFFCompany(&fastFileStream)); + SetType(pParseFFFileType(&fastFileStream)); + SetSignage(pParseFFSignage(&fastFileStream)); + SetMagic(pParseFFMagic(&fastFileStream)); + quint32 version = pParseFFVersion(&fastFileStream); + SetVersion(version); + SetPlatform(pCalculateFFPlatform(version)); + SetGame("COD7"); + + // Load the zone file with the decompressed data (using an Xbox platform flag). + ZoneFile_COD7_Wii zoneFile; + zoneFile.SetStem(GetStem()); + + // For COD7/COD9, use BigEndian. + fastFileStream.setByteOrder(QDataStream::BigEndian); + + // For COD7, simply decompress from offset 12. + decompressedData = Compression::DecompressZLIB(aData.mid(12)); + + Utils::ExportData(GetStem() + ".zone", decompressedData); + + QDir workingDir = QDir::currentPath(); + workingDir.mkdir("exports"); + + QFile outputFile("exports/" + GetStem() + ".zone"); + if (!outputFile.open(QIODevice::WriteOnly)) { + qDebug() << "Failed to extract IPAK file."; + } + qDebug() << " - File Name: " << outputFile.fileName(); + outputFile.write(decompressedData); + outputFile.close(); + + zoneFile.Load(decompressedData); + + SetZoneFile(std::make_shared(zoneFile)); + + return true; +} diff --git a/libs/fastfile/Wii/fastfile_cod8_wii.h b/libs/fastfile/Wii/fastfile_cod8_wii.h new file mode 100644 index 0000000..e5a8bc2 --- /dev/null +++ b/libs/fastfile/Wii/fastfile_cod8_wii.h @@ -0,0 +1,20 @@ +#ifndef FASTFILE_COD8_WII_H +#define FASTFILE_COD8_WII_H + +#include "fastfile.h" + +class FastFile_COD8_Wii : public FastFile +{ +public: + FastFile_COD8_Wii(); + FastFile_COD8_Wii(const QByteArray &aData); + FastFile_COD8_Wii(const QString aFilePath); + ~FastFile_COD8_Wii(); + + QByteArray GetBinaryData() override; + + bool Load(const QString aFilePath) override; + bool Load(const QByteArray aData) override; +}; + +#endif // FASTFILE_COD8_WII_H diff --git a/libs/fastfile/WiiU/fastfile_cod10_wiiu.cpp b/libs/fastfile/WiiU/fastfile_cod10_wiiu.cpp new file mode 100644 index 0000000..165dd42 --- /dev/null +++ b/libs/fastfile/WiiU/fastfile_cod10_wiiu.cpp @@ -0,0 +1,135 @@ +#include "fastfile_cod10_wiiu.h" +#include "zonefile_cod10_wiiu.h" +#include "encryption.h" + +#include +#include + +FastFile_COD10_WiiU::FastFile_COD10_WiiU() + : FastFile() { + SetCompany(COMPANY_INFINITY_WARD); + SetType(FILETYPE_FAST_FILE); + SetSignage(SIGNAGE_UNSIGNED); + SetMagic(0); + SetVersion(0); + SetGame("COD10"); + SetPlatform("WiiU"); +} + +FastFile_COD10_WiiU::FastFile_COD10_WiiU(const QByteArray& aData) + : FastFile_COD10_WiiU() { + if (!aData.isEmpty()) { + Load(aData); + } +} + +FastFile_COD10_WiiU::FastFile_COD10_WiiU(const QString aFilePath) + : FastFile_COD10_WiiU() { + if (!aFilePath.isEmpty()) { + Load(aFilePath); + } +} + +FastFile_COD10_WiiU::~FastFile_COD10_WiiU() { + +} + +QByteArray FastFile_COD10_WiiU::GetBinaryData() { + return QByteArray(); +} + +bool FastFile_COD10_WiiU::Load(const QString aFilePath) { + if (aFilePath.isEmpty()) { + return false; + } + + // Check fastfile can be read + QFile *file = new QFile(aFilePath); + if (!file->open(QIODevice::ReadOnly)) { + qDebug() << QString("Error: Failed to open FastFile: %1!").arg(aFilePath); + return false; + } + + // Decompress fastfile and close + const QString fastFileStem = aFilePath.section("/", -1, -1).section(".", 0, 0); + SetStem(fastFileStem); + if (!Load(file->readAll())) { + qDebug() << "Error: Failed to load fastfile: " << fastFileStem + ".ff"; + return false; + } + + file->close(); + + // Open zone file after decompressing ff and writing + return true; +} + +bool FastFile_COD10_WiiU::Load(const QByteArray aData) { + QByteArray decompressedData; + + // Create a QDataStream on the input data. + QDataStream fastFileStream(aData); + fastFileStream.setByteOrder(QDataStream::LittleEndian); + + // Parse header values. + SetCompany(pParseFFCompany(&fastFileStream)); + SetType(pParseFFFileType(&fastFileStream)); + SetSignage(pParseFFSignage(&fastFileStream)); + SetMagic(pParseFFMagic(&fastFileStream)); + quint32 version = pParseFFVersion(&fastFileStream); + SetVersion(version); + SetPlatform(pCalculateFFPlatform(version)); + SetGame("COD9"); + + // For COD7/COD9, use BigEndian. + fastFileStream.setByteOrder(QDataStream::BigEndian); + if (GetPlatform() == "PC") { + fastFileStream.setByteOrder(QDataStream::LittleEndian); + } + + // Select key based on game. + QByteArray key; + if (GetPlatform() == "360") { + key = QByteArray::fromHex("0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3"); + } else if (GetPlatform() == "PC") { + key = QByteArray::fromHex("641D8A2FE31D3AA63622BBC9CE8587229D42B0F8ED9B924130BF88B65EDC50BE"); + } + + // Read the 8-byte magic. + QByteArray fileMagic(8, Qt::Uninitialized); + fastFileStream.readRawData(fileMagic.data(), 8); + if (fileMagic != "PHEEBs71") { + qWarning() << "Invalid fast file magic!"; + return false; + } + fastFileStream.skipRawData(4); + + // Read IV table name (32 bytes). + QByteArray fileName(32, Qt::Uninitialized); + fastFileStream.readRawData(fileName.data(), 32); + + // Skip the RSA signature (256 bytes). + QByteArray rsaSignature(256, Qt::Uninitialized); + fastFileStream.readRawData(rsaSignature.data(), 256); + + if (GetPlatform() == "360") { + //decompressedData = Compressor::cod9_decryptFastFile(aData); + } else if (GetPlatform() == "PC") { + decompressedData = Encryption::decryptFastFile_BO2(aData); + } + + // For COD9, write out the complete decompressed zone for testing. + QFile testFile("exports/" + GetStem() + ".zone"); + if(testFile.open(QIODevice::WriteOnly)) { + testFile.write(decompressedData); + testFile.close(); + } + + // Load the zone file with the decompressed data (using an Xbox platform flag). + ZoneFile_COD10_WiiU zoneFile; + zoneFile.SetStem(GetStem()); + zoneFile.Load(decompressedData); + SetZoneFile(std::make_shared(zoneFile)); + + return true; +} diff --git a/libs/fastfile/WiiU/fastfile_cod10_wiiu.h b/libs/fastfile/WiiU/fastfile_cod10_wiiu.h new file mode 100644 index 0000000..85d209d --- /dev/null +++ b/libs/fastfile/WiiU/fastfile_cod10_wiiu.h @@ -0,0 +1,20 @@ +#ifndef FASTFILE_COD10_WIIU_H +#define FASTFILE_COD10_WIIU_H + +#include "fastfile.h" + +class FastFile_COD10_WiiU : public FastFile +{ +public: + FastFile_COD10_WiiU(); + FastFile_COD10_WiiU(const QByteArray &aData); + FastFile_COD10_WiiU(const QString aFilePath); + ~FastFile_COD10_WiiU(); + + QByteArray GetBinaryData() override; + + bool Load(const QString aFilePath) override; + bool Load(const QByteArray aData) override; +}; + +#endif // FASTFILE_COD10_WIIU_H diff --git a/libs/fastfile/WiiU/fastfile_cod9_wiiu.cpp b/libs/fastfile/WiiU/fastfile_cod9_wiiu.cpp new file mode 100644 index 0000000..52078d2 --- /dev/null +++ b/libs/fastfile/WiiU/fastfile_cod9_wiiu.cpp @@ -0,0 +1,135 @@ +#include "fastfile_cod9_wiiu.h" +#include "zonefile_cod9_wiiu.h" +#include "encryption.h" + +#include +#include + +FastFile_COD9_WiiU::FastFile_COD9_WiiU() + : FastFile() { + SetCompany(COMPANY_INFINITY_WARD); + SetType(FILETYPE_FAST_FILE); + SetSignage(SIGNAGE_UNSIGNED); + SetMagic(0); + SetVersion(0); + SetGame("COD9"); + SetPlatform("WiiU"); +} + +FastFile_COD9_WiiU::FastFile_COD9_WiiU(const QByteArray& aData) + : FastFile_COD9_WiiU() { + if (!aData.isEmpty()) { + Load(aData); + } +} + +FastFile_COD9_WiiU::FastFile_COD9_WiiU(const QString aFilePath) + : FastFile_COD9_WiiU() { + if (!aFilePath.isEmpty()) { + Load(aFilePath); + } +} + +FastFile_COD9_WiiU::~FastFile_COD9_WiiU() { + +} + +QByteArray FastFile_COD9_WiiU::GetBinaryData() { + return QByteArray(); +} + +bool FastFile_COD9_WiiU::Load(const QString aFilePath) { + if (aFilePath.isEmpty()) { + return false; + } + + // Check fastfile can be read + QFile *file = new QFile(aFilePath); + if (!file->open(QIODevice::ReadOnly)) { + qDebug() << QString("Error: Failed to open FastFile: %1!").arg(aFilePath); + return false; + } + + // Decompress fastfile and close + const QString fastFileStem = aFilePath.section("/", -1, -1).section(".", 0, 0); + SetStem(fastFileStem); + if (!Load(file->readAll())) { + qDebug() << "Error: Failed to load fastfile: " << fastFileStem + ".ff"; + return false; + } + + file->close(); + + // Open zone file after decompressing ff and writing + return true; +} + +bool FastFile_COD9_WiiU::Load(const QByteArray aData) { + QByteArray decompressedData; + + // Create a QDataStream on the input data. + QDataStream fastFileStream(aData); + fastFileStream.setByteOrder(QDataStream::LittleEndian); + + // Parse header values. + SetCompany(pParseFFCompany(&fastFileStream)); + SetType(pParseFFFileType(&fastFileStream)); + SetSignage(pParseFFSignage(&fastFileStream)); + SetMagic(pParseFFMagic(&fastFileStream)); + quint32 version = pParseFFVersion(&fastFileStream); + SetVersion(version); + SetPlatform(pCalculateFFPlatform(version)); + SetGame("COD9"); + + // For COD7/COD9, use BigEndian. + fastFileStream.setByteOrder(QDataStream::BigEndian); + if (GetPlatform() == "PC") { + fastFileStream.setByteOrder(QDataStream::LittleEndian); + } + + // Select key based on game. + QByteArray key; + if (GetPlatform() == "360") { + key = QByteArray::fromHex("0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3"); + } else if (GetPlatform() == "PC") { + key = QByteArray::fromHex("641D8A2FE31D3AA63622BBC9CE8587229D42B0F8ED9B924130BF88B65EDC50BE"); + } + + // Read the 8-byte magic. + QByteArray fileMagic(8, Qt::Uninitialized); + fastFileStream.readRawData(fileMagic.data(), 8); + if (fileMagic != "PHEEBs71") { + qWarning() << "Invalid fast file magic!"; + return false; + } + fastFileStream.skipRawData(4); + + // Read IV table name (32 bytes). + QByteArray fileName(32, Qt::Uninitialized); + fastFileStream.readRawData(fileName.data(), 32); + + // Skip the RSA signature (256 bytes). + QByteArray rsaSignature(256, Qt::Uninitialized); + fastFileStream.readRawData(rsaSignature.data(), 256); + + if (GetPlatform() == "360") { + //decompressedData = Compressor::cod9_decryptFastFile(aData); + } else if (GetPlatform() == "PC") { + decompressedData = Encryption::decryptFastFile_BO2(aData); + } + + // For COD9, write out the complete decompressed zone for testing. + QFile testFile("exports/" + GetStem() + ".zone"); + if(testFile.open(QIODevice::WriteOnly)) { + testFile.write(decompressedData); + testFile.close(); + } + + // Load the zone file with the decompressed data (using an Xbox platform flag). + ZoneFile_COD9_WiiU zoneFile; + zoneFile.SetStem(GetStem()); + zoneFile.Load(decompressedData); + SetZoneFile(std::make_shared(zoneFile)); + + return true; +} diff --git a/libs/fastfile/WiiU/fastfile_cod9_wiiu.h b/libs/fastfile/WiiU/fastfile_cod9_wiiu.h new file mode 100644 index 0000000..3ac7f58 --- /dev/null +++ b/libs/fastfile/WiiU/fastfile_cod9_wiiu.h @@ -0,0 +1,20 @@ +#ifndef FASTFILE_COD9_WIIU_H +#define FASTFILE_COD9_WIIU_H + +#include "fastfile.h" + +class FastFile_COD9_WiiU : public FastFile +{ +public: + FastFile_COD9_WiiU(); + FastFile_COD9_WiiU(const QByteArray &aData); + FastFile_COD9_WiiU(const QString aFilePath); + ~FastFile_COD9_WiiU(); + + QByteArray GetBinaryData() override; + + bool Load(const QString aFilePath) override; + bool Load(const QByteArray aData) override; +}; + +#endif // FASTFILE_COD9_WIIU_H diff --git a/libs/fastfile/fastfile.pro b/libs/fastfile/fastfile.pro index 63ec0f0..756d37b 100644 --- a/libs/fastfile/fastfile.pro +++ b/libs/fastfile/fastfile.pro @@ -3,37 +3,89 @@ TEMPLATE = lib CONFIG += staticlib c++17 SOURCES += \ + # Base class & factory fastfile.cpp \ + # 360 classes 360/fastfile_cod2_360.cpp \ + 360/fastfile_cod4_360.cpp \ 360/fastfile_cod5_360.cpp \ + 360/fastfile_cod6_360.cpp \ 360/fastfile_cod7_360.cpp \ + 360/fastfile_cod8_360.cpp \ 360/fastfile_cod9_360.cpp \ + 360/fastfile_cod10_360.cpp \ + 360/fastfile_cod11_360.cpp \ + 360/fastfile_cod12_360.cpp \ + # PS3 classes + PS3/fastfile_cod4_ps3.cpp \ PS3/fastfile_cod5_ps3.cpp \ + PS3/fastfile_cod6_ps3.cpp \ PS3/fastfile_cod7_ps3.cpp \ + PS3/fastfile_cod8_ps3.cpp \ PS3/fastfile_cod9_ps3.cpp \ + PS3/fastfile_cod10_ps3.cpp \ + PS3/fastfile_cod11_ps3.cpp \ + PS3/fastfile_cod12_ps3.cpp \ + # PC classes + PC/fastfile_cod4_pc.cpp \ PC/fastfile_cod5_pc.cpp \ + PC/fastfile_cod6_pc.cpp \ PC/fastfile_cod7_pc.cpp \ + PC/fastfile_cod8_pc.cpp \ PC/fastfile_cod9_pc.cpp \ + PC/fastfile_cod10_pc.cpp \ + PC/fastfile_cod11_pc.cpp \ PC/fastfile_cod12_pc.cpp \ + # Wii Classes + Wii/fastfile_cod4_wii.cpp \ Wii/fastfile_cod7_wii.cpp \ - WiiU/fastfile_cod9_wiiu.cpp + Wii/fastfile_cod8_wii.cpp \ + # WiiU Classes + WiiU/fastfile_cod9_wiiu.cpp \ + WiiU/fastfile_cod10_wiiu.cpp HEADERS += \ + # Base class & factory fastfile.h \ + fastfile_factory.h \ + # 360 classes 360/fastfile_cod2_360.h \ + 360/fastfile_cod4_360.h \ 360/fastfile_cod5_360.h \ + 360/fastfile_cod6_360.h \ 360/fastfile_cod7_360.h \ + 360/fastfile_cod8_360.h \ 360/fastfile_cod9_360.h \ + 360/fastfile_cod10_360.h \ + 360/fastfile_cod11_360.h \ + 360/fastfile_cod12_360.h \ + # PS3 classes + PS3/fastfile_cod4_ps3.h \ PS3/fastfile_cod5_ps3.h \ + PS3/fastfile_cod6_ps3.h \ PS3/fastfile_cod7_ps3.h \ + PS3/fastfile_cod8_ps3.h \ PS3/fastfile_cod9_ps3.h \ + PS3/fastfile_cod10_ps3.h \ + PS3/fastfile_cod11_ps3.h \ + PS3/fastfile_cod12_ps3.h \ + # PC classes + PC/fastfile_cod4_pc.h \ PC/fastfile_cod5_pc.h \ + PC/fastfile_cod6_pc.h \ PC/fastfile_cod7_pc.h \ + PC/fastfile_cod8_pc.h \ PC/fastfile_cod9_pc.h \ + PC/fastfile_cod10_pc.h \ + PC/fastfile_cod11_pc.h \ PC/fastfile_cod12_pc.h \ + # Wii Classes + Wii/fastfile_cod4_wii.h \ Wii/fastfile_cod7_wii.h \ + Wii/fastfile_cod8_wii.h \ + # WiiU classes WiiU/fastfile_cod9_wiiu.h \ - fastfile_factory.h + WiiU/fastfile_cod10_wiiu.h LIBS += \ -L$$OUT_PWD/../libs/core -lcore \ diff --git a/libs/fastfile/fastfile_factory.h b/libs/fastfile/fastfile_factory.h index 7b2186c..7707b25 100644 --- a/libs/fastfile/fastfile_factory.h +++ b/libs/fastfile/fastfile_factory.h @@ -3,42 +3,42 @@ #include "360/fastfile_cod2_360.h" //#include "360/fastfile_cod3_360.h" -//#include "360/fastfile_cod4_360.h" +#include "360/fastfile_cod4_360.h" #include "360/fastfile_cod5_360.h" -//#include "360/fastfile_cod6_360.h" +#include "360/fastfile_cod6_360.h" #include "360/fastfile_cod7_360.h" -//#include "360/fastfile_cod8_360.h" +#include "360/fastfile_cod8_360.h" #include "360/fastfile_cod9_360.h" -//#include "360/fastfile_cod10_360.h" -//#include "360/fastfile_cod11_360.h" -//#include "360/fastfile_cod12_360.h" +#include "360/fastfile_cod10_360.h" +#include "360/fastfile_cod11_360.h" +#include "360/fastfile_cod12_360.h" //#include "PS3/fastfile_cod3_ps3.h" -//#include "PS3/fastfile_cod4_ps3.h" +#include "PS3/fastfile_cod4_ps3.h" #include "PS3/fastfile_cod5_ps3.h" -//#include "PS3/fastfile_cod6_ps3.h" +#include "PS3/fastfile_cod6_ps3.h" #include "PS3/fastfile_cod7_ps3.h" -//#include "PS3/fastfile_cod8_ps3.h" +#include "PS3/fastfile_cod8_ps3.h" #include "PS3/fastfile_cod9_ps3.h" -//#include "PS3/fastfile_cod10_ps3.h" -//#include "PS3/fastfile_cod11_ps3.h" -//#include "PS3/fastfile_cod12_ps3.h" +#include "PS3/fastfile_cod10_ps3.h" +#include "PS3/fastfile_cod11_ps3.h" +#include "PS3/fastfile_cod12_ps3.h" //#include "PC/fastfile_cod3_pc.h" -//#include "PC/fastfile_cod4_pc.h" +#include "PC/fastfile_cod4_pc.h" #include "PC/fastfile_cod5_pc.h" -//#include "PC/fastfile_cod6_pc.h" +#include "PC/fastfile_cod6_pc.h" #include "PC/fastfile_cod7_pc.h" -//#include "PC/fastfile_cod8_360.h" +#include "PC/fastfile_cod8_pc.h" #include "PC/fastfile_cod9_pc.h" -//#include "PC/fastfile_cod10_pc.h" -//#include "PC/fastfile_cod11_pc.h" +#include "PC/fastfile_cod10_pc.h" +#include "PC/fastfile_cod11_pc.h" #include "PC/fastfile_cod12_pc.h" #include "Wii//fastfile_cod7_wii.h" #include "WiiU/fastfile_cod9_wiiu.h" -//#include "WiiU/fastfile_cod10_wiiu.h" +#include "WiiU/fastfile_cod10_wiiu.h" #include #include @@ -60,21 +60,20 @@ enum FastFile_Platform { enum FastFile_Game { GAME_NONE = 0x00, GAME_COD2 = 0x01, - GAME_COD3 = 0x02, - GAME_COD4 = 0x03, - GAME_COD5 = 0x04, - GAME_COD6 = 0x05, - GAME_COD7 = 0x06, - GAME_COD8 = 0x07, - GAME_COD9 = 0x08, - GAME_COD10 = 0x09, - GAME_COD11 = 0x010, - GAME_COD12 = 0x011 + GAME_COD4 = 0x02, + GAME_COD5 = 0x03, + GAME_COD6 = 0x04, + GAME_COD7 = 0x05, + GAME_COD8 = 0x06, + GAME_COD9 = 0x07, + GAME_COD10 = 0x08, + GAME_COD11 = 0x09, + GAME_COD12 = 0x010 }; class FastFileFactory { public: - static std::shared_ptr Create(const QString& aFilePath) { + static std::shared_ptr Create(const QString& aFilePath, bool aEmpty = false) { QFile fastFile(aFilePath); if (!fastFile.open(QIODevice::ReadOnly)) { qDebug() << "Factory failed to open fast file: " << aFilePath; @@ -82,168 +81,166 @@ public: } const QString stem = aFilePath.split('/').last().split('.').first(); + + const QString newPath = (aEmpty ? "" : aFilePath); + const QByteArray data = fastFile.readAll(); std::shared_ptr resultFF = nullptr; - if (pGetPlatform(data) == PLATFORM_360) { - if (pGetGame(data) == GAME_COD2) { - resultFF = std::make_shared(aFilePath); - } else if (pGetGame(data) == GAME_COD3) { - //resultFF = std::make_shared(aFilePath); - } else if (pGetGame(data) == GAME_COD4) { - //resultFF = std::make_shared(aFilePath); - } else if (pGetGame(data) == GAME_COD5) { - resultFF = std::make_shared(aFilePath); - } else if (pGetGame(data) == GAME_COD6) { - //resultFF = std::make_shared(aFilePath); - } else if (pGetGame(data) == GAME_COD7) { - resultFF = std::make_shared(aFilePath); - } else if (pGetGame(data) == GAME_COD8) { - //resultFF = std::make_shared(aFilePath); - } else if (pGetGame(data) == GAME_COD9) { - resultFF = std::make_shared(aFilePath); - } else if (pGetGame(data) == GAME_COD10) { - //resultFF = std::make_shared(aFilePath); - } else if (pGetGame(data) == GAME_COD11) { - //resultFF = std::make_shared(aFilePath); - } else if (pGetGame(data) == GAME_COD12) { - //resultFF = std::make_shared(aFilePath); + + const FastFile_Platform platform = pGetPlatform(data); + const FastFile_Game game = pGetGame(data); + + if (platform == PLATFORM_360) { + if (game == GAME_COD2) { + resultFF = std::make_shared(newPath); + } else if (game == GAME_COD4) { + resultFF = std::make_shared(newPath); + } else if (game == GAME_COD5) { + resultFF = std::make_shared(newPath); + } else if (game == GAME_COD6) { + resultFF = std::make_shared(newPath); + } else if (game == GAME_COD7) { + resultFF = std::make_shared(newPath); + } else if (game == GAME_COD8) { + resultFF = std::make_shared(newPath); + } else if (game == GAME_COD9) { + resultFF = std::make_shared(newPath); + } else if (game == GAME_COD10) { + resultFF = std::make_shared(newPath); + } else if (game == GAME_COD11) { + resultFF = std::make_shared(newPath); + } else if (game == GAME_COD12) { + resultFF = std::make_shared(newPath); } - } else if (pGetPlatform(data) == PLATFORM_PC) { - if (pGetGame(data) == GAME_COD3) { - //resultFF = std::make_shared(aFilePath); - } else if (pGetGame(data) == GAME_COD4) { - //resultFF = std::make_shared(aFilePath); - } else if (pGetGame(data) == GAME_COD5) { - resultFF = std::make_shared(aFilePath); - } else if (pGetGame(data) == GAME_COD6) { - //resultFF = std::make_shared(aFilePath); - } else if (pGetGame(data) == GAME_COD7) { - resultFF = std::make_shared(aFilePath); - } else if (pGetGame(data) == GAME_COD8) { - //resultFF = std::make_shared(aFilePath); - } else if (pGetGame(data) == GAME_COD9) { - resultFF = std::make_shared(aFilePath); - } else if (pGetGame(data) == GAME_COD10) { - //resultFF = std::make_shared(aFilePath); - } else if (pGetGame(data) == GAME_COD11) { - //resultFF = std::make_shared(aFilePath); - } else if (pGetGame(data) == GAME_COD12) { - resultFF = std::make_shared(aFilePath); + } else if (platform == PLATFORM_PC) { + if (game == GAME_COD4) { + resultFF = std::make_shared(newPath); + } else if (game == GAME_COD5) { + resultFF = std::make_shared(newPath); + } else if (game == GAME_COD6) { + resultFF = std::make_shared(newPath); + } else if (game == GAME_COD7) { + resultFF = std::make_shared(newPath); + } else if (game == GAME_COD8) { + resultFF = std::make_shared(newPath); + } else if (game == GAME_COD9) { + resultFF = std::make_shared(newPath); + } else if (game == GAME_COD10) { + resultFF = std::make_shared(newPath); + } else if (game == GAME_COD11) { + resultFF = std::make_shared(newPath); + } else if (game == GAME_COD12) { + resultFF = std::make_shared(newPath); } - } else if (pGetPlatform(data) == PLATFORM_PS3) { - if (pGetGame(data) == GAME_COD3) { - //resultFF = std::make_shared(aFilePath); - } else if (pGetGame(data) == GAME_COD4) { - //resultFF = std::make_shared(aFilePath); - } else if (pGetGame(data) == GAME_COD5) { - resultFF = std::make_shared(aFilePath); - } else if (pGetGame(data) == GAME_COD6) { - //resultFF = std::make_shared(aFilePath); - } else if (pGetGame(data) == GAME_COD7) { - resultFF = std::make_shared(aFilePath); - } else if (pGetGame(data) == GAME_COD8) { - //resultFF = std::make_shared(aFilePath); - } else if (pGetGame(data) == GAME_COD9) { - resultFF = std::make_shared(aFilePath); - } else if (pGetGame(data) == GAME_COD10) { - //resultFF = std::make_shared(aFilePath); - } else if (pGetGame(data) == GAME_COD11) { - //resultFF = std::make_shared(aFilePath); - } else if (pGetGame(data) == GAME_COD12) { - //resultFF = std::make_shared(aFilePath); + } else if (platform == PLATFORM_PS3) { + if (game == GAME_COD4) { + resultFF = std::make_shared(newPath); + } else if (game == GAME_COD5) { + resultFF = std::make_shared(newPath); + } else if (game == GAME_COD6) { + resultFF = std::make_shared(newPath); + } else if (game == GAME_COD7) { + resultFF = std::make_shared(newPath); + } else if (game == GAME_COD8) { + resultFF = std::make_shared(newPath); + } else if (game == GAME_COD9) { + resultFF = std::make_shared(newPath); + } else if (game == GAME_COD10) { + resultFF = std::make_shared(newPath); + } else if (game == GAME_COD11) { + resultFF = std::make_shared(newPath); + } else if (game == GAME_COD12) { + resultFF = std::make_shared(newPath); } - } else if (pGetPlatform(data) == PLATFORM_WII) { - if (pGetGame(data) == GAME_COD7) { - resultFF = std::make_shared(aFilePath); + } else if (platform == PLATFORM_WII) { + if (game == GAME_COD7) { + resultFF = std::make_shared(newPath); } - } else if (pGetPlatform(data) == PLATFORM_WIIU) { - if (pGetGame(data) == GAME_COD9) { - resultFF = std::make_shared(aFilePath); - } else if (pGetGame(data) == GAME_COD10) { - //resultFF = std::make_shared(aFilePath); + } else if (platform == PLATFORM_WIIU) { + if (game == GAME_COD9) { + resultFF = std::make_shared(newPath); + } else if (game == GAME_COD10) { + resultFF = std::make_shared(newPath); } } return resultFF; } static std::shared_ptr Create(const QByteArray& aData, const QString aStem = "no_name") { std::shared_ptr resultFF = nullptr; - if (pGetPlatform(aData) == PLATFORM_360) { - if (pGetGame(aData) == GAME_COD2) { + + const FastFile_Platform platform = pGetPlatform(aData); + const FastFile_Game game = pGetGame(aData); + if (platform == PLATFORM_360) { + if (game == GAME_COD2) { resultFF = std::make_shared(aData); - } else if (pGetGame(aData) == GAME_COD3) { - //resultFF = std::make_shared(data); - } else if (pGetGame(aData) == GAME_COD4) { - //resultFF = std::make_shared(data); - } else if (pGetGame(aData) == GAME_COD5) { + } else if (game == GAME_COD4) { + resultFF = std::make_shared(aData); + } else if (game == GAME_COD5) { resultFF = std::make_shared(aData); - } else if (pGetGame(aData) == GAME_COD6) { - //resultFF = std::make_shared(data); - } else if (pGetGame(aData) == GAME_COD7) { + } else if (game == GAME_COD6) { + resultFF = std::make_shared(aData); + } else if (game == GAME_COD7) { resultFF = std::make_shared(aData); - } else if (pGetGame(aData) == GAME_COD8) { - //resultFF = std::make_shared(data); - } else if (pGetGame(aData) == GAME_COD9) { + } else if (game == GAME_COD8) { + resultFF = std::make_shared(aData); + } else if (game == GAME_COD9) { resultFF = std::make_shared(aData); - } else if (pGetGame(aData) == GAME_COD10) { - //resultFF = std::make_shared(data); - } else if (pGetGame(aData) == GAME_COD11) { - //resultFF = std::make_shared(data); - } else if (pGetGame(aData) == GAME_COD12) { - //resultFF = std::make_shared(data); + } else if (game == GAME_COD10) { + resultFF = std::make_shared(aData); + } else if (game == GAME_COD11) { + resultFF = std::make_shared(aData); + } else if (game == GAME_COD12) { + resultFF = std::make_shared(aData); } - } else if (pGetPlatform(aData) == PLATFORM_PC) { - if (pGetGame(aData) == GAME_COD3) { - //resultFF = std::make_shared(data); - } else if (pGetGame(aData) == GAME_COD4) { - //resultFF = std::make_shared(data); - } else if (pGetGame(aData) == GAME_COD5) { + } else if (platform == PLATFORM_PC) { + if (game == GAME_COD4) { + resultFF = std::make_shared(aData); + } else if (game == GAME_COD5) { resultFF = std::make_shared(aData); - } else if (pGetGame(aData) == GAME_COD6) { - //resultFF = std::make_shared(data); - } else if (pGetGame(aData) == GAME_COD7) { + } else if (game == GAME_COD6) { + resultFF = std::make_shared(aData); + } else if (game == GAME_COD7) { resultFF = std::make_shared(aData); - } else if (pGetGame(aData) == GAME_COD8) { - //resultFF = std::make_shared(data); - } else if (pGetGame(aData) == GAME_COD9) { + } else if (game == GAME_COD8) { + resultFF = std::make_shared(aData); + } else if (game == GAME_COD9) { resultFF = std::make_shared(aData); - } else if (pGetGame(aData) == GAME_COD10) { - //resultFF = std::make_shared(data); - } else if (pGetGame(aData) == GAME_COD11) { - //resultFF = std::make_shared(data); - } else if (pGetGame(aData) == GAME_COD12) { - //resultFF = std::make_shared(data); + } else if (game == GAME_COD10) { + resultFF = std::make_shared(aData); + } else if (game == GAME_COD11) { + resultFF = std::make_shared(aData); + } else if (game == GAME_COD12) { + resultFF = std::make_shared(aData); } - } else if (pGetPlatform(aData) == PLATFORM_PS3) { - if (pGetGame(aData) == GAME_COD3) { - //resultFF = std::make_shared(data); - } else if (pGetGame(aData) == GAME_COD4) { - //resultFF = std::make_shared(data); - } else if (pGetGame(aData) == GAME_COD5) { + } else if (platform == PLATFORM_PS3) { + if (game == GAME_COD4) { + resultFF = std::make_shared(aData); + } else if (game == GAME_COD5) { resultFF = std::make_shared(aData); - } else if (pGetGame(aData) == GAME_COD6) { - //resultFF = std::make_shared(data); - } else if (pGetGame(aData) == GAME_COD7) { + } else if (game == GAME_COD6) { + resultFF = std::make_shared(aData); + } else if (game == GAME_COD7) { resultFF = std::make_shared(aData); - } else if (pGetGame(aData) == GAME_COD8) { - //resultFF = std::make_shared(data); - } else if (pGetGame(aData) == GAME_COD9) { + } else if (game == GAME_COD8) { + resultFF = std::make_shared(aData); + } else if (game == GAME_COD9) { resultFF = std::make_shared(aData); - } else if (pGetGame(aData) == GAME_COD10) { - //resultFF = std::make_shared(data); - } else if (pGetGame(aData) == GAME_COD11) { - //resultFF = std::make_shared(data); - } else if (pGetGame(aData) == GAME_COD12) { - //resultFF = std::make_shared(data); + } else if (game == GAME_COD10) { + resultFF = std::make_shared(aData); + } else if (game == GAME_COD11) { + resultFF = std::make_shared(aData); + } else if (game == GAME_COD12) { + resultFF = std::make_shared(aData); } - } else if (pGetPlatform(aData) == PLATFORM_WII) { - if (pGetGame(aData) == GAME_COD7) { + } else if (platform == PLATFORM_WII) { + if (game == GAME_COD7) { resultFF = std::make_shared(aData); } - } else if (pGetPlatform(aData) == PLATFORM_WIIU) { - if (pGetGame(aData) == GAME_COD9) { + } else if (platform == PLATFORM_WIIU) { + if (game == GAME_COD9) { resultFF = std::make_shared(aData); - } else if (pGetGame(aData) == GAME_COD10) { - //resultFF = std::make_shared(data); + } else if (game == GAME_COD10) { + resultFF = std::make_shared(aData); } } if (resultFF) { @@ -261,6 +258,8 @@ private: sections << aData.mid(6, 2).toHex().toUpper(); sections << aData.mid(8, 2).toHex().toUpper(); sections << aData.mid(10, 2).toHex().toUpper(); + sections << aData.mid(12, 2).toHex().toUpper(); + sections << aData.mid(14, 2).toHex().toUpper(); return sections; } @@ -270,29 +269,55 @@ private: if (sections[0] == "0000") { return PLATFORM_360; } else if (sections[4] == "0000") { - if (sections[5] == "0001" || - sections[5] == "0183" || - sections[5] == "010D" || - sections[5] == "01D9" || - sections[5] == "0070" || - sections[5] == "0092" || - sections[5] == "022E" || - sections[5] == "072E" || - sections[5] == "0253") { + + if (sections[5] == "0001" && sections[6] == "78DA") { + return PLATFORM_360; + } else if (sections[5] == "0183" && sections[6] == "7801") { + return PLATFORM_360; + } else if (sections[6] == "0101" && sections[7] == "CA3E") { + return PLATFORM_360; + } else if (sections[6] == "0000" && sections[7] == "0001") { + return PLATFORM_360; + } else if (sections[6] == "0101" && sections[7] == "CC76") { + return PLATFORM_360; + } else if (sections[6] == "0101" && sections[7] == "0101") { + return PLATFORM_360; + } else if (sections[2] == "7831") { + return PLATFORM_360; + } else if (sections[0] == "5331" && sections[2] == "7531") { + return PLATFORM_360; + } else if (sections[2] == "3030" && sections[3] == "3030") { return PLATFORM_360; } } else if (sections[5] == "0000") { return PLATFORM_PC; + } else if (sections[5] == "01DD" && sections[6] == "7801") { + return PLATFORM_WII; + } else if (sections[5] == "0094" || sections[6] == "0100") { + return PLATFORM_WIIU; } - return PLATFORM_NONE; + return PLATFORM_PS3; } static FastFile_Game pGetGame(const QByteArray& aData) { const QStringList sections = pGetDataSections(aData); if (sections[0] == "0000") { return GAME_COD2; - } else if (sections[5] == "0183") { + } else if (sections[4] == "0500" || sections[5] == "0001") { + return GAME_COD4; + } else if (sections[4] == "8301" || sections[5] == "0183") { return GAME_COD5; + } else if (sections[4] == "1401" || sections[5] == "010D") { + return GAME_COD6; + } else if (sections[4] == "D901" || sections[5] == "01D9") { + return GAME_COD7; + } else if (sections[4] == "0100" || sections[5] == "0070") { + return GAME_COD8; + } else if (sections[4] == "9300" || sections[5] == "0092" + || sections[5] == "0094") { + return GAME_COD9; + } else if (sections[4] == "3502" || sections[5] == "022E") { + return GAME_COD10; } else if (sections[0] == "5331") { return GAME_COD11; } else if (sections[2] == "3030") { diff --git a/libs/zonefile/360/zonefile_cod10_360.cpp b/libs/zonefile/360/zonefile_cod10_360.cpp new file mode 100644 index 0000000..38c3295 --- /dev/null +++ b/libs/zonefile/360/zonefile_cod10_360.cpp @@ -0,0 +1,1072 @@ +#include "zonefile_cod10_360.h" + +#include +#include +#include + +ZoneFile_COD10_360::ZoneFile_COD10_360() +{ + +} + +ZoneFile_COD10_360::~ZoneFile_COD10_360() +{ + +} + +bool ZoneFile_COD10_360::Load(const QByteArray aFileData) { + // Open zone file as little endian stream + QDataStream zoneFileStream(aFileData); + zoneFileStream.setByteOrder(QDataStream::BigEndian); + + // Parse data from zone file header + pParseZoneHeader(&zoneFileStream); + SetRecords(pParseZoneIndex(&zoneFileStream, GetRecordCount())); + SetAssetMap(pParseAssets(&zoneFileStream, GetRecords())); + + return true; +} + +void ZoneFile_COD10_360::pParseZoneHeader(QDataStream *aZoneFileStream) { + SetSize(pParseZoneSize(aZoneFileStream)); + pParseZoneUnknownsA(aZoneFileStream); + + SetTagCount(pParseZoneTagCount(aZoneFileStream)); + pParseZoneUnknownsB(aZoneFileStream); + + SetRecordCount(pParseZoneRecordCount(aZoneFileStream)); + + quint32 tagCount = GetTagCount(); + if (tagCount) { + pParseZoneUnknownsC(aZoneFileStream); + SetTags(pParseZoneTags(aZoneFileStream, tagCount)); + } else { + aZoneFileStream->skipRawData(4); + } +} + +quint32 ZoneFile_COD10_360::pParseZoneSize(QDataStream *aZoneFileStream) { + quint32 zoneFileSize; + *aZoneFileStream >> zoneFileSize; + if (zoneFileSize <= 0) { + qDebug() << "Tried to open empty zone file!"; + exit(-1); + } + zoneFileSize += 36; + return zoneFileSize; +} + +/* + ParseZoneUnknownsA() + + Parses the 1st section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD10_360::pParseZoneUnknownsA(QDataStream *aZoneFileStream) { + // Byte 4-7, 8-11, 12-15: unknown + QByteArray unknown1(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown1.data(), 4); + + QByteArray unknown2(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown2.data(), 4); + + QByteArray unknown3(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown3.data(), 4); + + // Byte 16-19, 20-23: empty/unknown + QByteArray unknown4(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown4.data(), 4); + + QByteArray unknown5(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown5.data(), 4); + + // Byte 24-27: somehow related to the filesize, but smaller value + QByteArray unknown6(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown6.data(), 4); + + // Byte 28-31, 32-35: unknown + QByteArray unknown7(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown7.data(), 4); + + QByteArray unknown8(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown8.data(), 4); +} + +/* + ParseZoneTagCount() + + Parses the number of string tags in the zone index +*/ +quint32 ZoneFile_COD10_360::pParseZoneTagCount(QDataStream *aZoneFileStream) { + quint32 tagCount; + *aZoneFileStream >> tagCount; + return tagCount; +} + +/* + ParseZoneRecordCount() + + Parses the number of records in the zone index +*/ +quint32 ZoneFile_COD10_360::pParseZoneRecordCount(QDataStream *aZoneFileStream) { + quint32 recordCount; + *aZoneFileStream >> recordCount; + return recordCount; +} + +/* + ParseZoneUnknownsB() + + Parses the 2nd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD10_360::pParseZoneUnknownsB(QDataStream *aZoneFileStream) { + // Byte 44-47: Unknown/empty? + QByteArray unknown9(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown9.data(), 4); +} + +/* + pParseZoneUnknownsC() + + Parses the 3rd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD10_360::pParseZoneUnknownsC(QDataStream *aZoneFileStream) { + // Byte 40-43: Unknown/empty? + QByteArray unknown10(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown10.data(), 4); + + // Byte 44-47: Unknown/empty? + QByteArray unknown11(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown11.data(), 4); +} + +/* + ParseZoneTags() + + Parses the string tags ate the start of zone file +*/ +QStringList ZoneFile_COD10_360::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) { + QStringList tags; + + // Byte 48-51: Repeated separators? ÿÿÿÿ x i + aZoneFileStream->skipRawData(4 * (tagCount - 1)); + + // Parse tags/strings before index + QString zoneTag; + char zoneTagChar; + for (quint32 i = 0; i < tagCount; i++) { + *aZoneFileStream >> zoneTagChar; + while (zoneTagChar != 0) { + zoneTag += zoneTagChar; + *aZoneFileStream >> zoneTagChar; + } + tags << zoneTag; + zoneTag.clear(); + } + return tags; +} + +/* + ParseZoneIndex() + + Parse the binary zone index data and populate table +*/ +QStringList ZoneFile_COD10_360::pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) { + QStringList result; + + // Don't parse if no records + if (!recordCount) { return result; } + + if (aZoneFileStream->device()->peek(4).toHex().contains("ffff")) { + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 2); + } + + // Parse index & map found asset types + for (quint32 i = 0; i <= recordCount; i++) { + // Skip record start + QByteArray rawAssetType(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rawAssetType.data(), 4); + result << rawAssetType.toHex(); + + // Skip separator + aZoneFileStream->skipRawData(4); + } + return result; +} + +AssetMap ZoneFile_COD10_360::pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) { + AssetMap result; + + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 8); + + for (int i = 0; i < assetOrder.size(); i++) { + const QString typeHex = assetOrder[i]; + const AssetType typeStr = AssetStrToEnum(typeHex); + + if (typeStr == ASSET_LOCAL_STRING) { // localized string asset + result.localStrings << pParseAsset_LocalString(aZoneFileStream); + } else if (typeStr == ASSET_RAW_FILE) { // gsc + auto rawFile = pParseAsset_RawFile(aZoneFileStream); + if (rawFile.length) { + result.rawFiles << rawFile; + } + } else if (typeStr == ASSET_PHYS_PRESET) { // physpreset + pParseAsset_PhysPreset(aZoneFileStream); + } else if (typeStr == ASSET_MODEL) { // xmodel + result.models << pParseAsset_Model(aZoneFileStream); + } else if (typeStr == ASSET_MATERIAL) { // material + pParseAsset_Material(aZoneFileStream); + } else if (typeStr == ASSET_SHADER) { // pixelshader + pParseAsset_Shader(aZoneFileStream); + } else if (typeStr == ASSET_TECH_SET) { // techset include + result.techSets << pParseAsset_TechSet(aZoneFileStream); + } else if (typeStr == ASSET_IMAGE) { // image + result.images << pParseAsset_Image(aZoneFileStream); + } else if (typeStr == ASSET_SOUND) { // loaded_sound + result.sounds << pParseAsset_Sound(aZoneFileStream); + } else if (typeStr == ASSET_COLLISION_MAP) { // col_map_mp + pParseAsset_ColMapMP(aZoneFileStream); + } else if (typeStr == ASSET_MP_MAP) { // game_map_sp + pParseAsset_GameMapSP(aZoneFileStream); + } else if (typeStr == ASSET_SP_MAP) { // game_map_mp + pParseAsset_GameMapMP(aZoneFileStream); + } else if (typeStr == ASSET_LIGHT_DEF) { // lightdef + pParseAsset_LightDef(aZoneFileStream); + } else if (typeStr == ASSET_UI_MAP) { // ui_map + pParseAsset_UIMap(aZoneFileStream); + } else if (typeStr == ASSET_SND_DRIVER_GLOBALS) { // snddriverglobals + pParseAsset_SNDDriverGlobals(aZoneFileStream); + } else if (typeStr == ASSET_AI_TYPE) { // aitype + pParseAsset_AIType(aZoneFileStream); + } else if (typeStr == ASSET_EFFECT) { // aitype + pParseAsset_FX(aZoneFileStream); + } else if (typeStr == ASSET_ANIMATION) { // aitype + result.animations << pParseAsset_Animation(aZoneFileStream); + } else if (typeStr == ASSET_STRING_TABLE) { // string_table + result.stringTables << pParseAsset_StringTable(aZoneFileStream); + } else if (typeStr == ASSET_MENU) { // string_table + result.menuFiles << pParseAsset_MenuFile(aZoneFileStream); + } else if (typeStr == ASSET_WEAPON) { // string_table + pParseAsset_Weapon(aZoneFileStream); + } else if (typeStr == ASSET_D3DBSP) { // string_table + pParseAsset_D3DBSP(aZoneFileStream); + } + } + return result; +} + +LocalString ZoneFile_COD10_360::pParseAsset_LocalString(QDataStream *aZoneFileStream) { + LocalString result; + + quint32 stringPtr, aliasPtr; + *aZoneFileStream >> stringPtr >> aliasPtr; + if (stringPtr == 4294967295) { + // Parse local string asset contents + QString localStr; + char localStrChar; + *aZoneFileStream >> localStrChar; + while (localStrChar != 0) { + result.string += localStrChar; + *aZoneFileStream >> localStrChar; + } + } else { + result.string = "String Ptr: " + QString::number(stringPtr); + } + + if (aliasPtr == 4294967295) { + // Parse rawfile name + QString aliasName; + char aliasNameChar; + *aZoneFileStream >> aliasNameChar; + while (aliasNameChar != 0) { + result.alias += aliasNameChar; + *aZoneFileStream >> aliasNameChar; + } + } else { + result.string = "Alias Ptr: " + QString::number(aliasPtr); + } + + return result; +} + +RawFile ZoneFile_COD10_360::pParseAsset_RawFile(QDataStream *aZoneFileStream) { + RawFile result; + + // Skip start separator FF FF FF FF (pointer?) + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.length; + + // Skip unknown 4 byte data + aZoneFileStream->skipRawData(4); + + // Parse rawfile path + char scriptPathChar; + *aZoneFileStream >> scriptPathChar; + while (scriptPathChar != 0) { + result.path += scriptPathChar; + *aZoneFileStream >> scriptPathChar; + } + result.path.replace(",", ""); + const QStringList pathParts = result.path.split('/'); + if (pathParts.size() == 0) { + qDebug() << "Failed to parse ff path! " << result.path; + exit(-1); + } + + // Parse gsc contents + char rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + while (rawFileContentsChar != 0 && rawFileContentsChar != -1) { + result.contents += rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + } + return result; +} + +void ZoneFile_COD10_360::pParseAsset_PhysPreset(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Model ZoneFile_COD10_360::pParseAsset_Model(QDataStream *aZoneFileStream) { + Model result; + + *aZoneFileStream >> result.namePtr >> result.tagCount >> result.rootTagCount + >> result.surfCount >> result.unknownCount >> result.boneNamePtr + >> result.parentListPtr >> result.quatsPtr >> result.transPtr + >> result.partClassPtr >> result.baseMatPtr + >> result.surfsPtr >> result.materialHandlesPtr; + + // Parse XModelLodInfo + for (int i = 1; i <= 4; i++) { + quint32 intDist; + *aZoneFileStream >> intDist; + + std::memcpy(&result.lodInfo[i].dist, &intDist, sizeof(result.lodInfo[i].dist)); + *aZoneFileStream >> result.lodInfo[i].numsurfs >> result.lodInfo[i].surfIndex; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.lodInfo[i].partBits[0] + >> result.lodInfo[i].partBits[1] + >> result.lodInfo[i].partBits[2] + >> result.lodInfo[i].partBits[3]; + } + + *aZoneFileStream >> result.collSurfsPtr >> result.numCollSurfs >> result.contents >> result.boneInfoPtr; + + quint32 intRadius, intMins[3], intMaxs[3]; + *aZoneFileStream >> intRadius >> intMins[0] >> intMins[1] + >> intMins[2] >> intMaxs[0] >> intMaxs[1] >> intMaxs[2]; + + std::memcpy(&result.radius, &intRadius, sizeof(result.radius)); + + std::memcpy(&result.mins[0], &intMins[0], sizeof(result.mins[0])); + std::memcpy(&result.mins[1], &intMins[1], sizeof(result.mins[1])); + std::memcpy(&result.mins[2], &intMins[2], sizeof(result.mins[2])); + + std::memcpy(&result.maxs[0], &intMaxs[0], sizeof(result.maxs[0])); + std::memcpy(&result.maxs[1], &intMaxs[1], sizeof(result.maxs[2])); + std::memcpy(&result.maxs[2], &intMaxs[2], sizeof(result.maxs[3])); + + *aZoneFileStream >> result.numLods >> result.collLod >> result.streamInfoPtr + >> result.memUsage >> result.flags >> result.physPresetPtr >> result.physGeomsPtr; + + // Parse model name + char modelNameChar; + *aZoneFileStream >> modelNameChar; + while (modelNameChar == 0) { + *aZoneFileStream >> modelNameChar; + } + while (modelNameChar != 0) { + result.modelName += modelNameChar; + *aZoneFileStream >> modelNameChar; + } + return result; +} + +Material ZoneFile_COD10_360::pParseAsset_Material(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); + + return Material(); +} + +Shader ZoneFile_COD10_360::pParseAsset_Shader(QDataStream *aZoneFileStream) { + Shader result = Shader(); + + quint8 minorVersion, majorVersion; + *aZoneFileStream >> minorVersion >> majorVersion; + + quint32 magic; + *aZoneFileStream >> magic; + + // Verify .fxc magic + if (magic != 65534 && magic != 65535) { return result; } + + SHADER_TYPE type = SHADER_NONE; + quint16 rawShaderType; + *aZoneFileStream >> rawShaderType; + if (rawShaderType == 65535) { // Pixel shader + type = SHADER_PIXEL; + } else if (rawShaderType == 65534) { // Vertex shader + type = SHADER_VERTEX; + } + Q_UNUSED(type); + + while (true) { + quint32 instructionToken; + *aZoneFileStream >> instructionToken; + + SHADER_OPCODE opCode = (SHADER_OPCODE)(instructionToken & 0xffff); + + int size; + if (opCode == OPCODE_End) { + break; + } else if (opCode == OPCODE_Comment) { + size = (int)((instructionToken >> 16) & 0x7FFF); + } else { + size = (int)((instructionToken >> 24) & 0x0f); + } + Q_UNUSED(size); + } + + + return result; +} + +TechSet ZoneFile_COD10_360::pParseAsset_TechSet(QDataStream *aZoneFileStream) { + TechSet result; + + for (int i = 1; i <= 62; i++) { + quint32 ptr; + *aZoneFileStream >> ptr; + + result.pointers << ptr; + } + qDebug() << aZoneFileStream->device()->pos(); + + // Parse techset name + char techSetNameChar; + *aZoneFileStream >> techSetNameChar; + while (techSetNameChar != 0) { + result.name += techSetNameChar; + *aZoneFileStream >> techSetNameChar; + } + result.name.replace(",", ""); + + return result; +} + +Image ZoneFile_COD10_360::pParseAsset_Image(QDataStream *aZoneFileStream) { + Image result; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknowna >> result.unknownb + >> result.unknownc >> result.unknownd + >> result.unknowne >> result.unknownf + >> result.unknowng; + + aZoneFileStream->skipRawData(15 * 4); + *aZoneFileStream >> result.unknownh >> result.unknowni; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknownj; + + aZoneFileStream->skipRawData(4); + + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + result.materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + result.materialName.replace(",", ""); + + if (result.unknowna) { + *aZoneFileStream >> result.unknownk; + *aZoneFileStream >> result.unknownl; + *aZoneFileStream >> result.unknownm; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown1; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown2 >> result.unknown3 + >> result.size1 >> result.size2 + >> result.unknown4 >> result.unknown5; + + aZoneFileStream->skipRawData(4); + + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + result.name += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + + *aZoneFileStream >> result.unknown6 >> result.unknown7; + + QByteArray compressionData(8, Qt::Uninitialized); + aZoneFileStream->readRawData(compressionData.data(), 8); + if (compressionData.contains("DXT1")) { + result.compression = COMPRESSION_DXT1; + } else if (compressionData.contains("DXT3")) { + result.compression = COMPRESSION_DXT3; + } else if (compressionData.contains("DXT5")) { + result.compression = COMPRESSION_DXT5; + } else { + result.compression = COMPRESSION_NONE; + } + + *aZoneFileStream >> result.unknown8 >> result.unknown9; + } + + return result; +} + +SoundAsset ZoneFile_COD10_360::pParseAsset_Sound(QDataStream *aZoneFileStream) { + SoundAsset result; + + qDebug() << aZoneFileStream->device()->pos(); + + QByteArray rootNamePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rootNamePtr.data(), 4); + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.count; + + if (rootNamePtr.toHex() == "ffffffff") { + // Read in sound file name + char soundNameChar; + *aZoneFileStream >> soundNameChar; + while (soundNameChar != 0) { + result.name += soundNameChar; + *aZoneFileStream >> soundNameChar; + } + } + + int tagCount = 0; + int resultCount = 0; + for (quint32 i = 0; i < result.count; i++) { + aZoneFileStream->skipRawData(12); + + QByteArray tagPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(tagPtr.data(), 4); + + if (tagPtr.toHex() == "ffffffff") { + tagCount++; + } + aZoneFileStream->skipRawData(4); + + QByteArray pathPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pathPtr.data(), 4); + + if (pathPtr.toHex() == "ffffffff") { + resultCount++; + } + + aZoneFileStream->skipRawData(160); + } + + for (int i = 0; i < tagCount; i++) { + // Read in tag? + QString tag; + char tagChar; + *aZoneFileStream >> tagChar; + while (tagChar != 0) { + tag += tagChar; + *aZoneFileStream >> tagChar; + } + } + + for (int i = 0; i < resultCount; i++) { + Sound sound; + + if (aZoneFileStream->device()->peek(12).toHex().contains("ffffffff00000000")) { + aZoneFileStream->skipRawData(12); + } + + aZoneFileStream->skipRawData(8); + + QByteArray aliasPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(aliasPtr.data(), 4); + + QByteArray namePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(namePtr.data(), 4); + + *aZoneFileStream >> sound.dataLength; + + if (aliasPtr.toHex() == "ffffffff") { + // Read in sound alias name + char soundAliasChar; + *aZoneFileStream >> soundAliasChar; + while (soundAliasChar != 0) { + sound.alias += soundAliasChar; + *aZoneFileStream >> soundAliasChar; + } + } + + if (aZoneFileStream->device()->peek(4) == "RIFF") { + sound.path = sound.alias; + sound.alias = ""; + } else if (namePtr.toHex() == "ffffffff") { + // Read in sound file path + char soundPathChar; + *aZoneFileStream >> soundPathChar; + while (soundPathChar != 0) { + sound.path += soundPathChar; + *aZoneFileStream >> soundPathChar; + } + sound.path.replace(",", ""); + } + + if (sound.dataLength) { + QByteArray data(sound.dataLength, Qt::Uninitialized); + aZoneFileStream->readRawData(data.data(), sound.dataLength); + sound.data = data; + } + result.sounds.append(sound); + } + + return result; +} + +void ZoneFile_COD10_360::pParseAsset_ColMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD10_360::pParseAsset_GameMapSP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD10_360::pParseAsset_GameMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD10_360::pParseAsset_LightDef(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD10_360::pParseAsset_UIMap(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD10_360::pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD10_360::pParseAsset_AIType(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD10_360::pParseAsset_FX(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Animation ZoneFile_COD10_360::pParseAsset_Animation(QDataStream *aZoneFileStream) { + Animation result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.dataByteCount + >> result.dataShortCount + >> result.dataIntCount + >> result.randomDataByteCount + >> result.randomDataIntCount + >> result.numframes + >> result.isLooped + >> result.isDelta + >> result.noneRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.normalTranslatedBoneCount + >> result.preciseTranslatedBoneCount + >> result.staticTranslatedBoneCount + >> result.noneTranslatedBoneCount + >> result.totalBoneCount + >> result.otherBoneCount1 + >> result.otherBoneCount2 + >> result.notifyCount + >> result.assetType + >> result.pad + >> result.randomDataShortCount + >> result.indexCount + >> result.frameRate + >> result.frequency + >> result.boneIDsPtr + >> result.dataBytePtr + >> result.dataShortPtr + >> result.dataIntPtr + >> result.randomDataShortPtr + >> result.randomDataBytePtr + >> result.randomDataIntPtr + >> result.longIndiciesPtr + >> result.notificationsPtr + >> result.deltaPartsPtr; + + // Read in x_anim file name + QString xAnimName; + char xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + while (xAnimNameChar != 0) { + result.name += xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + } + + // Parse x_anim index header + QVector sectionLengths; + for (int i = 0; i < result.numframes; i++) { + quint8 sectionlength; + *aZoneFileStream >> sectionlength; + sectionLengths.push_back(sectionlength); + // Skip padding + aZoneFileStream->skipRawData(1); + } + // Skip unknown section + aZoneFileStream->skipRawData(2 * 8); + + return result; +} + +MenuFile ZoneFile_COD10_360::pParseAsset_MenuFile(QDataStream *aZoneFileStream) { + //MENU_FILE + MenuFile result; + + aZoneFileStream->skipRawData(4); // Separator + + // Parse menu def count + *aZoneFileStream >> result.menuCount; + + // Clearly misparsed, never have this much + if (result.menuCount > 1000) { + qDebug() << "Failure reported when parsing menu file."; + return result; + } + for (uint i = 0; i < result.menuCount; i++) { + Menu menu; + + aZoneFileStream->skipRawData(4); // Separator + + // Read in x_anim file name + char menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + while (menuFilepathChar != 0) { + menu.filePath += menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + } + aZoneFileStream->skipRawData(4); // Separator + + *aZoneFileStream >> menu.menuNamePtr; + + float menuRectX, menuRectY, menuRectWidth, menuRectHeight; + *aZoneFileStream >> menuRectX >> menuRectY >> menuRectWidth >> menuRectHeight; + menu.rect = QRectF(menuRectX, menuRectY, menuRectWidth, menuRectHeight); + + quint32 hAlignInt, vAlignInt; + *aZoneFileStream >> hAlignInt >> vAlignInt; + menu.hAlign = (MENU_H_ALIGNMENT)hAlignInt; + menu.vAlign = (MENU_V_ALIGNMENT)vAlignInt; + + float rectClientX, rectClientY, rectClientWidth, rectClientHeight; + *aZoneFileStream >> rectClientX >> rectClientY >> rectClientWidth >> rectClientHeight; + menu.clientRect = QRectF(rectClientX, rectClientY, rectClientWidth, rectClientHeight); + + quint32 hClientAlignInt, vClientAlignInt, styleInt, borderInt; + *aZoneFileStream >> hClientAlignInt >> vClientAlignInt >> menu.groupPtr + >> styleInt >> borderInt >> menu.ownerDraw >> menu.ownerDrawFlags + >> menu.borderSize >> menu.staticFlags >> menu.dynamicFlags >> menu.nextTime; + menu.hClientAlign = (MENU_H_ALIGNMENT)hClientAlignInt; + menu.vClientAlign = (MENU_V_ALIGNMENT)vClientAlignInt; + menu.style = (MENU_WINDOW_STYLE)styleInt; + menu.border = (MENU_WINDOW_BORDER)borderInt; + + float foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA, + backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA, + borderColorR, borderColorG, borderColorB, borderColorA, + outlineColorR, outlineColorG, outlineColorB, outlineColorA; + *aZoneFileStream >> foregroundColorR >> foregroundColorG >> foregroundColorB >> foregroundColorA + >> backgroundColorR >> backgroundColorG >> backgroundColorB >> backgroundColorA + >> borderColorR >> borderColorG >> borderColorB >> borderColorA + >> outlineColorR >> outlineColorG >> outlineColorB >> outlineColorA; + + menu.foregroundColor = QColor(foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA); + menu.backgroundColor = QColor(backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA); + menu.borderColor = QColor(borderColorR, borderColorG, borderColorB, borderColorA); + menu.outlineColor = QColor(outlineColorR, outlineColorG, outlineColorB, outlineColorA); + + *aZoneFileStream >> menu.materialPtr >> menu.fontPtr >> menu.fullScreen >> menu.itemCount + >> menu.fontIndex >> menu.cursorItem >> menu.fadeCycle >> menu.fadeClamp + >> menu.fadeAmount >> menu.fadeInAmount >> menu.blurRadius >> menu.onOpenPtr + >> menu.onFocusPtr >> menu.onClosePtr >> menu.onESCPtr >> menu.onKeyPtr + >> menu.visibleExpCount >> menu.expEntryPtr >> menu.allowedBindingPtr + >> menu.soundNamePtr >> menu.imageTrack; + + float focusColorR, focusColorG, focusColorB, focusColorA, + disabledColorR, disabledColorG, disabledColorB, disabledColorA; + *aZoneFileStream >> focusColorR >> focusColorG >> focusColorB >> focusColorA + >> disabledColorR >> disabledColorG >> disabledColorB >> disabledColorA; + menu.focusColor = QColor(focusColorR, focusColorG, focusColorB, focusColorA); + menu.disabledColor = QColor(disabledColorR, disabledColorG, disabledColorB, disabledColorA); + + *aZoneFileStream >> menu.rectXExpCount >> menu.rectXExpPtr >> menu.rectYExpCount >> menu.rectYExpPtr; + + aZoneFileStream->skipRawData(4); // Separator + + char menuDefNameChar; + int menuDefNameLen = 0; + *aZoneFileStream >> menuDefNameChar; + while (menuDefNameChar != 0 && menuDefNameLen < 30) { + menuDefNameLen++; + menu.name += menuDefNameChar; + *aZoneFileStream >> menuDefNameChar; + } + + char defStringChar; + int defStringLen = 0; + *aZoneFileStream >> defStringChar; + while (defStringChar != 0 && defStringLen < 30) { + defStringLen++; + menu.definition += defStringChar; + *aZoneFileStream >> defStringChar; + } + aZoneFileStream->skipRawData(4 * 10); + + *aZoneFileStream >> menu.itemWindowDefNamePtr; + + float itemRectX, itemRectY, itemRectWidth, itemRectHeight; + *aZoneFileStream >> itemRectX >> itemRectY >> itemRectWidth >> itemRectHeight; + menu.itemRect = QRectF(itemRectX, itemRectY, itemRectWidth, itemRectHeight); + + *aZoneFileStream >> menu.itemHAlignment >> menu.itemVAlignment >> menu.itemGroupPtr + >> menu.itemWindowStyle >> menu.itemWindowBorder >> menu.itemOwnerDraw + >> menu.itemOwnerDrawFlags >> menu.itemBorderSize >> menu.itemStaticFlags + >> menu.itemDynamicFlags >> menu.itemNextTime; + + float itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA, + itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA, + itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA, + itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA; + *aZoneFileStream >> itemForegroundColorR >> itemForegroundColorG >> itemForegroundColorB >> itemForegroundColorA + >> itemBackgroundColorR >> itemBackgroundColorG >> itemBackgroundColorB >> itemBackgroundColorA + >> itemBorderColorR >> itemBorderColorG >> itemBorderColorB >> itemBorderColorA + >> itemOutlineColorR >> itemOutlineColorG >> itemOutlineColorB >> itemOutlineColorA; + + menu.itemForegroundColor = QColor(itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA); + menu.itemBackgroundColor = QColor(itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA); + menu.itemBorderColor = QColor(itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA); + menu.itemOutlineColor = QColor(itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA); + + *aZoneFileStream >> menu.itemMaterialPtr; + + float itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight; + *aZoneFileStream >> itemTextRectX >> itemTextRectY >> itemTextRectWidth >> itemTextRectHeight; + menu.itemTextRect = QRectF(itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight); + + quint32 hItemTextAlignInt, vItemTextAlignInt, itemType, fontTypeInt, textStyleInt; + *aZoneFileStream >> hItemTextAlignInt >> vItemTextAlignInt >> itemType >> menu.dataType + >> menu.alignment >> fontTypeInt >> menu.textAlignMode >> menu.textalignx >> menu.textaligny + >> menu.textscale >> textStyleInt >> menu.gameMsgWindowIndex >> menu.gameMsgWindowMode + >> menu.testPtr >> menu.textSavegameInfo >> menu.parentPtr; + menu.itemText_hAlign = (MENU_H_ALIGNMENT)hItemTextAlignInt; + menu.itemText_vAlign = (MENU_V_ALIGNMENT)vItemTextAlignInt; + menu.itemType = (MENU_ITEM_TYPE)itemType; + menu.fontEnum = (MENU_FONT_TYPE)fontTypeInt; + menu.textStyle = (MENU_ITEM_TEXTSTYLE)textStyleInt; + + *aZoneFileStream >> menu.mouseEnterText >> menu.mouseExitText >> menu.mouseEnter >> menu.mouseExit + >> menu.action >> menu.onAccept >> menu.onFocus >> menu.leaveFocus >> menu.dvar >> menu.dvarTest + >> menu.keyHandlerPtr >> menu.enableDvarPtr >> menu.dvarFlags >> menu.focusSoundPtr + >> menu.special >> menu.cursorPos; + + // itemDefData_t typeData; + + // listBoxDef_s *listBox; + + *aZoneFileStream >> menu.startPos >> menu.endPos >> menu.drawPadding; + + *aZoneFileStream >> menu.elementWidth >> menu.elementHeight; + + *aZoneFileStream >> menu.elementStyle >> menu.numColumns; + + //columnInfo_s columnInfo[16]; + + *aZoneFileStream >> menu.doubleClickPtr; + + + *aZoneFileStream >> menu.notselectable >> menu.noScrollBars >> menu.usePaging; + + float itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA, + itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA, + itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA; + *aZoneFileStream >> itemSelectBorderColorR >> itemSelectBorderColorG >> itemSelectBorderColorB >> itemSelectBorderColorA + >> itemDisableColorR >> itemDisableColorG >> itemDisableColorB >> itemDisableColorA + >> itemFocusColorR >> itemFocusColorG >> itemFocusColorB >> itemFocusColorA; + menu.itemSelectBorderColor = QColor(itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA); + menu.itemDisableColor = QColor(itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA); + menu.itemFocusColor = QColor(itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA); + + *aZoneFileStream >> menu.selectIconPtr >> menu.backgroundItemListboxPtr >> menu.highlightTexturePtr; + + // editFieldDef_s *editField; + + *aZoneFileStream >> menu.minVal >> menu.maxVal >> menu.defVal >> menu.range >> menu.maxChars + >> menu.maxCharsGotoNext >> menu.maxPaintChars >> menu.paintOffset; + + // multiDef_s *multi; + + for (int i = 0; i < 32; i++) { + quint32 dvarList; + *aZoneFileStream >> dvarList; + menu.dvarListPtrs.push_back(dvarList); + } + + for (int i = 0; i < 32; i++) { + quint32 dvarStr; + *aZoneFileStream >> dvarStr; + menu.dvarStrPtrs.push_back(dvarStr); + } + + for (int i = 0; i < 32; i++) { + float dvarValue; + *aZoneFileStream >> dvarValue; + menu.dvarValues.push_back(dvarValue); + } + + *aZoneFileStream >> menu.count >> menu.strDef >> menu.enumDvarNamePtr; + aZoneFileStream->skipRawData(4); + //>> menu.dataPtr + *aZoneFileStream >> menu.itemImageTrack; + + qDebug() << aZoneFileStream->device()->pos(); + + //statement_s visibleExp; + //statement_s textExp; + //statement_s materialExp; + //statement_s rectXExp; + //statement_s rectYExp; + //statement_s rectWExp; + //statement_s rectHExp; + //statement_s foreColorAExp; + result.menuDefs << menu; + } + return result; +} + +void ZoneFile_COD10_360::pParseAsset_Weapon(QDataStream *aZoneFileStream) { + //WEAPON_FILE + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD10_360::pParseAsset_D3DBSP(QDataStream *aZoneFileStream) { + //D3DBSP_DUMP + Q_UNUSED(aZoneFileStream); +} + +StringTable ZoneFile_COD10_360::pParseAsset_StringTable(QDataStream *aZoneFileStream) { + StringTable result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.columnCount + >> result.rowCount; + + // Todo fix this + result.columnCount = 0; + result.rowCount = 0; + + aZoneFileStream->skipRawData(4); + + QString stringTableName; + char stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + while (stringTableNameChar != 0) { + result.name += stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + } + + for (quint32 i = 0; i < result.rowCount; i++) { + QByteArray pointerData(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pointerData.data(), 4); + result.tablePointers.push_back(pointerData.toHex()); + + aZoneFileStream->skipRawData(4); + } + + for (const QString &pointerAddr : result.tablePointers) { + QString leadingContent = ""; + if (pointerAddr == "FFFFFFFF") { + char leadingContentChar; + *aZoneFileStream >> leadingContentChar; + while (leadingContentChar != 0) { + leadingContent += leadingContentChar; + *aZoneFileStream >> leadingContentChar; + } + } else { + leadingContent = pointerAddr; + } + + QString content; + char contentChar; + *aZoneFileStream >> contentChar; + while (contentChar != 0) { + content += contentChar; + *aZoneFileStream >> contentChar; + } + result.content[leadingContent] = content; + } + return result; +} + +AssetType ZoneFile_COD10_360::AssetStrToEnum(const QString aAssetType) { + const QString cleanedType = aAssetType.toUpper(); + if (cleanedType == "17000000") { // localized string PARTIALLY VERIFIED + return ASSET_LOCAL_STRING; + } else if (cleanedType == "20000000") { // raw_file PARTIALLY VERIFIED + return ASSET_RAW_FILE; + } else if (cleanedType == "1A000000") { // fx PARTIALLY VERIFIED + return ASSET_EFFECT; + } else if (cleanedType == "09000000") { // loaded_sound PARTIALLY VERIFIED + return ASSET_SOUND; + } else if (cleanedType == "04000000") { // x_anim PARTIALLY VERIFIED + return ASSET_ANIMATION; + } else if (cleanedType == "0C000000") { // collision_map PARTIALLY VERIFIED + return ASSET_COLLISION_MAP; + } else if (cleanedType == "21000000") { // string_table PARTIALLY VERIFIED + return ASSET_STRING_TABLE; + } else if (cleanedType == "15000000") { // menu_file PARTIALLY VERIFIED + return ASSET_MENU; + } else if (cleanedType == "07000000") { // tech set PARTIALLY VERIFIED + return ASSET_TECH_SET; + } else if (cleanedType == "18000000") { // weapon PARTIALLY VERIFIED + return ASSET_WEAPON; + } else if (cleanedType == "11000000") { // gfx map PARTIALLY VERIFIED + return ASSET_GFX_MAP; + } else if (cleanedType == "12000000") { // light_def PARTIALLY VERIFIED + return ASSET_LIGHT_DEF; + } else if (cleanedType == "14000000") { // font PARTIALLY VERIFIED + return ASSET_FONT; + } else if (cleanedType == "05000000") { // xmodel PARTIALLY VERIFIED + return ASSET_MODEL; + } else if (cleanedType == "0D000000") { // d3dbsp PARTIALLY VERIFIED + return ASSET_D3DBSP; + } else if (cleanedType == "06000000") { // image PARTIALLY VERIFIED + return ASSET_IMAGE; + } else if (cleanedType == "0E000000") { // game map sp PARTIALLY VERIFIED + return ASSET_GAME_MAP_SP; + } else if (cleanedType == "0B000000") { // col map sp PARTIALLY VERIFIED + return ASSET_COL_MAP_SP; + } + return ASSET_NONE; +} + +QByteArray ZoneFile_COD10_360::GetBinaryData() { + QByteArray result; + + return result; +} diff --git a/libs/zonefile/360/zonefile_cod10_360.h b/libs/zonefile/360/zonefile_cod10_360.h new file mode 100644 index 0000000..eae80e4 --- /dev/null +++ b/libs/zonefile/360/zonefile_cod10_360.h @@ -0,0 +1,52 @@ +#ifndef ZONEFILE_COD10_360_H +#define ZONEFILE_COD10_360_H + +#include "zonefile.h" + +class ZoneFile_COD10_360 : public ZoneFile +{ +public: + ZoneFile_COD10_360(); + ~ZoneFile_COD10_360(); + + bool Load(const QByteArray aFileData) override; + AssetType AssetStrToEnum(const QString aAssetType) override; + + QByteArray GetBinaryData() override; + +protected: + void pParseZoneHeader(QDataStream *aZoneFileStream) override; + quint32 pParseZoneSize(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsA(QDataStream *aZoneFileStream) override; + quint32 pParseZoneTagCount(QDataStream *aZoneFileStream) override; + quint32 pParseZoneRecordCount(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsB(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsC(QDataStream *aZoneFileStream) override; + QStringList pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) override; + QStringList pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) override; + AssetMap pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) override; + LocalString pParseAsset_LocalString(QDataStream *aZoneFileStream) override; + RawFile pParseAsset_RawFile(QDataStream *aZoneFileStream) override; + void pParseAsset_PhysPreset(QDataStream *aZoneFileStream) override; + Model pParseAsset_Model(QDataStream *aZoneFileStream) override; + Material pParseAsset_Material(QDataStream *aZoneFileStream) override; + Shader pParseAsset_Shader(QDataStream *aZoneFileStream) override; + TechSet pParseAsset_TechSet(QDataStream *aZoneFileStream) override; + Image pParseAsset_Image(QDataStream *aZoneFileStream) override; + SoundAsset pParseAsset_Sound(QDataStream *aZoneFileStream) override; + void pParseAsset_ColMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapSP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_LightDef(QDataStream *aZoneFileStream) override; + void pParseAsset_UIMap(QDataStream *aZoneFileStream) override; + void pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) override; + void pParseAsset_AIType(QDataStream *aZoneFileStream) override; + void pParseAsset_FX(QDataStream *aZoneFileStream) override; + Animation pParseAsset_Animation(QDataStream *aZoneFileStream) override; + MenuFile pParseAsset_MenuFile(QDataStream *aZoneFileStream) override; + void pParseAsset_Weapon(QDataStream *aZoneFileStream) override; + void pParseAsset_D3DBSP(QDataStream *aZoneFileStream) override; + StringTable pParseAsset_StringTable(QDataStream *aZoneFileStream) override; +}; + +#endif // ZONEFILE_COD10_360_H diff --git a/libs/zonefile/360/zonefile_cod11_360.cpp b/libs/zonefile/360/zonefile_cod11_360.cpp new file mode 100644 index 0000000..ac65795 --- /dev/null +++ b/libs/zonefile/360/zonefile_cod11_360.cpp @@ -0,0 +1,1072 @@ +#include "zonefile_cod11_360.h" + +#include +#include +#include + +ZoneFile_COD11_360::ZoneFile_COD11_360() +{ + +} + +ZoneFile_COD11_360::~ZoneFile_COD11_360() +{ + +} + +bool ZoneFile_COD11_360::Load(const QByteArray aFileData) { + // Open zone file as little endian stream + QDataStream zoneFileStream(aFileData); + zoneFileStream.setByteOrder(QDataStream::BigEndian); + + // Parse data from zone file header + pParseZoneHeader(&zoneFileStream); + SetRecords(pParseZoneIndex(&zoneFileStream, GetRecordCount())); + SetAssetMap(pParseAssets(&zoneFileStream, GetRecords())); + + return true; +} + +void ZoneFile_COD11_360::pParseZoneHeader(QDataStream *aZoneFileStream) { + SetSize(pParseZoneSize(aZoneFileStream)); + pParseZoneUnknownsA(aZoneFileStream); + + SetTagCount(pParseZoneTagCount(aZoneFileStream)); + pParseZoneUnknownsB(aZoneFileStream); + + SetRecordCount(pParseZoneRecordCount(aZoneFileStream)); + + quint32 tagCount = GetTagCount(); + if (tagCount) { + pParseZoneUnknownsC(aZoneFileStream); + SetTags(pParseZoneTags(aZoneFileStream, tagCount)); + } else { + aZoneFileStream->skipRawData(4); + } +} + +quint32 ZoneFile_COD11_360::pParseZoneSize(QDataStream *aZoneFileStream) { + quint32 zoneFileSize; + *aZoneFileStream >> zoneFileSize; + if (zoneFileSize <= 0) { + qDebug() << "Tried to open empty zone file!"; + exit(-1); + } + zoneFileSize += 36; + return zoneFileSize; +} + +/* + ParseZoneUnknownsA() + + Parses the 1st section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD11_360::pParseZoneUnknownsA(QDataStream *aZoneFileStream) { + // Byte 4-7, 8-11, 12-15: unknown + QByteArray unknown1(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown1.data(), 4); + + QByteArray unknown2(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown2.data(), 4); + + QByteArray unknown3(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown3.data(), 4); + + // Byte 16-19, 20-23: empty/unknown + QByteArray unknown4(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown4.data(), 4); + + QByteArray unknown5(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown5.data(), 4); + + // Byte 24-27: somehow related to the filesize, but smaller value + QByteArray unknown6(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown6.data(), 4); + + // Byte 28-31, 32-35: unknown + QByteArray unknown7(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown7.data(), 4); + + QByteArray unknown8(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown8.data(), 4); +} + +/* + ParseZoneTagCount() + + Parses the number of string tags in the zone index +*/ +quint32 ZoneFile_COD11_360::pParseZoneTagCount(QDataStream *aZoneFileStream) { + quint32 tagCount; + *aZoneFileStream >> tagCount; + return tagCount; +} + +/* + ParseZoneRecordCount() + + Parses the number of records in the zone index +*/ +quint32 ZoneFile_COD11_360::pParseZoneRecordCount(QDataStream *aZoneFileStream) { + quint32 recordCount; + *aZoneFileStream >> recordCount; + return recordCount; +} + +/* + ParseZoneUnknownsB() + + Parses the 2nd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD11_360::pParseZoneUnknownsB(QDataStream *aZoneFileStream) { + // Byte 44-47: Unknown/empty? + QByteArray unknown9(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown9.data(), 4); +} + +/* + pParseZoneUnknownsC() + + Parses the 3rd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD11_360::pParseZoneUnknownsC(QDataStream *aZoneFileStream) { + // Byte 40-43: Unknown/empty? + QByteArray unknown10(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown10.data(), 4); + + // Byte 44-47: Unknown/empty? + QByteArray unknown11(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown11.data(), 4); +} + +/* + ParseZoneTags() + + Parses the string tags ate the start of zone file +*/ +QStringList ZoneFile_COD11_360::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) { + QStringList tags; + + // Byte 48-51: Repeated separators? ÿÿÿÿ x i + aZoneFileStream->skipRawData(4 * (tagCount - 1)); + + // Parse tags/strings before index + QString zoneTag; + char zoneTagChar; + for (quint32 i = 0; i < tagCount; i++) { + *aZoneFileStream >> zoneTagChar; + while (zoneTagChar != 0) { + zoneTag += zoneTagChar; + *aZoneFileStream >> zoneTagChar; + } + tags << zoneTag; + zoneTag.clear(); + } + return tags; +} + +/* + ParseZoneIndex() + + Parse the binary zone index data and populate table +*/ +QStringList ZoneFile_COD11_360::pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) { + QStringList result; + + // Don't parse if no records + if (!recordCount) { return result; } + + if (aZoneFileStream->device()->peek(4).toHex().contains("ffff")) { + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 2); + } + + // Parse index & map found asset types + for (quint32 i = 0; i <= recordCount; i++) { + // Skip record start + QByteArray rawAssetType(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rawAssetType.data(), 4); + result << rawAssetType.toHex(); + + // Skip separator + aZoneFileStream->skipRawData(4); + } + return result; +} + +AssetMap ZoneFile_COD11_360::pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) { + AssetMap result; + + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 8); + + for (int i = 0; i < assetOrder.size(); i++) { + const QString typeHex = assetOrder[i]; + const AssetType typeStr = AssetStrToEnum(typeHex); + + if (typeStr == ASSET_LOCAL_STRING) { // localized string asset + result.localStrings << pParseAsset_LocalString(aZoneFileStream); + } else if (typeStr == ASSET_RAW_FILE) { // gsc + auto rawFile = pParseAsset_RawFile(aZoneFileStream); + if (rawFile.length) { + result.rawFiles << rawFile; + } + } else if (typeStr == ASSET_PHYS_PRESET) { // physpreset + pParseAsset_PhysPreset(aZoneFileStream); + } else if (typeStr == ASSET_MODEL) { // xmodel + result.models << pParseAsset_Model(aZoneFileStream); + } else if (typeStr == ASSET_MATERIAL) { // material + pParseAsset_Material(aZoneFileStream); + } else if (typeStr == ASSET_SHADER) { // pixelshader + pParseAsset_Shader(aZoneFileStream); + } else if (typeStr == ASSET_TECH_SET) { // techset include + result.techSets << pParseAsset_TechSet(aZoneFileStream); + } else if (typeStr == ASSET_IMAGE) { // image + result.images << pParseAsset_Image(aZoneFileStream); + } else if (typeStr == ASSET_SOUND) { // loaded_sound + result.sounds << pParseAsset_Sound(aZoneFileStream); + } else if (typeStr == ASSET_COLLISION_MAP) { // col_map_mp + pParseAsset_ColMapMP(aZoneFileStream); + } else if (typeStr == ASSET_MP_MAP) { // game_map_sp + pParseAsset_GameMapSP(aZoneFileStream); + } else if (typeStr == ASSET_SP_MAP) { // game_map_mp + pParseAsset_GameMapMP(aZoneFileStream); + } else if (typeStr == ASSET_LIGHT_DEF) { // lightdef + pParseAsset_LightDef(aZoneFileStream); + } else if (typeStr == ASSET_UI_MAP) { // ui_map + pParseAsset_UIMap(aZoneFileStream); + } else if (typeStr == ASSET_SND_DRIVER_GLOBALS) { // snddriverglobals + pParseAsset_SNDDriverGlobals(aZoneFileStream); + } else if (typeStr == ASSET_AI_TYPE) { // aitype + pParseAsset_AIType(aZoneFileStream); + } else if (typeStr == ASSET_EFFECT) { // aitype + pParseAsset_FX(aZoneFileStream); + } else if (typeStr == ASSET_ANIMATION) { // aitype + result.animations << pParseAsset_Animation(aZoneFileStream); + } else if (typeStr == ASSET_STRING_TABLE) { // string_table + result.stringTables << pParseAsset_StringTable(aZoneFileStream); + } else if (typeStr == ASSET_MENU) { // string_table + result.menuFiles << pParseAsset_MenuFile(aZoneFileStream); + } else if (typeStr == ASSET_WEAPON) { // string_table + pParseAsset_Weapon(aZoneFileStream); + } else if (typeStr == ASSET_D3DBSP) { // string_table + pParseAsset_D3DBSP(aZoneFileStream); + } + } + return result; +} + +LocalString ZoneFile_COD11_360::pParseAsset_LocalString(QDataStream *aZoneFileStream) { + LocalString result; + + quint32 stringPtr, aliasPtr; + *aZoneFileStream >> stringPtr >> aliasPtr; + if (stringPtr == 4294967295) { + // Parse local string asset contents + QString localStr; + char localStrChar; + *aZoneFileStream >> localStrChar; + while (localStrChar != 0) { + result.string += localStrChar; + *aZoneFileStream >> localStrChar; + } + } else { + result.string = "String Ptr: " + QString::number(stringPtr); + } + + if (aliasPtr == 4294967295) { + // Parse rawfile name + QString aliasName; + char aliasNameChar; + *aZoneFileStream >> aliasNameChar; + while (aliasNameChar != 0) { + result.alias += aliasNameChar; + *aZoneFileStream >> aliasNameChar; + } + } else { + result.string = "Alias Ptr: " + QString::number(aliasPtr); + } + + return result; +} + +RawFile ZoneFile_COD11_360::pParseAsset_RawFile(QDataStream *aZoneFileStream) { + RawFile result; + + // Skip start separator FF FF FF FF (pointer?) + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.length; + + // Skip unknown 4 byte data + aZoneFileStream->skipRawData(4); + + // Parse rawfile path + char scriptPathChar; + *aZoneFileStream >> scriptPathChar; + while (scriptPathChar != 0) { + result.path += scriptPathChar; + *aZoneFileStream >> scriptPathChar; + } + result.path.replace(",", ""); + const QStringList pathParts = result.path.split('/'); + if (pathParts.size() == 0) { + qDebug() << "Failed to parse ff path! " << result.path; + exit(-1); + } + + // Parse gsc contents + char rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + while (rawFileContentsChar != 0 && rawFileContentsChar != -1) { + result.contents += rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + } + return result; +} + +void ZoneFile_COD11_360::pParseAsset_PhysPreset(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Model ZoneFile_COD11_360::pParseAsset_Model(QDataStream *aZoneFileStream) { + Model result; + + *aZoneFileStream >> result.namePtr >> result.tagCount >> result.rootTagCount + >> result.surfCount >> result.unknownCount >> result.boneNamePtr + >> result.parentListPtr >> result.quatsPtr >> result.transPtr + >> result.partClassPtr >> result.baseMatPtr + >> result.surfsPtr >> result.materialHandlesPtr; + + // Parse XModelLodInfo + for (int i = 1; i <= 4; i++) { + quint32 intDist; + *aZoneFileStream >> intDist; + + std::memcpy(&result.lodInfo[i].dist, &intDist, sizeof(result.lodInfo[i].dist)); + *aZoneFileStream >> result.lodInfo[i].numsurfs >> result.lodInfo[i].surfIndex; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.lodInfo[i].partBits[0] + >> result.lodInfo[i].partBits[1] + >> result.lodInfo[i].partBits[2] + >> result.lodInfo[i].partBits[3]; + } + + *aZoneFileStream >> result.collSurfsPtr >> result.numCollSurfs >> result.contents >> result.boneInfoPtr; + + quint32 intRadius, intMins[3], intMaxs[3]; + *aZoneFileStream >> intRadius >> intMins[0] >> intMins[1] + >> intMins[2] >> intMaxs[0] >> intMaxs[1] >> intMaxs[2]; + + std::memcpy(&result.radius, &intRadius, sizeof(result.radius)); + + std::memcpy(&result.mins[0], &intMins[0], sizeof(result.mins[0])); + std::memcpy(&result.mins[1], &intMins[1], sizeof(result.mins[1])); + std::memcpy(&result.mins[2], &intMins[2], sizeof(result.mins[2])); + + std::memcpy(&result.maxs[0], &intMaxs[0], sizeof(result.maxs[0])); + std::memcpy(&result.maxs[1], &intMaxs[1], sizeof(result.maxs[2])); + std::memcpy(&result.maxs[2], &intMaxs[2], sizeof(result.maxs[3])); + + *aZoneFileStream >> result.numLods >> result.collLod >> result.streamInfoPtr + >> result.memUsage >> result.flags >> result.physPresetPtr >> result.physGeomsPtr; + + // Parse model name + char modelNameChar; + *aZoneFileStream >> modelNameChar; + while (modelNameChar == 0) { + *aZoneFileStream >> modelNameChar; + } + while (modelNameChar != 0) { + result.modelName += modelNameChar; + *aZoneFileStream >> modelNameChar; + } + return result; +} + +Material ZoneFile_COD11_360::pParseAsset_Material(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); + + return Material(); +} + +Shader ZoneFile_COD11_360::pParseAsset_Shader(QDataStream *aZoneFileStream) { + Shader result = Shader(); + + quint8 minorVersion, majorVersion; + *aZoneFileStream >> minorVersion >> majorVersion; + + quint32 magic; + *aZoneFileStream >> magic; + + // Verify .fxc magic + if (magic != 65534 && magic != 65535) { return result; } + + SHADER_TYPE type = SHADER_NONE; + quint16 rawShaderType; + *aZoneFileStream >> rawShaderType; + if (rawShaderType == 65535) { // Pixel shader + type = SHADER_PIXEL; + } else if (rawShaderType == 65534) { // Vertex shader + type = SHADER_VERTEX; + } + Q_UNUSED(type); + + while (true) { + quint32 instructionToken; + *aZoneFileStream >> instructionToken; + + SHADER_OPCODE opCode = (SHADER_OPCODE)(instructionToken & 0xffff); + + int size; + if (opCode == OPCODE_End) { + break; + } else if (opCode == OPCODE_Comment) { + size = (int)((instructionToken >> 16) & 0x7FFF); + } else { + size = (int)((instructionToken >> 24) & 0x0f); + } + Q_UNUSED(size); + } + + + return result; +} + +TechSet ZoneFile_COD11_360::pParseAsset_TechSet(QDataStream *aZoneFileStream) { + TechSet result; + + for (int i = 1; i <= 62; i++) { + quint32 ptr; + *aZoneFileStream >> ptr; + + result.pointers << ptr; + } + qDebug() << aZoneFileStream->device()->pos(); + + // Parse techset name + char techSetNameChar; + *aZoneFileStream >> techSetNameChar; + while (techSetNameChar != 0) { + result.name += techSetNameChar; + *aZoneFileStream >> techSetNameChar; + } + result.name.replace(",", ""); + + return result; +} + +Image ZoneFile_COD11_360::pParseAsset_Image(QDataStream *aZoneFileStream) { + Image result; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknowna >> result.unknownb + >> result.unknownc >> result.unknownd + >> result.unknowne >> result.unknownf + >> result.unknowng; + + aZoneFileStream->skipRawData(15 * 4); + *aZoneFileStream >> result.unknownh >> result.unknowni; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknownj; + + aZoneFileStream->skipRawData(4); + + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + result.materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + result.materialName.replace(",", ""); + + if (result.unknowna) { + *aZoneFileStream >> result.unknownk; + *aZoneFileStream >> result.unknownl; + *aZoneFileStream >> result.unknownm; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown1; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown2 >> result.unknown3 + >> result.size1 >> result.size2 + >> result.unknown4 >> result.unknown5; + + aZoneFileStream->skipRawData(4); + + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + result.name += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + + *aZoneFileStream >> result.unknown6 >> result.unknown7; + + QByteArray compressionData(8, Qt::Uninitialized); + aZoneFileStream->readRawData(compressionData.data(), 8); + if (compressionData.contains("DXT1")) { + result.compression = COMPRESSION_DXT1; + } else if (compressionData.contains("DXT3")) { + result.compression = COMPRESSION_DXT3; + } else if (compressionData.contains("DXT5")) { + result.compression = COMPRESSION_DXT5; + } else { + result.compression = COMPRESSION_NONE; + } + + *aZoneFileStream >> result.unknown8 >> result.unknown9; + } + + return result; +} + +SoundAsset ZoneFile_COD11_360::pParseAsset_Sound(QDataStream *aZoneFileStream) { + SoundAsset result; + + qDebug() << aZoneFileStream->device()->pos(); + + QByteArray rootNamePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rootNamePtr.data(), 4); + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.count; + + if (rootNamePtr.toHex() == "ffffffff") { + // Read in sound file name + char soundNameChar; + *aZoneFileStream >> soundNameChar; + while (soundNameChar != 0) { + result.name += soundNameChar; + *aZoneFileStream >> soundNameChar; + } + } + + int tagCount = 0; + int resultCount = 0; + for (quint32 i = 0; i < result.count; i++) { + aZoneFileStream->skipRawData(12); + + QByteArray tagPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(tagPtr.data(), 4); + + if (tagPtr.toHex() == "ffffffff") { + tagCount++; + } + aZoneFileStream->skipRawData(4); + + QByteArray pathPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pathPtr.data(), 4); + + if (pathPtr.toHex() == "ffffffff") { + resultCount++; + } + + aZoneFileStream->skipRawData(160); + } + + for (int i = 0; i < tagCount; i++) { + // Read in tag? + QString tag; + char tagChar; + *aZoneFileStream >> tagChar; + while (tagChar != 0) { + tag += tagChar; + *aZoneFileStream >> tagChar; + } + } + + for (int i = 0; i < resultCount; i++) { + Sound sound; + + if (aZoneFileStream->device()->peek(12).toHex().contains("ffffffff00000000")) { + aZoneFileStream->skipRawData(12); + } + + aZoneFileStream->skipRawData(8); + + QByteArray aliasPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(aliasPtr.data(), 4); + + QByteArray namePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(namePtr.data(), 4); + + *aZoneFileStream >> sound.dataLength; + + if (aliasPtr.toHex() == "ffffffff") { + // Read in sound alias name + char soundAliasChar; + *aZoneFileStream >> soundAliasChar; + while (soundAliasChar != 0) { + sound.alias += soundAliasChar; + *aZoneFileStream >> soundAliasChar; + } + } + + if (aZoneFileStream->device()->peek(4) == "RIFF") { + sound.path = sound.alias; + sound.alias = ""; + } else if (namePtr.toHex() == "ffffffff") { + // Read in sound file path + char soundPathChar; + *aZoneFileStream >> soundPathChar; + while (soundPathChar != 0) { + sound.path += soundPathChar; + *aZoneFileStream >> soundPathChar; + } + sound.path.replace(",", ""); + } + + if (sound.dataLength) { + QByteArray data(sound.dataLength, Qt::Uninitialized); + aZoneFileStream->readRawData(data.data(), sound.dataLength); + sound.data = data; + } + result.sounds.append(sound); + } + + return result; +} + +void ZoneFile_COD11_360::pParseAsset_ColMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD11_360::pParseAsset_GameMapSP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD11_360::pParseAsset_GameMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD11_360::pParseAsset_LightDef(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD11_360::pParseAsset_UIMap(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD11_360::pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD11_360::pParseAsset_AIType(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD11_360::pParseAsset_FX(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Animation ZoneFile_COD11_360::pParseAsset_Animation(QDataStream *aZoneFileStream) { + Animation result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.dataByteCount + >> result.dataShortCount + >> result.dataIntCount + >> result.randomDataByteCount + >> result.randomDataIntCount + >> result.numframes + >> result.isLooped + >> result.isDelta + >> result.noneRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.normalTranslatedBoneCount + >> result.preciseTranslatedBoneCount + >> result.staticTranslatedBoneCount + >> result.noneTranslatedBoneCount + >> result.totalBoneCount + >> result.otherBoneCount1 + >> result.otherBoneCount2 + >> result.notifyCount + >> result.assetType + >> result.pad + >> result.randomDataShortCount + >> result.indexCount + >> result.frameRate + >> result.frequency + >> result.boneIDsPtr + >> result.dataBytePtr + >> result.dataShortPtr + >> result.dataIntPtr + >> result.randomDataShortPtr + >> result.randomDataBytePtr + >> result.randomDataIntPtr + >> result.longIndiciesPtr + >> result.notificationsPtr + >> result.deltaPartsPtr; + + // Read in x_anim file name + QString xAnimName; + char xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + while (xAnimNameChar != 0) { + result.name += xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + } + + // Parse x_anim index header + QVector sectionLengths; + for (int i = 0; i < result.numframes; i++) { + quint8 sectionlength; + *aZoneFileStream >> sectionlength; + sectionLengths.push_back(sectionlength); + // Skip padding + aZoneFileStream->skipRawData(1); + } + // Skip unknown section + aZoneFileStream->skipRawData(2 * 8); + + return result; +} + +MenuFile ZoneFile_COD11_360::pParseAsset_MenuFile(QDataStream *aZoneFileStream) { + //MENU_FILE + MenuFile result; + + aZoneFileStream->skipRawData(4); // Separator + + // Parse menu def count + *aZoneFileStream >> result.menuCount; + + // Clearly misparsed, never have this much + if (result.menuCount > 1000) { + qDebug() << "Failure reported when parsing menu file."; + return result; + } + for (uint i = 0; i < result.menuCount; i++) { + Menu menu; + + aZoneFileStream->skipRawData(4); // Separator + + // Read in x_anim file name + char menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + while (menuFilepathChar != 0) { + menu.filePath += menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + } + aZoneFileStream->skipRawData(4); // Separator + + *aZoneFileStream >> menu.menuNamePtr; + + float menuRectX, menuRectY, menuRectWidth, menuRectHeight; + *aZoneFileStream >> menuRectX >> menuRectY >> menuRectWidth >> menuRectHeight; + menu.rect = QRectF(menuRectX, menuRectY, menuRectWidth, menuRectHeight); + + quint32 hAlignInt, vAlignInt; + *aZoneFileStream >> hAlignInt >> vAlignInt; + menu.hAlign = (MENU_H_ALIGNMENT)hAlignInt; + menu.vAlign = (MENU_V_ALIGNMENT)vAlignInt; + + float rectClientX, rectClientY, rectClientWidth, rectClientHeight; + *aZoneFileStream >> rectClientX >> rectClientY >> rectClientWidth >> rectClientHeight; + menu.clientRect = QRectF(rectClientX, rectClientY, rectClientWidth, rectClientHeight); + + quint32 hClientAlignInt, vClientAlignInt, styleInt, borderInt; + *aZoneFileStream >> hClientAlignInt >> vClientAlignInt >> menu.groupPtr + >> styleInt >> borderInt >> menu.ownerDraw >> menu.ownerDrawFlags + >> menu.borderSize >> menu.staticFlags >> menu.dynamicFlags >> menu.nextTime; + menu.hClientAlign = (MENU_H_ALIGNMENT)hClientAlignInt; + menu.vClientAlign = (MENU_V_ALIGNMENT)vClientAlignInt; + menu.style = (MENU_WINDOW_STYLE)styleInt; + menu.border = (MENU_WINDOW_BORDER)borderInt; + + float foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA, + backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA, + borderColorR, borderColorG, borderColorB, borderColorA, + outlineColorR, outlineColorG, outlineColorB, outlineColorA; + *aZoneFileStream >> foregroundColorR >> foregroundColorG >> foregroundColorB >> foregroundColorA + >> backgroundColorR >> backgroundColorG >> backgroundColorB >> backgroundColorA + >> borderColorR >> borderColorG >> borderColorB >> borderColorA + >> outlineColorR >> outlineColorG >> outlineColorB >> outlineColorA; + + menu.foregroundColor = QColor(foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA); + menu.backgroundColor = QColor(backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA); + menu.borderColor = QColor(borderColorR, borderColorG, borderColorB, borderColorA); + menu.outlineColor = QColor(outlineColorR, outlineColorG, outlineColorB, outlineColorA); + + *aZoneFileStream >> menu.materialPtr >> menu.fontPtr >> menu.fullScreen >> menu.itemCount + >> menu.fontIndex >> menu.cursorItem >> menu.fadeCycle >> menu.fadeClamp + >> menu.fadeAmount >> menu.fadeInAmount >> menu.blurRadius >> menu.onOpenPtr + >> menu.onFocusPtr >> menu.onClosePtr >> menu.onESCPtr >> menu.onKeyPtr + >> menu.visibleExpCount >> menu.expEntryPtr >> menu.allowedBindingPtr + >> menu.soundNamePtr >> menu.imageTrack; + + float focusColorR, focusColorG, focusColorB, focusColorA, + disabledColorR, disabledColorG, disabledColorB, disabledColorA; + *aZoneFileStream >> focusColorR >> focusColorG >> focusColorB >> focusColorA + >> disabledColorR >> disabledColorG >> disabledColorB >> disabledColorA; + menu.focusColor = QColor(focusColorR, focusColorG, focusColorB, focusColorA); + menu.disabledColor = QColor(disabledColorR, disabledColorG, disabledColorB, disabledColorA); + + *aZoneFileStream >> menu.rectXExpCount >> menu.rectXExpPtr >> menu.rectYExpCount >> menu.rectYExpPtr; + + aZoneFileStream->skipRawData(4); // Separator + + char menuDefNameChar; + int menuDefNameLen = 0; + *aZoneFileStream >> menuDefNameChar; + while (menuDefNameChar != 0 && menuDefNameLen < 30) { + menuDefNameLen++; + menu.name += menuDefNameChar; + *aZoneFileStream >> menuDefNameChar; + } + + char defStringChar; + int defStringLen = 0; + *aZoneFileStream >> defStringChar; + while (defStringChar != 0 && defStringLen < 30) { + defStringLen++; + menu.definition += defStringChar; + *aZoneFileStream >> defStringChar; + } + aZoneFileStream->skipRawData(4 * 10); + + *aZoneFileStream >> menu.itemWindowDefNamePtr; + + float itemRectX, itemRectY, itemRectWidth, itemRectHeight; + *aZoneFileStream >> itemRectX >> itemRectY >> itemRectWidth >> itemRectHeight; + menu.itemRect = QRectF(itemRectX, itemRectY, itemRectWidth, itemRectHeight); + + *aZoneFileStream >> menu.itemHAlignment >> menu.itemVAlignment >> menu.itemGroupPtr + >> menu.itemWindowStyle >> menu.itemWindowBorder >> menu.itemOwnerDraw + >> menu.itemOwnerDrawFlags >> menu.itemBorderSize >> menu.itemStaticFlags + >> menu.itemDynamicFlags >> menu.itemNextTime; + + float itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA, + itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA, + itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA, + itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA; + *aZoneFileStream >> itemForegroundColorR >> itemForegroundColorG >> itemForegroundColorB >> itemForegroundColorA + >> itemBackgroundColorR >> itemBackgroundColorG >> itemBackgroundColorB >> itemBackgroundColorA + >> itemBorderColorR >> itemBorderColorG >> itemBorderColorB >> itemBorderColorA + >> itemOutlineColorR >> itemOutlineColorG >> itemOutlineColorB >> itemOutlineColorA; + + menu.itemForegroundColor = QColor(itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA); + menu.itemBackgroundColor = QColor(itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA); + menu.itemBorderColor = QColor(itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA); + menu.itemOutlineColor = QColor(itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA); + + *aZoneFileStream >> menu.itemMaterialPtr; + + float itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight; + *aZoneFileStream >> itemTextRectX >> itemTextRectY >> itemTextRectWidth >> itemTextRectHeight; + menu.itemTextRect = QRectF(itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight); + + quint32 hItemTextAlignInt, vItemTextAlignInt, itemType, fontTypeInt, textStyleInt; + *aZoneFileStream >> hItemTextAlignInt >> vItemTextAlignInt >> itemType >> menu.dataType + >> menu.alignment >> fontTypeInt >> menu.textAlignMode >> menu.textalignx >> menu.textaligny + >> menu.textscale >> textStyleInt >> menu.gameMsgWindowIndex >> menu.gameMsgWindowMode + >> menu.testPtr >> menu.textSavegameInfo >> menu.parentPtr; + menu.itemText_hAlign = (MENU_H_ALIGNMENT)hItemTextAlignInt; + menu.itemText_vAlign = (MENU_V_ALIGNMENT)vItemTextAlignInt; + menu.itemType = (MENU_ITEM_TYPE)itemType; + menu.fontEnum = (MENU_FONT_TYPE)fontTypeInt; + menu.textStyle = (MENU_ITEM_TEXTSTYLE)textStyleInt; + + *aZoneFileStream >> menu.mouseEnterText >> menu.mouseExitText >> menu.mouseEnter >> menu.mouseExit + >> menu.action >> menu.onAccept >> menu.onFocus >> menu.leaveFocus >> menu.dvar >> menu.dvarTest + >> menu.keyHandlerPtr >> menu.enableDvarPtr >> menu.dvarFlags >> menu.focusSoundPtr + >> menu.special >> menu.cursorPos; + + // itemDefData_t typeData; + + // listBoxDef_s *listBox; + + *aZoneFileStream >> menu.startPos >> menu.endPos >> menu.drawPadding; + + *aZoneFileStream >> menu.elementWidth >> menu.elementHeight; + + *aZoneFileStream >> menu.elementStyle >> menu.numColumns; + + //columnInfo_s columnInfo[16]; + + *aZoneFileStream >> menu.doubleClickPtr; + + + *aZoneFileStream >> menu.notselectable >> menu.noScrollBars >> menu.usePaging; + + float itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA, + itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA, + itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA; + *aZoneFileStream >> itemSelectBorderColorR >> itemSelectBorderColorG >> itemSelectBorderColorB >> itemSelectBorderColorA + >> itemDisableColorR >> itemDisableColorG >> itemDisableColorB >> itemDisableColorA + >> itemFocusColorR >> itemFocusColorG >> itemFocusColorB >> itemFocusColorA; + menu.itemSelectBorderColor = QColor(itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA); + menu.itemDisableColor = QColor(itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA); + menu.itemFocusColor = QColor(itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA); + + *aZoneFileStream >> menu.selectIconPtr >> menu.backgroundItemListboxPtr >> menu.highlightTexturePtr; + + // editFieldDef_s *editField; + + *aZoneFileStream >> menu.minVal >> menu.maxVal >> menu.defVal >> menu.range >> menu.maxChars + >> menu.maxCharsGotoNext >> menu.maxPaintChars >> menu.paintOffset; + + // multiDef_s *multi; + + for (int i = 0; i < 32; i++) { + quint32 dvarList; + *aZoneFileStream >> dvarList; + menu.dvarListPtrs.push_back(dvarList); + } + + for (int i = 0; i < 32; i++) { + quint32 dvarStr; + *aZoneFileStream >> dvarStr; + menu.dvarStrPtrs.push_back(dvarStr); + } + + for (int i = 0; i < 32; i++) { + float dvarValue; + *aZoneFileStream >> dvarValue; + menu.dvarValues.push_back(dvarValue); + } + + *aZoneFileStream >> menu.count >> menu.strDef >> menu.enumDvarNamePtr; + aZoneFileStream->skipRawData(4); + //>> menu.dataPtr + *aZoneFileStream >> menu.itemImageTrack; + + qDebug() << aZoneFileStream->device()->pos(); + + //statement_s visibleExp; + //statement_s textExp; + //statement_s materialExp; + //statement_s rectXExp; + //statement_s rectYExp; + //statement_s rectWExp; + //statement_s rectHExp; + //statement_s foreColorAExp; + result.menuDefs << menu; + } + return result; +} + +void ZoneFile_COD11_360::pParseAsset_Weapon(QDataStream *aZoneFileStream) { + //WEAPON_FILE + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD11_360::pParseAsset_D3DBSP(QDataStream *aZoneFileStream) { + //D3DBSP_DUMP + Q_UNUSED(aZoneFileStream); +} + +StringTable ZoneFile_COD11_360::pParseAsset_StringTable(QDataStream *aZoneFileStream) { + StringTable result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.columnCount + >> result.rowCount; + + // Todo fix this + result.columnCount = 0; + result.rowCount = 0; + + aZoneFileStream->skipRawData(4); + + QString stringTableName; + char stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + while (stringTableNameChar != 0) { + result.name += stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + } + + for (quint32 i = 0; i < result.rowCount; i++) { + QByteArray pointerData(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pointerData.data(), 4); + result.tablePointers.push_back(pointerData.toHex()); + + aZoneFileStream->skipRawData(4); + } + + for (const QString &pointerAddr : result.tablePointers) { + QString leadingContent = ""; + if (pointerAddr == "FFFFFFFF") { + char leadingContentChar; + *aZoneFileStream >> leadingContentChar; + while (leadingContentChar != 0) { + leadingContent += leadingContentChar; + *aZoneFileStream >> leadingContentChar; + } + } else { + leadingContent = pointerAddr; + } + + QString content; + char contentChar; + *aZoneFileStream >> contentChar; + while (contentChar != 0) { + content += contentChar; + *aZoneFileStream >> contentChar; + } + result.content[leadingContent] = content; + } + return result; +} + +AssetType ZoneFile_COD11_360::AssetStrToEnum(const QString aAssetType) { + const QString cleanedType = aAssetType.toUpper(); + if (cleanedType == "17000000") { // localized string PARTIALLY VERIFIED + return ASSET_LOCAL_STRING; + } else if (cleanedType == "20000000") { // raw_file PARTIALLY VERIFIED + return ASSET_RAW_FILE; + } else if (cleanedType == "1A000000") { // fx PARTIALLY VERIFIED + return ASSET_EFFECT; + } else if (cleanedType == "09000000") { // loaded_sound PARTIALLY VERIFIED + return ASSET_SOUND; + } else if (cleanedType == "04000000") { // x_anim PARTIALLY VERIFIED + return ASSET_ANIMATION; + } else if (cleanedType == "0C000000") { // collision_map PARTIALLY VERIFIED + return ASSET_COLLISION_MAP; + } else if (cleanedType == "21000000") { // string_table PARTIALLY VERIFIED + return ASSET_STRING_TABLE; + } else if (cleanedType == "15000000") { // menu_file PARTIALLY VERIFIED + return ASSET_MENU; + } else if (cleanedType == "07000000") { // tech set PARTIALLY VERIFIED + return ASSET_TECH_SET; + } else if (cleanedType == "18000000") { // weapon PARTIALLY VERIFIED + return ASSET_WEAPON; + } else if (cleanedType == "11000000") { // gfx map PARTIALLY VERIFIED + return ASSET_GFX_MAP; + } else if (cleanedType == "12000000") { // light_def PARTIALLY VERIFIED + return ASSET_LIGHT_DEF; + } else if (cleanedType == "14000000") { // font PARTIALLY VERIFIED + return ASSET_FONT; + } else if (cleanedType == "05000000") { // xmodel PARTIALLY VERIFIED + return ASSET_MODEL; + } else if (cleanedType == "0D000000") { // d3dbsp PARTIALLY VERIFIED + return ASSET_D3DBSP; + } else if (cleanedType == "06000000") { // image PARTIALLY VERIFIED + return ASSET_IMAGE; + } else if (cleanedType == "0E000000") { // game map sp PARTIALLY VERIFIED + return ASSET_GAME_MAP_SP; + } else if (cleanedType == "0B000000") { // col map sp PARTIALLY VERIFIED + return ASSET_COL_MAP_SP; + } + return ASSET_NONE; +} + +QByteArray ZoneFile_COD11_360::GetBinaryData() { + QByteArray result; + + return result; +} diff --git a/libs/zonefile/360/zonefile_cod11_360.h b/libs/zonefile/360/zonefile_cod11_360.h new file mode 100644 index 0000000..b916039 --- /dev/null +++ b/libs/zonefile/360/zonefile_cod11_360.h @@ -0,0 +1,52 @@ +#ifndef ZONEFILE_COD11_360_H +#define ZONEFILE_COD11_360_H + +#include "zonefile.h" + +class ZoneFile_COD11_360 : public ZoneFile +{ +public: + ZoneFile_COD11_360(); + ~ZoneFile_COD11_360(); + + bool Load(const QByteArray aFileData) override; + AssetType AssetStrToEnum(const QString aAssetType) override; + + QByteArray GetBinaryData() override; + +protected: + void pParseZoneHeader(QDataStream *aZoneFileStream) override; + quint32 pParseZoneSize(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsA(QDataStream *aZoneFileStream) override; + quint32 pParseZoneTagCount(QDataStream *aZoneFileStream) override; + quint32 pParseZoneRecordCount(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsB(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsC(QDataStream *aZoneFileStream) override; + QStringList pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) override; + QStringList pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) override; + AssetMap pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) override; + LocalString pParseAsset_LocalString(QDataStream *aZoneFileStream) override; + RawFile pParseAsset_RawFile(QDataStream *aZoneFileStream) override; + void pParseAsset_PhysPreset(QDataStream *aZoneFileStream) override; + Model pParseAsset_Model(QDataStream *aZoneFileStream) override; + Material pParseAsset_Material(QDataStream *aZoneFileStream) override; + Shader pParseAsset_Shader(QDataStream *aZoneFileStream) override; + TechSet pParseAsset_TechSet(QDataStream *aZoneFileStream) override; + Image pParseAsset_Image(QDataStream *aZoneFileStream) override; + SoundAsset pParseAsset_Sound(QDataStream *aZoneFileStream) override; + void pParseAsset_ColMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapSP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_LightDef(QDataStream *aZoneFileStream) override; + void pParseAsset_UIMap(QDataStream *aZoneFileStream) override; + void pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) override; + void pParseAsset_AIType(QDataStream *aZoneFileStream) override; + void pParseAsset_FX(QDataStream *aZoneFileStream) override; + Animation pParseAsset_Animation(QDataStream *aZoneFileStream) override; + MenuFile pParseAsset_MenuFile(QDataStream *aZoneFileStream) override; + void pParseAsset_Weapon(QDataStream *aZoneFileStream) override; + void pParseAsset_D3DBSP(QDataStream *aZoneFileStream) override; + StringTable pParseAsset_StringTable(QDataStream *aZoneFileStream) override; +}; + +#endif // ZONEFILE_COD11_360_H diff --git a/libs/zonefile/360/zonefile_cod12_360.cpp b/libs/zonefile/360/zonefile_cod12_360.cpp new file mode 100644 index 0000000..bfe764c --- /dev/null +++ b/libs/zonefile/360/zonefile_cod12_360.cpp @@ -0,0 +1,1207 @@ +#include "zonefile_cod12_360.h" + +#include +#include +#include + +ZoneFile_COD12_360::ZoneFile_COD12_360() +{ + +} + +ZoneFile_COD12_360::~ZoneFile_COD12_360() +{ + +} + +bool ZoneFile_COD12_360::Load(const QByteArray aFileData) { + // Open zone file as little endian stream + QDataStream zoneFileStream(aFileData); + zoneFileStream.setByteOrder(QDataStream::LittleEndian); + + // Parse data from zone file header + pParseZoneHeader(&zoneFileStream); + SetRecords(pParseZoneIndex(&zoneFileStream, GetRecordCount())); + SetAssetMap(pParseAssets(&zoneFileStream, GetRecords())); + + return true; +} + +void ZoneFile_COD12_360::pParseZoneHeader(QDataStream *aZoneFileStream) { + quint32 tagCount = pParseZoneTagCount(aZoneFileStream); + SetTagCount(tagCount); + + aZoneFileStream->skipRawData(7 * 4); + + quint32 recordCount = pParseZoneRecordCount(aZoneFileStream) - 1; + SetRecordCount(recordCount); + + aZoneFileStream->skipRawData(5 * 4); + + if (tagCount) { + SetTags(pParseZoneTags(aZoneFileStream, tagCount)); + } +} + +quint32 ZoneFile_COD12_360::pParseZoneSize(QDataStream *aZoneFileStream) { + quint32 zoneFileSize; + *aZoneFileStream >> zoneFileSize; + if (zoneFileSize <= 0) { + qDebug() << "Tried to open empty zone file!"; + exit(-1); + } + zoneFileSize += 36; + return zoneFileSize; +} + +/* + ParseZoneUnknownsA() + + Parses the 1st section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD12_360::pParseZoneUnknownsA(QDataStream *aZoneFileStream) { + // Byte 4-7, 8-11, 12-15: unknown + QByteArray unknown1(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown1.data(), 4); + + QByteArray unknown2(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown2.data(), 4); + + QByteArray unknown3(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown3.data(), 4); + + // Byte 16-19, 20-23: empty/unknown + QByteArray unknown4(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown4.data(), 4); + + QByteArray unknown5(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown5.data(), 4); + + // Byte 24-27: somehow related to the filesize, but smaller value + QByteArray unknown6(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown6.data(), 4); + + // Byte 28-31, 32-35: unknown + QByteArray unknown7(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown7.data(), 4); + + QByteArray unknown8(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown8.data(), 4); +} + +/* + ParseZoneTagCount() + + Parses the number of string tags in the zone index +*/ +quint32 ZoneFile_COD12_360::pParseZoneTagCount(QDataStream *aZoneFileStream) { + quint32 tagCount; + *aZoneFileStream >> tagCount; + return tagCount; +} + +/* + ParseZoneRecordCount() + + Parses the number of records in the zone index +*/ +quint32 ZoneFile_COD12_360::pParseZoneRecordCount(QDataStream *aZoneFileStream) { + quint32 recordCount; + *aZoneFileStream >> recordCount; + return recordCount; +} + +/* + ParseZoneUnknownsB() + + Parses the 2nd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD12_360::pParseZoneUnknownsB(QDataStream *aZoneFileStream) { + // Byte 44-47: Unknown/empty? + QByteArray unknown9(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown9.data(), 4); +} + +/* + pParseZoneUnknownsC() + + Parses the 3rd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD12_360::pParseZoneUnknownsC(QDataStream *aZoneFileStream) { + // Byte 40-43: Unknown/empty? + QByteArray unknown10(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown10.data(), 4); + + // Byte 44-47: Unknown/empty? + QByteArray unknown11(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown11.data(), 4); +} + +/* + ParseZoneTags() + + Parses the string tags ate the start of zone file +*/ +QStringList ZoneFile_COD12_360::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) { + QStringList tags; + + // Byte 48-51: Repeated separators? ÿÿÿÿ x i + aZoneFileStream->skipRawData(8 * (tagCount - 1)); + + // Parse tags/strings before index + QString zoneTag; + char zoneTagChar; + for (quint32 i = 0; i < tagCount; i++) { + if (aZoneFileStream->device()->peek(8).toHex().contains("00000000")) { + break; + } + + *aZoneFileStream >> zoneTagChar; + while (zoneTagChar != 0) { + zoneTag += zoneTagChar; + *aZoneFileStream >> zoneTagChar; + } + tags << zoneTag; + zoneTag.clear(); + } + return tags; +} + +/* + ParseZoneIndex() + + Parse the binary zone index data and populate table +*/ +QStringList ZoneFile_COD12_360::pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) { + QStringList result; + + // Don't parse if no records + if (!recordCount) { return result; } + + // Parse index & map found asset types + for (quint32 i = 0; i <= recordCount; i++) { + // Skip record start + QByteArray rawAssetType(8, Qt::Uninitialized); + aZoneFileStream->readRawData(rawAssetType.data(), 8); + result << rawAssetType.toHex(); + + // Skip separator + aZoneFileStream->skipRawData(8); + } + return result; +} + +AssetMap ZoneFile_COD12_360::pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) { + AssetMap result; + + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 8); + + for (int i = 0; i < assetOrder.size(); i++) { + const QString typeHex = assetOrder[i]; + const AssetType typeStr = AssetStrToEnum(typeHex); + + if (typeStr == ASSET_LOCAL_STRING) { // localized string asset + result.localStrings << pParseAsset_LocalString(aZoneFileStream); + } else if (typeStr == ASSET_RAW_FILE) { // raw file + auto rawFile = pParseAsset_RawFile(aZoneFileStream); + if (rawFile.length) { + result.rawFiles << rawFile; + } + } else if (typeStr == ASSET_SCRIPT_PARSE_TREE) { // gsc + auto gscFile = pParseAsset_GSCFile(aZoneFileStream); + if (gscFile.length) { + result.gscFiles << gscFile; + } + } else if (typeStr == ASSET_PHYS_PRESET) { // physpreset + pParseAsset_PhysPreset(aZoneFileStream); + } else if (typeStr == ASSET_MODEL) { // xmodel + result.models << pParseAsset_Model(aZoneFileStream); + } else if (typeStr == ASSET_MATERIAL) { // material + pParseAsset_Material(aZoneFileStream); + } else if (typeStr == ASSET_SHADER) { // pixelshader + pParseAsset_Shader(aZoneFileStream); + } else if (typeStr == ASSET_TECH_SET) { // techset include + result.techSets << pParseAsset_TechSet(aZoneFileStream); + } else if (typeStr == ASSET_IMAGE) { // image + result.images << pParseAsset_Image(aZoneFileStream); + } else if (typeStr == ASSET_SOUND) { // loaded_sound + result.sounds << pParseAsset_Sound(aZoneFileStream); + } else if (typeStr == ASSET_COLLISION_MAP) { // col_map_mp + pParseAsset_ColMapMP(aZoneFileStream); + } else if (typeStr == ASSET_MP_MAP) { // game_map_sp + pParseAsset_GameMapSP(aZoneFileStream); + } else if (typeStr == ASSET_SP_MAP) { // game_map_mp + pParseAsset_GameMapMP(aZoneFileStream); + } else if (typeStr == ASSET_LIGHT_DEF) { // lightdef + pParseAsset_LightDef(aZoneFileStream); + } else if (typeStr == ASSET_UI_MAP) { // ui_map + pParseAsset_UIMap(aZoneFileStream); + } else if (typeStr == ASSET_SND_DRIVER_GLOBALS) { // snddriverglobals + pParseAsset_SNDDriverGlobals(aZoneFileStream); + } else if (typeStr == ASSET_AI_TYPE) { // aitype + pParseAsset_AIType(aZoneFileStream); + } else if (typeStr == ASSET_EFFECT) { // aitype + pParseAsset_FX(aZoneFileStream); + } else if (typeStr == ASSET_ANIMATION) { // aitype + result.animations << pParseAsset_Animation(aZoneFileStream); + } else if (typeStr == ASSET_STRING_TABLE) { // string_table + result.stringTables << pParseAsset_StringTable(aZoneFileStream); + } else if (typeStr == ASSET_MENU) { // string_table + result.menuFiles << pParseAsset_MenuFile(aZoneFileStream); + } else if (typeStr == ASSET_WEAPON) { // string_table + pParseAsset_Weapon(aZoneFileStream); + } else if (typeStr == ASSET_D3DBSP) { // string_table + pParseAsset_D3DBSP(aZoneFileStream); + } + } + return result; +} + +LocalString ZoneFile_COD12_360::pParseAsset_LocalString(QDataStream *aZoneFileStream) { + LocalString result; + + quint32 stringPtr, aliasPtr; + *aZoneFileStream >> stringPtr >> aliasPtr; + if (stringPtr == 4294967295) { + // Parse local string asset contents + QString localStr; + char localStrChar; + *aZoneFileStream >> localStrChar; + while (localStrChar != 0) { + result.string += localStrChar; + *aZoneFileStream >> localStrChar; + } + } else { + result.string = "String Ptr: " + QString::number(stringPtr); + } + + if (aliasPtr == 4294967295) { + // Parse rawfile name + QString aliasName; + char aliasNameChar; + *aZoneFileStream >> aliasNameChar; + while (aliasNameChar != 0) { + result.alias += aliasNameChar; + *aZoneFileStream >> aliasNameChar; + } + } else { + result.string = "Alias Ptr: " + QString::number(aliasPtr); + } + + return result; +} + +RawFile ZoneFile_COD12_360::pParseAsset_RawFile(QDataStream *aZoneFileStream) { + RawFile result; + + // Skip start separator FF FF FF FF (pointer?) + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.length; + + // Skip unknown 4 byte data + aZoneFileStream->skipRawData(4); + + // Parse rawfile path + char scriptPathChar; + *aZoneFileStream >> scriptPathChar; + while (scriptPathChar != 0) { + result.path += scriptPathChar; + *aZoneFileStream >> scriptPathChar; + } + result.path.replace(",", ""); + const QStringList pathParts = result.path.split('/'); + if (pathParts.size() == 0) { + qDebug() << "Failed to parse ff path! " << result.path; + exit(-1); + } + + // Parse gsc contents + char rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + while (rawFileContentsChar != 0 && rawFileContentsChar != -1) { + result.contents += rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + } + return result; +} + +GscFile ZoneFile_COD12_360::pParseAsset_GSCFile(QDataStream *aZoneFileStream) { + GscFile result; + + // Skip start separator FF FF FF FF (pointer?) + aZoneFileStream->skipRawData(8); + + *aZoneFileStream >> result.length; + + // Skip unknown 4 byte data + aZoneFileStream->skipRawData(8); + + // Parse rawfile path + char scriptPathChar; + *aZoneFileStream >> scriptPathChar; + while (scriptPathChar != 0) { + result.path += scriptPathChar; + *aZoneFileStream >> scriptPathChar; + } + const QStringList pathParts = result.path.split('/'); + if (pathParts.size() == 0) { + qDebug() << "Failed to parse ff path! " << result.path; + exit(-1); + } + + // Parse gsc contents + char rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + while (rawFileContentsChar != 0 && rawFileContentsChar != -1) { + result.contents += rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + } + return result; +} + +void ZoneFile_COD12_360::pParseAsset_PhysPreset(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Model ZoneFile_COD12_360::pParseAsset_Model(QDataStream *aZoneFileStream) { + Model result; + + *aZoneFileStream >> result.namePtr >> result.tagCount >> result.rootTagCount + >> result.surfCount >> result.unknownCount >> result.boneNamePtr + >> result.parentListPtr >> result.quatsPtr >> result.transPtr + >> result.partClassPtr >> result.baseMatPtr + >> result.surfsPtr >> result.materialHandlesPtr; + + // Parse XModelLodInfo + for (int i = 1; i <= 4; i++) { + quint32 intDist; + *aZoneFileStream >> intDist; + + std::memcpy(&result.lodInfo[i].dist, &intDist, sizeof(result.lodInfo[i].dist)); + *aZoneFileStream >> result.lodInfo[i].numsurfs >> result.lodInfo[i].surfIndex; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.lodInfo[i].partBits[0] + >> result.lodInfo[i].partBits[1] + >> result.lodInfo[i].partBits[2] + >> result.lodInfo[i].partBits[3]; + } + + *aZoneFileStream >> result.collSurfsPtr >> result.numCollSurfs >> result.contents >> result.boneInfoPtr; + + quint32 intRadius, intMins[3], intMaxs[3]; + *aZoneFileStream >> intRadius >> intMins[0] >> intMins[1] + >> intMins[2] >> intMaxs[0] >> intMaxs[1] >> intMaxs[2]; + + std::memcpy(&result.radius, &intRadius, sizeof(result.radius)); + + std::memcpy(&result.mins[0], &intMins[0], sizeof(result.mins[0])); + std::memcpy(&result.mins[1], &intMins[1], sizeof(result.mins[1])); + std::memcpy(&result.mins[2], &intMins[2], sizeof(result.mins[2])); + + std::memcpy(&result.maxs[0], &intMaxs[0], sizeof(result.maxs[0])); + std::memcpy(&result.maxs[1], &intMaxs[1], sizeof(result.maxs[2])); + std::memcpy(&result.maxs[2], &intMaxs[2], sizeof(result.maxs[3])); + + *aZoneFileStream >> result.numLods >> result.collLod >> result.streamInfoPtr + >> result.memUsage >> result.flags >> result.physPresetPtr >> result.physGeomsPtr; + + // Parse model name + char modelNameChar; + *aZoneFileStream >> modelNameChar; + while (modelNameChar == 0) { + *aZoneFileStream >> modelNameChar; + } + while (modelNameChar != 0) { + result.modelName += modelNameChar; + *aZoneFileStream >> modelNameChar; + } + return result; +} + +Material ZoneFile_COD12_360::pParseAsset_Material(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); + + return Material(); +} + +Shader ZoneFile_COD12_360::pParseAsset_Shader(QDataStream *aZoneFileStream) { + Shader result = Shader(); + + quint8 minorVersion, majorVersion; + *aZoneFileStream >> minorVersion >> majorVersion; + + quint32 magic; + *aZoneFileStream >> magic; + + // Verify .fxc magic + if (magic != 65534 && magic != 65535) { return result; } + + SHADER_TYPE type = SHADER_NONE; + quint16 rawShaderType; + *aZoneFileStream >> rawShaderType; + if (rawShaderType == 65535) { // Pixel shader + type = SHADER_PIXEL; + } else if (rawShaderType == 65534) { // Vertex shader + type = SHADER_VERTEX; + } + Q_UNUSED(type); + + while (true) { + quint32 instructionToken; + *aZoneFileStream >> instructionToken; + + SHADER_OPCODE opCode = (SHADER_OPCODE)(instructionToken & 0xffff); + + int size; + if (opCode == OPCODE_End) { + break; + } else if (opCode == OPCODE_Comment) { + size = (int)((instructionToken >> 16) & 0x7FFF); + } else { + size = (int)((instructionToken >> 24) & 0x0f); + } + Q_UNUSED(size); + } + + + return result; +} + +TechSet ZoneFile_COD12_360::pParseAsset_TechSet(QDataStream *aZoneFileStream) { + TechSet result; + + for (int i = 1; i <= 62; i++) { + quint32 ptr; + *aZoneFileStream >> ptr; + + result.pointers << ptr; + } + qDebug() << aZoneFileStream->device()->pos(); + + // Parse techset name + char techSetNameChar; + *aZoneFileStream >> techSetNameChar; + while (techSetNameChar != 0) { + result.name += techSetNameChar; + *aZoneFileStream >> techSetNameChar; + } + result.name.replace(",", ""); + + return result; +} + +Image ZoneFile_COD12_360::pParseAsset_Image(QDataStream *aZoneFileStream) { + Image result; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknowna >> result.unknownb + >> result.unknownc >> result.unknownd + >> result.unknowne >> result.unknownf + >> result.unknowng; + + aZoneFileStream->skipRawData(15 * 4); + *aZoneFileStream >> result.unknownh >> result.unknowni; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknownj; + + aZoneFileStream->skipRawData(4); + + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + result.materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + result.materialName.replace(",", ""); + + if (result.unknowna) { + *aZoneFileStream >> result.unknownk; + *aZoneFileStream >> result.unknownl; + *aZoneFileStream >> result.unknownm; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown1; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown2 >> result.unknown3 + >> result.size1 >> result.size2 + >> result.unknown4 >> result.unknown5; + + aZoneFileStream->skipRawData(4); + + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + result.name += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + + *aZoneFileStream >> result.unknown6 >> result.unknown7; + + QByteArray compressionData(8, Qt::Uninitialized); + aZoneFileStream->readRawData(compressionData.data(), 8); + if (compressionData.contains("DXT1")) { + result.compression = COMPRESSION_DXT1; + } else if (compressionData.contains("DXT3")) { + result.compression = COMPRESSION_DXT3; + } else if (compressionData.contains("DXT5")) { + result.compression = COMPRESSION_DXT5; + } else { + result.compression = COMPRESSION_NONE; + } + + *aZoneFileStream >> result.unknown8 >> result.unknown9; + } + + return result; +} + +SoundAsset ZoneFile_COD12_360::pParseAsset_Sound(QDataStream *aZoneFileStream) { + SoundAsset result; + return result; + + qDebug() << aZoneFileStream->device()->pos(); + + QByteArray rootNamePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rootNamePtr.data(), 4); + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.count; + + if (rootNamePtr.toHex() == "ffffffff") { + // Read in sound file name + char soundNameChar; + *aZoneFileStream >> soundNameChar; + while (soundNameChar != 0) { + result.name += soundNameChar; + *aZoneFileStream >> soundNameChar; + } + } + + int tagCount = 0; + int resultCount = 0; + for (quint32 i = 0; i < result.count; i++) { + aZoneFileStream->skipRawData(12); + + QByteArray tagPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(tagPtr.data(), 4); + + if (tagPtr.toHex() == "ffffffff") { + tagCount++; + } + aZoneFileStream->skipRawData(4); + + QByteArray pathPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pathPtr.data(), 4); + + if (pathPtr.toHex() == "ffffffff") { + resultCount++; + } + + aZoneFileStream->skipRawData(160); + } + + for (int i = 0; i < tagCount; i++) { + // Read in tag? + QString tag; + char tagChar; + *aZoneFileStream >> tagChar; + while (tagChar != 0) { + tag += tagChar; + *aZoneFileStream >> tagChar; + } + } + + for (int i = 0; i < resultCount; i++) { + Sound sound; + + if (aZoneFileStream->device()->peek(12).toHex().contains("ffffffff00000000")) { + aZoneFileStream->skipRawData(12); + } + + aZoneFileStream->skipRawData(8); + + QByteArray aliasPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(aliasPtr.data(), 4); + + QByteArray namePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(namePtr.data(), 4); + + *aZoneFileStream >> sound.dataLength; + + if (aliasPtr.toHex() == "ffffffff") { + // Read in sound alias name + char soundAliasChar; + *aZoneFileStream >> soundAliasChar; + while (soundAliasChar != 0) { + sound.alias += soundAliasChar; + *aZoneFileStream >> soundAliasChar; + } + } + + if (aZoneFileStream->device()->peek(4) == "RIFF") { + sound.path = sound.alias; + sound.alias = ""; + } else if (namePtr.toHex() == "ffffffff") { + // Read in sound file path + char soundPathChar; + *aZoneFileStream >> soundPathChar; + while (soundPathChar != 0) { + sound.path += soundPathChar; + *aZoneFileStream >> soundPathChar; + } + sound.path.replace(",", ""); + } + + if (sound.dataLength) { + QByteArray data(sound.dataLength, Qt::Uninitialized); + aZoneFileStream->readRawData(data.data(), sound.dataLength); + sound.data = data; + } + result.sounds.append(sound); + } + + return result; +} + +void ZoneFile_COD12_360::pParseAsset_ColMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD12_360::pParseAsset_GameMapSP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD12_360::pParseAsset_GameMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD12_360::pParseAsset_LightDef(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD12_360::pParseAsset_UIMap(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD12_360::pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD12_360::pParseAsset_AIType(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD12_360::pParseAsset_FX(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Animation ZoneFile_COD12_360::pParseAsset_Animation(QDataStream *aZoneFileStream) { + Animation result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.dataByteCount + >> result.dataShortCount + >> result.dataIntCount + >> result.randomDataByteCount + >> result.randomDataIntCount + >> result.numframes + >> result.isLooped + >> result.isDelta + >> result.noneRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.normalTranslatedBoneCount + >> result.preciseTranslatedBoneCount + >> result.staticTranslatedBoneCount + >> result.noneTranslatedBoneCount + >> result.totalBoneCount + >> result.otherBoneCount1 + >> result.otherBoneCount2 + >> result.notifyCount + >> result.assetType + >> result.pad + >> result.randomDataShortCount + >> result.indexCount + >> result.frameRate + >> result.frequency + >> result.boneIDsPtr + >> result.dataBytePtr + >> result.dataShortPtr + >> result.dataIntPtr + >> result.randomDataShortPtr + >> result.randomDataBytePtr + >> result.randomDataIntPtr + >> result.longIndiciesPtr + >> result.notificationsPtr + >> result.deltaPartsPtr; + + // Read in x_anim file name + QString xAnimName; + char xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + while (xAnimNameChar != 0) { + result.name += xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + } + + // Parse x_anim index header + QVector sectionLengths; + for (int i = 0; i < result.numframes; i++) { + quint8 sectionlength; + *aZoneFileStream >> sectionlength; + sectionLengths.push_back(sectionlength); + // Skip padding + aZoneFileStream->skipRawData(1); + } + // Skip unknown section + aZoneFileStream->skipRawData(2 * 8); + + return result; +} + +MenuFile ZoneFile_COD12_360::pParseAsset_MenuFile(QDataStream *aZoneFileStream) { + //MENU_FILE + MenuFile result; + + aZoneFileStream->skipRawData(4); // Separator + + // Parse menu def count + *aZoneFileStream >> result.menuCount; + + // Clearly misparsed, never have this much + if (result.menuCount > 1000) { + qDebug() << "Failure reported when parsing menu file."; + return result; + } + for (uint i = 0; i < result.menuCount; i++) { + Menu menu; + + aZoneFileStream->skipRawData(4); // Separator + + // Read in x_anim file name + char menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + while (menuFilepathChar != 0) { + menu.filePath += menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + } + aZoneFileStream->skipRawData(4); // Separator + + *aZoneFileStream >> menu.menuNamePtr; + + float menuRectX, menuRectY, menuRectWidth, menuRectHeight; + *aZoneFileStream >> menuRectX >> menuRectY >> menuRectWidth >> menuRectHeight; + menu.rect = QRectF(menuRectX, menuRectY, menuRectWidth, menuRectHeight); + + quint32 hAlignInt, vAlignInt; + *aZoneFileStream >> hAlignInt >> vAlignInt; + menu.hAlign = (MENU_H_ALIGNMENT)hAlignInt; + menu.vAlign = (MENU_V_ALIGNMENT)vAlignInt; + + float rectClientX, rectClientY, rectClientWidth, rectClientHeight; + *aZoneFileStream >> rectClientX >> rectClientY >> rectClientWidth >> rectClientHeight; + menu.clientRect = QRectF(rectClientX, rectClientY, rectClientWidth, rectClientHeight); + + quint32 hClientAlignInt, vClientAlignInt, styleInt, borderInt; + *aZoneFileStream >> hClientAlignInt >> vClientAlignInt >> menu.groupPtr + >> styleInt >> borderInt >> menu.ownerDraw >> menu.ownerDrawFlags + >> menu.borderSize >> menu.staticFlags >> menu.dynamicFlags >> menu.nextTime; + menu.hClientAlign = (MENU_H_ALIGNMENT)hClientAlignInt; + menu.vClientAlign = (MENU_V_ALIGNMENT)vClientAlignInt; + menu.style = (MENU_WINDOW_STYLE)styleInt; + menu.border = (MENU_WINDOW_BORDER)borderInt; + + float foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA, + backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA, + borderColorR, borderColorG, borderColorB, borderColorA, + outlineColorR, outlineColorG, outlineColorB, outlineColorA; + *aZoneFileStream >> foregroundColorR >> foregroundColorG >> foregroundColorB >> foregroundColorA + >> backgroundColorR >> backgroundColorG >> backgroundColorB >> backgroundColorA + >> borderColorR >> borderColorG >> borderColorB >> borderColorA + >> outlineColorR >> outlineColorG >> outlineColorB >> outlineColorA; + + menu.foregroundColor = QColor(foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA); + menu.backgroundColor = QColor(backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA); + menu.borderColor = QColor(borderColorR, borderColorG, borderColorB, borderColorA); + menu.outlineColor = QColor(outlineColorR, outlineColorG, outlineColorB, outlineColorA); + + *aZoneFileStream >> menu.materialPtr >> menu.fontPtr >> menu.fullScreen >> menu.itemCount + >> menu.fontIndex >> menu.cursorItem >> menu.fadeCycle >> menu.fadeClamp + >> menu.fadeAmount >> menu.fadeInAmount >> menu.blurRadius >> menu.onOpenPtr + >> menu.onFocusPtr >> menu.onClosePtr >> menu.onESCPtr >> menu.onKeyPtr + >> menu.visibleExpCount >> menu.expEntryPtr >> menu.allowedBindingPtr + >> menu.soundNamePtr >> menu.imageTrack; + + float focusColorR, focusColorG, focusColorB, focusColorA, + disabledColorR, disabledColorG, disabledColorB, disabledColorA; + *aZoneFileStream >> focusColorR >> focusColorG >> focusColorB >> focusColorA + >> disabledColorR >> disabledColorG >> disabledColorB >> disabledColorA; + menu.focusColor = QColor(focusColorR, focusColorG, focusColorB, focusColorA); + menu.disabledColor = QColor(disabledColorR, disabledColorG, disabledColorB, disabledColorA); + + *aZoneFileStream >> menu.rectXExpCount >> menu.rectXExpPtr >> menu.rectYExpCount >> menu.rectYExpPtr; + + aZoneFileStream->skipRawData(4); // Separator + + char menuDefNameChar; + int menuDefNameLen = 0; + *aZoneFileStream >> menuDefNameChar; + while (menuDefNameChar != 0 && menuDefNameLen < 30) { + menuDefNameLen++; + menu.name += menuDefNameChar; + *aZoneFileStream >> menuDefNameChar; + } + + char defStringChar; + int defStringLen = 0; + *aZoneFileStream >> defStringChar; + while (defStringChar != 0 && defStringLen < 30) { + defStringLen++; + menu.definition += defStringChar; + *aZoneFileStream >> defStringChar; + } + aZoneFileStream->skipRawData(4 * 10); + + *aZoneFileStream >> menu.itemWindowDefNamePtr; + + float itemRectX, itemRectY, itemRectWidth, itemRectHeight; + *aZoneFileStream >> itemRectX >> itemRectY >> itemRectWidth >> itemRectHeight; + menu.itemRect = QRectF(itemRectX, itemRectY, itemRectWidth, itemRectHeight); + + *aZoneFileStream >> menu.itemHAlignment >> menu.itemVAlignment >> menu.itemGroupPtr + >> menu.itemWindowStyle >> menu.itemWindowBorder >> menu.itemOwnerDraw + >> menu.itemOwnerDrawFlags >> menu.itemBorderSize >> menu.itemStaticFlags + >> menu.itemDynamicFlags >> menu.itemNextTime; + + float itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA, + itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA, + itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA, + itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA; + *aZoneFileStream >> itemForegroundColorR >> itemForegroundColorG >> itemForegroundColorB >> itemForegroundColorA + >> itemBackgroundColorR >> itemBackgroundColorG >> itemBackgroundColorB >> itemBackgroundColorA + >> itemBorderColorR >> itemBorderColorG >> itemBorderColorB >> itemBorderColorA + >> itemOutlineColorR >> itemOutlineColorG >> itemOutlineColorB >> itemOutlineColorA; + + menu.itemForegroundColor = QColor(itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA); + menu.itemBackgroundColor = QColor(itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA); + menu.itemBorderColor = QColor(itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA); + menu.itemOutlineColor = QColor(itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA); + + *aZoneFileStream >> menu.itemMaterialPtr; + + float itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight; + *aZoneFileStream >> itemTextRectX >> itemTextRectY >> itemTextRectWidth >> itemTextRectHeight; + menu.itemTextRect = QRectF(itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight); + + quint32 hItemTextAlignInt, vItemTextAlignInt, itemType, fontTypeInt, textStyleInt; + *aZoneFileStream >> hItemTextAlignInt >> vItemTextAlignInt >> itemType >> menu.dataType + >> menu.alignment >> fontTypeInt >> menu.textAlignMode >> menu.textalignx >> menu.textaligny + >> menu.textscale >> textStyleInt >> menu.gameMsgWindowIndex >> menu.gameMsgWindowMode + >> menu.testPtr >> menu.textSavegameInfo >> menu.parentPtr; + menu.itemText_hAlign = (MENU_H_ALIGNMENT)hItemTextAlignInt; + menu.itemText_vAlign = (MENU_V_ALIGNMENT)vItemTextAlignInt; + menu.itemType = (MENU_ITEM_TYPE)itemType; + menu.fontEnum = (MENU_FONT_TYPE)fontTypeInt; + menu.textStyle = (MENU_ITEM_TEXTSTYLE)textStyleInt; + + *aZoneFileStream >> menu.mouseEnterText >> menu.mouseExitText >> menu.mouseEnter >> menu.mouseExit + >> menu.action >> menu.onAccept >> menu.onFocus >> menu.leaveFocus >> menu.dvar >> menu.dvarTest + >> menu.keyHandlerPtr >> menu.enableDvarPtr >> menu.dvarFlags >> menu.focusSoundPtr + >> menu.special >> menu.cursorPos; + + // itemDefData_t typeData; + + // listBoxDef_s *listBox; + + *aZoneFileStream >> menu.startPos >> menu.endPos >> menu.drawPadding; + + *aZoneFileStream >> menu.elementWidth >> menu.elementHeight; + + *aZoneFileStream >> menu.elementStyle >> menu.numColumns; + + //columnInfo_s columnInfo[16]; + + *aZoneFileStream >> menu.doubleClickPtr; + + + *aZoneFileStream >> menu.notselectable >> menu.noScrollBars >> menu.usePaging; + + float itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA, + itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA, + itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA; + *aZoneFileStream >> itemSelectBorderColorR >> itemSelectBorderColorG >> itemSelectBorderColorB >> itemSelectBorderColorA + >> itemDisableColorR >> itemDisableColorG >> itemDisableColorB >> itemDisableColorA + >> itemFocusColorR >> itemFocusColorG >> itemFocusColorB >> itemFocusColorA; + menu.itemSelectBorderColor = QColor(itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA); + menu.itemDisableColor = QColor(itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA); + menu.itemFocusColor = QColor(itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA); + + *aZoneFileStream >> menu.selectIconPtr >> menu.backgroundItemListboxPtr >> menu.highlightTexturePtr; + + // editFieldDef_s *editField; + + *aZoneFileStream >> menu.minVal >> menu.maxVal >> menu.defVal >> menu.range >> menu.maxChars + >> menu.maxCharsGotoNext >> menu.maxPaintChars >> menu.paintOffset; + + // multiDef_s *multi; + + for (int i = 0; i < 32; i++) { + quint32 dvarList; + *aZoneFileStream >> dvarList; + menu.dvarListPtrs.push_back(dvarList); + } + + for (int i = 0; i < 32; i++) { + quint32 dvarStr; + *aZoneFileStream >> dvarStr; + menu.dvarStrPtrs.push_back(dvarStr); + } + + for (int i = 0; i < 32; i++) { + float dvarValue; + *aZoneFileStream >> dvarValue; + menu.dvarValues.push_back(dvarValue); + } + + *aZoneFileStream >> menu.count >> menu.strDef >> menu.enumDvarNamePtr; + aZoneFileStream->skipRawData(4); + //>> menu.dataPtr + *aZoneFileStream >> menu.itemImageTrack; + + qDebug() << aZoneFileStream->device()->pos(); + + //statement_s visibleExp; + //statement_s textExp; + //statement_s materialExp; + //statement_s rectXExp; + //statement_s rectYExp; + //statement_s rectWExp; + //statement_s rectHExp; + //statement_s foreColorAExp; + result.menuDefs << menu; + } + return result; +} + +void ZoneFile_COD12_360::pParseAsset_Weapon(QDataStream *aZoneFileStream) { + //WEAPON_FILE + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD12_360::pParseAsset_D3DBSP(QDataStream *aZoneFileStream) { + //D3DBSP_DUMP + Q_UNUSED(aZoneFileStream); +} + +StringTable ZoneFile_COD12_360::pParseAsset_StringTable(QDataStream *aZoneFileStream) { + StringTable result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.columnCount + >> result.rowCount; + + // Todo fix this + result.columnCount = 0; + result.rowCount = 0; + + aZoneFileStream->skipRawData(4); + + QString stringTableName; + char stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + while (stringTableNameChar != 0) { + result.name += stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + } + + for (quint32 i = 0; i < result.rowCount; i++) { + QByteArray pointerData(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pointerData.data(), 4); + result.tablePointers.push_back(pointerData.toHex()); + + aZoneFileStream->skipRawData(4); + } + + for (const QString &pointerAddr : result.tablePointers) { + QString leadingContent = ""; + if (pointerAddr == "FFFFFFFF") { + char leadingContentChar; + *aZoneFileStream >> leadingContentChar; + while (leadingContentChar != 0) { + leadingContent += leadingContentChar; + *aZoneFileStream >> leadingContentChar; + } + } else { + leadingContent = pointerAddr; + } + + QString content; + char contentChar; + *aZoneFileStream >> contentChar; + while (contentChar != 0) { + content += contentChar; + *aZoneFileStream >> contentChar; + } + result.content[leadingContent] = content; + } + return result; +} + +AssetType ZoneFile_COD12_360::AssetStrToEnum(const QString aAssetType) { + const QString cleanedType = aAssetType.toUpper(); + if (cleanedType == "0000000000000000") { + return ASSET_PHYS_PRESET; + } else if (cleanedType == "0100000000000000") { + return ASSET_PHYS_CONSTRAINTS; + } else if (cleanedType == "0200000000000000") { + return ASSET_DESTRUCTIBLE_DEF; + } else if (cleanedType == "0300000000000000") { + return ASSET_ANIMATION; + } else if (cleanedType == "0400000000000000") { + return ASSET_MODEL; + } else if (cleanedType == "0500000000000000") { + return ASSET_MODEL_MESH; + } else if (cleanedType == "0600000000000000") { + return ASSET_MATERIAL; + } else if (cleanedType == "0700000000000000") { + return ASSET_COMPUTE_SHADER_SET; + } else if (cleanedType == "0800000000000000") { + return ASSET_TECH_SET; + } else if (cleanedType == "0900000000000000") { + return ASSET_IMAGE; + } else if (cleanedType == "0A00000000000000") { + return ASSET_SOUND; + } else if (cleanedType == "1100000000000000") { + return ASSET_LIGHT_DEF; + } else if (cleanedType == "1500000000000000") { + return ASSET_FONT_ICON; + } else if (cleanedType == "1700000000000000") { + return ASSET_WEAPON; + } else if (cleanedType == "1C00000000000000") { + return ASSET_PLAYER_SOUNDS_TABLE; + } else if (cleanedType == "1D00000000000000") { + return ASSET_PLAYER_FX_TABLE; + } else if (cleanedType == "1E00000000000000") { + return ASSET_SHARED_WEAPON_SOUNDS; + } else if (cleanedType == "1F00000000000000") { + return ASSET_ATTACHMENT; + } else if (cleanedType == "2000000000000000") { + return ASSET_ATTACHMENT_UNIQUE; + } else if (cleanedType == "2100000000000000") { + return ASSET_WEAPON_CAMO; + } else if (cleanedType == "2200000000000000") { + return ASSET_CUSTOMIZATION_TABLE; + } else if (cleanedType == "2300000000000000") { + return ASSET_CUSTOMIZATION_TABLE_FEIMAGES; + } else if (cleanedType == "2400000000000000") { + return ASSET_CUSTOMIZATION_TABLE_COLOR; + }else if (cleanedType == "2600000000000000") { + return ASSET_EFFECT; + } else if (cleanedType == "2F00000000000000") { + return ASSET_RAW_FILE; + } else if (cleanedType == "3000000000000000") { + return ASSET_STRING_TABLE; + } else if (cleanedType == "3100000000000000") { + return ASSET_STRUCTURED_TABLE; + } else if (cleanedType == "3200000000000000") { + return ASSET_LEADERBOARD_DEF; + } else if (cleanedType == "3300000000000000") { + return ASSET_DDL; + } else if (cleanedType == "3600000000000000") { + return ASSET_SCRIPT_PARSE_TREE; + } else if (cleanedType == "3700000000000000") { + return ASSET_KEY_VALUE_PAIRS; + } else if (cleanedType == "3800000000000000") { + return ASSET_VEHICLE; + } else if (cleanedType == "3A00000000000000") { + return ASSET_VEHICLE_TRACER; + } else if (cleanedType == "3C00000000000000") { + return ASSET_SURFACE_FX_TABLE; + } else if (cleanedType == "3D00000000000000") { + return ASSET_SURFACE_SOUND_DEF; + } else if (cleanedType == "3E00000000000000") { + return ASSET_FOOTSTEP_TABLE; + } else if (cleanedType == "3F00000000000000") { + return ASSET_ENTITY_FX_IMPACTS; + } else if (cleanedType == "4000000000000000") { + return ASSET_ENTITY_SOUND_IMPACTS; + } else if (cleanedType == "4200000000000000") { + return ASSET_VEHICLE_FX_DEF; + } else if (cleanedType == "4300000000000000") { + return ASSET_VEHICLE_SOUND_DEF; + } else if (cleanedType == "4500000000000000") { + return ASSET_SCRIPT_BUNDLE; + } else if (cleanedType == "4600000000000000") { + return ASSET_SCRIPT_BUNDLE_LIST; + } else if (cleanedType == "4700000000000000") { + return ASSET_RUMBLE; + } else if (cleanedType == "4A00000000000000") { + return ASSET_AIM_TABLE; + } else if (cleanedType == "4B00000000000000") { + return ASSET_ANIM_SELECTOR_TABLE; + } else if (cleanedType == "4C00000000000000") { + return ASSET_ANIM_MAPPING_TABLE; + } else if (cleanedType == "4D00000000000000") { + return ASSET_ANIM_STATE_MACHINE; + } else if (cleanedType == "4E00000000000000") { + return ASSET_BEHAVIOR_TREE; + } else if (cleanedType == "4F00000000000000") { + return ASSET_BEHAVIOR_STATE_MACHINE; + } else if (cleanedType == "5100000000000000") { + return ASSET_S_ANIM; + } else if (cleanedType == "5200000000000000") { + return ASSET_LIGHT_DEF; + } else if (cleanedType == "5300000000000000") { + return ASSET_BIT_FIELD; + } else if (cleanedType == "5400000000000000") { + return ASSET_SURFACE_SOUND_DEF; + } else if (cleanedType == "5500000000000000") { + return ASSET_SURFACE_FX_TABLE; + } else if (cleanedType == "5600000000000000") { + return ASSET_RUMBLE; + } else if (cleanedType == "5900000000000000") { + return ASSET_AIM_TABLE; + } else if (cleanedType == "5A00000000000000") { + return ASSET_MAP_TABLE; + } else if (cleanedType == "5B00000000000000") { + return ASSET_MAP_TABLE_LOADING_IMAGES; + } else if (cleanedType == "5C00000000000000") { + return ASSET_MEDAL; + } else if (cleanedType == "5D00000000000000") { + return ASSET_MEDAL_TABLE; + } else if (cleanedType == "5E00000000000000") { + return ASSET_OBJECTIVE; + } else if (cleanedType == "5F00000000000000") { + return ASSET_OBJECTIVE_LIST; + } else if (cleanedType == "6400000000000000") { + return ASSET_LASER; + } else if (cleanedType == "6500000000000000") { + return ASSET_BEAM; + } else if (cleanedType == "6600000000000000") { + return ASSET_STREAMER_HINT; + } else if (cleanedType == "1B00000000000000") { + return ASSET_CG_MEDIA_TABLE; + } + + return ASSET_NONE; +} + +QByteArray ZoneFile_COD12_360::GetBinaryData() { + QByteArray result; + + return result; +} diff --git a/libs/zonefile/360/zonefile_cod12_360.h b/libs/zonefile/360/zonefile_cod12_360.h new file mode 100644 index 0000000..9aacabe --- /dev/null +++ b/libs/zonefile/360/zonefile_cod12_360.h @@ -0,0 +1,53 @@ +#ifndef ZONEFILE_COD12_360_H +#define ZONEFILE_COD12_360_H + +#include "zonefile.h" + +class ZoneFile_COD12_360: public ZoneFile +{ +public: + ZoneFile_COD12_360(); + ~ZoneFile_COD12_360(); + + bool Load(const QByteArray aFileData) override; + AssetType AssetStrToEnum(const QString aAssetType) override; + + QByteArray GetBinaryData() override; + +protected: + void pParseZoneHeader(QDataStream *aZoneFileStream) override; + quint32 pParseZoneSize(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsA(QDataStream *aZoneFileStream) override; + quint32 pParseZoneTagCount(QDataStream *aZoneFileStream) override; + quint32 pParseZoneRecordCount(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsB(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsC(QDataStream *aZoneFileStream) override; + QStringList pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) override; + QStringList pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) override; + AssetMap pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) override; + LocalString pParseAsset_LocalString(QDataStream *aZoneFileStream) override; + RawFile pParseAsset_RawFile(QDataStream *aZoneFileStream) override; + GscFile pParseAsset_GSCFile(QDataStream *aZoneFileStream) ; + void pParseAsset_PhysPreset(QDataStream *aZoneFileStream) override; + Model pParseAsset_Model(QDataStream *aZoneFileStream) override; + Material pParseAsset_Material(QDataStream *aZoneFileStream) override; + Shader pParseAsset_Shader(QDataStream *aZoneFileStream) override; + TechSet pParseAsset_TechSet(QDataStream *aZoneFileStream) override; + Image pParseAsset_Image(QDataStream *aZoneFileStream) override; + SoundAsset pParseAsset_Sound(QDataStream *aZoneFileStream) override; + void pParseAsset_ColMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapSP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_LightDef(QDataStream *aZoneFileStream) override; + void pParseAsset_UIMap(QDataStream *aZoneFileStream) override; + void pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) override; + void pParseAsset_AIType(QDataStream *aZoneFileStream) override; + void pParseAsset_FX(QDataStream *aZoneFileStream) override; + Animation pParseAsset_Animation(QDataStream *aZoneFileStream) override; + MenuFile pParseAsset_MenuFile(QDataStream *aZoneFileStream) override; + void pParseAsset_Weapon(QDataStream *aZoneFileStream) override; + void pParseAsset_D3DBSP(QDataStream *aZoneFileStream) override; + StringTable pParseAsset_StringTable(QDataStream *aZoneFileStream) override; +}; + +#endif // ZONEFILE_COD12_PC_H diff --git a/libs/zonefile/360/zonefile_cod2_360.cpp b/libs/zonefile/360/zonefile_cod2_360.cpp new file mode 100644 index 0000000..aff7269 --- /dev/null +++ b/libs/zonefile/360/zonefile_cod2_360.cpp @@ -0,0 +1,1112 @@ +#include "zonefile_cod2_360.h" + +#include +#include +#include + +ZoneFile_COD2_360::ZoneFile_COD2_360() +{ + +} + +ZoneFile_COD2_360::~ZoneFile_COD2_360() +{ + +} + +bool ZoneFile_COD2_360::Load(const QByteArray aFileData) { + // Open zone file as little endian stream + QDataStream zoneFileStream(aFileData); + zoneFileStream.setByteOrder(QDataStream::BigEndian); + + // Parse data from zone file header + pParseZoneHeader(&zoneFileStream); + SetRecords(pParseZoneIndex(&zoneFileStream, GetRecordCount())); + SetAssetMap(pParseAssets(&zoneFileStream, GetRecords())); + + return true; +} + +void ZoneFile_COD2_360::pParseZoneHeader(QDataStream *aZoneFileStream) { + SetTagCount(pParseZoneTagCount(aZoneFileStream)); + pParseZoneUnknownsB(aZoneFileStream); + pParseZoneUnknownsC(aZoneFileStream); + SetRecordCount(pParseZoneRecordCount(aZoneFileStream)); + + aZoneFileStream->skipRawData(4); + + quint32 tagCount = GetTagCount(); + if (tagCount) { + SetTags(pParseZoneTags(aZoneFileStream, tagCount)); + } else { + aZoneFileStream->skipRawData(4); + } +} + +quint32 ZoneFile_COD2_360::pParseZoneSize(QDataStream *aZoneFileStream) { + quint32 zoneFileSize; + *aZoneFileStream >> zoneFileSize; + if (zoneFileSize <= 0) { + qDebug() << "Tried to open empty zone file!"; + exit(-1); + } + zoneFileSize += 36; + return zoneFileSize; +} + +/* + ParseZoneUnknownsA() + + Parses the 1st section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD2_360::pParseZoneUnknownsA(QDataStream *aZoneFileStream) { + // Byte 4-7, 8-11, 12-15: unknown + QByteArray unknown1(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown1.data(), 4); + + QByteArray unknown2(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown2.data(), 4); + + QByteArray unknown3(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown3.data(), 4); + + // Byte 16-19, 20-23: empty/unknown + QByteArray unknown4(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown4.data(), 4); + + QByteArray unknown5(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown5.data(), 4); + + // Byte 24-27: somehow related to the filesize, but smaller value + QByteArray unknown6(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown6.data(), 4); + + // Byte 28-31, 32-35: unknown + QByteArray unknown7(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown7.data(), 4); + + QByteArray unknown8(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown8.data(), 4); +} + +/* + ParseZoneTagCount() + + Parses the number of string tags in the zone index +*/ +quint32 ZoneFile_COD2_360::pParseZoneTagCount(QDataStream *aZoneFileStream) { + quint32 tagCount; + *aZoneFileStream >> tagCount; + return tagCount; +} + +/* + ParseZoneRecordCount() + + Parses the number of records in the zone index +*/ +quint32 ZoneFile_COD2_360::pParseZoneRecordCount(QDataStream *aZoneFileStream) { + quint32 recordCount; + *aZoneFileStream >> recordCount; + return recordCount; +} + +/* + ParseZoneUnknownsB() + + Parses the 2nd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD2_360::pParseZoneUnknownsB(QDataStream *aZoneFileStream) { + // Byte 44-47: Unknown/empty? + QByteArray unknown9(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown9.data(), 4); +} + +/* + pParseZoneUnknownsC() + + Parses the 3rd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD2_360::pParseZoneUnknownsC(QDataStream *aZoneFileStream) { + // Byte 40-43: Unknown/empty? + QByteArray unknown10(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown10.data(), 4); + + // Byte 44-47: Unknown/empty? + QByteArray unknown11(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown11.data(), 4); +} + +/* + ParseZoneTags() + + Parses the string tags ate the start of zone file +*/ +QStringList ZoneFile_COD2_360::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) { + QStringList tags; + + // Byte 48-51: Repeated separators? ÿÿÿÿ x i + aZoneFileStream->skipRawData(4 * tagCount); + + // Parse tags/strings before index + QString zoneTag; + char zoneTagChar; + for (quint32 i = 0; i < tagCount; i++) { + *aZoneFileStream >> zoneTagChar; + while (zoneTagChar != 0) { + zoneTag += zoneTagChar; + *aZoneFileStream >> zoneTagChar; + } + tags << zoneTag; + zoneTag.clear(); + } + return tags; +} + +/* + ParseZoneIndex() + + Parse the binary zone index data and populate table +*/ +QStringList ZoneFile_COD2_360::pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) { + QStringList result; + + // Don't parse if no records + if (!recordCount) { return result; } + + // Parse index & map found asset types + for (quint32 i = 0; i < recordCount; i++) { + // Skip record start + QByteArray rawAssetType(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rawAssetType.data(), 4); + result << rawAssetType.toHex(); + + // Skip separator + aZoneFileStream->skipRawData(4); + } + return result; +} + +AssetMap ZoneFile_COD2_360::pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) { + AssetMap result; + + //aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 8); + + for (int i = 0; i < assetOrder.size(); i++) { + const QString typeHex = assetOrder[i]; + const AssetType assetType = AssetStrToEnum(typeHex); + + if (assetType == ASSET_LOCAL_STRING) { // localized string asset + result.localStrings << pParseAsset_LocalString(aZoneFileStream); + } else if (assetType == ASSET_RAW_FILE) { // gsc + auto rawFile = pParseAsset_RawFile(aZoneFileStream); + if (rawFile.length) { + result.rawFiles << rawFile; + } + } else if (assetType == ASSET_PHYS_PRESET) { // physpreset + pParseAsset_PhysPreset(aZoneFileStream); + } else if (assetType == ASSET_MODEL) { // xmodel + result.models << pParseAsset_Model(aZoneFileStream); + } else if (assetType == ASSET_MATERIAL) { // material + result.materials << pParseAsset_Material(aZoneFileStream); + } else if (assetType == ASSET_SHADER) { // pixelshader + pParseAsset_Shader(aZoneFileStream); + } else if (assetType == ASSET_TECH_SET) { // techset include + result.techSets << pParseAsset_TechSet(aZoneFileStream); + } else if (assetType == ASSET_IMAGE) { // image + result.images << pParseAsset_Image(aZoneFileStream); + } else if (assetType == ASSET_SOUND) { // loaded_sound + result.sounds << pParseAsset_Sound(aZoneFileStream); + } else if (assetType == ASSET_COLLISION_MAP) { // col_map_mp + pParseAsset_ColMapMP(aZoneFileStream); + } else if (assetType == ASSET_MP_MAP) { // game_map_sp + pParseAsset_GameMapSP(aZoneFileStream); + } else if (assetType == ASSET_SP_MAP) { // game_map_mp + pParseAsset_GameMapMP(aZoneFileStream); + } else if (assetType == ASSET_LIGHT_DEF) { // lightdef + pParseAsset_LightDef(aZoneFileStream); + } else if (assetType == ASSET_UI_MAP) { // ui_map + pParseAsset_UIMap(aZoneFileStream); + } else if (assetType == ASSET_SND_DRIVER_GLOBALS) { // snddriverglobals + pParseAsset_SNDDriverGlobals(aZoneFileStream); + } else if (assetType == ASSET_AI_TYPE) { // aitype + pParseAsset_AIType(aZoneFileStream); + } else if (assetType == ASSET_EFFECT) { // aitype + pParseAsset_FX(aZoneFileStream); + } else if (assetType == ASSET_ANIMATION) { // aitype + result.animations << pParseAsset_Animation(aZoneFileStream); + } else if (assetType == ASSET_STRING_TABLE) { // string_table + result.stringTables << pParseAsset_StringTable(aZoneFileStream); + } else if (assetType == ASSET_MENU) { // string_table + result.menuFiles << pParseAsset_MenuFile(aZoneFileStream); + } else if (assetType == ASSET_WEAPON) { // string_table + pParseAsset_Weapon(aZoneFileStream); + } else if (assetType == ASSET_D3DBSP) { // string_table + pParseAsset_D3DBSP(aZoneFileStream); + } + } + return result; +} + +LocalString ZoneFile_COD2_360::pParseAsset_LocalString(QDataStream *aZoneFileStream) { + LocalString result; + + quint32 stringPtr, aliasPtr; + *aZoneFileStream >> stringPtr >> aliasPtr; + if (stringPtr == 4294967295) { + // Parse local string asset contents + QString localStr; + char localStrChar; + *aZoneFileStream >> localStrChar; + while (localStrChar != 0) { + result.string += localStrChar; + *aZoneFileStream >> localStrChar; + } + } else { + result.string = "String Ptr: " + QString::number(stringPtr); + } + + if (aliasPtr == 4294967295) { + // Parse rawfile name + QString aliasName; + char aliasNameChar; + *aZoneFileStream >> aliasNameChar; + while (aliasNameChar != 0) { + result.alias += aliasNameChar; + *aZoneFileStream >> aliasNameChar; + } + } else { + result.string = "Alias Ptr: " + QString::number(aliasPtr); + } + + return result; +} + +RawFile ZoneFile_COD2_360::pParseAsset_RawFile(QDataStream *aZoneFileStream) { + RawFile result; + + // Skip start separator FF FF FF FF (pointer?) + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.length; + + // Skip unknown 4 byte data + aZoneFileStream->skipRawData(4); + + // Parse rawfile path + char scriptPathChar; + *aZoneFileStream >> scriptPathChar; + while (scriptPathChar != 0) { + result.path += scriptPathChar; + *aZoneFileStream >> scriptPathChar; + } + result.path.replace(",", ""); + const QStringList pathParts = result.path.split('/'); + if (pathParts.size() == 0) { + qDebug() << "Failed to parse ff path! " << result.path; + exit(-1); + } + + // Parse gsc contents + char rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + while (rawFileContentsChar != 0 && rawFileContentsChar != -1) { + result.contents += rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + } + return result; +} + +void ZoneFile_COD2_360::pParseAsset_PhysPreset(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Model ZoneFile_COD2_360::pParseAsset_Model(QDataStream *aZoneFileStream) { + Model result; + + *aZoneFileStream >> result.namePtr >> result.tagCount >> result.rootTagCount + >> result.surfCount >> result.unknownCount >> result.boneNamePtr + >> result.parentListPtr >> result.quatsPtr >> result.transPtr + >> result.partClassPtr >> result.baseMatPtr + >> result.surfsPtr >> result.materialHandlesPtr; + + // Parse XModelLodInfo + for (int i = 1; i <= 4; i++) { + quint32 intDist; + *aZoneFileStream >> intDist; + + std::memcpy(&result.lodInfo[i].dist, &intDist, sizeof(result.lodInfo[i].dist)); + *aZoneFileStream >> result.lodInfo[i].numsurfs >> result.lodInfo[i].surfIndex; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.lodInfo[i].partBits[0] + >> result.lodInfo[i].partBits[1] + >> result.lodInfo[i].partBits[2] + >> result.lodInfo[i].partBits[3]; + } + + *aZoneFileStream >> result.collSurfsPtr >> result.numCollSurfs >> result.contents >> result.boneInfoPtr; + + quint32 intRadius, intMins[3], intMaxs[3]; + *aZoneFileStream >> intRadius >> intMins[0] >> intMins[1] + >> intMins[2] >> intMaxs[0] >> intMaxs[1] >> intMaxs[2]; + + std::memcpy(&result.radius, &intRadius, sizeof(result.radius)); + + std::memcpy(&result.mins[0], &intMins[0], sizeof(result.mins[0])); + std::memcpy(&result.mins[1], &intMins[1], sizeof(result.mins[1])); + std::memcpy(&result.mins[2], &intMins[2], sizeof(result.mins[2])); + + std::memcpy(&result.maxs[0], &intMaxs[0], sizeof(result.maxs[0])); + std::memcpy(&result.maxs[1], &intMaxs[1], sizeof(result.maxs[2])); + std::memcpy(&result.maxs[2], &intMaxs[2], sizeof(result.maxs[3])); + + *aZoneFileStream >> result.numLods >> result.collLod >> result.streamInfoPtr + >> result.memUsage >> result.flags >> result.physPresetPtr >> result.physGeomsPtr; + + // Parse model name + char modelNameChar; + *aZoneFileStream >> modelNameChar; + while (modelNameChar == 0) { + *aZoneFileStream >> modelNameChar; + } + while (modelNameChar != 0) { + result.modelName += modelNameChar; + *aZoneFileStream >> modelNameChar; + } + return result; +} + +Shader ZoneFile_COD2_360::pParseAsset_Shader(QDataStream *aZoneFileStream) { + Shader result = Shader(); + + quint8 minorVersion, majorVersion; + *aZoneFileStream >> minorVersion >> majorVersion; + + quint32 magic; + *aZoneFileStream >> magic; + + // Verify .fxc magic + if (magic != 65534 && magic != 65535) { return result; } + + SHADER_TYPE type = SHADER_NONE; + quint16 rawShaderType; + *aZoneFileStream >> rawShaderType; + if (rawShaderType == 65535) { // Pixel shader + type = SHADER_PIXEL; + } else if (rawShaderType == 65534) { // Vertex shader + type = SHADER_VERTEX; + } + Q_UNUSED(type); + + while (true) { + quint32 instructionToken; + *aZoneFileStream >> instructionToken; + + SHADER_OPCODE opCode = (SHADER_OPCODE)(instructionToken & 0xffff); + + int size; + if (opCode == OPCODE_End) { + break; + } else if (opCode == OPCODE_Comment) { + size = (int)((instructionToken >> 16) & 0x7FFF); + } else { + size = (int)((instructionToken >> 24) & 0x0f); + } + Q_UNUSED(size); + } + + + return result; +} + +TechSet ZoneFile_COD2_360::pParseAsset_TechSet(QDataStream *aZoneFileStream) { + TechSet result; + + for (int i = 1; i <= 62; i++) { + quint32 ptr; + *aZoneFileStream >> ptr; + + result.pointers << ptr; + } + qDebug() << aZoneFileStream->device()->pos(); + + // Parse techset name + char techSetNameChar; + *aZoneFileStream >> techSetNameChar; + while (techSetNameChar != 0) { + result.name += techSetNameChar; + *aZoneFileStream >> techSetNameChar; + } + result.name.replace(",", ""); + + return result; +} + +Image ZoneFile_COD2_360::pParseAsset_Image(QDataStream *aZoneFileStream) { + Image result; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknowna >> result.unknownb + >> result.unknownc >> result.unknownd + >> result.unknowne >> result.unknownf + >> result.unknowng; + + aZoneFileStream->skipRawData(15 * 4); + *aZoneFileStream >> result.unknownh >> result.unknowni; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknownj; + + aZoneFileStream->skipRawData(4); + + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + result.materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + result.materialName.replace(",", ""); + + if (result.unknowna) { + *aZoneFileStream >> result.unknownk; + *aZoneFileStream >> result.unknownl; + *aZoneFileStream >> result.unknownm; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown1; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown2 >> result.unknown3 + >> result.size1 >> result.size2 + >> result.unknown4 >> result.unknown5; + + aZoneFileStream->skipRawData(4); + + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + result.name += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + + *aZoneFileStream >> result.unknown6 >> result.unknown7; + + QByteArray compressionData(8, Qt::Uninitialized); + aZoneFileStream->readRawData(compressionData.data(), 8); + if (compressionData.contains("DXT1")) { + result.compression = COMPRESSION_DXT1; + } else if (compressionData.contains("DXT3")) { + result.compression = COMPRESSION_DXT3; + } else if (compressionData.contains("DXT5")) { + result.compression = COMPRESSION_DXT5; + } else { + result.compression = COMPRESSION_NONE; + } + + *aZoneFileStream >> result.unknown8 >> result.unknown9; + } + + return result; +} + +Material ZoneFile_COD2_360::pParseAsset_Material(QDataStream *aZoneFileStream) { + Material result; + + *aZoneFileStream >> result.namePtr; + if (result.namePtr != quint32(-1) && result.namePtr > 0 && + GetTagCount() > static_cast(result.namePtr - 1)) { + result.name = GetTags()[result.namePtr - 1]; + } + *aZoneFileStream >> result.refNamePtr; + if (result.refNamePtr != 4294967295 && GetTagCount() > result.refNamePtr - 1) { + result.refName = GetTags()[result.refNamePtr - 1]; + } + aZoneFileStream->skipRawData(12); + + for (int i = 0; i < 13; i++) { + qint32 unknownPtr; + *aZoneFileStream >> unknownPtr; + result.pointers << unknownPtr; + } + + *aZoneFileStream >> result.stateBits[0] >> result.stateBits[1] + >> result.textureCount >> result.constCount >> result.techSetPtr + >> result.texturePtr >> result.constPtr; + + + return result; +} + +SoundAsset ZoneFile_COD2_360::pParseAsset_Sound(QDataStream *aZoneFileStream) { + SoundAsset result; + + qDebug() << aZoneFileStream->device()->pos(); + + QByteArray rootNamePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rootNamePtr.data(), 4); + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.count; + + if (rootNamePtr.toHex() == "ffffffff") { + // Read in sound file name + char soundNameChar; + *aZoneFileStream >> soundNameChar; + while (soundNameChar != 0) { + result.name += soundNameChar; + *aZoneFileStream >> soundNameChar; + } + } + + int tagCount = 0; + int resultCount = 0; + for (quint32 i = 0; i < result.count; i++) { + aZoneFileStream->skipRawData(12); + + QByteArray tagPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(tagPtr.data(), 4); + + if (tagPtr.toHex() == "ffffffff") { + tagCount++; + } + aZoneFileStream->skipRawData(4); + + QByteArray pathPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pathPtr.data(), 4); + + if (pathPtr.toHex() == "ffffffff") { + resultCount++; + } + + aZoneFileStream->skipRawData(160); + } + + for (int i = 0; i < tagCount; i++) { + // Read in tag? + QString tag; + char tagChar; + *aZoneFileStream >> tagChar; + while (tagChar != 0) { + tag += tagChar; + *aZoneFileStream >> tagChar; + } + } + + for (int i = 0; i < resultCount; i++) { + Sound sound; + + if (aZoneFileStream->device()->peek(12).toHex().contains("ffffffff00000000")) { + aZoneFileStream->skipRawData(12); + } + + aZoneFileStream->skipRawData(8); + + qDebug() << "- " << aZoneFileStream->device()->pos(); + QByteArray aliasPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(aliasPtr.data(), 4); + + QByteArray namePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(namePtr.data(), 4); + + *aZoneFileStream >> sound.dataLength; + + if (aliasPtr.toHex() == "ffffffff") { + // Read in sound alias name + char soundAliasChar; + *aZoneFileStream >> soundAliasChar; + while (soundAliasChar != 0) { + sound.alias += soundAliasChar; + *aZoneFileStream >> soundAliasChar; + } + } + + if (aZoneFileStream->device()->peek(4) == "RIFF") { + sound.path = sound.alias; + sound.alias = ""; + } else if (namePtr.toHex() == "ffffffff") { + // Read in sound file path + char soundPathChar; + *aZoneFileStream >> soundPathChar; + while (soundPathChar != 0) { + sound.path += soundPathChar; + *aZoneFileStream >> soundPathChar; + } + sound.path.replace(",", ""); + } + + if (sound.dataLength) { + QByteArray data(sound.dataLength, Qt::Uninitialized); + aZoneFileStream->readRawData(data.data(), sound.dataLength); + sound.data = data; + } + result.sounds.append(sound); + } + + return result; +} + +void ZoneFile_COD2_360::pParseAsset_ColMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD2_360::pParseAsset_GameMapSP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD2_360::pParseAsset_GameMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD2_360::pParseAsset_LightDef(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD2_360::pParseAsset_UIMap(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD2_360::pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD2_360::pParseAsset_AIType(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD2_360::pParseAsset_FX(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Animation ZoneFile_COD2_360::pParseAsset_Animation(QDataStream *aZoneFileStream) { + Animation result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.dataByteCount + >> result.dataShortCount + >> result.dataIntCount + >> result.randomDataByteCount + >> result.randomDataIntCount + >> result.numframes + >> result.isLooped + >> result.isDelta + >> result.noneRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.normalTranslatedBoneCount + >> result.preciseTranslatedBoneCount + >> result.staticTranslatedBoneCount + >> result.noneTranslatedBoneCount + >> result.totalBoneCount + >> result.otherBoneCount1 + >> result.otherBoneCount2 + >> result.notifyCount + >> result.assetType + >> result.pad + >> result.randomDataShortCount + >> result.indexCount + >> result.frameRate + >> result.frequency + >> result.boneIDsPtr + >> result.dataBytePtr + >> result.dataShortPtr + >> result.dataIntPtr + >> result.randomDataShortPtr + >> result.randomDataBytePtr + >> result.randomDataIntPtr + >> result.longIndiciesPtr + >> result.notificationsPtr + >> result.deltaPartsPtr; + + // Read in x_anim file name + QString xAnimName; + char xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + while (xAnimNameChar != 0) { + result.name += xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + } + + // Parse x_anim index header + QVector sectionLengths; + for (int i = 0; i < result.numframes; i++) { + quint8 sectionlength; + *aZoneFileStream >> sectionlength; + sectionLengths.push_back(sectionlength); + // Skip padding + aZoneFileStream->skipRawData(1); + } + // Skip unknown section + aZoneFileStream->skipRawData(2 * 8); + + return result; +} + +MenuFile ZoneFile_COD2_360::pParseAsset_MenuFile(QDataStream *aZoneFileStream) { + //MENU_FILE + MenuFile result; + + aZoneFileStream->skipRawData(4); // Separator + + // Parse menu def count + *aZoneFileStream >> result.menuCount; + + // Clearly misparsed, never have this much + if (result.menuCount > 1000) { + qDebug() << "Failure reported when parsing menu file."; + return result; + } + for (uint i = 0; i < result.menuCount; i++) { + Menu menu; + + aZoneFileStream->skipRawData(4); // Separator + + // Read in x_anim file name + char menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + while (menuFilepathChar != 0) { + menu.filePath += menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + } + aZoneFileStream->skipRawData(4); // Separator + + *aZoneFileStream >> menu.menuNamePtr; + + float menuRectX, menuRectY, menuRectWidth, menuRectHeight; + *aZoneFileStream >> menuRectX >> menuRectY >> menuRectWidth >> menuRectHeight; + menu.rect = QRectF(menuRectX, menuRectY, menuRectWidth, menuRectHeight); + + quint32 hAlignInt, vAlignInt; + *aZoneFileStream >> hAlignInt >> vAlignInt; + menu.hAlign = (MENU_H_ALIGNMENT)hAlignInt; + menu.vAlign = (MENU_V_ALIGNMENT)vAlignInt; + + float rectClientX, rectClientY, rectClientWidth, rectClientHeight; + *aZoneFileStream >> rectClientX >> rectClientY >> rectClientWidth >> rectClientHeight; + menu.clientRect = QRectF(rectClientX, rectClientY, rectClientWidth, rectClientHeight); + + quint32 hClientAlignInt, vClientAlignInt, styleInt, borderInt; + *aZoneFileStream >> hClientAlignInt >> vClientAlignInt >> menu.groupPtr + >> styleInt >> borderInt >> menu.ownerDraw >> menu.ownerDrawFlags + >> menu.borderSize >> menu.staticFlags >> menu.dynamicFlags >> menu.nextTime; + menu.hClientAlign = (MENU_H_ALIGNMENT)hClientAlignInt; + menu.vClientAlign = (MENU_V_ALIGNMENT)vClientAlignInt; + menu.style = (MENU_WINDOW_STYLE)styleInt; + menu.border = (MENU_WINDOW_BORDER)borderInt; + + float foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA, + backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA, + borderColorR, borderColorG, borderColorB, borderColorA, + outlineColorR, outlineColorG, outlineColorB, outlineColorA; + *aZoneFileStream >> foregroundColorR >> foregroundColorG >> foregroundColorB >> foregroundColorA + >> backgroundColorR >> backgroundColorG >> backgroundColorB >> backgroundColorA + >> borderColorR >> borderColorG >> borderColorB >> borderColorA + >> outlineColorR >> outlineColorG >> outlineColorB >> outlineColorA; + + menu.foregroundColor = QColor(foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA); + menu.backgroundColor = QColor(backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA); + menu.borderColor = QColor(borderColorR, borderColorG, borderColorB, borderColorA); + menu.outlineColor = QColor(outlineColorR, outlineColorG, outlineColorB, outlineColorA); + + *aZoneFileStream >> menu.materialPtr >> menu.fontPtr >> menu.fullScreen >> menu.itemCount + >> menu.fontIndex >> menu.cursorItem >> menu.fadeCycle >> menu.fadeClamp + >> menu.fadeAmount >> menu.fadeInAmount >> menu.blurRadius >> menu.onOpenPtr + >> menu.onFocusPtr >> menu.onClosePtr >> menu.onESCPtr >> menu.onKeyPtr + >> menu.visibleExpCount >> menu.expEntryPtr >> menu.allowedBindingPtr + >> menu.soundNamePtr >> menu.imageTrack; + + float focusColorR, focusColorG, focusColorB, focusColorA, + disabledColorR, disabledColorG, disabledColorB, disabledColorA; + *aZoneFileStream >> focusColorR >> focusColorG >> focusColorB >> focusColorA + >> disabledColorR >> disabledColorG >> disabledColorB >> disabledColorA; + menu.focusColor = QColor(focusColorR, focusColorG, focusColorB, focusColorA); + menu.disabledColor = QColor(disabledColorR, disabledColorG, disabledColorB, disabledColorA); + + *aZoneFileStream >> menu.rectXExpCount >> menu.rectXExpPtr >> menu.rectYExpCount >> menu.rectYExpPtr; + + aZoneFileStream->skipRawData(4); // Separator + + char menuDefNameChar; + int menuDefNameLen = 0; + *aZoneFileStream >> menuDefNameChar; + while (menuDefNameChar != 0 && menuDefNameLen < 30) { + menuDefNameLen++; + menu.name += menuDefNameChar; + *aZoneFileStream >> menuDefNameChar; + } + + char defStringChar; + int defStringLen = 0; + *aZoneFileStream >> defStringChar; + while (defStringChar != 0 && defStringLen < 30) { + defStringLen++; + menu.definition += defStringChar; + *aZoneFileStream >> defStringChar; + } + aZoneFileStream->skipRawData(4 * 10); + + *aZoneFileStream >> menu.itemWindowDefNamePtr; + + float itemRectX, itemRectY, itemRectWidth, itemRectHeight; + *aZoneFileStream >> itemRectX >> itemRectY >> itemRectWidth >> itemRectHeight; + menu.itemRect = QRectF(itemRectX, itemRectY, itemRectWidth, itemRectHeight); + + *aZoneFileStream >> menu.itemHAlignment >> menu.itemVAlignment >> menu.itemGroupPtr + >> menu.itemWindowStyle >> menu.itemWindowBorder >> menu.itemOwnerDraw + >> menu.itemOwnerDrawFlags >> menu.itemBorderSize >> menu.itemStaticFlags + >> menu.itemDynamicFlags >> menu.itemNextTime; + + float itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA, + itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA, + itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA, + itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA; + *aZoneFileStream >> itemForegroundColorR >> itemForegroundColorG >> itemForegroundColorB >> itemForegroundColorA + >> itemBackgroundColorR >> itemBackgroundColorG >> itemBackgroundColorB >> itemBackgroundColorA + >> itemBorderColorR >> itemBorderColorG >> itemBorderColorB >> itemBorderColorA + >> itemOutlineColorR >> itemOutlineColorG >> itemOutlineColorB >> itemOutlineColorA; + + menu.itemForegroundColor = QColor(itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA); + menu.itemBackgroundColor = QColor(itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA); + menu.itemBorderColor = QColor(itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA); + menu.itemOutlineColor = QColor(itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA); + + *aZoneFileStream >> menu.itemMaterialPtr; + + float itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight; + *aZoneFileStream >> itemTextRectX >> itemTextRectY >> itemTextRectWidth >> itemTextRectHeight; + menu.itemTextRect = QRectF(itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight); + + quint32 hItemTextAlignInt, vItemTextAlignInt, itemType, fontTypeInt, textStyleInt; + *aZoneFileStream >> hItemTextAlignInt >> vItemTextAlignInt >> itemType >> menu.dataType + >> menu.alignment >> fontTypeInt >> menu.textAlignMode >> menu.textalignx >> menu.textaligny + >> menu.textscale >> textStyleInt >> menu.gameMsgWindowIndex >> menu.gameMsgWindowMode + >> menu.testPtr >> menu.textSavegameInfo >> menu.parentPtr; + menu.itemText_hAlign = (MENU_H_ALIGNMENT)hItemTextAlignInt; + menu.itemText_vAlign = (MENU_V_ALIGNMENT)vItemTextAlignInt; + menu.itemType = (MENU_ITEM_TYPE)itemType; + menu.fontEnum = (MENU_FONT_TYPE)fontTypeInt; + menu.textStyle = (MENU_ITEM_TEXTSTYLE)textStyleInt; + + *aZoneFileStream >> menu.mouseEnterText >> menu.mouseExitText >> menu.mouseEnter >> menu.mouseExit + >> menu.action >> menu.onAccept >> menu.onFocus >> menu.leaveFocus >> menu.dvar >> menu.dvarTest + >> menu.keyHandlerPtr >> menu.enableDvarPtr >> menu.dvarFlags >> menu.focusSoundPtr + >> menu.special >> menu.cursorPos; + + // itemDefData_t typeData; + + // listBoxDef_s *listBox; + + *aZoneFileStream >> menu.startPos >> menu.endPos >> menu.drawPadding; + + *aZoneFileStream >> menu.elementWidth >> menu.elementHeight; + + *aZoneFileStream >> menu.elementStyle >> menu.numColumns; + + //columnInfo_s columnInfo[16]; + + *aZoneFileStream >> menu.doubleClickPtr; + + + *aZoneFileStream >> menu.notselectable >> menu.noScrollBars >> menu.usePaging; + + float itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA, + itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA, + itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA; + *aZoneFileStream >> itemSelectBorderColorR >> itemSelectBorderColorG >> itemSelectBorderColorB >> itemSelectBorderColorA + >> itemDisableColorR >> itemDisableColorG >> itemDisableColorB >> itemDisableColorA + >> itemFocusColorR >> itemFocusColorG >> itemFocusColorB >> itemFocusColorA; + menu.itemSelectBorderColor = QColor(itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA); + menu.itemDisableColor = QColor(itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA); + menu.itemFocusColor = QColor(itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA); + + *aZoneFileStream >> menu.selectIconPtr >> menu.backgroundItemListboxPtr >> menu.highlightTexturePtr; + + // editFieldDef_s *editField; + + *aZoneFileStream >> menu.minVal >> menu.maxVal >> menu.defVal >> menu.range >> menu.maxChars + >> menu.maxCharsGotoNext >> menu.maxPaintChars >> menu.paintOffset; + + // multiDef_s *multi; + + for (int i = 0; i < 32; i++) { + quint32 dvarList; + *aZoneFileStream >> dvarList; + menu.dvarListPtrs.push_back(dvarList); + } + + for (int i = 0; i < 32; i++) { + quint32 dvarStr; + *aZoneFileStream >> dvarStr; + menu.dvarStrPtrs.push_back(dvarStr); + } + + for (int i = 0; i < 32; i++) { + float dvarValue; + *aZoneFileStream >> dvarValue; + menu.dvarValues.push_back(dvarValue); + } + + *aZoneFileStream >> menu.count >> menu.strDef >> menu.enumDvarNamePtr; + aZoneFileStream->skipRawData(4); + //>> menu.dataPtr + *aZoneFileStream >> menu.itemImageTrack; + + qDebug() << aZoneFileStream->device()->pos(); + + //statement_s visibleExp; + //statement_s textExp; + //statement_s materialExp; + //statement_s rectXExp; + //statement_s rectYExp; + //statement_s rectWExp; + //statement_s rectHExp; + //statement_s foreColorAExp; + result.menuDefs << menu; + } + return result; +} + +void ZoneFile_COD2_360::pParseAsset_Weapon(QDataStream *aZoneFileStream) { + //WEAPON_FILE + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD2_360::pParseAsset_D3DBSP(QDataStream *aZoneFileStream) { + //D3DBSP_DUMP + Q_UNUSED(aZoneFileStream); +} + +StringTable ZoneFile_COD2_360::pParseAsset_StringTable(QDataStream *aZoneFileStream) { + StringTable result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.columnCount + >> result.rowCount; + + // Todo fix this + result.columnCount = 0; + result.rowCount = 0; + + aZoneFileStream->skipRawData(4); + + QString stringTableName; + char stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + while (stringTableNameChar != 0) { + result.name += stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + } + + for (quint32 i = 0; i < result.rowCount; i++) { + QByteArray pointerData(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pointerData.data(), 4); + result.tablePointers.push_back(pointerData.toHex()); + + aZoneFileStream->skipRawData(4); + } + + for (const QString &pointerAddr : result.tablePointers) { + QString leadingContent = ""; + if (pointerAddr == "FFFFFFFF") { + char leadingContentChar; + *aZoneFileStream >> leadingContentChar; + while (leadingContentChar != 0) { + leadingContent += leadingContentChar; + *aZoneFileStream >> leadingContentChar; + } + } else { + leadingContent = pointerAddr; + } + + QString content; + char contentChar; + *aZoneFileStream >> contentChar; + while (contentChar != 0) { + content += contentChar; + *aZoneFileStream >> contentChar; + } + result.content[leadingContent] = content; + } + return result; +} +// "parts", +// ASSET_MODEL, +// ASSET_MATERIAL, +// ASSET_IMAGE, +// ASSET_SOUND, +// "sndCurve", +// "clipMap", +// "world", +// "lightDef", +// ASSET_FONT, +// "menuList", +// ASSET_MENU, +// "localize", +// ASSET_WEAPON, +// "sndDriverGlobals", +// "fx", +// "impactFx", +// "rawfile", +// "data" + +AssetType ZoneFile_COD2_360::AssetStrToEnum(const QString aAssetType) { + const QString cleanedType = aAssetType.toUpper(); + if (cleanedType == "") { + return ASSET_RAW_FILE; + } else if (cleanedType == "") { + return ASSET_EFFECT; + } else if (cleanedType == "") { + return ASSET_SOUND; + } else if (cleanedType == "") { + return ASSET_ANIMATION; + } else if (cleanedType == "") { + return ASSET_COLLISION_MAP; + } else if (cleanedType == "") { + return ASSET_STRING_TABLE; + } else if (cleanedType == "") { + return ASSET_MENU; + } else if (cleanedType == "") { + return ASSET_TECH_SET; + } else if (cleanedType == "") { + return ASSET_LOCAL_STRING; + } else if (cleanedType == "") { + return ASSET_GFX_MAP; + } else if (cleanedType == "") { + return ASSET_LIGHT_DEF; + } else if (cleanedType == "") { + return ASSET_FONT; + } else if (cleanedType == "") { + return ASSET_MODEL; + } else if (cleanedType == "") { + return ASSET_D3DBSP; + } else if (cleanedType == "00000002") { + return ASSET_MATERIAL; + } else if (cleanedType == "") { + return ASSET_GAME_MAP_SP; + } else if (cleanedType == "") { + return ASSET_COL_MAP_SP; + } else if (cleanedType == "") { + return ASSET_PHYS_PRESET; + } else if (cleanedType == "") { + return ASSET_DESTRUCTIBLE; + } else if (cleanedType == "") { + return ASSET_MENU; + } + return ASSET_NONE; +} + +QByteArray ZoneFile_COD2_360::GetBinaryData() { + QByteArray result; + + return result; +} diff --git a/libs/zonefile/360/zonefile_cod2_360.h b/libs/zonefile/360/zonefile_cod2_360.h new file mode 100644 index 0000000..0cdbbed --- /dev/null +++ b/libs/zonefile/360/zonefile_cod2_360.h @@ -0,0 +1,52 @@ +#ifndef ZONEFILE_COD2_360_H +#define ZONEFILE_COD2_360_H + +#include "zonefile.h" + +class ZoneFile_COD2_360 : public ZoneFile +{ +public: + ZoneFile_COD2_360(); + ~ZoneFile_COD2_360(); + + bool Load(const QByteArray aFileData) override; + AssetType AssetStrToEnum(const QString aAssetType) override; + + QByteArray GetBinaryData() override; + +protected: + void pParseZoneHeader(QDataStream *aZoneFileStream) override; + quint32 pParseZoneSize(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsA(QDataStream *aZoneFileStream) override; + quint32 pParseZoneTagCount(QDataStream *aZoneFileStream) override; + quint32 pParseZoneRecordCount(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsB(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsC(QDataStream *aZoneFileStream) override; + QStringList pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) override; + QStringList pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) override; + AssetMap pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) override; + LocalString pParseAsset_LocalString(QDataStream *aZoneFileStream) override; + RawFile pParseAsset_RawFile(QDataStream *aZoneFileStream) override; + void pParseAsset_PhysPreset(QDataStream *aZoneFileStream) override; + Model pParseAsset_Model(QDataStream *aZoneFileStream) override; + Material pParseAsset_Material(QDataStream *aZoneFileStream) override; + Shader pParseAsset_Shader(QDataStream *aZoneFileStream) override; + TechSet pParseAsset_TechSet(QDataStream *aZoneFileStream) override; + Image pParseAsset_Image(QDataStream *aZoneFileStream) override; + SoundAsset pParseAsset_Sound(QDataStream *aZoneFileStream) override; + void pParseAsset_ColMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapSP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_LightDef(QDataStream *aZoneFileStream) override; + void pParseAsset_UIMap(QDataStream *aZoneFileStream) override; + void pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) override; + void pParseAsset_AIType(QDataStream *aZoneFileStream) override; + void pParseAsset_FX(QDataStream *aZoneFileStream) override; + Animation pParseAsset_Animation(QDataStream *aZoneFileStream) override; + MenuFile pParseAsset_MenuFile(QDataStream *aZoneFileStream) override; + void pParseAsset_Weapon(QDataStream *aZoneFileStream) override; + void pParseAsset_D3DBSP(QDataStream *aZoneFileStream) override; + StringTable pParseAsset_StringTable(QDataStream *aZoneFileStream) override; +}; + +#endif // ZONEFILE_COD2_360_H diff --git a/libs/zonefile/360/zonefile_cod4_360.cpp b/libs/zonefile/360/zonefile_cod4_360.cpp new file mode 100644 index 0000000..8e1955e --- /dev/null +++ b/libs/zonefile/360/zonefile_cod4_360.cpp @@ -0,0 +1,1151 @@ +#include "zonefile_cod4_360.h" + +#include +#include +#include + +ZoneFile_COD4_360::ZoneFile_COD4_360() + : ZoneFile() { + +} + +ZoneFile_COD4_360::~ZoneFile_COD4_360() { + +} + +bool ZoneFile_COD4_360::Load(const QByteArray aFileData) { + // Open zone file as little endian stream + QDataStream zoneFileStream(aFileData); + zoneFileStream.setByteOrder(QDataStream::BigEndian); + + // Parse data from zone file header + pParseZoneHeader(&zoneFileStream); + SetRecords(pParseZoneIndex(&zoneFileStream, GetRecordCount())); + SetAssetMap(pParseAssets(&zoneFileStream, GetRecords())); + + return true; +} + +void ZoneFile_COD4_360::pParseZoneHeader(QDataStream *aZoneFileStream) { + SetSize(pParseZoneSize(aZoneFileStream)); + pParseZoneUnknownsA(aZoneFileStream); + + SetTagCount(pParseZoneTagCount(aZoneFileStream)); + pParseZoneUnknownsB(aZoneFileStream); + + SetRecordCount(pParseZoneRecordCount(aZoneFileStream)); + + quint32 tagCount = GetTagCount(); + if (tagCount) { + pParseZoneUnknownsC(aZoneFileStream); + SetTags(pParseZoneTags(aZoneFileStream, tagCount)); + } else { + aZoneFileStream->skipRawData(4); + } +} + +quint32 ZoneFile_COD4_360::pParseZoneSize(QDataStream *aZoneFileStream) { + quint32 zoneFileSize; + *aZoneFileStream >> zoneFileSize; + if (zoneFileSize <= 0) { + qDebug() << "Tried to open empty zone file!"; + exit(-1); + } + zoneFileSize += 36; + return zoneFileSize; +} + +/* + ParseZoneUnknownsA() + + Parses the 1st section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD4_360::pParseZoneUnknownsA(QDataStream *aZoneFileStream) { + // Byte 4-7, 8-11, 12-15: unknown + QByteArray unknown1(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown1.data(), 4); + + QByteArray unknown2(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown2.data(), 4); + + QByteArray unknown3(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown3.data(), 4); + + // Byte 16-19, 20-23: empty/unknown + QByteArray unknown4(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown4.data(), 4); + + QByteArray unknown5(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown5.data(), 4); + + // Byte 24-27: somehow related to the filesize, but smaller value + QByteArray unknown6(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown6.data(), 4); + + // Byte 28-31, 32-35: unknown + QByteArray unknown7(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown7.data(), 4); + + QByteArray unknown8(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown8.data(), 4); +} + +/* + ParseZoneTagCount() + + Parses the number of string tags in the zone index +*/ +quint32 ZoneFile_COD4_360::pParseZoneTagCount(QDataStream *aZoneFileStream) { + quint32 tagCount; + *aZoneFileStream >> tagCount; + return tagCount; +} + +/* + ParseZoneRecordCount() + + Parses the number of records in the zone index +*/ +quint32 ZoneFile_COD4_360::pParseZoneRecordCount(QDataStream *aZoneFileStream) { + quint32 recordCount; + *aZoneFileStream >> recordCount; + return recordCount; +} + +/* + ParseZoneUnknownsB() + + Parses the 2nd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD4_360::pParseZoneUnknownsB(QDataStream *aZoneFileStream) { + // Byte 44-47: Unknown/empty? + QByteArray unknown9(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown9.data(), 4); +} + +/* + pParseZoneUnknownsC() + + Parses the 3rd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD4_360::pParseZoneUnknownsC(QDataStream *aZoneFileStream) { + // Byte 40-43: Unknown/empty? + QByteArray unknown10(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown10.data(), 4); + + // Byte 44-47: Unknown/empty? + QByteArray unknown11(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown11.data(), 4); +} + +/* + ParseZoneTags() + + Parses the string tags ate the start of zone file +*/ +QStringList ZoneFile_COD4_360::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) { + QStringList tags; + + // Byte 48-51: Repeated separators? ÿÿÿÿ x i + aZoneFileStream->skipRawData(4 * (tagCount - 1)); + + // Parse tags/strings before index + QString zoneTag; + char zoneTagChar; + for (quint32 i = 0; i < tagCount - 1; i++) { + *aZoneFileStream >> zoneTagChar; + while (zoneTagChar != 0) { + zoneTag += zoneTagChar; + *aZoneFileStream >> zoneTagChar; + } + if (!zoneTag.isEmpty()) { + tags << zoneTag; + } + zoneTag.clear(); + } + return tags; +} + +/* + ParseZoneIndex() + + Parse the binary zone index data and populate table +*/ +QStringList ZoneFile_COD4_360::pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) { + QStringList result; + + // Don't parse if no records + if (!recordCount) { return result; } + + // Parse index & map found asset types + for (quint32 i = 0; i < recordCount; i++) { + // Skip record start + QByteArray rawAssetType(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rawAssetType.data(), 4); + result << rawAssetType.toHex(); + + // Skip separator + aZoneFileStream->skipRawData(4); + } + return result; +} + +AssetMap ZoneFile_COD4_360::pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) { + AssetMap result; + + for (int i = 0; i < assetOrder.size(); i++) { + const QString typeHex = assetOrder[i]; + const AssetType assetType = AssetStrToEnum(typeHex); + const QString typeStr = AssetEnumToStr(assetType); + + if (assetType == ASSET_LOCAL_STRING) { // localized string asset + result.localStrings << pParseAsset_LocalString(aZoneFileStream); + } else if (assetType == ASSET_RAW_FILE) { // gsc + auto rawFile = pParseAsset_RawFile(aZoneFileStream); + if (rawFile.length) { + result.rawFiles << rawFile; + } + } else if (assetType == ASSET_PHYS_PRESET) { // physpreset + pParseAsset_PhysPreset(aZoneFileStream); + } else if (assetType == ASSET_MODEL) { // xmodel + result.models << pParseAsset_Model(aZoneFileStream); + } else if (assetType == ASSET_MATERIAL) { // material + result.materials << pParseAsset_Material(aZoneFileStream); + } else if (assetType == ASSET_SHADER) { // pixelshader + pParseAsset_Shader(aZoneFileStream); + } else if (assetType == ASSET_TECH_SET) { // techset include + result.techSets << pParseAsset_TechSet(aZoneFileStream); + } else if (assetType == ASSET_IMAGE) { // image + result.images << pParseAsset_Image(aZoneFileStream); + } else if (assetType == ASSET_SOUND) { // loaded_sound + result.sounds << pParseAsset_Sound(aZoneFileStream); + } else if (assetType == ASSET_COLLISION_MAP) { // col_map_mp + pParseAsset_ColMapMP(aZoneFileStream); + } else if (assetType == ASSET_MP_MAP) { // game_map_sp + pParseAsset_GameMapSP(aZoneFileStream); + } else if (assetType == ASSET_SP_MAP) { // game_map_mp + pParseAsset_GameMapMP(aZoneFileStream); + } else if (assetType == ASSET_LIGHT_DEF) { // lightdef + pParseAsset_LightDef(aZoneFileStream); + } else if (assetType == ASSET_UI_MAP) { // ui_map + pParseAsset_UIMap(aZoneFileStream); + } else if (assetType == ASSET_SND_DRIVER_GLOBALS) { // snddriverglobals + pParseAsset_SNDDriverGlobals(aZoneFileStream); + } else if (assetType == ASSET_AI_TYPE) { // aitype + pParseAsset_AIType(aZoneFileStream); + } else if (assetType == ASSET_EFFECT) { // aitype + pParseAsset_FX(aZoneFileStream); + } else if (assetType == ASSET_ANIMATION) { // aitype + result.animations << pParseAsset_Animation(aZoneFileStream); + } else if (assetType == ASSET_STRING_TABLE) { // string_table + result.stringTables << pParseAsset_StringTable(aZoneFileStream); + } else if (assetType == ASSET_MENU) { // string_table + result.menuFiles << pParseAsset_MenuFile(aZoneFileStream); + } else if (assetType == ASSET_WEAPON) { // string_table + pParseAsset_Weapon(aZoneFileStream); + } else if (assetType == ASSET_D3DBSP) { // string_table + pParseAsset_D3DBSP(aZoneFileStream); + } + } + return result; +} + +LocalString ZoneFile_COD4_360::pParseAsset_LocalString(QDataStream *aZoneFileStream) { + LocalString result; + + quint32 stringPtr, aliasPtr; + *aZoneFileStream >> stringPtr >> aliasPtr; + if (stringPtr == 4294967295) { + // Parse local string asset contents + QString localStr; + char localStrChar; + *aZoneFileStream >> localStrChar; + while (localStrChar != 0) { + result.string += localStrChar; + *aZoneFileStream >> localStrChar; + } + } else { + result.string = "String Ptr: " + QString::number(stringPtr); + } + + if (aliasPtr == 4294967295) { + // Parse rawfile name + QString aliasName; + char aliasNameChar; + *aZoneFileStream >> aliasNameChar; + while (aliasNameChar != 0) { + result.alias += aliasNameChar; + *aZoneFileStream >> aliasNameChar; + } + } else { + result.string = "Alias Ptr: " + QString::number(aliasPtr); + } + + return result; +} + +RawFile ZoneFile_COD4_360::pParseAsset_RawFile(QDataStream *aZoneFileStream) { + RawFile result; + + // Skip start separator FF FF FF FF (pointer?) + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.length; + + // Skip unknown 4 byte data + aZoneFileStream->skipRawData(4); + + // Parse rawfile path + char scriptPathChar; + *aZoneFileStream >> scriptPathChar; + while (scriptPathChar != 0) { + result.path += scriptPathChar; + *aZoneFileStream >> scriptPathChar; + } + result.path.replace(",", ""); + + const QStringList pathParts = result.path.split('/'); + if (pathParts.size() == 0) { + qDebug() << "Failed to parse ff path! " << result.path; + exit(-1); + } + if (result.path.contains(".bik")) { + QByteArray bikData(result.length, Qt::Uninitialized); + aZoneFileStream->readRawData(bikData.data(), result.length); + + //QFile bikFile(QDir::currentPath() + "/" + rawFilePath.split('/').last()); + //qDebug() << bikFile.fileName(); + //if (!bikFile.open(QIODevice::WriteOnly)) { + // qWarning() << "Failed to open .bik file for writing!"; + // return; + //} + //qDebug() << QString("%1: %2").arg(rawFilePath).arg(bikFile.fileName()); + //bikFile.write(bikData); + } else { + // Parse gsc contents + char rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + while (rawFileContentsChar != 0 && rawFileContentsChar != -1) { + result.contents += rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + } + } + return result; +} + +void ZoneFile_COD4_360::pParseAsset_PhysPreset(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Model ZoneFile_COD4_360::pParseAsset_Model(QDataStream *aZoneFileStream) { + Model result; + + *aZoneFileStream >> result.namePtr >> result.tagCount >> result.rootTagCount + >> result.surfCount >> result.unknownCount >> result.boneNamePtr + >> result.parentListPtr >> result.quatsPtr >> result.transPtr + >> result.partClassPtr >> result.baseMatPtr + >> result.surfsPtr >> result.materialHandlesPtr; + + // Parse XModelLodInfo + for (int i = 1; i <= 4; i++) { + quint32 intDist; + *aZoneFileStream >> intDist; + + std::memcpy(&result.lodInfo[i].dist, &intDist, sizeof(result.lodInfo[i].dist)); + *aZoneFileStream >> result.lodInfo[i].numsurfs >> result.lodInfo[i].surfIndex; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.lodInfo[i].partBits[0] + >> result.lodInfo[i].partBits[1] + >> result.lodInfo[i].partBits[2] + >> result.lodInfo[i].partBits[3]; + } + + *aZoneFileStream >> result.collSurfsPtr >> result.numCollSurfs >> result.contents >> result.boneInfoPtr; + + quint32 intRadius, intMins[3], intMaxs[3]; + *aZoneFileStream >> intRadius >> intMins[0] >> intMins[1] + >> intMins[2] >> intMaxs[0] >> intMaxs[1] >> intMaxs[2]; + + std::memcpy(&result.radius, &intRadius, sizeof(result.radius)); + + std::memcpy(&result.mins[0], &intMins[0], sizeof(result.mins[0])); + std::memcpy(&result.mins[1], &intMins[1], sizeof(result.mins[1])); + std::memcpy(&result.mins[2], &intMins[2], sizeof(result.mins[2])); + + std::memcpy(&result.maxs[0], &intMaxs[0], sizeof(result.maxs[0])); + std::memcpy(&result.maxs[1], &intMaxs[1], sizeof(result.maxs[2])); + std::memcpy(&result.maxs[2], &intMaxs[2], sizeof(result.maxs[3])); + + *aZoneFileStream >> result.numLods >> result.collLod >> result.streamInfoPtr + >> result.memUsage >> result.flags >> result.physPresetPtr >> result.physGeomsPtr; + + // Parse model name + char modelNameChar; + *aZoneFileStream >> modelNameChar; + while (modelNameChar == 0) { + *aZoneFileStream >> modelNameChar; + } + while (modelNameChar != 0) { + result.modelName += modelNameChar; + *aZoneFileStream >> modelNameChar; + } + return result; +} + +Material ZoneFile_COD4_360::pParseAsset_Material(QDataStream *aZoneFileStream) { + Material result; + + *aZoneFileStream >> result.namePtr; + + //aZoneFileStream->skipRawData(23 * 4); + + for (int i = 0; i < 23; i++) { + qint32 unknownPtr; + *aZoneFileStream >> unknownPtr; + result.pointers << unknownPtr; + } + + if (result.namePtr == -1) { + aZoneFileStream->skipRawData(1); + + QString materialName; + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + result.name += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + } + + aZoneFileStream->skipRawData(3 * 4); + + qint32 compressionPtr, compression, unknownSectionPtr; + *aZoneFileStream >> compressionPtr; + if (compressionPtr == -1) { + *aZoneFileStream >> compression; + + *aZoneFileStream >> unknownSectionPtr; + if (unknownSectionPtr == -2) { + aZoneFileStream->skipRawData(6 * 4); + } + } + + qint32 imageNamePtr; + *aZoneFileStream >> imageNamePtr; + if (imageNamePtr == -1) { + QString imageName; + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + imageName += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + } + + QByteArray compressionData(4, Qt::Uninitialized); + QString compressionStr; + if (compressionPtr == -1) { + aZoneFileStream->skipRawData(2 * 4); + aZoneFileStream->readRawData(compressionData.data(), 4); + aZoneFileStream->skipRawData(4); + compressionStr = QString::fromUtf8(compressionData); + aZoneFileStream->skipRawData(4); + } + aZoneFileStream->skipRawData(4); + + return result; +} + +Shader ZoneFile_COD4_360::pParseAsset_Shader(QDataStream *aZoneFileStream) { + Shader result = Shader(); + + quint8 minorVersion, majorVersion; + *aZoneFileStream >> minorVersion >> majorVersion; + + quint32 magic; + *aZoneFileStream >> magic; + + // Verify .fxc magic + if (magic != 65534 && magic != 65535) { return result; } + + SHADER_TYPE type = SHADER_NONE; + quint16 rawShaderType; + *aZoneFileStream >> rawShaderType; + if (rawShaderType == 65535) { // Pixel shader + type = SHADER_PIXEL; + } else if (rawShaderType == 65534) { // Vertex shader + type = SHADER_VERTEX; + } + Q_UNUSED(type); + + while (true) { + quint32 instructionToken; + *aZoneFileStream >> instructionToken; + + SHADER_OPCODE opCode = (SHADER_OPCODE)(instructionToken & 0xffff); + + int size; + if (opCode == OPCODE_End) { + break; + } else if (opCode == OPCODE_Comment) { + size = (int)((instructionToken >> 16) & 0x7FFF); + } else { + size = (int)((instructionToken >> 24) & 0x0f); + } + Q_UNUSED(size); + } + + + return result; +} + +TechSet ZoneFile_COD4_360::pParseAsset_TechSet(QDataStream *aZoneFileStream) { + TechSet result; + + qint32 namePtr; + *aZoneFileStream >> namePtr; + + + for (int i = 0; i < 53; i++) { + quint32 ptr; + *aZoneFileStream >> ptr; + + result.pointers << ptr; + } + + //aZoneFileStream->skipRawData(53 * 4); + + if (namePtr == -1) { + aZoneFileStream->skipRawData(1); + + // Parse techset name + char techSetNameChar; + *aZoneFileStream >> techSetNameChar; + while (techSetNameChar != 0) { + result.name += techSetNameChar; + *aZoneFileStream >> techSetNameChar; + } + } + + //result.name.replace(",", ""); + return result; +} + +Image ZoneFile_COD4_360::pParseAsset_Image(QDataStream *aZoneFileStream) { + Image result; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknowna >> result.unknownb + >> result.unknownc >> result.unknownd + >> result.unknowne >> result.unknownf + >> result.unknowng; + + aZoneFileStream->skipRawData(15 * 4); + *aZoneFileStream >> result.unknownh >> result.unknowni; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknownj; + + aZoneFileStream->skipRawData(4); + + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + result.materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + result.materialName.replace(",", ""); + + if (result.unknowna) { + *aZoneFileStream >> result.unknownk; + *aZoneFileStream >> result.unknownl; + *aZoneFileStream >> result.unknownm; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown1; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown2 >> result.unknown3 + >> result.size1 >> result.size2 + >> result.unknown4 >> result.unknown5; + + aZoneFileStream->skipRawData(4); + + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + result.name += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + + *aZoneFileStream >> result.unknown6 >> result.unknown7; + + QByteArray compressionData(8, Qt::Uninitialized); + aZoneFileStream->readRawData(compressionData.data(), 8); + if (compressionData.contains("DXT1")) { + result.compression = COMPRESSION_DXT1; + } else if (compressionData.contains("DXT3")) { + result.compression = COMPRESSION_DXT3; + } else if (compressionData.contains("DXT5")) { + result.compression = COMPRESSION_DXT5; + } else { + result.compression = COMPRESSION_NONE; + } + + *aZoneFileStream >> result.unknown8 >> result.unknown9; + } + + return result; +} + +SoundAsset ZoneFile_COD4_360::pParseAsset_Sound(QDataStream *aZoneFileStream) { + SoundAsset result; + + QByteArray rootNamePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rootNamePtr.data(), 4); + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.count; + + if (rootNamePtr.toHex() == "ffffffff") { + // Read in sound file name + char soundNameChar; + *aZoneFileStream >> soundNameChar; + while (soundNameChar != 0) { + result.name += soundNameChar; + *aZoneFileStream >> soundNameChar; + } + } + + int tagCount = 0; + int resultCount = 0; + for (quint32 i = 0; i < result.count; i++) { + aZoneFileStream->skipRawData(12); + + QByteArray tagPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(tagPtr.data(), 4); + + if (tagPtr.toHex() == "ffffffff") { + tagCount++; + } + aZoneFileStream->skipRawData(4); + + QByteArray pathPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pathPtr.data(), 4); + + if (pathPtr.toHex() == "ffffffff") { + resultCount++; + } + + aZoneFileStream->skipRawData(160); + } + + for (int i = 0; i < tagCount; i++) { + // Read in tag? + QString tag; + char tagChar; + *aZoneFileStream >> tagChar; + while (tagChar != 0) { + tag += tagChar; + *aZoneFileStream >> tagChar; + } + } + + for (int i = 0; i < resultCount; i++) { + Sound sound; + + if (aZoneFileStream->device()->peek(12).toHex().contains("ffffffff00000000")) { + aZoneFileStream->skipRawData(12); + } + + aZoneFileStream->skipRawData(8); + + QByteArray aliasPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(aliasPtr.data(), 4); + + QByteArray namePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(namePtr.data(), 4); + + *aZoneFileStream >> sound.dataLength; + + if (aliasPtr.toHex() == "ffffffff") { + // Read in sound alias name + char soundAliasChar; + *aZoneFileStream >> soundAliasChar; + while (soundAliasChar != 0) { + sound.alias += soundAliasChar; + *aZoneFileStream >> soundAliasChar; + } + } + + if (aZoneFileStream->device()->peek(4) == "RIFF") { + sound.path = sound.alias; + sound.alias = ""; + } else if (namePtr.toHex() == "ffffffff") { + // Read in sound file path + char soundPathChar; + *aZoneFileStream >> soundPathChar; + while (soundPathChar != 0) { + sound.path += soundPathChar; + *aZoneFileStream >> soundPathChar; + } + sound.path.replace(",", ""); + } + + if (sound.dataLength) { + QByteArray data(sound.dataLength, Qt::Uninitialized); + aZoneFileStream->readRawData(data.data(), sound.dataLength); + sound.data = data; + } + result.sounds.append(sound); + } + + return result; +} + +void ZoneFile_COD4_360::pParseAsset_ColMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD4_360::pParseAsset_GameMapSP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD4_360::pParseAsset_GameMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD4_360::pParseAsset_LightDef(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD4_360::pParseAsset_UIMap(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD4_360::pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD4_360::pParseAsset_AIType(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD4_360::pParseAsset_FX(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Animation ZoneFile_COD4_360::pParseAsset_Animation(QDataStream *aZoneFileStream) { + Animation result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.dataByteCount + >> result.dataShortCount + >> result.dataIntCount + >> result.randomDataByteCount + >> result.randomDataIntCount + >> result.numframes + >> result.isLooped + >> result.isDelta + >> result.noneRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.normalTranslatedBoneCount + >> result.preciseTranslatedBoneCount + >> result.staticTranslatedBoneCount + >> result.noneTranslatedBoneCount + >> result.totalBoneCount + >> result.otherBoneCount1 + >> result.otherBoneCount2 + >> result.notifyCount + >> result.assetType + >> result.pad + >> result.randomDataShortCount + >> result.indexCount + >> result.frameRate + >> result.frequency + >> result.boneIDsPtr + >> result.dataBytePtr + >> result.dataShortPtr + >> result.dataIntPtr + >> result.randomDataShortPtr + >> result.randomDataBytePtr + >> result.randomDataIntPtr + >> result.longIndiciesPtr + >> result.notificationsPtr + >> result.deltaPartsPtr; + + // Read in x_anim file name + QString xAnimName; + char xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + while (xAnimNameChar != 0) { + result.name += xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + } + + // Parse x_anim index header + QVector sectionLengths; + for (int i = 0; i < result.numframes; i++) { + quint8 sectionlength; + *aZoneFileStream >> sectionlength; + sectionLengths.push_back(sectionlength); + // Skip padding + aZoneFileStream->skipRawData(1); + } + // Skip unknown section + aZoneFileStream->skipRawData(2 * 8); + + return result; +} + +MenuFile ZoneFile_COD4_360::pParseAsset_MenuFile(QDataStream *aZoneFileStream) { + //MENU_FILE + MenuFile result; + + aZoneFileStream->skipRawData(4); // Separator + + // Parse menu def count + *aZoneFileStream >> result.menuCount; + + // Clearly misparsed, never have this much + if (result.menuCount > 1000) { + qDebug() << "Failure reported when parsing menu file."; + return result; + } + for (uint i = 0; i < result.menuCount; i++) { + Menu menu; + + aZoneFileStream->skipRawData(4); // Separator + + // Read in x_anim file name + char menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + while (menuFilepathChar != 0) { + menu.filePath += menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + } + aZoneFileStream->skipRawData(4); // Separator + + *aZoneFileStream >> menu.menuNamePtr; + + float menuRectX, menuRectY, menuRectWidth, menuRectHeight; + *aZoneFileStream >> menuRectX >> menuRectY >> menuRectWidth >> menuRectHeight; + menu.rect = QRectF(menuRectX, menuRectY, menuRectWidth, menuRectHeight); + + quint32 hAlignInt, vAlignInt; + *aZoneFileStream >> hAlignInt >> vAlignInt; + menu.hAlign = (MENU_H_ALIGNMENT)hAlignInt; + menu.vAlign = (MENU_V_ALIGNMENT)vAlignInt; + + float rectClientX, rectClientY, rectClientWidth, rectClientHeight; + *aZoneFileStream >> rectClientX >> rectClientY >> rectClientWidth >> rectClientHeight; + menu.clientRect = QRectF(rectClientX, rectClientY, rectClientWidth, rectClientHeight); + + quint32 hClientAlignInt, vClientAlignInt, styleInt, borderInt; + *aZoneFileStream >> hClientAlignInt >> vClientAlignInt >> menu.groupPtr + >> styleInt >> borderInt >> menu.ownerDraw >> menu.ownerDrawFlags + >> menu.borderSize >> menu.staticFlags >> menu.dynamicFlags >> menu.nextTime; + menu.hClientAlign = (MENU_H_ALIGNMENT)hClientAlignInt; + menu.vClientAlign = (MENU_V_ALIGNMENT)vClientAlignInt; + menu.style = (MENU_WINDOW_STYLE)styleInt; + menu.border = (MENU_WINDOW_BORDER)borderInt; + + float foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA, + backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA, + borderColorR, borderColorG, borderColorB, borderColorA, + outlineColorR, outlineColorG, outlineColorB, outlineColorA; + *aZoneFileStream >> foregroundColorR >> foregroundColorG >> foregroundColorB >> foregroundColorA + >> backgroundColorR >> backgroundColorG >> backgroundColorB >> backgroundColorA + >> borderColorR >> borderColorG >> borderColorB >> borderColorA + >> outlineColorR >> outlineColorG >> outlineColorB >> outlineColorA; + + menu.foregroundColor = QColor(foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA); + menu.backgroundColor = QColor(backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA); + menu.borderColor = QColor(borderColorR, borderColorG, borderColorB, borderColorA); + menu.outlineColor = QColor(outlineColorR, outlineColorG, outlineColorB, outlineColorA); + + *aZoneFileStream >> menu.materialPtr >> menu.fontPtr >> menu.fullScreen >> menu.itemCount + >> menu.fontIndex >> menu.cursorItem >> menu.fadeCycle >> menu.fadeClamp + >> menu.fadeAmount >> menu.fadeInAmount >> menu.blurRadius >> menu.onOpenPtr + >> menu.onFocusPtr >> menu.onClosePtr >> menu.onESCPtr >> menu.onKeyPtr + >> menu.visibleExpCount >> menu.expEntryPtr >> menu.allowedBindingPtr + >> menu.soundNamePtr >> menu.imageTrack; + + float focusColorR, focusColorG, focusColorB, focusColorA, + disabledColorR, disabledColorG, disabledColorB, disabledColorA; + *aZoneFileStream >> focusColorR >> focusColorG >> focusColorB >> focusColorA + >> disabledColorR >> disabledColorG >> disabledColorB >> disabledColorA; + menu.focusColor = QColor(focusColorR, focusColorG, focusColorB, focusColorA); + menu.disabledColor = QColor(disabledColorR, disabledColorG, disabledColorB, disabledColorA); + + *aZoneFileStream >> menu.rectXExpCount >> menu.rectXExpPtr >> menu.rectYExpCount >> menu.rectYExpPtr; + + aZoneFileStream->skipRawData(4); // Separator + + char menuDefNameChar; + int menuDefNameLen = 0; + *aZoneFileStream >> menuDefNameChar; + while (menuDefNameChar != 0 && menuDefNameLen < 30) { + menuDefNameLen++; + menu.name += menuDefNameChar; + *aZoneFileStream >> menuDefNameChar; + } + + char defStringChar; + int defStringLen = 0; + *aZoneFileStream >> defStringChar; + while (defStringChar != 0 && defStringLen < 30) { + defStringLen++; + menu.definition += defStringChar; + *aZoneFileStream >> defStringChar; + } + aZoneFileStream->skipRawData(4 * 10); + + *aZoneFileStream >> menu.itemWindowDefNamePtr; + + float itemRectX, itemRectY, itemRectWidth, itemRectHeight; + *aZoneFileStream >> itemRectX >> itemRectY >> itemRectWidth >> itemRectHeight; + menu.itemRect = QRectF(itemRectX, itemRectY, itemRectWidth, itemRectHeight); + + *aZoneFileStream >> menu.itemHAlignment >> menu.itemVAlignment >> menu.itemGroupPtr + >> menu.itemWindowStyle >> menu.itemWindowBorder >> menu.itemOwnerDraw + >> menu.itemOwnerDrawFlags >> menu.itemBorderSize >> menu.itemStaticFlags + >> menu.itemDynamicFlags >> menu.itemNextTime; + + float itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA, + itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA, + itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA, + itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA; + *aZoneFileStream >> itemForegroundColorR >> itemForegroundColorG >> itemForegroundColorB >> itemForegroundColorA + >> itemBackgroundColorR >> itemBackgroundColorG >> itemBackgroundColorB >> itemBackgroundColorA + >> itemBorderColorR >> itemBorderColorG >> itemBorderColorB >> itemBorderColorA + >> itemOutlineColorR >> itemOutlineColorG >> itemOutlineColorB >> itemOutlineColorA; + + menu.itemForegroundColor = QColor(itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA); + menu.itemBackgroundColor = QColor(itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA); + menu.itemBorderColor = QColor(itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA); + menu.itemOutlineColor = QColor(itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA); + + *aZoneFileStream >> menu.itemMaterialPtr; + + float itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight; + *aZoneFileStream >> itemTextRectX >> itemTextRectY >> itemTextRectWidth >> itemTextRectHeight; + menu.itemTextRect = QRectF(itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight); + + quint32 hItemTextAlignInt, vItemTextAlignInt, itemType, fontTypeInt, textStyleInt; + *aZoneFileStream >> hItemTextAlignInt >> vItemTextAlignInt >> itemType >> menu.dataType + >> menu.alignment >> fontTypeInt >> menu.textAlignMode >> menu.textalignx >> menu.textaligny + >> menu.textscale >> textStyleInt >> menu.gameMsgWindowIndex >> menu.gameMsgWindowMode + >> menu.testPtr >> menu.textSavegameInfo >> menu.parentPtr; + menu.itemText_hAlign = (MENU_H_ALIGNMENT)hItemTextAlignInt; + menu.itemText_vAlign = (MENU_V_ALIGNMENT)vItemTextAlignInt; + menu.itemType = (MENU_ITEM_TYPE)itemType; + menu.fontEnum = (MENU_FONT_TYPE)fontTypeInt; + menu.textStyle = (MENU_ITEM_TEXTSTYLE)textStyleInt; + + *aZoneFileStream >> menu.mouseEnterText >> menu.mouseExitText >> menu.mouseEnter >> menu.mouseExit + >> menu.action >> menu.onAccept >> menu.onFocus >> menu.leaveFocus >> menu.dvar >> menu.dvarTest + >> menu.keyHandlerPtr >> menu.enableDvarPtr >> menu.dvarFlags >> menu.focusSoundPtr + >> menu.special >> menu.cursorPos; + + // itemDefData_t typeData; + + // listBoxDef_s *listBox; + + *aZoneFileStream >> menu.startPos >> menu.endPos >> menu.drawPadding; + + *aZoneFileStream >> menu.elementWidth >> menu.elementHeight; + + *aZoneFileStream >> menu.elementStyle >> menu.numColumns; + + //columnInfo_s columnInfo[16]; + + *aZoneFileStream >> menu.doubleClickPtr; + + + *aZoneFileStream >> menu.notselectable >> menu.noScrollBars >> menu.usePaging; + + float itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA, + itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA, + itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA; + *aZoneFileStream >> itemSelectBorderColorR >> itemSelectBorderColorG >> itemSelectBorderColorB >> itemSelectBorderColorA + >> itemDisableColorR >> itemDisableColorG >> itemDisableColorB >> itemDisableColorA + >> itemFocusColorR >> itemFocusColorG >> itemFocusColorB >> itemFocusColorA; + menu.itemSelectBorderColor = QColor(itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA); + menu.itemDisableColor = QColor(itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA); + menu.itemFocusColor = QColor(itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA); + + *aZoneFileStream >> menu.selectIconPtr >> menu.backgroundItemListboxPtr >> menu.highlightTexturePtr; + + // editFieldDef_s *editField; + + *aZoneFileStream >> menu.minVal >> menu.maxVal >> menu.defVal >> menu.range >> menu.maxChars + >> menu.maxCharsGotoNext >> menu.maxPaintChars >> menu.paintOffset; + + // multiDef_s *multi; + + for (int i = 0; i < 32; i++) { + quint32 dvarList; + *aZoneFileStream >> dvarList; + menu.dvarListPtrs.push_back(dvarList); + } + + for (int i = 0; i < 32; i++) { + quint32 dvarStr; + *aZoneFileStream >> dvarStr; + menu.dvarStrPtrs.push_back(dvarStr); + } + + for (int i = 0; i < 32; i++) { + float dvarValue; + *aZoneFileStream >> dvarValue; + menu.dvarValues.push_back(dvarValue); + } + + *aZoneFileStream >> menu.count >> menu.strDef >> menu.enumDvarNamePtr; + aZoneFileStream->skipRawData(4); + //>> menu.dataPtr + *aZoneFileStream >> menu.itemImageTrack; + + qDebug() << aZoneFileStream->device()->pos(); + + //statement_s visibleExp; + //statement_s textExp; + //statement_s materialExp; + //statement_s rectXExp; + //statement_s rectYExp; + //statement_s rectWExp; + //statement_s rectHExp; + //statement_s foreColorAExp; + result.menuDefs << menu; + } + return result; +} + +void ZoneFile_COD4_360::pParseAsset_Weapon(QDataStream *aZoneFileStream) { + //WEAPON_FILE + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD4_360::pParseAsset_D3DBSP(QDataStream *aZoneFileStream) { + //D3DBSP_DUMP + Q_UNUSED(aZoneFileStream); +} + +StringTable ZoneFile_COD4_360::pParseAsset_StringTable(QDataStream *aZoneFileStream) { + StringTable result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.columnCount + >> result.rowCount; + + // Todo fix this + result.columnCount = 0; + result.rowCount = 0; + + aZoneFileStream->skipRawData(4); + + QString stringTableName; + char stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + while (stringTableNameChar != 0) { + result.name += stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + } + + for (quint32 i = 0; i < result.rowCount; i++) { + QByteArray pointerData(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pointerData.data(), 4); + result.tablePointers.push_back(pointerData.toHex()); + + aZoneFileStream->skipRawData(4); + } + + for (const QString &pointerAddr : result.tablePointers) { + QString leadingContent = ""; + if (pointerAddr == "FFFFFFFF") { + char leadingContentChar; + *aZoneFileStream >> leadingContentChar; + while (leadingContentChar != 0) { + leadingContent += leadingContentChar; + *aZoneFileStream >> leadingContentChar; + } + } else { + leadingContent = pointerAddr; + } + + QString content; + char contentChar; + *aZoneFileStream >> contentChar; + while (contentChar != 0) { + content += contentChar; + *aZoneFileStream >> contentChar; + } + result.content[leadingContent] = content; + } + return result; +} + +AssetType ZoneFile_COD4_360::AssetStrToEnum(const QString aAssetType) { + const QString cleanedType = aAssetType.toUpper(); + if (cleanedType == "00000021") { + return ASSET_RAW_FILE; + } else if (cleanedType == "0000001A") { + return ASSET_EFFECT; + } else if (cleanedType == "00000009") { + return ASSET_SOUND; + } else if (cleanedType == "00000004") { + return ASSET_ANIMATION; + } else if (cleanedType == "0000000C") { + return ASSET_COLLISION_MAP; + } else if (cleanedType == "00000021") { + return ASSET_STRING_TABLE; + } else if (cleanedType == "00000015") { + return ASSET_MENU; + } else if (cleanedType == "00000008") { + return ASSET_TECH_SET; + } else if (cleanedType == "00000018") { + return ASSET_LOCAL_STRING; + } else if (cleanedType == "00000011") { + return ASSET_GFX_MAP; + } else if (cleanedType == "00000012") { + return ASSET_LIGHT_DEF; + } else if (cleanedType == "00000014") { + return ASSET_FONT; + } else if (cleanedType == "00000005") { + return ASSET_MODEL; + } else if (cleanedType == "0000000D") { + return ASSET_D3DBSP; + } else if (cleanedType == "00000006") { + return ASSET_MATERIAL; + } else if (cleanedType == "0000000E") { + return ASSET_GAME_MAP_SP; + } else if (cleanedType == "0000000B") { + return ASSET_COL_MAP_SP; + } else if (cleanedType == "00000001") { + return ASSET_PHYS_PRESET; + } else if (cleanedType == "00000003") { + return ASSET_DESTRUCTIBLE; + } else if (cleanedType == "00000016") { + return ASSET_MENU; + } + return ASSET_NONE; +} + +QByteArray ZoneFile_COD4_360::GetBinaryData() { + QByteArray result; + + return result; +} diff --git a/libs/zonefile/360/zonefile_cod4_360.h b/libs/zonefile/360/zonefile_cod4_360.h new file mode 100644 index 0000000..173db2d --- /dev/null +++ b/libs/zonefile/360/zonefile_cod4_360.h @@ -0,0 +1,54 @@ +#ifndef ZONEFILE_COD4_360_H +#define ZONEFILE_COD4_360_H + +#include + +#include "zonefile.h" + +class ZoneFile_COD4_360 : public ZoneFile +{ +public: + ZoneFile_COD4_360(); + ~ZoneFile_COD4_360(); + + bool Load(const QByteArray aFileData) override; + AssetType AssetStrToEnum(const QString aAssetType) override; + + QByteArray GetBinaryData() override; + +private: + void pParseZoneHeader(QDataStream *aZoneFileStream) override; + quint32 pParseZoneSize(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsA(QDataStream *aZoneFileStream) override; + quint32 pParseZoneTagCount(QDataStream *aZoneFileStream) override; + quint32 pParseZoneRecordCount(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsB(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsC(QDataStream *aZoneFileStream) override; + QStringList pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) override; + QStringList pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) override; + AssetMap pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) override; + LocalString pParseAsset_LocalString(QDataStream *aZoneFileStream) override; + RawFile pParseAsset_RawFile(QDataStream *aZoneFileStream) override; + void pParseAsset_PhysPreset(QDataStream *aZoneFileStream) override; + Model pParseAsset_Model(QDataStream *aZoneFileStream) override; + Material pParseAsset_Material(QDataStream *aZoneFileStream) override; + Shader pParseAsset_Shader(QDataStream *aZoneFileStream) override; + TechSet pParseAsset_TechSet(QDataStream *aZoneFileStream) override; + Image pParseAsset_Image(QDataStream *aZoneFileStream) override; + SoundAsset pParseAsset_Sound(QDataStream *aZoneFileStream) override; + void pParseAsset_ColMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapSP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_LightDef(QDataStream *aZoneFileStream) override; + void pParseAsset_UIMap(QDataStream *aZoneFileStream) override; + void pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) override; + void pParseAsset_AIType(QDataStream *aZoneFileStream) override; + void pParseAsset_FX(QDataStream *aZoneFileStream) override; + Animation pParseAsset_Animation(QDataStream *aZoneFileStream) override; + MenuFile pParseAsset_MenuFile(QDataStream *aZoneFileStream) override; + void pParseAsset_Weapon(QDataStream *aZoneFileStream) override; + void pParseAsset_D3DBSP(QDataStream *aZoneFileStream) override; + StringTable pParseAsset_StringTable(QDataStream *aZoneFileStream) override; +}; + +#endif // ZONEFILE_COD4_360_H diff --git a/libs/zonefile/360/zonefile_cod5_360.cpp b/libs/zonefile/360/zonefile_cod5_360.cpp new file mode 100644 index 0000000..1149637 --- /dev/null +++ b/libs/zonefile/360/zonefile_cod5_360.cpp @@ -0,0 +1,1151 @@ +#include "zonefile_cod5_360.h" + +#include +#include +#include + +ZoneFile_COD5_360::ZoneFile_COD5_360() + : ZoneFile() { + +} + +ZoneFile_COD5_360::~ZoneFile_COD5_360() { + +} + +bool ZoneFile_COD5_360::Load(const QByteArray aFileData) { + // Open zone file as little endian stream + QDataStream zoneFileStream(aFileData); + zoneFileStream.setByteOrder(QDataStream::BigEndian); + + // Parse data from zone file header + pParseZoneHeader(&zoneFileStream); + SetRecords(pParseZoneIndex(&zoneFileStream, GetRecordCount())); + SetAssetMap(pParseAssets(&zoneFileStream, GetRecords())); + + return true; +} + +void ZoneFile_COD5_360::pParseZoneHeader(QDataStream *aZoneFileStream) { + SetSize(pParseZoneSize(aZoneFileStream)); + pParseZoneUnknownsA(aZoneFileStream); + + SetTagCount(pParseZoneTagCount(aZoneFileStream)); + pParseZoneUnknownsB(aZoneFileStream); + + SetRecordCount(pParseZoneRecordCount(aZoneFileStream)); + + quint32 tagCount = GetTagCount(); + if (tagCount) { + pParseZoneUnknownsC(aZoneFileStream); + SetTags(pParseZoneTags(aZoneFileStream, tagCount)); + } else { + aZoneFileStream->skipRawData(4); + } +} + +quint32 ZoneFile_COD5_360::pParseZoneSize(QDataStream *aZoneFileStream) { + quint32 zoneFileSize; + *aZoneFileStream >> zoneFileSize; + if (zoneFileSize <= 0) { + qDebug() << "Tried to open empty zone file!"; + exit(-1); + } + zoneFileSize += 36; + return zoneFileSize; +} + +/* + ParseZoneUnknownsA() + + Parses the 1st section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD5_360::pParseZoneUnknownsA(QDataStream *aZoneFileStream) { + // Byte 4-7, 8-11, 12-15: unknown + QByteArray unknown1(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown1.data(), 4); + + QByteArray unknown2(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown2.data(), 4); + + QByteArray unknown3(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown3.data(), 4); + + // Byte 16-19, 20-23: empty/unknown + QByteArray unknown4(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown4.data(), 4); + + QByteArray unknown5(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown5.data(), 4); + + // Byte 24-27: somehow related to the filesize, but smaller value + QByteArray unknown6(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown6.data(), 4); + + // Byte 28-31, 32-35: unknown + QByteArray unknown7(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown7.data(), 4); + + QByteArray unknown8(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown8.data(), 4); +} + +/* + ParseZoneTagCount() + + Parses the number of string tags in the zone index +*/ +quint32 ZoneFile_COD5_360::pParseZoneTagCount(QDataStream *aZoneFileStream) { + quint32 tagCount; + *aZoneFileStream >> tagCount; + return tagCount; +} + +/* + ParseZoneRecordCount() + + Parses the number of records in the zone index +*/ +quint32 ZoneFile_COD5_360::pParseZoneRecordCount(QDataStream *aZoneFileStream) { + quint32 recordCount; + *aZoneFileStream >> recordCount; + return recordCount; +} + +/* + ParseZoneUnknownsB() + + Parses the 2nd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD5_360::pParseZoneUnknownsB(QDataStream *aZoneFileStream) { + // Byte 44-47: Unknown/empty? + QByteArray unknown9(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown9.data(), 4); +} + +/* + pParseZoneUnknownsC() + + Parses the 3rd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD5_360::pParseZoneUnknownsC(QDataStream *aZoneFileStream) { + // Byte 40-43: Unknown/empty? + QByteArray unknown10(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown10.data(), 4); + + // Byte 44-47: Unknown/empty? + QByteArray unknown11(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown11.data(), 4); +} + +/* + ParseZoneTags() + + Parses the string tags ate the start of zone file +*/ +QStringList ZoneFile_COD5_360::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) { + QStringList tags; + + // Byte 48-51: Repeated separators? ÿÿÿÿ x i + aZoneFileStream->skipRawData(4 * (tagCount - 1)); + + // Parse tags/strings before index + QString zoneTag; + char zoneTagChar; + for (quint32 i = 0; i < tagCount - 1; i++) { + *aZoneFileStream >> zoneTagChar; + while (zoneTagChar != 0) { + zoneTag += zoneTagChar; + *aZoneFileStream >> zoneTagChar; + } + if (!zoneTag.isEmpty()) { + tags << zoneTag; + } + zoneTag.clear(); + } + return tags; +} + +/* + ParseZoneIndex() + + Parse the binary zone index data and populate table +*/ +QStringList ZoneFile_COD5_360::pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) { + QStringList result; + + // Don't parse if no records + if (!recordCount) { return result; } + + // Parse index & map found asset types + for (quint32 i = 0; i < recordCount; i++) { + // Skip record start + QByteArray rawAssetType(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rawAssetType.data(), 4); + result << rawAssetType.toHex(); + + // Skip separator + aZoneFileStream->skipRawData(4); + } + return result; +} + +AssetMap ZoneFile_COD5_360::pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) { + AssetMap result; + + for (int i = 0; i < assetOrder.size(); i++) { + const QString typeHex = assetOrder[i]; + const AssetType assetType = AssetStrToEnum(typeHex); + const QString typeStr = AssetEnumToStr(assetType); + + if (assetType == ASSET_LOCAL_STRING) { // localized string asset + result.localStrings << pParseAsset_LocalString(aZoneFileStream); + } else if (assetType == ASSET_RAW_FILE) { // gsc + auto rawFile = pParseAsset_RawFile(aZoneFileStream); + if (rawFile.length) { + result.rawFiles << rawFile; + } + } else if (assetType == ASSET_PHYS_PRESET) { // physpreset + pParseAsset_PhysPreset(aZoneFileStream); + } else if (assetType == ASSET_MODEL) { // xmodel + result.models << pParseAsset_Model(aZoneFileStream); + } else if (assetType == ASSET_MATERIAL) { // material + result.materials << pParseAsset_Material(aZoneFileStream); + } else if (assetType == ASSET_SHADER) { // pixelshader + pParseAsset_Shader(aZoneFileStream); + } else if (assetType == ASSET_TECH_SET) { // techset include + result.techSets << pParseAsset_TechSet(aZoneFileStream); + } else if (assetType == ASSET_IMAGE) { // image + result.images << pParseAsset_Image(aZoneFileStream); + } else if (assetType == ASSET_SOUND) { // loaded_sound + result.sounds << pParseAsset_Sound(aZoneFileStream); + } else if (assetType == ASSET_COLLISION_MAP) { // col_map_mp + pParseAsset_ColMapMP(aZoneFileStream); + } else if (assetType == ASSET_MP_MAP) { // game_map_sp + pParseAsset_GameMapSP(aZoneFileStream); + } else if (assetType == ASSET_SP_MAP) { // game_map_mp + pParseAsset_GameMapMP(aZoneFileStream); + } else if (assetType == ASSET_LIGHT_DEF) { // lightdef + pParseAsset_LightDef(aZoneFileStream); + } else if (assetType == ASSET_UI_MAP) { // ui_map + pParseAsset_UIMap(aZoneFileStream); + } else if (assetType == ASSET_SND_DRIVER_GLOBALS) { // snddriverglobals + pParseAsset_SNDDriverGlobals(aZoneFileStream); + } else if (assetType == ASSET_AI_TYPE) { // aitype + pParseAsset_AIType(aZoneFileStream); + } else if (assetType == ASSET_EFFECT) { // aitype + pParseAsset_FX(aZoneFileStream); + } else if (assetType == ASSET_ANIMATION) { // aitype + result.animations << pParseAsset_Animation(aZoneFileStream); + } else if (assetType == ASSET_STRING_TABLE) { // string_table + result.stringTables << pParseAsset_StringTable(aZoneFileStream); + } else if (assetType == ASSET_MENU) { // string_table + result.menuFiles << pParseAsset_MenuFile(aZoneFileStream); + } else if (assetType == ASSET_WEAPON) { // string_table + pParseAsset_Weapon(aZoneFileStream); + } else if (assetType == ASSET_D3DBSP) { // string_table + pParseAsset_D3DBSP(aZoneFileStream); + } + } + return result; +} + +LocalString ZoneFile_COD5_360::pParseAsset_LocalString(QDataStream *aZoneFileStream) { + LocalString result; + + quint32 stringPtr, aliasPtr; + *aZoneFileStream >> stringPtr >> aliasPtr; + if (stringPtr == 4294967295) { + // Parse local string asset contents + QString localStr; + char localStrChar; + *aZoneFileStream >> localStrChar; + while (localStrChar != 0) { + result.string += localStrChar; + *aZoneFileStream >> localStrChar; + } + } else { + result.string = "String Ptr: " + QString::number(stringPtr); + } + + if (aliasPtr == 4294967295) { + // Parse rawfile name + QString aliasName; + char aliasNameChar; + *aZoneFileStream >> aliasNameChar; + while (aliasNameChar != 0) { + result.alias += aliasNameChar; + *aZoneFileStream >> aliasNameChar; + } + } else { + result.string = "Alias Ptr: " + QString::number(aliasPtr); + } + + return result; +} + +RawFile ZoneFile_COD5_360::pParseAsset_RawFile(QDataStream *aZoneFileStream) { + RawFile result; + + // Skip start separator FF FF FF FF (pointer?) + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.length; + + // Skip unknown 4 byte data + aZoneFileStream->skipRawData(4); + + // Parse rawfile path + char scriptPathChar; + *aZoneFileStream >> scriptPathChar; + while (scriptPathChar != 0) { + result.path += scriptPathChar; + *aZoneFileStream >> scriptPathChar; + } + result.path.replace(",", ""); + + const QStringList pathParts = result.path.split('/'); + if (pathParts.size() == 0) { + qDebug() << "Failed to parse ff path! " << result.path; + exit(-1); + } + if (result.path.contains(".bik")) { + QByteArray bikData(result.length, Qt::Uninitialized); + aZoneFileStream->readRawData(bikData.data(), result.length); + + //QFile bikFile(QDir::currentPath() + "/" + rawFilePath.split('/').last()); + //qDebug() << bikFile.fileName(); + //if (!bikFile.open(QIODevice::WriteOnly)) { + // qWarning() << "Failed to open .bik file for writing!"; + // return; + //} + //qDebug() << QString("%1: %2").arg(rawFilePath).arg(bikFile.fileName()); + //bikFile.write(bikData); + } else { + // Parse gsc contents + char rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + while (rawFileContentsChar != 0 && rawFileContentsChar != -1) { + result.contents += rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + } + } + return result; +} + +void ZoneFile_COD5_360::pParseAsset_PhysPreset(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Model ZoneFile_COD5_360::pParseAsset_Model(QDataStream *aZoneFileStream) { + Model result; + + *aZoneFileStream >> result.namePtr >> result.tagCount >> result.rootTagCount + >> result.surfCount >> result.unknownCount >> result.boneNamePtr + >> result.parentListPtr >> result.quatsPtr >> result.transPtr + >> result.partClassPtr >> result.baseMatPtr + >> result.surfsPtr >> result.materialHandlesPtr; + + // Parse XModelLodInfo + for (int i = 1; i <= 4; i++) { + quint32 intDist; + *aZoneFileStream >> intDist; + + std::memcpy(&result.lodInfo[i].dist, &intDist, sizeof(result.lodInfo[i].dist)); + *aZoneFileStream >> result.lodInfo[i].numsurfs >> result.lodInfo[i].surfIndex; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.lodInfo[i].partBits[0] + >> result.lodInfo[i].partBits[1] + >> result.lodInfo[i].partBits[2] + >> result.lodInfo[i].partBits[3]; + } + + *aZoneFileStream >> result.collSurfsPtr >> result.numCollSurfs >> result.contents >> result.boneInfoPtr; + + quint32 intRadius, intMins[3], intMaxs[3]; + *aZoneFileStream >> intRadius >> intMins[0] >> intMins[1] + >> intMins[2] >> intMaxs[0] >> intMaxs[1] >> intMaxs[2]; + + std::memcpy(&result.radius, &intRadius, sizeof(result.radius)); + + std::memcpy(&result.mins[0], &intMins[0], sizeof(result.mins[0])); + std::memcpy(&result.mins[1], &intMins[1], sizeof(result.mins[1])); + std::memcpy(&result.mins[2], &intMins[2], sizeof(result.mins[2])); + + std::memcpy(&result.maxs[0], &intMaxs[0], sizeof(result.maxs[0])); + std::memcpy(&result.maxs[1], &intMaxs[1], sizeof(result.maxs[2])); + std::memcpy(&result.maxs[2], &intMaxs[2], sizeof(result.maxs[3])); + + *aZoneFileStream >> result.numLods >> result.collLod >> result.streamInfoPtr + >> result.memUsage >> result.flags >> result.physPresetPtr >> result.physGeomsPtr; + + // Parse model name + char modelNameChar; + *aZoneFileStream >> modelNameChar; + while (modelNameChar == 0) { + *aZoneFileStream >> modelNameChar; + } + while (modelNameChar != 0) { + result.modelName += modelNameChar; + *aZoneFileStream >> modelNameChar; + } + return result; +} + +Material ZoneFile_COD5_360::pParseAsset_Material(QDataStream *aZoneFileStream) { + Material result; + + *aZoneFileStream >> result.namePtr; + + //aZoneFileStream->skipRawData(23 * 4); + + for (int i = 0; i < 23; i++) { + qint32 unknownPtr; + *aZoneFileStream >> unknownPtr; + result.pointers << unknownPtr; + } + + if (result.namePtr == -1) { + aZoneFileStream->skipRawData(1); + + QString materialName; + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + result.name += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + } + + aZoneFileStream->skipRawData(3 * 4); + + qint32 compressionPtr, compression, unknownSectionPtr; + *aZoneFileStream >> compressionPtr; + if (compressionPtr == -1) { + *aZoneFileStream >> compression; + + *aZoneFileStream >> unknownSectionPtr; + if (unknownSectionPtr == -2) { + aZoneFileStream->skipRawData(6 * 4); + } + } + + qint32 imageNamePtr; + *aZoneFileStream >> imageNamePtr; + if (imageNamePtr == -1) { + QString imageName; + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + imageName += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + } + + QByteArray compressionData(4, Qt::Uninitialized); + QString compressionStr; + if (compressionPtr == -1) { + aZoneFileStream->skipRawData(2 * 4); + aZoneFileStream->readRawData(compressionData.data(), 4); + aZoneFileStream->skipRawData(4); + compressionStr = QString::fromUtf8(compressionData); + aZoneFileStream->skipRawData(4); + } + aZoneFileStream->skipRawData(4); + + return result; +} + +Shader ZoneFile_COD5_360::pParseAsset_Shader(QDataStream *aZoneFileStream) { + Shader result = Shader(); + + quint8 minorVersion, majorVersion; + *aZoneFileStream >> minorVersion >> majorVersion; + + quint32 magic; + *aZoneFileStream >> magic; + + // Verify .fxc magic + if (magic != 65534 && magic != 65535) { return result; } + + SHADER_TYPE type = SHADER_NONE; + quint16 rawShaderType; + *aZoneFileStream >> rawShaderType; + if (rawShaderType == 65535) { // Pixel shader + type = SHADER_PIXEL; + } else if (rawShaderType == 65534) { // Vertex shader + type = SHADER_VERTEX; + } + Q_UNUSED(type); + + while (true) { + quint32 instructionToken; + *aZoneFileStream >> instructionToken; + + SHADER_OPCODE opCode = (SHADER_OPCODE)(instructionToken & 0xffff); + + int size; + if (opCode == OPCODE_End) { + break; + } else if (opCode == OPCODE_Comment) { + size = (int)((instructionToken >> 16) & 0x7FFF); + } else { + size = (int)((instructionToken >> 24) & 0x0f); + } + Q_UNUSED(size); + } + + + return result; +} + +TechSet ZoneFile_COD5_360::pParseAsset_TechSet(QDataStream *aZoneFileStream) { + TechSet result; + + qint32 namePtr; + *aZoneFileStream >> namePtr; + + + for (int i = 0; i < 53; i++) { + quint32 ptr; + *aZoneFileStream >> ptr; + + result.pointers << ptr; + } + + //aZoneFileStream->skipRawData(53 * 4); + + if (namePtr == -1) { + aZoneFileStream->skipRawData(1); + + // Parse techset name + char techSetNameChar; + *aZoneFileStream >> techSetNameChar; + while (techSetNameChar != 0) { + result.name += techSetNameChar; + *aZoneFileStream >> techSetNameChar; + } + } + + //result.name.replace(",", ""); + return result; +} + +Image ZoneFile_COD5_360::pParseAsset_Image(QDataStream *aZoneFileStream) { + Image result; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknowna >> result.unknownb + >> result.unknownc >> result.unknownd + >> result.unknowne >> result.unknownf + >> result.unknowng; + + aZoneFileStream->skipRawData(15 * 4); + *aZoneFileStream >> result.unknownh >> result.unknowni; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknownj; + + aZoneFileStream->skipRawData(4); + + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + result.materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + result.materialName.replace(",", ""); + + if (result.unknowna) { + *aZoneFileStream >> result.unknownk; + *aZoneFileStream >> result.unknownl; + *aZoneFileStream >> result.unknownm; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown1; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown2 >> result.unknown3 + >> result.size1 >> result.size2 + >> result.unknown4 >> result.unknown5; + + aZoneFileStream->skipRawData(4); + + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + result.name += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + + *aZoneFileStream >> result.unknown6 >> result.unknown7; + + QByteArray compressionData(8, Qt::Uninitialized); + aZoneFileStream->readRawData(compressionData.data(), 8); + if (compressionData.contains("DXT1")) { + result.compression = COMPRESSION_DXT1; + } else if (compressionData.contains("DXT3")) { + result.compression = COMPRESSION_DXT3; + } else if (compressionData.contains("DXT5")) { + result.compression = COMPRESSION_DXT5; + } else { + result.compression = COMPRESSION_NONE; + } + + *aZoneFileStream >> result.unknown8 >> result.unknown9; + } + + return result; +} + +SoundAsset ZoneFile_COD5_360::pParseAsset_Sound(QDataStream *aZoneFileStream) { + SoundAsset result; + + QByteArray rootNamePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rootNamePtr.data(), 4); + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.count; + + if (rootNamePtr.toHex() == "ffffffff") { + // Read in sound file name + char soundNameChar; + *aZoneFileStream >> soundNameChar; + while (soundNameChar != 0) { + result.name += soundNameChar; + *aZoneFileStream >> soundNameChar; + } + } + + int tagCount = 0; + int resultCount = 0; + for (quint32 i = 0; i < result.count; i++) { + aZoneFileStream->skipRawData(12); + + QByteArray tagPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(tagPtr.data(), 4); + + if (tagPtr.toHex() == "ffffffff") { + tagCount++; + } + aZoneFileStream->skipRawData(4); + + QByteArray pathPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pathPtr.data(), 4); + + if (pathPtr.toHex() == "ffffffff") { + resultCount++; + } + + aZoneFileStream->skipRawData(160); + } + + for (int i = 0; i < tagCount; i++) { + // Read in tag? + QString tag; + char tagChar; + *aZoneFileStream >> tagChar; + while (tagChar != 0) { + tag += tagChar; + *aZoneFileStream >> tagChar; + } + } + + for (int i = 0; i < resultCount; i++) { + Sound sound; + + if (aZoneFileStream->device()->peek(12).toHex().contains("ffffffff00000000")) { + aZoneFileStream->skipRawData(12); + } + + aZoneFileStream->skipRawData(8); + + QByteArray aliasPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(aliasPtr.data(), 4); + + QByteArray namePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(namePtr.data(), 4); + + *aZoneFileStream >> sound.dataLength; + + if (aliasPtr.toHex() == "ffffffff") { + // Read in sound alias name + char soundAliasChar; + *aZoneFileStream >> soundAliasChar; + while (soundAliasChar != 0) { + sound.alias += soundAliasChar; + *aZoneFileStream >> soundAliasChar; + } + } + + if (aZoneFileStream->device()->peek(4) == "RIFF") { + sound.path = sound.alias; + sound.alias = ""; + } else if (namePtr.toHex() == "ffffffff") { + // Read in sound file path + char soundPathChar; + *aZoneFileStream >> soundPathChar; + while (soundPathChar != 0) { + sound.path += soundPathChar; + *aZoneFileStream >> soundPathChar; + } + sound.path.replace(",", ""); + } + + if (sound.dataLength) { + QByteArray data(sound.dataLength, Qt::Uninitialized); + aZoneFileStream->readRawData(data.data(), sound.dataLength); + sound.data = data; + } + result.sounds.append(sound); + } + + return result; +} + +void ZoneFile_COD5_360::pParseAsset_ColMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD5_360::pParseAsset_GameMapSP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD5_360::pParseAsset_GameMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD5_360::pParseAsset_LightDef(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD5_360::pParseAsset_UIMap(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD5_360::pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD5_360::pParseAsset_AIType(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD5_360::pParseAsset_FX(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Animation ZoneFile_COD5_360::pParseAsset_Animation(QDataStream *aZoneFileStream) { + Animation result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.dataByteCount + >> result.dataShortCount + >> result.dataIntCount + >> result.randomDataByteCount + >> result.randomDataIntCount + >> result.numframes + >> result.isLooped + >> result.isDelta + >> result.noneRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.normalTranslatedBoneCount + >> result.preciseTranslatedBoneCount + >> result.staticTranslatedBoneCount + >> result.noneTranslatedBoneCount + >> result.totalBoneCount + >> result.otherBoneCount1 + >> result.otherBoneCount2 + >> result.notifyCount + >> result.assetType + >> result.pad + >> result.randomDataShortCount + >> result.indexCount + >> result.frameRate + >> result.frequency + >> result.boneIDsPtr + >> result.dataBytePtr + >> result.dataShortPtr + >> result.dataIntPtr + >> result.randomDataShortPtr + >> result.randomDataBytePtr + >> result.randomDataIntPtr + >> result.longIndiciesPtr + >> result.notificationsPtr + >> result.deltaPartsPtr; + + // Read in x_anim file name + QString xAnimName; + char xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + while (xAnimNameChar != 0) { + result.name += xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + } + + // Parse x_anim index header + QVector sectionLengths; + for (int i = 0; i < result.numframes; i++) { + quint8 sectionlength; + *aZoneFileStream >> sectionlength; + sectionLengths.push_back(sectionlength); + // Skip padding + aZoneFileStream->skipRawData(1); + } + // Skip unknown section + aZoneFileStream->skipRawData(2 * 8); + + return result; +} + +MenuFile ZoneFile_COD5_360::pParseAsset_MenuFile(QDataStream *aZoneFileStream) { + //MENU_FILE + MenuFile result; + + aZoneFileStream->skipRawData(4); // Separator + + // Parse menu def count + *aZoneFileStream >> result.menuCount; + + // Clearly misparsed, never have this much + if (result.menuCount > 1000) { + qDebug() << "Failure reported when parsing menu file."; + return result; + } + for (uint i = 0; i < result.menuCount; i++) { + Menu menu; + + aZoneFileStream->skipRawData(4); // Separator + + // Read in x_anim file name + char menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + while (menuFilepathChar != 0) { + menu.filePath += menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + } + aZoneFileStream->skipRawData(4); // Separator + + *aZoneFileStream >> menu.menuNamePtr; + + float menuRectX, menuRectY, menuRectWidth, menuRectHeight; + *aZoneFileStream >> menuRectX >> menuRectY >> menuRectWidth >> menuRectHeight; + menu.rect = QRectF(menuRectX, menuRectY, menuRectWidth, menuRectHeight); + + quint32 hAlignInt, vAlignInt; + *aZoneFileStream >> hAlignInt >> vAlignInt; + menu.hAlign = (MENU_H_ALIGNMENT)hAlignInt; + menu.vAlign = (MENU_V_ALIGNMENT)vAlignInt; + + float rectClientX, rectClientY, rectClientWidth, rectClientHeight; + *aZoneFileStream >> rectClientX >> rectClientY >> rectClientWidth >> rectClientHeight; + menu.clientRect = QRectF(rectClientX, rectClientY, rectClientWidth, rectClientHeight); + + quint32 hClientAlignInt, vClientAlignInt, styleInt, borderInt; + *aZoneFileStream >> hClientAlignInt >> vClientAlignInt >> menu.groupPtr + >> styleInt >> borderInt >> menu.ownerDraw >> menu.ownerDrawFlags + >> menu.borderSize >> menu.staticFlags >> menu.dynamicFlags >> menu.nextTime; + menu.hClientAlign = (MENU_H_ALIGNMENT)hClientAlignInt; + menu.vClientAlign = (MENU_V_ALIGNMENT)vClientAlignInt; + menu.style = (MENU_WINDOW_STYLE)styleInt; + menu.border = (MENU_WINDOW_BORDER)borderInt; + + float foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA, + backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA, + borderColorR, borderColorG, borderColorB, borderColorA, + outlineColorR, outlineColorG, outlineColorB, outlineColorA; + *aZoneFileStream >> foregroundColorR >> foregroundColorG >> foregroundColorB >> foregroundColorA + >> backgroundColorR >> backgroundColorG >> backgroundColorB >> backgroundColorA + >> borderColorR >> borderColorG >> borderColorB >> borderColorA + >> outlineColorR >> outlineColorG >> outlineColorB >> outlineColorA; + + menu.foregroundColor = QColor(foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA); + menu.backgroundColor = QColor(backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA); + menu.borderColor = QColor(borderColorR, borderColorG, borderColorB, borderColorA); + menu.outlineColor = QColor(outlineColorR, outlineColorG, outlineColorB, outlineColorA); + + *aZoneFileStream >> menu.materialPtr >> menu.fontPtr >> menu.fullScreen >> menu.itemCount + >> menu.fontIndex >> menu.cursorItem >> menu.fadeCycle >> menu.fadeClamp + >> menu.fadeAmount >> menu.fadeInAmount >> menu.blurRadius >> menu.onOpenPtr + >> menu.onFocusPtr >> menu.onClosePtr >> menu.onESCPtr >> menu.onKeyPtr + >> menu.visibleExpCount >> menu.expEntryPtr >> menu.allowedBindingPtr + >> menu.soundNamePtr >> menu.imageTrack; + + float focusColorR, focusColorG, focusColorB, focusColorA, + disabledColorR, disabledColorG, disabledColorB, disabledColorA; + *aZoneFileStream >> focusColorR >> focusColorG >> focusColorB >> focusColorA + >> disabledColorR >> disabledColorG >> disabledColorB >> disabledColorA; + menu.focusColor = QColor(focusColorR, focusColorG, focusColorB, focusColorA); + menu.disabledColor = QColor(disabledColorR, disabledColorG, disabledColorB, disabledColorA); + + *aZoneFileStream >> menu.rectXExpCount >> menu.rectXExpPtr >> menu.rectYExpCount >> menu.rectYExpPtr; + + aZoneFileStream->skipRawData(4); // Separator + + char menuDefNameChar; + int menuDefNameLen = 0; + *aZoneFileStream >> menuDefNameChar; + while (menuDefNameChar != 0 && menuDefNameLen < 30) { + menuDefNameLen++; + menu.name += menuDefNameChar; + *aZoneFileStream >> menuDefNameChar; + } + + char defStringChar; + int defStringLen = 0; + *aZoneFileStream >> defStringChar; + while (defStringChar != 0 && defStringLen < 30) { + defStringLen++; + menu.definition += defStringChar; + *aZoneFileStream >> defStringChar; + } + aZoneFileStream->skipRawData(4 * 10); + + *aZoneFileStream >> menu.itemWindowDefNamePtr; + + float itemRectX, itemRectY, itemRectWidth, itemRectHeight; + *aZoneFileStream >> itemRectX >> itemRectY >> itemRectWidth >> itemRectHeight; + menu.itemRect = QRectF(itemRectX, itemRectY, itemRectWidth, itemRectHeight); + + *aZoneFileStream >> menu.itemHAlignment >> menu.itemVAlignment >> menu.itemGroupPtr + >> menu.itemWindowStyle >> menu.itemWindowBorder >> menu.itemOwnerDraw + >> menu.itemOwnerDrawFlags >> menu.itemBorderSize >> menu.itemStaticFlags + >> menu.itemDynamicFlags >> menu.itemNextTime; + + float itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA, + itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA, + itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA, + itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA; + *aZoneFileStream >> itemForegroundColorR >> itemForegroundColorG >> itemForegroundColorB >> itemForegroundColorA + >> itemBackgroundColorR >> itemBackgroundColorG >> itemBackgroundColorB >> itemBackgroundColorA + >> itemBorderColorR >> itemBorderColorG >> itemBorderColorB >> itemBorderColorA + >> itemOutlineColorR >> itemOutlineColorG >> itemOutlineColorB >> itemOutlineColorA; + + menu.itemForegroundColor = QColor(itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA); + menu.itemBackgroundColor = QColor(itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA); + menu.itemBorderColor = QColor(itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA); + menu.itemOutlineColor = QColor(itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA); + + *aZoneFileStream >> menu.itemMaterialPtr; + + float itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight; + *aZoneFileStream >> itemTextRectX >> itemTextRectY >> itemTextRectWidth >> itemTextRectHeight; + menu.itemTextRect = QRectF(itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight); + + quint32 hItemTextAlignInt, vItemTextAlignInt, itemType, fontTypeInt, textStyleInt; + *aZoneFileStream >> hItemTextAlignInt >> vItemTextAlignInt >> itemType >> menu.dataType + >> menu.alignment >> fontTypeInt >> menu.textAlignMode >> menu.textalignx >> menu.textaligny + >> menu.textscale >> textStyleInt >> menu.gameMsgWindowIndex >> menu.gameMsgWindowMode + >> menu.testPtr >> menu.textSavegameInfo >> menu.parentPtr; + menu.itemText_hAlign = (MENU_H_ALIGNMENT)hItemTextAlignInt; + menu.itemText_vAlign = (MENU_V_ALIGNMENT)vItemTextAlignInt; + menu.itemType = (MENU_ITEM_TYPE)itemType; + menu.fontEnum = (MENU_FONT_TYPE)fontTypeInt; + menu.textStyle = (MENU_ITEM_TEXTSTYLE)textStyleInt; + + *aZoneFileStream >> menu.mouseEnterText >> menu.mouseExitText >> menu.mouseEnter >> menu.mouseExit + >> menu.action >> menu.onAccept >> menu.onFocus >> menu.leaveFocus >> menu.dvar >> menu.dvarTest + >> menu.keyHandlerPtr >> menu.enableDvarPtr >> menu.dvarFlags >> menu.focusSoundPtr + >> menu.special >> menu.cursorPos; + + // itemDefData_t typeData; + + // listBoxDef_s *listBox; + + *aZoneFileStream >> menu.startPos >> menu.endPos >> menu.drawPadding; + + *aZoneFileStream >> menu.elementWidth >> menu.elementHeight; + + *aZoneFileStream >> menu.elementStyle >> menu.numColumns; + + //columnInfo_s columnInfo[16]; + + *aZoneFileStream >> menu.doubleClickPtr; + + + *aZoneFileStream >> menu.notselectable >> menu.noScrollBars >> menu.usePaging; + + float itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA, + itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA, + itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA; + *aZoneFileStream >> itemSelectBorderColorR >> itemSelectBorderColorG >> itemSelectBorderColorB >> itemSelectBorderColorA + >> itemDisableColorR >> itemDisableColorG >> itemDisableColorB >> itemDisableColorA + >> itemFocusColorR >> itemFocusColorG >> itemFocusColorB >> itemFocusColorA; + menu.itemSelectBorderColor = QColor(itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA); + menu.itemDisableColor = QColor(itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA); + menu.itemFocusColor = QColor(itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA); + + *aZoneFileStream >> menu.selectIconPtr >> menu.backgroundItemListboxPtr >> menu.highlightTexturePtr; + + // editFieldDef_s *editField; + + *aZoneFileStream >> menu.minVal >> menu.maxVal >> menu.defVal >> menu.range >> menu.maxChars + >> menu.maxCharsGotoNext >> menu.maxPaintChars >> menu.paintOffset; + + // multiDef_s *multi; + + for (int i = 0; i < 32; i++) { + quint32 dvarList; + *aZoneFileStream >> dvarList; + menu.dvarListPtrs.push_back(dvarList); + } + + for (int i = 0; i < 32; i++) { + quint32 dvarStr; + *aZoneFileStream >> dvarStr; + menu.dvarStrPtrs.push_back(dvarStr); + } + + for (int i = 0; i < 32; i++) { + float dvarValue; + *aZoneFileStream >> dvarValue; + menu.dvarValues.push_back(dvarValue); + } + + *aZoneFileStream >> menu.count >> menu.strDef >> menu.enumDvarNamePtr; + aZoneFileStream->skipRawData(4); + //>> menu.dataPtr + *aZoneFileStream >> menu.itemImageTrack; + + qDebug() << aZoneFileStream->device()->pos(); + + //statement_s visibleExp; + //statement_s textExp; + //statement_s materialExp; + //statement_s rectXExp; + //statement_s rectYExp; + //statement_s rectWExp; + //statement_s rectHExp; + //statement_s foreColorAExp; + result.menuDefs << menu; + } + return result; +} + +void ZoneFile_COD5_360::pParseAsset_Weapon(QDataStream *aZoneFileStream) { + //WEAPON_FILE + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD5_360::pParseAsset_D3DBSP(QDataStream *aZoneFileStream) { + //D3DBSP_DUMP + Q_UNUSED(aZoneFileStream); +} + +StringTable ZoneFile_COD5_360::pParseAsset_StringTable(QDataStream *aZoneFileStream) { + StringTable result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.columnCount + >> result.rowCount; + + // Todo fix this + result.columnCount = 0; + result.rowCount = 0; + + aZoneFileStream->skipRawData(4); + + QString stringTableName; + char stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + while (stringTableNameChar != 0) { + result.name += stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + } + + for (quint32 i = 0; i < result.rowCount; i++) { + QByteArray pointerData(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pointerData.data(), 4); + result.tablePointers.push_back(pointerData.toHex()); + + aZoneFileStream->skipRawData(4); + } + + for (const QString &pointerAddr : result.tablePointers) { + QString leadingContent = ""; + if (pointerAddr == "FFFFFFFF") { + char leadingContentChar; + *aZoneFileStream >> leadingContentChar; + while (leadingContentChar != 0) { + leadingContent += leadingContentChar; + *aZoneFileStream >> leadingContentChar; + } + } else { + leadingContent = pointerAddr; + } + + QString content; + char contentChar; + *aZoneFileStream >> contentChar; + while (contentChar != 0) { + content += contentChar; + *aZoneFileStream >> contentChar; + } + result.content[leadingContent] = content; + } + return result; +} + +AssetType ZoneFile_COD5_360::AssetStrToEnum(const QString aAssetType) { + const QString cleanedType = aAssetType.toUpper(); + if (cleanedType == "00000021") { + return ASSET_RAW_FILE; + } else if (cleanedType == "0000001A") { + return ASSET_EFFECT; + } else if (cleanedType == "00000009") { + return ASSET_SOUND; + } else if (cleanedType == "00000004") { + return ASSET_ANIMATION; + } else if (cleanedType == "0000000C") { + return ASSET_COLLISION_MAP; + } else if (cleanedType == "00000021") { + return ASSET_STRING_TABLE; + } else if (cleanedType == "00000015") { + return ASSET_MENU; + } else if (cleanedType == "00000008") { + return ASSET_TECH_SET; + } else if (cleanedType == "00000018") { + return ASSET_LOCAL_STRING; + } else if (cleanedType == "00000011") { + return ASSET_GFX_MAP; + } else if (cleanedType == "00000012") { + return ASSET_LIGHT_DEF; + } else if (cleanedType == "00000014") { + return ASSET_FONT; + } else if (cleanedType == "00000005") { + return ASSET_MODEL; + } else if (cleanedType == "0000000D") { + return ASSET_D3DBSP; + } else if (cleanedType == "00000006") { + return ASSET_MATERIAL; + } else if (cleanedType == "0000000E") { + return ASSET_GAME_MAP_SP; + } else if (cleanedType == "0000000B") { + return ASSET_COL_MAP_SP; + } else if (cleanedType == "00000001") { + return ASSET_PHYS_PRESET; + } else if (cleanedType == "00000003") { + return ASSET_DESTRUCTIBLE; + } else if (cleanedType == "00000016") { + return ASSET_MENU; + } + return ASSET_NONE; +} + +QByteArray ZoneFile_COD5_360::GetBinaryData() { + QByteArray result; + + return result; +} diff --git a/libs/zonefile/360/zonefile_cod5_360.h b/libs/zonefile/360/zonefile_cod5_360.h new file mode 100644 index 0000000..b46409d --- /dev/null +++ b/libs/zonefile/360/zonefile_cod5_360.h @@ -0,0 +1,54 @@ +#ifndef ZONEFILE_COD5_360_H +#define ZONEFILE_COD5_360_H + +#include + +#include "zonefile.h" + +class ZoneFile_COD5_360 : public ZoneFile +{ +public: + ZoneFile_COD5_360(); + ~ZoneFile_COD5_360(); + + bool Load(const QByteArray aFileData) override; + AssetType AssetStrToEnum(const QString aAssetType) override; + + QByteArray GetBinaryData() override; + +private: + void pParseZoneHeader(QDataStream *aZoneFileStream) override; + quint32 pParseZoneSize(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsA(QDataStream *aZoneFileStream) override; + quint32 pParseZoneTagCount(QDataStream *aZoneFileStream) override; + quint32 pParseZoneRecordCount(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsB(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsC(QDataStream *aZoneFileStream) override; + QStringList pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) override; + QStringList pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) override; + AssetMap pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) override; + LocalString pParseAsset_LocalString(QDataStream *aZoneFileStream) override; + RawFile pParseAsset_RawFile(QDataStream *aZoneFileStream) override; + void pParseAsset_PhysPreset(QDataStream *aZoneFileStream) override; + Model pParseAsset_Model(QDataStream *aZoneFileStream) override; + Material pParseAsset_Material(QDataStream *aZoneFileStream) override; + Shader pParseAsset_Shader(QDataStream *aZoneFileStream) override; + TechSet pParseAsset_TechSet(QDataStream *aZoneFileStream) override; + Image pParseAsset_Image(QDataStream *aZoneFileStream) override; + SoundAsset pParseAsset_Sound(QDataStream *aZoneFileStream) override; + void pParseAsset_ColMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapSP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_LightDef(QDataStream *aZoneFileStream) override; + void pParseAsset_UIMap(QDataStream *aZoneFileStream) override; + void pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) override; + void pParseAsset_AIType(QDataStream *aZoneFileStream) override; + void pParseAsset_FX(QDataStream *aZoneFileStream) override; + Animation pParseAsset_Animation(QDataStream *aZoneFileStream) override; + MenuFile pParseAsset_MenuFile(QDataStream *aZoneFileStream) override; + void pParseAsset_Weapon(QDataStream *aZoneFileStream) override; + void pParseAsset_D3DBSP(QDataStream *aZoneFileStream) override; + StringTable pParseAsset_StringTable(QDataStream *aZoneFileStream) override; +}; + +#endif // ZONEFILE_COD5_360_H diff --git a/libs/zonefile/360/zonefile_cod6_360.cpp b/libs/zonefile/360/zonefile_cod6_360.cpp new file mode 100644 index 0000000..aaf7d38 --- /dev/null +++ b/libs/zonefile/360/zonefile_cod6_360.cpp @@ -0,0 +1,1151 @@ +#include "zonefile_cod6_360.h" + +#include +#include +#include + +ZoneFile_COD6_360::ZoneFile_COD6_360() + : ZoneFile() { + +} + +ZoneFile_COD6_360::~ZoneFile_COD6_360() { + +} + +bool ZoneFile_COD6_360::Load(const QByteArray aFileData) { + // Open zone file as little endian stream + QDataStream zoneFileStream(aFileData); + zoneFileStream.setByteOrder(QDataStream::BigEndian); + + // Parse data from zone file header + pParseZoneHeader(&zoneFileStream); + SetRecords(pParseZoneIndex(&zoneFileStream, GetRecordCount())); + SetAssetMap(pParseAssets(&zoneFileStream, GetRecords())); + + return true; +} + +void ZoneFile_COD6_360::pParseZoneHeader(QDataStream *aZoneFileStream) { + SetSize(pParseZoneSize(aZoneFileStream)); + pParseZoneUnknownsA(aZoneFileStream); + + SetTagCount(pParseZoneTagCount(aZoneFileStream)); + pParseZoneUnknownsB(aZoneFileStream); + + SetRecordCount(pParseZoneRecordCount(aZoneFileStream)); + + quint32 tagCount = GetTagCount(); + if (tagCount) { + pParseZoneUnknownsC(aZoneFileStream); + SetTags(pParseZoneTags(aZoneFileStream, tagCount)); + } else { + aZoneFileStream->skipRawData(4); + } +} + +quint32 ZoneFile_COD6_360::pParseZoneSize(QDataStream *aZoneFileStream) { + quint32 zoneFileSize; + *aZoneFileStream >> zoneFileSize; + if (zoneFileSize <= 0) { + qDebug() << "Tried to open empty zone file!"; + exit(-1); + } + zoneFileSize += 36; + return zoneFileSize; +} + +/* + ParseZoneUnknownsA() + + Parses the 1st section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD6_360::pParseZoneUnknownsA(QDataStream *aZoneFileStream) { + // Byte 4-7, 8-11, 12-15: unknown + QByteArray unknown1(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown1.data(), 4); + + QByteArray unknown2(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown2.data(), 4); + + QByteArray unknown3(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown3.data(), 4); + + // Byte 16-19, 20-23: empty/unknown + QByteArray unknown4(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown4.data(), 4); + + QByteArray unknown5(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown5.data(), 4); + + // Byte 24-27: somehow related to the filesize, but smaller value + QByteArray unknown6(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown6.data(), 4); + + // Byte 28-31, 32-35: unknown + QByteArray unknown7(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown7.data(), 4); + + QByteArray unknown8(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown8.data(), 4); +} + +/* + ParseZoneTagCount() + + Parses the number of string tags in the zone index +*/ +quint32 ZoneFile_COD6_360::pParseZoneTagCount(QDataStream *aZoneFileStream) { + quint32 tagCount; + *aZoneFileStream >> tagCount; + return tagCount; +} + +/* + ParseZoneRecordCount() + + Parses the number of records in the zone index +*/ +quint32 ZoneFile_COD6_360::pParseZoneRecordCount(QDataStream *aZoneFileStream) { + quint32 recordCount; + *aZoneFileStream >> recordCount; + return recordCount; +} + +/* + ParseZoneUnknownsB() + + Parses the 2nd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD6_360::pParseZoneUnknownsB(QDataStream *aZoneFileStream) { + // Byte 44-47: Unknown/empty? + QByteArray unknown9(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown9.data(), 4); +} + +/* + pParseZoneUnknownsC() + + Parses the 3rd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD6_360::pParseZoneUnknownsC(QDataStream *aZoneFileStream) { + // Byte 40-43: Unknown/empty? + QByteArray unknown10(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown10.data(), 4); + + // Byte 44-47: Unknown/empty? + QByteArray unknown11(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown11.data(), 4); +} + +/* + ParseZoneTags() + + Parses the string tags ate the start of zone file +*/ +QStringList ZoneFile_COD6_360::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) { + QStringList tags; + + // Byte 48-51: Repeated separators? ÿÿÿÿ x i + aZoneFileStream->skipRawData(4 * (tagCount - 1)); + + // Parse tags/strings before index + QString zoneTag; + char zoneTagChar; + for (quint32 i = 0; i < tagCount - 1; i++) { + *aZoneFileStream >> zoneTagChar; + while (zoneTagChar != 0) { + zoneTag += zoneTagChar; + *aZoneFileStream >> zoneTagChar; + } + if (!zoneTag.isEmpty()) { + tags << zoneTag; + } + zoneTag.clear(); + } + return tags; +} + +/* + ParseZoneIndex() + + Parse the binary zone index data and populate table +*/ +QStringList ZoneFile_COD6_360::pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) { + QStringList result; + + // Don't parse if no records + if (!recordCount) { return result; } + + // Parse index & map found asset types + for (quint32 i = 0; i < recordCount; i++) { + // Skip record start + QByteArray rawAssetType(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rawAssetType.data(), 4); + result << rawAssetType.toHex(); + + // Skip separator + aZoneFileStream->skipRawData(4); + } + return result; +} + +AssetMap ZoneFile_COD6_360::pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) { + AssetMap result; + + for (int i = 0; i < assetOrder.size(); i++) { + const QString typeHex = assetOrder[i]; + const AssetType assetType = AssetStrToEnum(typeHex); + const QString typeStr = AssetEnumToStr(assetType); + + if (assetType == ASSET_LOCAL_STRING) { // localized string asset + result.localStrings << pParseAsset_LocalString(aZoneFileStream); + } else if (assetType == ASSET_RAW_FILE) { // gsc + auto rawFile = pParseAsset_RawFile(aZoneFileStream); + if (rawFile.length) { + result.rawFiles << rawFile; + } + } else if (assetType == ASSET_PHYS_PRESET) { // physpreset + pParseAsset_PhysPreset(aZoneFileStream); + } else if (assetType == ASSET_MODEL) { // xmodel + result.models << pParseAsset_Model(aZoneFileStream); + } else if (assetType == ASSET_MATERIAL) { // material + result.materials << pParseAsset_Material(aZoneFileStream); + } else if (assetType == ASSET_SHADER) { // pixelshader + pParseAsset_Shader(aZoneFileStream); + } else if (assetType == ASSET_TECH_SET) { // techset include + result.techSets << pParseAsset_TechSet(aZoneFileStream); + } else if (assetType == ASSET_IMAGE) { // image + result.images << pParseAsset_Image(aZoneFileStream); + } else if (assetType == ASSET_SOUND) { // loaded_sound + result.sounds << pParseAsset_Sound(aZoneFileStream); + } else if (assetType == ASSET_COLLISION_MAP) { // col_map_mp + pParseAsset_ColMapMP(aZoneFileStream); + } else if (assetType == ASSET_MP_MAP) { // game_map_sp + pParseAsset_GameMapSP(aZoneFileStream); + } else if (assetType == ASSET_SP_MAP) { // game_map_mp + pParseAsset_GameMapMP(aZoneFileStream); + } else if (assetType == ASSET_LIGHT_DEF) { // lightdef + pParseAsset_LightDef(aZoneFileStream); + } else if (assetType == ASSET_UI_MAP) { // ui_map + pParseAsset_UIMap(aZoneFileStream); + } else if (assetType == ASSET_SND_DRIVER_GLOBALS) { // snddriverglobals + pParseAsset_SNDDriverGlobals(aZoneFileStream); + } else if (assetType == ASSET_AI_TYPE) { // aitype + pParseAsset_AIType(aZoneFileStream); + } else if (assetType == ASSET_EFFECT) { // aitype + pParseAsset_FX(aZoneFileStream); + } else if (assetType == ASSET_ANIMATION) { // aitype + result.animations << pParseAsset_Animation(aZoneFileStream); + } else if (assetType == ASSET_STRING_TABLE) { // string_table + result.stringTables << pParseAsset_StringTable(aZoneFileStream); + } else if (assetType == ASSET_MENU) { // string_table + result.menuFiles << pParseAsset_MenuFile(aZoneFileStream); + } else if (assetType == ASSET_WEAPON) { // string_table + pParseAsset_Weapon(aZoneFileStream); + } else if (assetType == ASSET_D3DBSP) { // string_table + pParseAsset_D3DBSP(aZoneFileStream); + } + } + return result; +} + +LocalString ZoneFile_COD6_360::pParseAsset_LocalString(QDataStream *aZoneFileStream) { + LocalString result; + + quint32 stringPtr, aliasPtr; + *aZoneFileStream >> stringPtr >> aliasPtr; + if (stringPtr == 4294967295) { + // Parse local string asset contents + QString localStr; + char localStrChar; + *aZoneFileStream >> localStrChar; + while (localStrChar != 0) { + result.string += localStrChar; + *aZoneFileStream >> localStrChar; + } + } else { + result.string = "String Ptr: " + QString::number(stringPtr); + } + + if (aliasPtr == 4294967295) { + // Parse rawfile name + QString aliasName; + char aliasNameChar; + *aZoneFileStream >> aliasNameChar; + while (aliasNameChar != 0) { + result.alias += aliasNameChar; + *aZoneFileStream >> aliasNameChar; + } + } else { + result.string = "Alias Ptr: " + QString::number(aliasPtr); + } + + return result; +} + +RawFile ZoneFile_COD6_360::pParseAsset_RawFile(QDataStream *aZoneFileStream) { + RawFile result; + + // Skip start separator FF FF FF FF (pointer?) + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.length; + + // Skip unknown 4 byte data + aZoneFileStream->skipRawData(4); + + // Parse rawfile path + char scriptPathChar; + *aZoneFileStream >> scriptPathChar; + while (scriptPathChar != 0) { + result.path += scriptPathChar; + *aZoneFileStream >> scriptPathChar; + } + result.path.replace(",", ""); + + const QStringList pathParts = result.path.split('/'); + if (pathParts.size() == 0) { + qDebug() << "Failed to parse ff path! " << result.path; + exit(-1); + } + if (result.path.contains(".bik")) { + QByteArray bikData(result.length, Qt::Uninitialized); + aZoneFileStream->readRawData(bikData.data(), result.length); + + //QFile bikFile(QDir::currentPath() + "/" + rawFilePath.split('/').last()); + //qDebug() << bikFile.fileName(); + //if (!bikFile.open(QIODevice::WriteOnly)) { + // qWarning() << "Failed to open .bik file for writing!"; + // return; + //} + //qDebug() << QString("%1: %2").arg(rawFilePath).arg(bikFile.fileName()); + //bikFile.write(bikData); + } else { + // Parse gsc contents + char rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + while (rawFileContentsChar != 0 && rawFileContentsChar != -1) { + result.contents += rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + } + } + return result; +} + +void ZoneFile_COD6_360::pParseAsset_PhysPreset(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Model ZoneFile_COD6_360::pParseAsset_Model(QDataStream *aZoneFileStream) { + Model result; + + *aZoneFileStream >> result.namePtr >> result.tagCount >> result.rootTagCount + >> result.surfCount >> result.unknownCount >> result.boneNamePtr + >> result.parentListPtr >> result.quatsPtr >> result.transPtr + >> result.partClassPtr >> result.baseMatPtr + >> result.surfsPtr >> result.materialHandlesPtr; + + // Parse XModelLodInfo + for (int i = 1; i <= 4; i++) { + quint32 intDist; + *aZoneFileStream >> intDist; + + std::memcpy(&result.lodInfo[i].dist, &intDist, sizeof(result.lodInfo[i].dist)); + *aZoneFileStream >> result.lodInfo[i].numsurfs >> result.lodInfo[i].surfIndex; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.lodInfo[i].partBits[0] + >> result.lodInfo[i].partBits[1] + >> result.lodInfo[i].partBits[2] + >> result.lodInfo[i].partBits[3]; + } + + *aZoneFileStream >> result.collSurfsPtr >> result.numCollSurfs >> result.contents >> result.boneInfoPtr; + + quint32 intRadius, intMins[3], intMaxs[3]; + *aZoneFileStream >> intRadius >> intMins[0] >> intMins[1] + >> intMins[2] >> intMaxs[0] >> intMaxs[1] >> intMaxs[2]; + + std::memcpy(&result.radius, &intRadius, sizeof(result.radius)); + + std::memcpy(&result.mins[0], &intMins[0], sizeof(result.mins[0])); + std::memcpy(&result.mins[1], &intMins[1], sizeof(result.mins[1])); + std::memcpy(&result.mins[2], &intMins[2], sizeof(result.mins[2])); + + std::memcpy(&result.maxs[0], &intMaxs[0], sizeof(result.maxs[0])); + std::memcpy(&result.maxs[1], &intMaxs[1], sizeof(result.maxs[2])); + std::memcpy(&result.maxs[2], &intMaxs[2], sizeof(result.maxs[3])); + + *aZoneFileStream >> result.numLods >> result.collLod >> result.streamInfoPtr + >> result.memUsage >> result.flags >> result.physPresetPtr >> result.physGeomsPtr; + + // Parse model name + char modelNameChar; + *aZoneFileStream >> modelNameChar; + while (modelNameChar == 0) { + *aZoneFileStream >> modelNameChar; + } + while (modelNameChar != 0) { + result.modelName += modelNameChar; + *aZoneFileStream >> modelNameChar; + } + return result; +} + +Material ZoneFile_COD6_360::pParseAsset_Material(QDataStream *aZoneFileStream) { + Material result; + + *aZoneFileStream >> result.namePtr; + + //aZoneFileStream->skipRawData(23 * 4); + + for (int i = 0; i < 23; i++) { + qint32 unknownPtr; + *aZoneFileStream >> unknownPtr; + result.pointers << unknownPtr; + } + + if (result.namePtr == -1) { + aZoneFileStream->skipRawData(1); + + QString materialName; + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + result.name += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + } + + aZoneFileStream->skipRawData(3 * 4); + + qint32 compressionPtr, compression, unknownSectionPtr; + *aZoneFileStream >> compressionPtr; + if (compressionPtr == -1) { + *aZoneFileStream >> compression; + + *aZoneFileStream >> unknownSectionPtr; + if (unknownSectionPtr == -2) { + aZoneFileStream->skipRawData(6 * 4); + } + } + + qint32 imageNamePtr; + *aZoneFileStream >> imageNamePtr; + if (imageNamePtr == -1) { + QString imageName; + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + imageName += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + } + + QByteArray compressionData(4, Qt::Uninitialized); + QString compressionStr; + if (compressionPtr == -1) { + aZoneFileStream->skipRawData(2 * 4); + aZoneFileStream->readRawData(compressionData.data(), 4); + aZoneFileStream->skipRawData(4); + compressionStr = QString::fromUtf8(compressionData); + aZoneFileStream->skipRawData(4); + } + aZoneFileStream->skipRawData(4); + + return result; +} + +Shader ZoneFile_COD6_360::pParseAsset_Shader(QDataStream *aZoneFileStream) { + Shader result = Shader(); + + quint8 minorVersion, majorVersion; + *aZoneFileStream >> minorVersion >> majorVersion; + + quint32 magic; + *aZoneFileStream >> magic; + + // Verify .fxc magic + if (magic != 65534 && magic != 65535) { return result; } + + SHADER_TYPE type = SHADER_NONE; + quint16 rawShaderType; + *aZoneFileStream >> rawShaderType; + if (rawShaderType == 65535) { // Pixel shader + type = SHADER_PIXEL; + } else if (rawShaderType == 65534) { // Vertex shader + type = SHADER_VERTEX; + } + Q_UNUSED(type); + + while (true) { + quint32 instructionToken; + *aZoneFileStream >> instructionToken; + + SHADER_OPCODE opCode = (SHADER_OPCODE)(instructionToken & 0xffff); + + int size; + if (opCode == OPCODE_End) { + break; + } else if (opCode == OPCODE_Comment) { + size = (int)((instructionToken >> 16) & 0x7FFF); + } else { + size = (int)((instructionToken >> 24) & 0x0f); + } + Q_UNUSED(size); + } + + + return result; +} + +TechSet ZoneFile_COD6_360::pParseAsset_TechSet(QDataStream *aZoneFileStream) { + TechSet result; + + qint32 namePtr; + *aZoneFileStream >> namePtr; + + + for (int i = 0; i < 53; i++) { + quint32 ptr; + *aZoneFileStream >> ptr; + + result.pointers << ptr; + } + + //aZoneFileStream->skipRawData(53 * 4); + + if (namePtr == -1) { + aZoneFileStream->skipRawData(1); + + // Parse techset name + char techSetNameChar; + *aZoneFileStream >> techSetNameChar; + while (techSetNameChar != 0) { + result.name += techSetNameChar; + *aZoneFileStream >> techSetNameChar; + } + } + + //result.name.replace(",", ""); + return result; +} + +Image ZoneFile_COD6_360::pParseAsset_Image(QDataStream *aZoneFileStream) { + Image result; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknowna >> result.unknownb + >> result.unknownc >> result.unknownd + >> result.unknowne >> result.unknownf + >> result.unknowng; + + aZoneFileStream->skipRawData(15 * 4); + *aZoneFileStream >> result.unknownh >> result.unknowni; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknownj; + + aZoneFileStream->skipRawData(4); + + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + result.materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + result.materialName.replace(",", ""); + + if (result.unknowna) { + *aZoneFileStream >> result.unknownk; + *aZoneFileStream >> result.unknownl; + *aZoneFileStream >> result.unknownm; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown1; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown2 >> result.unknown3 + >> result.size1 >> result.size2 + >> result.unknown4 >> result.unknown5; + + aZoneFileStream->skipRawData(4); + + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + result.name += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + + *aZoneFileStream >> result.unknown6 >> result.unknown7; + + QByteArray compressionData(8, Qt::Uninitialized); + aZoneFileStream->readRawData(compressionData.data(), 8); + if (compressionData.contains("DXT1")) { + result.compression = COMPRESSION_DXT1; + } else if (compressionData.contains("DXT3")) { + result.compression = COMPRESSION_DXT3; + } else if (compressionData.contains("DXT5")) { + result.compression = COMPRESSION_DXT5; + } else { + result.compression = COMPRESSION_NONE; + } + + *aZoneFileStream >> result.unknown8 >> result.unknown9; + } + + return result; +} + +SoundAsset ZoneFile_COD6_360::pParseAsset_Sound(QDataStream *aZoneFileStream) { + SoundAsset result; + + QByteArray rootNamePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rootNamePtr.data(), 4); + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.count; + + if (rootNamePtr.toHex() == "ffffffff") { + // Read in sound file name + char soundNameChar; + *aZoneFileStream >> soundNameChar; + while (soundNameChar != 0) { + result.name += soundNameChar; + *aZoneFileStream >> soundNameChar; + } + } + + int tagCount = 0; + int resultCount = 0; + for (quint32 i = 0; i < result.count; i++) { + aZoneFileStream->skipRawData(12); + + QByteArray tagPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(tagPtr.data(), 4); + + if (tagPtr.toHex() == "ffffffff") { + tagCount++; + } + aZoneFileStream->skipRawData(4); + + QByteArray pathPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pathPtr.data(), 4); + + if (pathPtr.toHex() == "ffffffff") { + resultCount++; + } + + aZoneFileStream->skipRawData(160); + } + + for (int i = 0; i < tagCount; i++) { + // Read in tag? + QString tag; + char tagChar; + *aZoneFileStream >> tagChar; + while (tagChar != 0) { + tag += tagChar; + *aZoneFileStream >> tagChar; + } + } + + for (int i = 0; i < resultCount; i++) { + Sound sound; + + if (aZoneFileStream->device()->peek(12).toHex().contains("ffffffff00000000")) { + aZoneFileStream->skipRawData(12); + } + + aZoneFileStream->skipRawData(8); + + QByteArray aliasPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(aliasPtr.data(), 4); + + QByteArray namePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(namePtr.data(), 4); + + *aZoneFileStream >> sound.dataLength; + + if (aliasPtr.toHex() == "ffffffff") { + // Read in sound alias name + char soundAliasChar; + *aZoneFileStream >> soundAliasChar; + while (soundAliasChar != 0) { + sound.alias += soundAliasChar; + *aZoneFileStream >> soundAliasChar; + } + } + + if (aZoneFileStream->device()->peek(4) == "RIFF") { + sound.path = sound.alias; + sound.alias = ""; + } else if (namePtr.toHex() == "ffffffff") { + // Read in sound file path + char soundPathChar; + *aZoneFileStream >> soundPathChar; + while (soundPathChar != 0) { + sound.path += soundPathChar; + *aZoneFileStream >> soundPathChar; + } + sound.path.replace(",", ""); + } + + if (sound.dataLength) { + QByteArray data(sound.dataLength, Qt::Uninitialized); + aZoneFileStream->readRawData(data.data(), sound.dataLength); + sound.data = data; + } + result.sounds.append(sound); + } + + return result; +} + +void ZoneFile_COD6_360::pParseAsset_ColMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD6_360::pParseAsset_GameMapSP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD6_360::pParseAsset_GameMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD6_360::pParseAsset_LightDef(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD6_360::pParseAsset_UIMap(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD6_360::pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD6_360::pParseAsset_AIType(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD6_360::pParseAsset_FX(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Animation ZoneFile_COD6_360::pParseAsset_Animation(QDataStream *aZoneFileStream) { + Animation result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.dataByteCount + >> result.dataShortCount + >> result.dataIntCount + >> result.randomDataByteCount + >> result.randomDataIntCount + >> result.numframes + >> result.isLooped + >> result.isDelta + >> result.noneRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.normalTranslatedBoneCount + >> result.preciseTranslatedBoneCount + >> result.staticTranslatedBoneCount + >> result.noneTranslatedBoneCount + >> result.totalBoneCount + >> result.otherBoneCount1 + >> result.otherBoneCount2 + >> result.notifyCount + >> result.assetType + >> result.pad + >> result.randomDataShortCount + >> result.indexCount + >> result.frameRate + >> result.frequency + >> result.boneIDsPtr + >> result.dataBytePtr + >> result.dataShortPtr + >> result.dataIntPtr + >> result.randomDataShortPtr + >> result.randomDataBytePtr + >> result.randomDataIntPtr + >> result.longIndiciesPtr + >> result.notificationsPtr + >> result.deltaPartsPtr; + + // Read in x_anim file name + QString xAnimName; + char xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + while (xAnimNameChar != 0) { + result.name += xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + } + + // Parse x_anim index header + QVector sectionLengths; + for (int i = 0; i < result.numframes; i++) { + quint8 sectionlength; + *aZoneFileStream >> sectionlength; + sectionLengths.push_back(sectionlength); + // Skip padding + aZoneFileStream->skipRawData(1); + } + // Skip unknown section + aZoneFileStream->skipRawData(2 * 8); + + return result; +} + +MenuFile ZoneFile_COD6_360::pParseAsset_MenuFile(QDataStream *aZoneFileStream) { + //MENU_FILE + MenuFile result; + + aZoneFileStream->skipRawData(4); // Separator + + // Parse menu def count + *aZoneFileStream >> result.menuCount; + + // Clearly misparsed, never have this much + if (result.menuCount > 1000) { + qDebug() << "Failure reported when parsing menu file."; + return result; + } + for (uint i = 0; i < result.menuCount; i++) { + Menu menu; + + aZoneFileStream->skipRawData(4); // Separator + + // Read in x_anim file name + char menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + while (menuFilepathChar != 0) { + menu.filePath += menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + } + aZoneFileStream->skipRawData(4); // Separator + + *aZoneFileStream >> menu.menuNamePtr; + + float menuRectX, menuRectY, menuRectWidth, menuRectHeight; + *aZoneFileStream >> menuRectX >> menuRectY >> menuRectWidth >> menuRectHeight; + menu.rect = QRectF(menuRectX, menuRectY, menuRectWidth, menuRectHeight); + + quint32 hAlignInt, vAlignInt; + *aZoneFileStream >> hAlignInt >> vAlignInt; + menu.hAlign = (MENU_H_ALIGNMENT)hAlignInt; + menu.vAlign = (MENU_V_ALIGNMENT)vAlignInt; + + float rectClientX, rectClientY, rectClientWidth, rectClientHeight; + *aZoneFileStream >> rectClientX >> rectClientY >> rectClientWidth >> rectClientHeight; + menu.clientRect = QRectF(rectClientX, rectClientY, rectClientWidth, rectClientHeight); + + quint32 hClientAlignInt, vClientAlignInt, styleInt, borderInt; + *aZoneFileStream >> hClientAlignInt >> vClientAlignInt >> menu.groupPtr + >> styleInt >> borderInt >> menu.ownerDraw >> menu.ownerDrawFlags + >> menu.borderSize >> menu.staticFlags >> menu.dynamicFlags >> menu.nextTime; + menu.hClientAlign = (MENU_H_ALIGNMENT)hClientAlignInt; + menu.vClientAlign = (MENU_V_ALIGNMENT)vClientAlignInt; + menu.style = (MENU_WINDOW_STYLE)styleInt; + menu.border = (MENU_WINDOW_BORDER)borderInt; + + float foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA, + backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA, + borderColorR, borderColorG, borderColorB, borderColorA, + outlineColorR, outlineColorG, outlineColorB, outlineColorA; + *aZoneFileStream >> foregroundColorR >> foregroundColorG >> foregroundColorB >> foregroundColorA + >> backgroundColorR >> backgroundColorG >> backgroundColorB >> backgroundColorA + >> borderColorR >> borderColorG >> borderColorB >> borderColorA + >> outlineColorR >> outlineColorG >> outlineColorB >> outlineColorA; + + menu.foregroundColor = QColor(foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA); + menu.backgroundColor = QColor(backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA); + menu.borderColor = QColor(borderColorR, borderColorG, borderColorB, borderColorA); + menu.outlineColor = QColor(outlineColorR, outlineColorG, outlineColorB, outlineColorA); + + *aZoneFileStream >> menu.materialPtr >> menu.fontPtr >> menu.fullScreen >> menu.itemCount + >> menu.fontIndex >> menu.cursorItem >> menu.fadeCycle >> menu.fadeClamp + >> menu.fadeAmount >> menu.fadeInAmount >> menu.blurRadius >> menu.onOpenPtr + >> menu.onFocusPtr >> menu.onClosePtr >> menu.onESCPtr >> menu.onKeyPtr + >> menu.visibleExpCount >> menu.expEntryPtr >> menu.allowedBindingPtr + >> menu.soundNamePtr >> menu.imageTrack; + + float focusColorR, focusColorG, focusColorB, focusColorA, + disabledColorR, disabledColorG, disabledColorB, disabledColorA; + *aZoneFileStream >> focusColorR >> focusColorG >> focusColorB >> focusColorA + >> disabledColorR >> disabledColorG >> disabledColorB >> disabledColorA; + menu.focusColor = QColor(focusColorR, focusColorG, focusColorB, focusColorA); + menu.disabledColor = QColor(disabledColorR, disabledColorG, disabledColorB, disabledColorA); + + *aZoneFileStream >> menu.rectXExpCount >> menu.rectXExpPtr >> menu.rectYExpCount >> menu.rectYExpPtr; + + aZoneFileStream->skipRawData(4); // Separator + + char menuDefNameChar; + int menuDefNameLen = 0; + *aZoneFileStream >> menuDefNameChar; + while (menuDefNameChar != 0 && menuDefNameLen < 30) { + menuDefNameLen++; + menu.name += menuDefNameChar; + *aZoneFileStream >> menuDefNameChar; + } + + char defStringChar; + int defStringLen = 0; + *aZoneFileStream >> defStringChar; + while (defStringChar != 0 && defStringLen < 30) { + defStringLen++; + menu.definition += defStringChar; + *aZoneFileStream >> defStringChar; + } + aZoneFileStream->skipRawData(4 * 10); + + *aZoneFileStream >> menu.itemWindowDefNamePtr; + + float itemRectX, itemRectY, itemRectWidth, itemRectHeight; + *aZoneFileStream >> itemRectX >> itemRectY >> itemRectWidth >> itemRectHeight; + menu.itemRect = QRectF(itemRectX, itemRectY, itemRectWidth, itemRectHeight); + + *aZoneFileStream >> menu.itemHAlignment >> menu.itemVAlignment >> menu.itemGroupPtr + >> menu.itemWindowStyle >> menu.itemWindowBorder >> menu.itemOwnerDraw + >> menu.itemOwnerDrawFlags >> menu.itemBorderSize >> menu.itemStaticFlags + >> menu.itemDynamicFlags >> menu.itemNextTime; + + float itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA, + itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA, + itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA, + itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA; + *aZoneFileStream >> itemForegroundColorR >> itemForegroundColorG >> itemForegroundColorB >> itemForegroundColorA + >> itemBackgroundColorR >> itemBackgroundColorG >> itemBackgroundColorB >> itemBackgroundColorA + >> itemBorderColorR >> itemBorderColorG >> itemBorderColorB >> itemBorderColorA + >> itemOutlineColorR >> itemOutlineColorG >> itemOutlineColorB >> itemOutlineColorA; + + menu.itemForegroundColor = QColor(itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA); + menu.itemBackgroundColor = QColor(itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA); + menu.itemBorderColor = QColor(itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA); + menu.itemOutlineColor = QColor(itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA); + + *aZoneFileStream >> menu.itemMaterialPtr; + + float itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight; + *aZoneFileStream >> itemTextRectX >> itemTextRectY >> itemTextRectWidth >> itemTextRectHeight; + menu.itemTextRect = QRectF(itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight); + + quint32 hItemTextAlignInt, vItemTextAlignInt, itemType, fontTypeInt, textStyleInt; + *aZoneFileStream >> hItemTextAlignInt >> vItemTextAlignInt >> itemType >> menu.dataType + >> menu.alignment >> fontTypeInt >> menu.textAlignMode >> menu.textalignx >> menu.textaligny + >> menu.textscale >> textStyleInt >> menu.gameMsgWindowIndex >> menu.gameMsgWindowMode + >> menu.testPtr >> menu.textSavegameInfo >> menu.parentPtr; + menu.itemText_hAlign = (MENU_H_ALIGNMENT)hItemTextAlignInt; + menu.itemText_vAlign = (MENU_V_ALIGNMENT)vItemTextAlignInt; + menu.itemType = (MENU_ITEM_TYPE)itemType; + menu.fontEnum = (MENU_FONT_TYPE)fontTypeInt; + menu.textStyle = (MENU_ITEM_TEXTSTYLE)textStyleInt; + + *aZoneFileStream >> menu.mouseEnterText >> menu.mouseExitText >> menu.mouseEnter >> menu.mouseExit + >> menu.action >> menu.onAccept >> menu.onFocus >> menu.leaveFocus >> menu.dvar >> menu.dvarTest + >> menu.keyHandlerPtr >> menu.enableDvarPtr >> menu.dvarFlags >> menu.focusSoundPtr + >> menu.special >> menu.cursorPos; + + // itemDefData_t typeData; + + // listBoxDef_s *listBox; + + *aZoneFileStream >> menu.startPos >> menu.endPos >> menu.drawPadding; + + *aZoneFileStream >> menu.elementWidth >> menu.elementHeight; + + *aZoneFileStream >> menu.elementStyle >> menu.numColumns; + + //columnInfo_s columnInfo[16]; + + *aZoneFileStream >> menu.doubleClickPtr; + + + *aZoneFileStream >> menu.notselectable >> menu.noScrollBars >> menu.usePaging; + + float itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA, + itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA, + itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA; + *aZoneFileStream >> itemSelectBorderColorR >> itemSelectBorderColorG >> itemSelectBorderColorB >> itemSelectBorderColorA + >> itemDisableColorR >> itemDisableColorG >> itemDisableColorB >> itemDisableColorA + >> itemFocusColorR >> itemFocusColorG >> itemFocusColorB >> itemFocusColorA; + menu.itemSelectBorderColor = QColor(itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA); + menu.itemDisableColor = QColor(itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA); + menu.itemFocusColor = QColor(itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA); + + *aZoneFileStream >> menu.selectIconPtr >> menu.backgroundItemListboxPtr >> menu.highlightTexturePtr; + + // editFieldDef_s *editField; + + *aZoneFileStream >> menu.minVal >> menu.maxVal >> menu.defVal >> menu.range >> menu.maxChars + >> menu.maxCharsGotoNext >> menu.maxPaintChars >> menu.paintOffset; + + // multiDef_s *multi; + + for (int i = 0; i < 32; i++) { + quint32 dvarList; + *aZoneFileStream >> dvarList; + menu.dvarListPtrs.push_back(dvarList); + } + + for (int i = 0; i < 32; i++) { + quint32 dvarStr; + *aZoneFileStream >> dvarStr; + menu.dvarStrPtrs.push_back(dvarStr); + } + + for (int i = 0; i < 32; i++) { + float dvarValue; + *aZoneFileStream >> dvarValue; + menu.dvarValues.push_back(dvarValue); + } + + *aZoneFileStream >> menu.count >> menu.strDef >> menu.enumDvarNamePtr; + aZoneFileStream->skipRawData(4); + //>> menu.dataPtr + *aZoneFileStream >> menu.itemImageTrack; + + qDebug() << aZoneFileStream->device()->pos(); + + //statement_s visibleExp; + //statement_s textExp; + //statement_s materialExp; + //statement_s rectXExp; + //statement_s rectYExp; + //statement_s rectWExp; + //statement_s rectHExp; + //statement_s foreColorAExp; + result.menuDefs << menu; + } + return result; +} + +void ZoneFile_COD6_360::pParseAsset_Weapon(QDataStream *aZoneFileStream) { + //WEAPON_FILE + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD6_360::pParseAsset_D3DBSP(QDataStream *aZoneFileStream) { + //D3DBSP_DUMP + Q_UNUSED(aZoneFileStream); +} + +StringTable ZoneFile_COD6_360::pParseAsset_StringTable(QDataStream *aZoneFileStream) { + StringTable result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.columnCount + >> result.rowCount; + + // Todo fix this + result.columnCount = 0; + result.rowCount = 0; + + aZoneFileStream->skipRawData(4); + + QString stringTableName; + char stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + while (stringTableNameChar != 0) { + result.name += stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + } + + for (quint32 i = 0; i < result.rowCount; i++) { + QByteArray pointerData(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pointerData.data(), 4); + result.tablePointers.push_back(pointerData.toHex()); + + aZoneFileStream->skipRawData(4); + } + + for (const QString &pointerAddr : result.tablePointers) { + QString leadingContent = ""; + if (pointerAddr == "FFFFFFFF") { + char leadingContentChar; + *aZoneFileStream >> leadingContentChar; + while (leadingContentChar != 0) { + leadingContent += leadingContentChar; + *aZoneFileStream >> leadingContentChar; + } + } else { + leadingContent = pointerAddr; + } + + QString content; + char contentChar; + *aZoneFileStream >> contentChar; + while (contentChar != 0) { + content += contentChar; + *aZoneFileStream >> contentChar; + } + result.content[leadingContent] = content; + } + return result; +} + +AssetType ZoneFile_COD6_360::AssetStrToEnum(const QString aAssetType) { + const QString cleanedType = aAssetType.toUpper(); + if (cleanedType == "00000021") { + return ASSET_RAW_FILE; + } else if (cleanedType == "0000001A") { + return ASSET_EFFECT; + } else if (cleanedType == "00000009") { + return ASSET_SOUND; + } else if (cleanedType == "00000004") { + return ASSET_ANIMATION; + } else if (cleanedType == "0000000C") { + return ASSET_COLLISION_MAP; + } else if (cleanedType == "00000021") { + return ASSET_STRING_TABLE; + } else if (cleanedType == "00000015") { + return ASSET_MENU; + } else if (cleanedType == "00000008") { + return ASSET_TECH_SET; + } else if (cleanedType == "00000018") { + return ASSET_LOCAL_STRING; + } else if (cleanedType == "00000011") { + return ASSET_GFX_MAP; + } else if (cleanedType == "00000012") { + return ASSET_LIGHT_DEF; + } else if (cleanedType == "00000014") { + return ASSET_FONT; + } else if (cleanedType == "00000005") { + return ASSET_MODEL; + } else if (cleanedType == "0000000D") { + return ASSET_D3DBSP; + } else if (cleanedType == "00000006") { + return ASSET_MATERIAL; + } else if (cleanedType == "0000000E") { + return ASSET_GAME_MAP_SP; + } else if (cleanedType == "0000000B") { + return ASSET_COL_MAP_SP; + } else if (cleanedType == "00000001") { + return ASSET_PHYS_PRESET; + } else if (cleanedType == "00000003") { + return ASSET_DESTRUCTIBLE; + } else if (cleanedType == "00000016") { + return ASSET_MENU; + } + return ASSET_NONE; +} + +QByteArray ZoneFile_COD6_360::GetBinaryData() { + QByteArray result; + + return result; +} diff --git a/libs/zonefile/360/zonefile_cod6_360.h b/libs/zonefile/360/zonefile_cod6_360.h new file mode 100644 index 0000000..3086068 --- /dev/null +++ b/libs/zonefile/360/zonefile_cod6_360.h @@ -0,0 +1,54 @@ +#ifndef ZONEFILE_COD6_360_H +#define ZONEFILE_COD6_360_H + +#include + +#include "zonefile.h" + +class ZoneFile_COD6_360 : public ZoneFile +{ +public: + ZoneFile_COD6_360(); + ~ZoneFile_COD6_360(); + + bool Load(const QByteArray aFileData) override; + AssetType AssetStrToEnum(const QString aAssetType) override; + + QByteArray GetBinaryData() override; + +private: + void pParseZoneHeader(QDataStream *aZoneFileStream) override; + quint32 pParseZoneSize(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsA(QDataStream *aZoneFileStream) override; + quint32 pParseZoneTagCount(QDataStream *aZoneFileStream) override; + quint32 pParseZoneRecordCount(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsB(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsC(QDataStream *aZoneFileStream) override; + QStringList pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) override; + QStringList pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) override; + AssetMap pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) override; + LocalString pParseAsset_LocalString(QDataStream *aZoneFileStream) override; + RawFile pParseAsset_RawFile(QDataStream *aZoneFileStream) override; + void pParseAsset_PhysPreset(QDataStream *aZoneFileStream) override; + Model pParseAsset_Model(QDataStream *aZoneFileStream) override; + Material pParseAsset_Material(QDataStream *aZoneFileStream) override; + Shader pParseAsset_Shader(QDataStream *aZoneFileStream) override; + TechSet pParseAsset_TechSet(QDataStream *aZoneFileStream) override; + Image pParseAsset_Image(QDataStream *aZoneFileStream) override; + SoundAsset pParseAsset_Sound(QDataStream *aZoneFileStream) override; + void pParseAsset_ColMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapSP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_LightDef(QDataStream *aZoneFileStream) override; + void pParseAsset_UIMap(QDataStream *aZoneFileStream) override; + void pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) override; + void pParseAsset_AIType(QDataStream *aZoneFileStream) override; + void pParseAsset_FX(QDataStream *aZoneFileStream) override; + Animation pParseAsset_Animation(QDataStream *aZoneFileStream) override; + MenuFile pParseAsset_MenuFile(QDataStream *aZoneFileStream) override; + void pParseAsset_Weapon(QDataStream *aZoneFileStream) override; + void pParseAsset_D3DBSP(QDataStream *aZoneFileStream) override; + StringTable pParseAsset_StringTable(QDataStream *aZoneFileStream) override; +}; + +#endif // ZONEFILE_COD6_360_H diff --git a/libs/zonefile/360/zonefile_cod7_360.cpp b/libs/zonefile/360/zonefile_cod7_360.cpp new file mode 100644 index 0000000..4d745bb --- /dev/null +++ b/libs/zonefile/360/zonefile_cod7_360.cpp @@ -0,0 +1,1077 @@ +#include "zonefile_cod7_360.h" + +#include +#include +#include + +ZoneFile_COD7_360::ZoneFile_COD7_360() +{ + +} + +ZoneFile_COD7_360::~ZoneFile_COD7_360() +{ + +} + +bool ZoneFile_COD7_360::Load(const QByteArray aFileData) { + // Open zone file as little endian stream + QDataStream zoneFileStream(aFileData); + zoneFileStream.setByteOrder(QDataStream::BigEndian); + + // Parse data from zone file header + pParseZoneHeader(&zoneFileStream); + zoneFileStream.device()->seek(zoneFileStream.device()->pos() - 1); + SetRecords(pParseZoneIndex(&zoneFileStream, GetRecordCount())); + SetAssetMap(pParseAssets(&zoneFileStream, GetRecords())); + + return true; +} + +void ZoneFile_COD7_360::pParseZoneHeader(QDataStream *aZoneFileStream) { + quint32 size = pParseZoneSize(aZoneFileStream); + SetSize(size); + + pParseZoneUnknownsA(aZoneFileStream); + + quint32 tagCount = pParseZoneTagCount(aZoneFileStream); + SetTagCount(tagCount); + + pParseZoneUnknownsB(aZoneFileStream); + + quint32 recordCount = pParseZoneRecordCount(aZoneFileStream); + SetRecordCount(recordCount); + + if (tagCount) { + pParseZoneUnknownsC(aZoneFileStream); + SetTags(pParseZoneTags(aZoneFileStream, tagCount)); + } else { + aZoneFileStream->skipRawData(4); + } +} + +quint32 ZoneFile_COD7_360::pParseZoneSize(QDataStream *aZoneFileStream) { + quint32 zoneFileSize; + *aZoneFileStream >> zoneFileSize; + if (zoneFileSize <= 0) { + qDebug() << "Tried to open empty zone file!"; + exit(-1); + } + zoneFileSize += 36; + return zoneFileSize; +} + +/* + ParseZoneUnknownsA() + + Parses the 1st section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD7_360::pParseZoneUnknownsA(QDataStream *aZoneFileStream) { + // Byte 4-7, 8-11, 12-15: unknown + QByteArray unknown1(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown1.data(), 4); + + QByteArray unknown2(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown2.data(), 4); + + QByteArray unknown3(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown3.data(), 4); + + // Byte 16-19, 20-23: empty/unknown + QByteArray unknown4(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown4.data(), 4); + + QByteArray unknown5(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown5.data(), 4); + + // Byte 24-27: somehow related to the filesize, but smaller value + QByteArray unknown6(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown6.data(), 4); + + // Byte 28-31, 32-35: unknown + QByteArray unknown7(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown7.data(), 4); + + QByteArray unknown8(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown8.data(), 4); +} + +/* + ParseZoneTagCount() + + Parses the number of string tags in the zone index +*/ +quint32 ZoneFile_COD7_360::pParseZoneTagCount(QDataStream *aZoneFileStream) { + quint32 tagCount; + *aZoneFileStream >> tagCount; + return tagCount; +} + +/* + ParseZoneRecordCount() + + Parses the number of records in the zone index +*/ +quint32 ZoneFile_COD7_360::pParseZoneRecordCount(QDataStream *aZoneFileStream) { + quint32 recordCount; + *aZoneFileStream >> recordCount; + return recordCount; +} + +/* + ParseZoneUnknownsB() + + Parses the 2nd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD7_360::pParseZoneUnknownsB(QDataStream *aZoneFileStream) { + // Byte 44-47: Unknown/empty? + QByteArray unknown9(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown9.data(), 4); +} + +/* + pParseZoneUnknownsC() + + Parses the 3rd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD7_360::pParseZoneUnknownsC(QDataStream *aZoneFileStream) { + // Byte 40-43: Unknown/empty? + QByteArray unknown10(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown10.data(), 4); + + // Byte 44-47: Unknown/empty? + QByteArray unknown11(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown11.data(), 4); +} + +/* + ParseZoneTags() + + Parses the string tags ate the start of zone file +*/ +QStringList ZoneFile_COD7_360::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) { + QStringList tags; + + // Byte 48-51: Repeated separators? ÿÿÿÿ x i + aZoneFileStream->skipRawData(4 * (tagCount - 1)); + + // Parse tags/strings before index + QString zoneTag; + char zoneTagChar; + for (quint32 i = 0; i < tagCount; i++) { + *aZoneFileStream >> zoneTagChar; + while (zoneTagChar != 0) { + zoneTag += zoneTagChar; + *aZoneFileStream >> zoneTagChar; + } + tags << zoneTag; + zoneTag.clear(); + } + return tags; +} + +/* + ParseZoneIndex() + + Parse the binary zone index data and populate table +*/ +QStringList ZoneFile_COD7_360::pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) { + QStringList result; + + // Don't parse if no records + if (!recordCount) { return result; } + + if (aZoneFileStream->device()->peek(4).toHex().contains("ffff")) { + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 2); + } + + // Parse index & map found asset types + for (quint32 i = 0; i <= recordCount; i++) { + // Skip record start + QByteArray rawAssetType(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rawAssetType.data(), 4); + result << rawAssetType.toHex(); + + // Skip separator + aZoneFileStream->skipRawData(4); + } + return result; +} + +AssetMap ZoneFile_COD7_360::pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) { + AssetMap result; + + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 8); + + for (int i = 0; i < assetOrder.size(); i++) { + const QString typeHex = assetOrder[i]; + const AssetType typeStr = AssetStrToEnum(typeHex); + + if (typeStr == ASSET_LOCAL_STRING) { // localized string asset + result.localStrings << pParseAsset_LocalString(aZoneFileStream); + } else if (typeStr == ASSET_RAW_FILE) { // gsc + auto rawFile = pParseAsset_RawFile(aZoneFileStream); + if (rawFile.length) { + result.rawFiles << rawFile; + } + } else if (typeStr == ASSET_PHYS_PRESET) { // physpreset + pParseAsset_PhysPreset(aZoneFileStream); + } else if (typeStr == ASSET_MODEL) { // xmodel + result.models << pParseAsset_Model(aZoneFileStream); + } else if (typeStr == ASSET_MATERIAL) { // material + pParseAsset_Material(aZoneFileStream); + } else if (typeStr == ASSET_SHADER) { // pixelshader + pParseAsset_Shader(aZoneFileStream); + } else if (typeStr == ASSET_TECH_SET) { // techset include + result.techSets << pParseAsset_TechSet(aZoneFileStream); + } else if (typeStr == ASSET_IMAGE) { // image + result.images << pParseAsset_Image(aZoneFileStream); + } else if (typeStr == ASSET_SOUND) { // loaded_sound + result.sounds << pParseAsset_Sound(aZoneFileStream); + } else if (typeStr == ASSET_COLLISION_MAP) { // col_map_mp + pParseAsset_ColMapMP(aZoneFileStream); + } else if (typeStr == ASSET_MP_MAP) { // game_map_sp + pParseAsset_GameMapSP(aZoneFileStream); + } else if (typeStr == ASSET_SP_MAP) { // game_map_mp + pParseAsset_GameMapMP(aZoneFileStream); + } else if (typeStr == ASSET_LIGHT_DEF) { // lightdef + pParseAsset_LightDef(aZoneFileStream); + } else if (typeStr == ASSET_UI_MAP) { // ui_map + pParseAsset_UIMap(aZoneFileStream); + } else if (typeStr == ASSET_SND_DRIVER_GLOBALS) { // snddriverglobals + pParseAsset_SNDDriverGlobals(aZoneFileStream); + } else if (typeStr == ASSET_AI_TYPE) { // aitype + pParseAsset_AIType(aZoneFileStream); + } else if (typeStr == ASSET_EFFECT) { // aitype + pParseAsset_FX(aZoneFileStream); + } else if (typeStr == ASSET_ANIMATION) { // aitype + result.animations << pParseAsset_Animation(aZoneFileStream); + } else if (typeStr == ASSET_STRING_TABLE) { // string_table + result.stringTables << pParseAsset_StringTable(aZoneFileStream); + } else if (typeStr == ASSET_MENU) { // string_table + result.menuFiles << pParseAsset_MenuFile(aZoneFileStream); + } else if (typeStr == ASSET_WEAPON) { // string_table + pParseAsset_Weapon(aZoneFileStream); + } else if (typeStr == ASSET_D3DBSP) { // string_table + pParseAsset_D3DBSP(aZoneFileStream); + } + } + return result; +} + +LocalString ZoneFile_COD7_360::pParseAsset_LocalString(QDataStream *aZoneFileStream) { + LocalString result; + + quint32 stringPtr, aliasPtr; + *aZoneFileStream >> stringPtr >> aliasPtr; + if (stringPtr == 4294967295) { + // Parse local string asset contents + QString localStr; + char localStrChar; + *aZoneFileStream >> localStrChar; + while (localStrChar != 0) { + result.string += localStrChar; + *aZoneFileStream >> localStrChar; + } + } else { + result.string = "String Ptr: " + QString::number(stringPtr); + } + + if (aliasPtr == 4294967295) { + // Parse rawfile name + QString aliasName; + char aliasNameChar; + *aZoneFileStream >> aliasNameChar; + while (aliasNameChar != 0) { + result.alias += aliasNameChar; + *aZoneFileStream >> aliasNameChar; + } + } else { + result.string = "Alias Ptr: " + QString::number(aliasPtr); + } + + return result; +} + +RawFile ZoneFile_COD7_360::pParseAsset_RawFile(QDataStream *aZoneFileStream) { + RawFile result; + + // Skip start separator FF FF FF FF (pointer?) + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.length; + + // Skip unknown 4 byte data + aZoneFileStream->skipRawData(4); + + // Parse rawfile path + char scriptPathChar; + *aZoneFileStream >> scriptPathChar; + while (scriptPathChar != 0) { + result.path += scriptPathChar; + *aZoneFileStream >> scriptPathChar; + } + result.path.replace(",", ""); + const QStringList pathParts = result.path.split('/'); + if (pathParts.size() == 0) { + qDebug() << "Failed to parse ff path! " << result.path; + exit(-1); + } + + // Parse gsc contents + char rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + while (rawFileContentsChar != 0 && rawFileContentsChar != -1) { + result.contents += rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + } + return result; +} + +void ZoneFile_COD7_360::pParseAsset_PhysPreset(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Model ZoneFile_COD7_360::pParseAsset_Model(QDataStream *aZoneFileStream) { + Model result; + + *aZoneFileStream >> result.namePtr >> result.tagCount >> result.rootTagCount + >> result.surfCount >> result.unknownCount >> result.boneNamePtr + >> result.parentListPtr >> result.quatsPtr >> result.transPtr + >> result.partClassPtr >> result.baseMatPtr + >> result.surfsPtr >> result.materialHandlesPtr; + + // Parse XModelLodInfo + for (int i = 1; i <= 4; i++) { + quint32 intDist; + *aZoneFileStream >> intDist; + + std::memcpy(&result.lodInfo[i].dist, &intDist, sizeof(result.lodInfo[i].dist)); + *aZoneFileStream >> result.lodInfo[i].numsurfs >> result.lodInfo[i].surfIndex; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.lodInfo[i].partBits[0] + >> result.lodInfo[i].partBits[1] + >> result.lodInfo[i].partBits[2] + >> result.lodInfo[i].partBits[3]; + } + + *aZoneFileStream >> result.collSurfsPtr >> result.numCollSurfs >> result.contents >> result.boneInfoPtr; + + quint32 intRadius, intMins[3], intMaxs[3]; + *aZoneFileStream >> intRadius >> intMins[0] >> intMins[1] + >> intMins[2] >> intMaxs[0] >> intMaxs[1] >> intMaxs[2]; + + std::memcpy(&result.radius, &intRadius, sizeof(result.radius)); + + std::memcpy(&result.mins[0], &intMins[0], sizeof(result.mins[0])); + std::memcpy(&result.mins[1], &intMins[1], sizeof(result.mins[1])); + std::memcpy(&result.mins[2], &intMins[2], sizeof(result.mins[2])); + + std::memcpy(&result.maxs[0], &intMaxs[0], sizeof(result.maxs[0])); + std::memcpy(&result.maxs[1], &intMaxs[1], sizeof(result.maxs[2])); + std::memcpy(&result.maxs[2], &intMaxs[2], sizeof(result.maxs[3])); + + *aZoneFileStream >> result.numLods >> result.collLod >> result.streamInfoPtr + >> result.memUsage >> result.flags >> result.physPresetPtr >> result.physGeomsPtr; + + // Parse model name + char modelNameChar; + *aZoneFileStream >> modelNameChar; + while (modelNameChar == 0) { + *aZoneFileStream >> modelNameChar; + } + while (modelNameChar != 0) { + result.modelName += modelNameChar; + *aZoneFileStream >> modelNameChar; + } + return result; +} + +Material ZoneFile_COD7_360::pParseAsset_Material(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); + + return Material(); +} + +Shader ZoneFile_COD7_360::pParseAsset_Shader(QDataStream *aZoneFileStream) { + Shader result = Shader(); + + quint8 minorVersion, majorVersion; + *aZoneFileStream >> minorVersion >> majorVersion; + + quint32 magic; + *aZoneFileStream >> magic; + + // Verify .fxc magic + if (magic != 65534 && magic != 65535) { return result; } + + SHADER_TYPE type = SHADER_NONE; + quint16 rawShaderType; + *aZoneFileStream >> rawShaderType; + if (rawShaderType == 65535) { // Pixel shader + type = SHADER_PIXEL; + } else if (rawShaderType == 65534) { // Vertex shader + type = SHADER_VERTEX; + } + Q_UNUSED(type); + + while (true) { + quint32 instructionToken; + *aZoneFileStream >> instructionToken; + + SHADER_OPCODE opCode = (SHADER_OPCODE)(instructionToken & 0xffff); + + int size; + if (opCode == OPCODE_End) { + break; + } else if (opCode == OPCODE_Comment) { + size = (int)((instructionToken >> 16) & 0x7FFF); + } else { + size = (int)((instructionToken >> 24) & 0x0f); + } + Q_UNUSED(size); + } + + + return result; +} + +TechSet ZoneFile_COD7_360::pParseAsset_TechSet(QDataStream *aZoneFileStream) { + TechSet result; + + for (int i = 1; i <= 62; i++) { + quint32 ptr; + *aZoneFileStream >> ptr; + + result.pointers << ptr; + } + qDebug() << aZoneFileStream->device()->pos(); + + // Parse techset name + char techSetNameChar; + *aZoneFileStream >> techSetNameChar; + while (techSetNameChar != 0) { + result.name += techSetNameChar; + *aZoneFileStream >> techSetNameChar; + } + result.name.replace(",", ""); + + return result; +} + +Image ZoneFile_COD7_360::pParseAsset_Image(QDataStream *aZoneFileStream) { + Image result; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknowna >> result.unknownb + >> result.unknownc >> result.unknownd + >> result.unknowne >> result.unknownf + >> result.unknowng; + + aZoneFileStream->skipRawData(15 * 4); + *aZoneFileStream >> result.unknownh >> result.unknowni; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknownj; + + aZoneFileStream->skipRawData(4); + + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + result.materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + result.materialName.replace(",", ""); + + if (result.unknowna) { + *aZoneFileStream >> result.unknownk; + *aZoneFileStream >> result.unknownl; + *aZoneFileStream >> result.unknownm; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown1; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown2 >> result.unknown3 + >> result.size1 >> result.size2 + >> result.unknown4 >> result.unknown5; + + aZoneFileStream->skipRawData(4); + + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + result.name += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + + *aZoneFileStream >> result.unknown6 >> result.unknown7; + + QByteArray compressionData(8, Qt::Uninitialized); + aZoneFileStream->readRawData(compressionData.data(), 8); + if (compressionData.contains("DXT1")) { + result.compression = COMPRESSION_DXT1; + } else if (compressionData.contains("DXT3")) { + result.compression = COMPRESSION_DXT3; + } else if (compressionData.contains("DXT5")) { + result.compression = COMPRESSION_DXT5; + } else { + result.compression = COMPRESSION_NONE; + } + + *aZoneFileStream >> result.unknown8 >> result.unknown9; + } + + return result; +} + +SoundAsset ZoneFile_COD7_360::pParseAsset_Sound(QDataStream *aZoneFileStream) { + SoundAsset result; + + qDebug() << aZoneFileStream->device()->pos(); + + QByteArray rootNamePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rootNamePtr.data(), 4); + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.count; + + if (rootNamePtr.toHex() == "ffffffff") { + // Read in sound file name + char soundNameChar; + *aZoneFileStream >> soundNameChar; + while (soundNameChar != 0) { + result.name += soundNameChar; + *aZoneFileStream >> soundNameChar; + } + } + + int tagCount = 0; + int resultCount = 0; + for (quint32 i = 0; i < result.count; i++) { + aZoneFileStream->skipRawData(12); + + QByteArray tagPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(tagPtr.data(), 4); + + if (tagPtr.toHex() == "ffffffff") { + tagCount++; + } + aZoneFileStream->skipRawData(4); + + QByteArray pathPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pathPtr.data(), 4); + + if (pathPtr.toHex() == "ffffffff") { + resultCount++; + } + + aZoneFileStream->skipRawData(160); + } + + for (int i = 0; i < tagCount; i++) { + // Read in tag? + QString tag; + char tagChar; + *aZoneFileStream >> tagChar; + while (tagChar != 0) { + tag += tagChar; + *aZoneFileStream >> tagChar; + } + } + + for (int i = 0; i < resultCount; i++) { + Sound sound; + + if (aZoneFileStream->device()->peek(12).toHex().contains("ffffffff00000000")) { + aZoneFileStream->skipRawData(12); + } + + aZoneFileStream->skipRawData(8); + + QByteArray aliasPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(aliasPtr.data(), 4); + + QByteArray namePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(namePtr.data(), 4); + + *aZoneFileStream >> sound.dataLength; + + if (aliasPtr.toHex() == "ffffffff") { + // Read in sound alias name + char soundAliasChar; + *aZoneFileStream >> soundAliasChar; + while (soundAliasChar != 0) { + sound.alias += soundAliasChar; + *aZoneFileStream >> soundAliasChar; + } + } + + if (aZoneFileStream->device()->peek(4) == "RIFF") { + sound.path = sound.alias; + sound.alias = ""; + } else if (namePtr.toHex() == "ffffffff") { + // Read in sound file path + char soundPathChar; + *aZoneFileStream >> soundPathChar; + while (soundPathChar != 0) { + sound.path += soundPathChar; + *aZoneFileStream >> soundPathChar; + } + sound.path.replace(",", ""); + } + + if (sound.dataLength) { + QByteArray data(sound.dataLength, Qt::Uninitialized); + aZoneFileStream->readRawData(data.data(), sound.dataLength); + sound.data = data; + } + result.sounds.append(sound); + } + + return result; +} + +void ZoneFile_COD7_360::pParseAsset_ColMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD7_360::pParseAsset_GameMapSP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD7_360::pParseAsset_GameMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD7_360::pParseAsset_LightDef(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD7_360::pParseAsset_UIMap(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD7_360::pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD7_360::pParseAsset_AIType(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD7_360::pParseAsset_FX(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Animation ZoneFile_COD7_360::pParseAsset_Animation(QDataStream *aZoneFileStream) { + Animation result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.dataByteCount + >> result.dataShortCount + >> result.dataIntCount + >> result.randomDataByteCount + >> result.randomDataIntCount + >> result.numframes + >> result.isLooped + >> result.isDelta + >> result.noneRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.normalTranslatedBoneCount + >> result.preciseTranslatedBoneCount + >> result.staticTranslatedBoneCount + >> result.noneTranslatedBoneCount + >> result.totalBoneCount + >> result.otherBoneCount1 + >> result.otherBoneCount2 + >> result.notifyCount + >> result.assetType + >> result.pad + >> result.randomDataShortCount + >> result.indexCount + >> result.frameRate + >> result.frequency + >> result.boneIDsPtr + >> result.dataBytePtr + >> result.dataShortPtr + >> result.dataIntPtr + >> result.randomDataShortPtr + >> result.randomDataBytePtr + >> result.randomDataIntPtr + >> result.longIndiciesPtr + >> result.notificationsPtr + >> result.deltaPartsPtr; + + // Read in x_anim file name + QString xAnimName; + char xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + while (xAnimNameChar != 0) { + result.name += xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + } + + // Parse x_anim index header + QVector sectionLengths; + for (int i = 0; i < result.numframes; i++) { + quint8 sectionlength; + *aZoneFileStream >> sectionlength; + sectionLengths.push_back(sectionlength); + // Skip padding + aZoneFileStream->skipRawData(1); + } + // Skip unknown section + aZoneFileStream->skipRawData(2 * 8); + + return result; +} + +MenuFile ZoneFile_COD7_360::pParseAsset_MenuFile(QDataStream *aZoneFileStream) { + //MENU_FILE + MenuFile result; + + aZoneFileStream->skipRawData(4); // Separator + + // Parse menu def count + *aZoneFileStream >> result.menuCount; + + // Clearly misparsed, never have this much + if (result.menuCount > 1000) { + qDebug() << "Failure reported when parsing menu file."; + return result; + } + for (uint i = 0; i < result.menuCount; i++) { + Menu menu; + + aZoneFileStream->skipRawData(4); // Separator + + // Read in x_anim file name + char menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + while (menuFilepathChar != 0) { + menu.filePath += menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + } + aZoneFileStream->skipRawData(4); // Separator + + *aZoneFileStream >> menu.menuNamePtr; + + float menuRectX, menuRectY, menuRectWidth, menuRectHeight; + *aZoneFileStream >> menuRectX >> menuRectY >> menuRectWidth >> menuRectHeight; + menu.rect = QRectF(menuRectX, menuRectY, menuRectWidth, menuRectHeight); + + quint32 hAlignInt, vAlignInt; + *aZoneFileStream >> hAlignInt >> vAlignInt; + menu.hAlign = (MENU_H_ALIGNMENT)hAlignInt; + menu.vAlign = (MENU_V_ALIGNMENT)vAlignInt; + + float rectClientX, rectClientY, rectClientWidth, rectClientHeight; + *aZoneFileStream >> rectClientX >> rectClientY >> rectClientWidth >> rectClientHeight; + menu.clientRect = QRectF(rectClientX, rectClientY, rectClientWidth, rectClientHeight); + + quint32 hClientAlignInt, vClientAlignInt, styleInt, borderInt; + *aZoneFileStream >> hClientAlignInt >> vClientAlignInt >> menu.groupPtr + >> styleInt >> borderInt >> menu.ownerDraw >> menu.ownerDrawFlags + >> menu.borderSize >> menu.staticFlags >> menu.dynamicFlags >> menu.nextTime; + menu.hClientAlign = (MENU_H_ALIGNMENT)hClientAlignInt; + menu.vClientAlign = (MENU_V_ALIGNMENT)vClientAlignInt; + menu.style = (MENU_WINDOW_STYLE)styleInt; + menu.border = (MENU_WINDOW_BORDER)borderInt; + + float foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA, + backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA, + borderColorR, borderColorG, borderColorB, borderColorA, + outlineColorR, outlineColorG, outlineColorB, outlineColorA; + *aZoneFileStream >> foregroundColorR >> foregroundColorG >> foregroundColorB >> foregroundColorA + >> backgroundColorR >> backgroundColorG >> backgroundColorB >> backgroundColorA + >> borderColorR >> borderColorG >> borderColorB >> borderColorA + >> outlineColorR >> outlineColorG >> outlineColorB >> outlineColorA; + + menu.foregroundColor = QColor(foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA); + menu.backgroundColor = QColor(backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA); + menu.borderColor = QColor(borderColorR, borderColorG, borderColorB, borderColorA); + menu.outlineColor = QColor(outlineColorR, outlineColorG, outlineColorB, outlineColorA); + + *aZoneFileStream >> menu.materialPtr >> menu.fontPtr >> menu.fullScreen >> menu.itemCount + >> menu.fontIndex >> menu.cursorItem >> menu.fadeCycle >> menu.fadeClamp + >> menu.fadeAmount >> menu.fadeInAmount >> menu.blurRadius >> menu.onOpenPtr + >> menu.onFocusPtr >> menu.onClosePtr >> menu.onESCPtr >> menu.onKeyPtr + >> menu.visibleExpCount >> menu.expEntryPtr >> menu.allowedBindingPtr + >> menu.soundNamePtr >> menu.imageTrack; + + float focusColorR, focusColorG, focusColorB, focusColorA, + disabledColorR, disabledColorG, disabledColorB, disabledColorA; + *aZoneFileStream >> focusColorR >> focusColorG >> focusColorB >> focusColorA + >> disabledColorR >> disabledColorG >> disabledColorB >> disabledColorA; + menu.focusColor = QColor(focusColorR, focusColorG, focusColorB, focusColorA); + menu.disabledColor = QColor(disabledColorR, disabledColorG, disabledColorB, disabledColorA); + + *aZoneFileStream >> menu.rectXExpCount >> menu.rectXExpPtr >> menu.rectYExpCount >> menu.rectYExpPtr; + + aZoneFileStream->skipRawData(4); // Separator + + char menuDefNameChar; + int menuDefNameLen = 0; + *aZoneFileStream >> menuDefNameChar; + while (menuDefNameChar != 0 && menuDefNameLen < 30) { + menuDefNameLen++; + menu.name += menuDefNameChar; + *aZoneFileStream >> menuDefNameChar; + } + + char defStringChar; + int defStringLen = 0; + *aZoneFileStream >> defStringChar; + while (defStringChar != 0 && defStringLen < 30) { + defStringLen++; + menu.definition += defStringChar; + *aZoneFileStream >> defStringChar; + } + aZoneFileStream->skipRawData(4 * 10); + + *aZoneFileStream >> menu.itemWindowDefNamePtr; + + float itemRectX, itemRectY, itemRectWidth, itemRectHeight; + *aZoneFileStream >> itemRectX >> itemRectY >> itemRectWidth >> itemRectHeight; + menu.itemRect = QRectF(itemRectX, itemRectY, itemRectWidth, itemRectHeight); + + *aZoneFileStream >> menu.itemHAlignment >> menu.itemVAlignment >> menu.itemGroupPtr + >> menu.itemWindowStyle >> menu.itemWindowBorder >> menu.itemOwnerDraw + >> menu.itemOwnerDrawFlags >> menu.itemBorderSize >> menu.itemStaticFlags + >> menu.itemDynamicFlags >> menu.itemNextTime; + + float itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA, + itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA, + itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA, + itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA; + *aZoneFileStream >> itemForegroundColorR >> itemForegroundColorG >> itemForegroundColorB >> itemForegroundColorA + >> itemBackgroundColorR >> itemBackgroundColorG >> itemBackgroundColorB >> itemBackgroundColorA + >> itemBorderColorR >> itemBorderColorG >> itemBorderColorB >> itemBorderColorA + >> itemOutlineColorR >> itemOutlineColorG >> itemOutlineColorB >> itemOutlineColorA; + + menu.itemForegroundColor = QColor(itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA); + menu.itemBackgroundColor = QColor(itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA); + menu.itemBorderColor = QColor(itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA); + menu.itemOutlineColor = QColor(itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA); + + *aZoneFileStream >> menu.itemMaterialPtr; + + float itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight; + *aZoneFileStream >> itemTextRectX >> itemTextRectY >> itemTextRectWidth >> itemTextRectHeight; + menu.itemTextRect = QRectF(itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight); + + quint32 hItemTextAlignInt, vItemTextAlignInt, itemType, fontTypeInt, textStyleInt; + *aZoneFileStream >> hItemTextAlignInt >> vItemTextAlignInt >> itemType >> menu.dataType + >> menu.alignment >> fontTypeInt >> menu.textAlignMode >> menu.textalignx >> menu.textaligny + >> menu.textscale >> textStyleInt >> menu.gameMsgWindowIndex >> menu.gameMsgWindowMode + >> menu.testPtr >> menu.textSavegameInfo >> menu.parentPtr; + menu.itemText_hAlign = (MENU_H_ALIGNMENT)hItemTextAlignInt; + menu.itemText_vAlign = (MENU_V_ALIGNMENT)vItemTextAlignInt; + menu.itemType = (MENU_ITEM_TYPE)itemType; + menu.fontEnum = (MENU_FONT_TYPE)fontTypeInt; + menu.textStyle = (MENU_ITEM_TEXTSTYLE)textStyleInt; + + *aZoneFileStream >> menu.mouseEnterText >> menu.mouseExitText >> menu.mouseEnter >> menu.mouseExit + >> menu.action >> menu.onAccept >> menu.onFocus >> menu.leaveFocus >> menu.dvar >> menu.dvarTest + >> menu.keyHandlerPtr >> menu.enableDvarPtr >> menu.dvarFlags >> menu.focusSoundPtr + >> menu.special >> menu.cursorPos; + + // itemDefData_t typeData; + + // listBoxDef_s *listBox; + + *aZoneFileStream >> menu.startPos >> menu.endPos >> menu.drawPadding; + + *aZoneFileStream >> menu.elementWidth >> menu.elementHeight; + + *aZoneFileStream >> menu.elementStyle >> menu.numColumns; + + //columnInfo_s columnInfo[16]; + + *aZoneFileStream >> menu.doubleClickPtr; + + + *aZoneFileStream >> menu.notselectable >> menu.noScrollBars >> menu.usePaging; + + float itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA, + itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA, + itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA; + *aZoneFileStream >> itemSelectBorderColorR >> itemSelectBorderColorG >> itemSelectBorderColorB >> itemSelectBorderColorA + >> itemDisableColorR >> itemDisableColorG >> itemDisableColorB >> itemDisableColorA + >> itemFocusColorR >> itemFocusColorG >> itemFocusColorB >> itemFocusColorA; + menu.itemSelectBorderColor = QColor(itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA); + menu.itemDisableColor = QColor(itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA); + menu.itemFocusColor = QColor(itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA); + + *aZoneFileStream >> menu.selectIconPtr >> menu.backgroundItemListboxPtr >> menu.highlightTexturePtr; + + // editFieldDef_s *editField; + + *aZoneFileStream >> menu.minVal >> menu.maxVal >> menu.defVal >> menu.range >> menu.maxChars + >> menu.maxCharsGotoNext >> menu.maxPaintChars >> menu.paintOffset; + + // multiDef_s *multi; + + for (int i = 0; i < 32; i++) { + quint32 dvarList; + *aZoneFileStream >> dvarList; + menu.dvarListPtrs.push_back(dvarList); + } + + for (int i = 0; i < 32; i++) { + quint32 dvarStr; + *aZoneFileStream >> dvarStr; + menu.dvarStrPtrs.push_back(dvarStr); + } + + for (int i = 0; i < 32; i++) { + float dvarValue; + *aZoneFileStream >> dvarValue; + menu.dvarValues.push_back(dvarValue); + } + + *aZoneFileStream >> menu.count >> menu.strDef >> menu.enumDvarNamePtr; + aZoneFileStream->skipRawData(4); + //>> menu.dataPtr + *aZoneFileStream >> menu.itemImageTrack; + + qDebug() << aZoneFileStream->device()->pos(); + + //statement_s visibleExp; + //statement_s textExp; + //statement_s materialExp; + //statement_s rectXExp; + //statement_s rectYExp; + //statement_s rectWExp; + //statement_s rectHExp; + //statement_s foreColorAExp; + result.menuDefs << menu; + } + return result; +} + +void ZoneFile_COD7_360::pParseAsset_Weapon(QDataStream *aZoneFileStream) { + //WEAPON_FILE + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD7_360::pParseAsset_D3DBSP(QDataStream *aZoneFileStream) { + //D3DBSP_DUMP + Q_UNUSED(aZoneFileStream); +} + +StringTable ZoneFile_COD7_360::pParseAsset_StringTable(QDataStream *aZoneFileStream) { + StringTable result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.columnCount + >> result.rowCount; + + // Todo fix this + result.columnCount = 0; + result.rowCount = 0; + + aZoneFileStream->skipRawData(4); + + QString stringTableName; + char stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + while (stringTableNameChar != 0) { + result.name += stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + } + + for (quint32 i = 0; i < result.rowCount; i++) { + QByteArray pointerData(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pointerData.data(), 4); + result.tablePointers.push_back(pointerData.toHex()); + + aZoneFileStream->skipRawData(4); + } + + for (const QString &pointerAddr : result.tablePointers) { + QString leadingContent = ""; + if (pointerAddr == "FFFFFFFF") { + char leadingContentChar; + *aZoneFileStream >> leadingContentChar; + while (leadingContentChar != 0) { + leadingContent += leadingContentChar; + *aZoneFileStream >> leadingContentChar; + } + } else { + leadingContent = pointerAddr; + } + + QString content; + char contentChar; + *aZoneFileStream >> contentChar; + while (contentChar != 0) { + content += contentChar; + *aZoneFileStream >> contentChar; + } + result.content[leadingContent] = content; + } + return result; +} + +AssetType ZoneFile_COD7_360::AssetStrToEnum(const QString aAssetType) { + const QString cleanedType = aAssetType.toUpper(); + if (cleanedType == "17000000") { // localized string PARTIALLY VERIFIED + return ASSET_LOCAL_STRING; + } else if (cleanedType == "20000000") { // raw_file PARTIALLY VERIFIED + return ASSET_RAW_FILE; + } else if (cleanedType == "1A000000") { // fx PARTIALLY VERIFIED + return ASSET_EFFECT; + } else if (cleanedType == "09000000") { // loaded_sound PARTIALLY VERIFIED + return ASSET_SOUND; + } else if (cleanedType == "04000000") { // x_anim PARTIALLY VERIFIED + return ASSET_ANIMATION; + } else if (cleanedType == "0C000000") { // collision_map PARTIALLY VERIFIED + return ASSET_COLLISION_MAP; + } else if (cleanedType == "21000000") { // string_table PARTIALLY VERIFIED + return ASSET_STRING_TABLE; + } else if (cleanedType == "15000000") { // menu_file PARTIALLY VERIFIED + return ASSET_MENU; + } else if (cleanedType == "07000000") { // tech set PARTIALLY VERIFIED + return ASSET_TECH_SET; + } else if (cleanedType == "18000000") { // weapon PARTIALLY VERIFIED + return ASSET_WEAPON; + } else if (cleanedType == "11000000") { // gfx map PARTIALLY VERIFIED + return ASSET_GFX_MAP; + } else if (cleanedType == "12000000") { // light_def PARTIALLY VERIFIED + return ASSET_LIGHT_DEF; + } else if (cleanedType == "14000000") { // font PARTIALLY VERIFIED + return ASSET_FONT; + } else if (cleanedType == "05000000") { // xmodel PARTIALLY VERIFIED + return ASSET_MODEL; + } else if (cleanedType == "0D000000") { // d3dbsp PARTIALLY VERIFIED + return ASSET_D3DBSP; + } else if (cleanedType == "06000000") { // image PARTIALLY VERIFIED + return ASSET_IMAGE; + } else if (cleanedType == "0E000000") { // game map sp PARTIALLY VERIFIED + return ASSET_GAME_MAP_SP; + } else if (cleanedType == "0B000000") { // col map sp PARTIALLY VERIFIED + return ASSET_COL_MAP_SP; + } + return ASSET_NONE; +} + +QByteArray ZoneFile_COD7_360::GetBinaryData() { + QByteArray result; + + return result; +} diff --git a/libs/zonefile/360/zonefile_cod7_360.h b/libs/zonefile/360/zonefile_cod7_360.h new file mode 100644 index 0000000..f61f040 --- /dev/null +++ b/libs/zonefile/360/zonefile_cod7_360.h @@ -0,0 +1,52 @@ +#ifndef ZONEFILE_COD7_360_H +#define ZONEFILE_COD7_360_H + +#include "zonefile.h" + +class ZoneFile_COD7_360 : public ZoneFile +{ +public: + ZoneFile_COD7_360(); + ~ZoneFile_COD7_360(); + + bool Load(const QByteArray aFileData) override; + AssetType AssetStrToEnum(const QString aAssetType) override; + + QByteArray GetBinaryData() override; + +protected: + void pParseZoneHeader(QDataStream *aZoneFileStream) override; + quint32 pParseZoneSize(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsA(QDataStream *aZoneFileStream) override; + quint32 pParseZoneTagCount(QDataStream *aZoneFileStream) override; + quint32 pParseZoneRecordCount(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsB(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsC(QDataStream *aZoneFileStream) override; + QStringList pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) override; + QStringList pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) override; + AssetMap pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) override; + LocalString pParseAsset_LocalString(QDataStream *aZoneFileStream) override; + RawFile pParseAsset_RawFile(QDataStream *aZoneFileStream) override; + void pParseAsset_PhysPreset(QDataStream *aZoneFileStream) override; + Model pParseAsset_Model(QDataStream *aZoneFileStream) override; + Material pParseAsset_Material(QDataStream *aZoneFileStream) override; + Shader pParseAsset_Shader(QDataStream *aZoneFileStream) override; + TechSet pParseAsset_TechSet(QDataStream *aZoneFileStream) override; + Image pParseAsset_Image(QDataStream *aZoneFileStream) override; + SoundAsset pParseAsset_Sound(QDataStream *aZoneFileStream) override; + void pParseAsset_ColMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapSP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_LightDef(QDataStream *aZoneFileStream) override; + void pParseAsset_UIMap(QDataStream *aZoneFileStream) override; + void pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) override; + void pParseAsset_AIType(QDataStream *aZoneFileStream) override; + void pParseAsset_FX(QDataStream *aZoneFileStream) override; + Animation pParseAsset_Animation(QDataStream *aZoneFileStream) override; + MenuFile pParseAsset_MenuFile(QDataStream *aZoneFileStream) override; + void pParseAsset_Weapon(QDataStream *aZoneFileStream) override; + void pParseAsset_D3DBSP(QDataStream *aZoneFileStream) override; + StringTable pParseAsset_StringTable(QDataStream *aZoneFileStream) override; +}; + +#endif // ZONEFILE_COD7_360_H diff --git a/libs/zonefile/360/zonefile_cod8_360.cpp b/libs/zonefile/360/zonefile_cod8_360.cpp new file mode 100644 index 0000000..c17fa3e --- /dev/null +++ b/libs/zonefile/360/zonefile_cod8_360.cpp @@ -0,0 +1,1077 @@ +#include "zonefile_cod8_360.h" + +#include +#include +#include + +ZoneFile_COD8_360::ZoneFile_COD8_360() +{ + +} + +ZoneFile_COD8_360::~ZoneFile_COD8_360() +{ + +} + +bool ZoneFile_COD8_360::Load(const QByteArray aFileData) { + // Open zone file as little endian stream + QDataStream zoneFileStream(aFileData); + zoneFileStream.setByteOrder(QDataStream::BigEndian); + + // Parse data from zone file header + pParseZoneHeader(&zoneFileStream); + zoneFileStream.device()->seek(zoneFileStream.device()->pos() - 1); + SetRecords(pParseZoneIndex(&zoneFileStream, GetRecordCount())); + SetAssetMap(pParseAssets(&zoneFileStream, GetRecords())); + + return true; +} + +void ZoneFile_COD8_360::pParseZoneHeader(QDataStream *aZoneFileStream) { + quint32 size = pParseZoneSize(aZoneFileStream); + SetSize(size); + + pParseZoneUnknownsA(aZoneFileStream); + + quint32 tagCount = pParseZoneTagCount(aZoneFileStream); + SetTagCount(tagCount); + + pParseZoneUnknownsB(aZoneFileStream); + + quint32 recordCount = pParseZoneRecordCount(aZoneFileStream); + SetRecordCount(recordCount); + + if (tagCount) { + pParseZoneUnknownsC(aZoneFileStream); + SetTags(pParseZoneTags(aZoneFileStream, tagCount)); + } else { + aZoneFileStream->skipRawData(4); + } +} + +quint32 ZoneFile_COD8_360::pParseZoneSize(QDataStream *aZoneFileStream) { + quint32 zoneFileSize; + *aZoneFileStream >> zoneFileSize; + if (zoneFileSize <= 0) { + qDebug() << "Tried to open empty zone file!"; + exit(-1); + } + zoneFileSize += 36; + return zoneFileSize; +} + +/* + ParseZoneUnknownsA() + + Parses the 1st section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD8_360::pParseZoneUnknownsA(QDataStream *aZoneFileStream) { + // Byte 4-7, 8-11, 12-15: unknown + QByteArray unknown1(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown1.data(), 4); + + QByteArray unknown2(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown2.data(), 4); + + QByteArray unknown3(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown3.data(), 4); + + // Byte 16-19, 20-23: empty/unknown + QByteArray unknown4(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown4.data(), 4); + + QByteArray unknown5(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown5.data(), 4); + + // Byte 24-27: somehow related to the filesize, but smaller value + QByteArray unknown6(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown6.data(), 4); + + // Byte 28-31, 32-35: unknown + QByteArray unknown7(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown7.data(), 4); + + QByteArray unknown8(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown8.data(), 4); +} + +/* + ParseZoneTagCount() + + Parses the number of string tags in the zone index +*/ +quint32 ZoneFile_COD8_360::pParseZoneTagCount(QDataStream *aZoneFileStream) { + quint32 tagCount; + *aZoneFileStream >> tagCount; + return tagCount; +} + +/* + ParseZoneRecordCount() + + Parses the number of records in the zone index +*/ +quint32 ZoneFile_COD8_360::pParseZoneRecordCount(QDataStream *aZoneFileStream) { + quint32 recordCount; + *aZoneFileStream >> recordCount; + return recordCount; +} + +/* + ParseZoneUnknownsB() + + Parses the 2nd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD8_360::pParseZoneUnknownsB(QDataStream *aZoneFileStream) { + // Byte 44-47: Unknown/empty? + QByteArray unknown9(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown9.data(), 4); +} + +/* + pParseZoneUnknownsC() + + Parses the 3rd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD8_360::pParseZoneUnknownsC(QDataStream *aZoneFileStream) { + // Byte 40-43: Unknown/empty? + QByteArray unknown10(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown10.data(), 4); + + // Byte 44-47: Unknown/empty? + QByteArray unknown11(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown11.data(), 4); +} + +/* + ParseZoneTags() + + Parses the string tags ate the start of zone file +*/ +QStringList ZoneFile_COD8_360::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) { + QStringList tags; + + // Byte 48-51: Repeated separators? ÿÿÿÿ x i + aZoneFileStream->skipRawData(4 * (tagCount - 1)); + + // Parse tags/strings before index + QString zoneTag; + char zoneTagChar; + for (quint32 i = 0; i < tagCount; i++) { + *aZoneFileStream >> zoneTagChar; + while (zoneTagChar != 0) { + zoneTag += zoneTagChar; + *aZoneFileStream >> zoneTagChar; + } + tags << zoneTag; + zoneTag.clear(); + } + return tags; +} + +/* + ParseZoneIndex() + + Parse the binary zone index data and populate table +*/ +QStringList ZoneFile_COD8_360::pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) { + QStringList result; + + // Don't parse if no records + if (!recordCount) { return result; } + + if (aZoneFileStream->device()->peek(4).toHex().contains("ffff")) { + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 2); + } + + // Parse index & map found asset types + for (quint32 i = 0; i <= recordCount; i++) { + // Skip record start + QByteArray rawAssetType(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rawAssetType.data(), 4); + result << rawAssetType.toHex(); + + // Skip separator + aZoneFileStream->skipRawData(4); + } + return result; +} + +AssetMap ZoneFile_COD8_360::pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) { + AssetMap result; + + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 8); + + for (int i = 0; i < assetOrder.size(); i++) { + const QString typeHex = assetOrder[i]; + const AssetType typeStr = AssetStrToEnum(typeHex); + + if (typeStr == ASSET_LOCAL_STRING) { // localized string asset + result.localStrings << pParseAsset_LocalString(aZoneFileStream); + } else if (typeStr == ASSET_RAW_FILE) { // gsc + auto rawFile = pParseAsset_RawFile(aZoneFileStream); + if (rawFile.length) { + result.rawFiles << rawFile; + } + } else if (typeStr == ASSET_PHYS_PRESET) { // physpreset + pParseAsset_PhysPreset(aZoneFileStream); + } else if (typeStr == ASSET_MODEL) { // xmodel + result.models << pParseAsset_Model(aZoneFileStream); + } else if (typeStr == ASSET_MATERIAL) { // material + pParseAsset_Material(aZoneFileStream); + } else if (typeStr == ASSET_SHADER) { // pixelshader + pParseAsset_Shader(aZoneFileStream); + } else if (typeStr == ASSET_TECH_SET) { // techset include + result.techSets << pParseAsset_TechSet(aZoneFileStream); + } else if (typeStr == ASSET_IMAGE) { // image + result.images << pParseAsset_Image(aZoneFileStream); + } else if (typeStr == ASSET_SOUND) { // loaded_sound + result.sounds << pParseAsset_Sound(aZoneFileStream); + } else if (typeStr == ASSET_COLLISION_MAP) { // col_map_mp + pParseAsset_ColMapMP(aZoneFileStream); + } else if (typeStr == ASSET_MP_MAP) { // game_map_sp + pParseAsset_GameMapSP(aZoneFileStream); + } else if (typeStr == ASSET_SP_MAP) { // game_map_mp + pParseAsset_GameMapMP(aZoneFileStream); + } else if (typeStr == ASSET_LIGHT_DEF) { // lightdef + pParseAsset_LightDef(aZoneFileStream); + } else if (typeStr == ASSET_UI_MAP) { // ui_map + pParseAsset_UIMap(aZoneFileStream); + } else if (typeStr == ASSET_SND_DRIVER_GLOBALS) { // snddriverglobals + pParseAsset_SNDDriverGlobals(aZoneFileStream); + } else if (typeStr == ASSET_AI_TYPE) { // aitype + pParseAsset_AIType(aZoneFileStream); + } else if (typeStr == ASSET_EFFECT) { // aitype + pParseAsset_FX(aZoneFileStream); + } else if (typeStr == ASSET_ANIMATION) { // aitype + result.animations << pParseAsset_Animation(aZoneFileStream); + } else if (typeStr == ASSET_STRING_TABLE) { // string_table + result.stringTables << pParseAsset_StringTable(aZoneFileStream); + } else if (typeStr == ASSET_MENU) { // string_table + result.menuFiles << pParseAsset_MenuFile(aZoneFileStream); + } else if (typeStr == ASSET_WEAPON) { // string_table + pParseAsset_Weapon(aZoneFileStream); + } else if (typeStr == ASSET_D3DBSP) { // string_table + pParseAsset_D3DBSP(aZoneFileStream); + } + } + return result; +} + +LocalString ZoneFile_COD8_360::pParseAsset_LocalString(QDataStream *aZoneFileStream) { + LocalString result; + + quint32 stringPtr, aliasPtr; + *aZoneFileStream >> stringPtr >> aliasPtr; + if (stringPtr == 4294967295) { + // Parse local string asset contents + QString localStr; + char localStrChar; + *aZoneFileStream >> localStrChar; + while (localStrChar != 0) { + result.string += localStrChar; + *aZoneFileStream >> localStrChar; + } + } else { + result.string = "String Ptr: " + QString::number(stringPtr); + } + + if (aliasPtr == 4294967295) { + // Parse rawfile name + QString aliasName; + char aliasNameChar; + *aZoneFileStream >> aliasNameChar; + while (aliasNameChar != 0) { + result.alias += aliasNameChar; + *aZoneFileStream >> aliasNameChar; + } + } else { + result.string = "Alias Ptr: " + QString::number(aliasPtr); + } + + return result; +} + +RawFile ZoneFile_COD8_360::pParseAsset_RawFile(QDataStream *aZoneFileStream) { + RawFile result; + + // Skip start separator FF FF FF FF (pointer?) + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.length; + + // Skip unknown 4 byte data + aZoneFileStream->skipRawData(4); + + // Parse rawfile path + char scriptPathChar; + *aZoneFileStream >> scriptPathChar; + while (scriptPathChar != 0) { + result.path += scriptPathChar; + *aZoneFileStream >> scriptPathChar; + } + result.path.replace(",", ""); + const QStringList pathParts = result.path.split('/'); + if (pathParts.size() == 0) { + qDebug() << "Failed to parse ff path! " << result.path; + exit(-1); + } + + // Parse gsc contents + char rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + while (rawFileContentsChar != 0 && rawFileContentsChar != -1) { + result.contents += rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + } + return result; +} + +void ZoneFile_COD8_360::pParseAsset_PhysPreset(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Model ZoneFile_COD8_360::pParseAsset_Model(QDataStream *aZoneFileStream) { + Model result; + + *aZoneFileStream >> result.namePtr >> result.tagCount >> result.rootTagCount + >> result.surfCount >> result.unknownCount >> result.boneNamePtr + >> result.parentListPtr >> result.quatsPtr >> result.transPtr + >> result.partClassPtr >> result.baseMatPtr + >> result.surfsPtr >> result.materialHandlesPtr; + + // Parse XModelLodInfo + for (int i = 1; i <= 4; i++) { + quint32 intDist; + *aZoneFileStream >> intDist; + + std::memcpy(&result.lodInfo[i].dist, &intDist, sizeof(result.lodInfo[i].dist)); + *aZoneFileStream >> result.lodInfo[i].numsurfs >> result.lodInfo[i].surfIndex; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.lodInfo[i].partBits[0] + >> result.lodInfo[i].partBits[1] + >> result.lodInfo[i].partBits[2] + >> result.lodInfo[i].partBits[3]; + } + + *aZoneFileStream >> result.collSurfsPtr >> result.numCollSurfs >> result.contents >> result.boneInfoPtr; + + quint32 intRadius, intMins[3], intMaxs[3]; + *aZoneFileStream >> intRadius >> intMins[0] >> intMins[1] + >> intMins[2] >> intMaxs[0] >> intMaxs[1] >> intMaxs[2]; + + std::memcpy(&result.radius, &intRadius, sizeof(result.radius)); + + std::memcpy(&result.mins[0], &intMins[0], sizeof(result.mins[0])); + std::memcpy(&result.mins[1], &intMins[1], sizeof(result.mins[1])); + std::memcpy(&result.mins[2], &intMins[2], sizeof(result.mins[2])); + + std::memcpy(&result.maxs[0], &intMaxs[0], sizeof(result.maxs[0])); + std::memcpy(&result.maxs[1], &intMaxs[1], sizeof(result.maxs[2])); + std::memcpy(&result.maxs[2], &intMaxs[2], sizeof(result.maxs[3])); + + *aZoneFileStream >> result.numLods >> result.collLod >> result.streamInfoPtr + >> result.memUsage >> result.flags >> result.physPresetPtr >> result.physGeomsPtr; + + // Parse model name + char modelNameChar; + *aZoneFileStream >> modelNameChar; + while (modelNameChar == 0) { + *aZoneFileStream >> modelNameChar; + } + while (modelNameChar != 0) { + result.modelName += modelNameChar; + *aZoneFileStream >> modelNameChar; + } + return result; +} + +Material ZoneFile_COD8_360::pParseAsset_Material(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); + + return Material(); +} + +Shader ZoneFile_COD8_360::pParseAsset_Shader(QDataStream *aZoneFileStream) { + Shader result = Shader(); + + quint8 minorVersion, majorVersion; + *aZoneFileStream >> minorVersion >> majorVersion; + + quint32 magic; + *aZoneFileStream >> magic; + + // Verify .fxc magic + if (magic != 65534 && magic != 65535) { return result; } + + SHADER_TYPE type = SHADER_NONE; + quint16 rawShaderType; + *aZoneFileStream >> rawShaderType; + if (rawShaderType == 65535) { // Pixel shader + type = SHADER_PIXEL; + } else if (rawShaderType == 65534) { // Vertex shader + type = SHADER_VERTEX; + } + Q_UNUSED(type); + + while (true) { + quint32 instructionToken; + *aZoneFileStream >> instructionToken; + + SHADER_OPCODE opCode = (SHADER_OPCODE)(instructionToken & 0xffff); + + int size; + if (opCode == OPCODE_End) { + break; + } else if (opCode == OPCODE_Comment) { + size = (int)((instructionToken >> 16) & 0x7FFF); + } else { + size = (int)((instructionToken >> 24) & 0x0f); + } + Q_UNUSED(size); + } + + + return result; +} + +TechSet ZoneFile_COD8_360::pParseAsset_TechSet(QDataStream *aZoneFileStream) { + TechSet result; + + for (int i = 1; i <= 62; i++) { + quint32 ptr; + *aZoneFileStream >> ptr; + + result.pointers << ptr; + } + qDebug() << aZoneFileStream->device()->pos(); + + // Parse techset name + char techSetNameChar; + *aZoneFileStream >> techSetNameChar; + while (techSetNameChar != 0) { + result.name += techSetNameChar; + *aZoneFileStream >> techSetNameChar; + } + result.name.replace(",", ""); + + return result; +} + +Image ZoneFile_COD8_360::pParseAsset_Image(QDataStream *aZoneFileStream) { + Image result; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknowna >> result.unknownb + >> result.unknownc >> result.unknownd + >> result.unknowne >> result.unknownf + >> result.unknowng; + + aZoneFileStream->skipRawData(15 * 4); + *aZoneFileStream >> result.unknownh >> result.unknowni; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknownj; + + aZoneFileStream->skipRawData(4); + + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + result.materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + result.materialName.replace(",", ""); + + if (result.unknowna) { + *aZoneFileStream >> result.unknownk; + *aZoneFileStream >> result.unknownl; + *aZoneFileStream >> result.unknownm; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown1; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown2 >> result.unknown3 + >> result.size1 >> result.size2 + >> result.unknown4 >> result.unknown5; + + aZoneFileStream->skipRawData(4); + + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + result.name += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + + *aZoneFileStream >> result.unknown6 >> result.unknown7; + + QByteArray compressionData(8, Qt::Uninitialized); + aZoneFileStream->readRawData(compressionData.data(), 8); + if (compressionData.contains("DXT1")) { + result.compression = COMPRESSION_DXT1; + } else if (compressionData.contains("DXT3")) { + result.compression = COMPRESSION_DXT3; + } else if (compressionData.contains("DXT5")) { + result.compression = COMPRESSION_DXT5; + } else { + result.compression = COMPRESSION_NONE; + } + + *aZoneFileStream >> result.unknown8 >> result.unknown9; + } + + return result; +} + +SoundAsset ZoneFile_COD8_360::pParseAsset_Sound(QDataStream *aZoneFileStream) { + SoundAsset result; + + qDebug() << aZoneFileStream->device()->pos(); + + QByteArray rootNamePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rootNamePtr.data(), 4); + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.count; + + if (rootNamePtr.toHex() == "ffffffff") { + // Read in sound file name + char soundNameChar; + *aZoneFileStream >> soundNameChar; + while (soundNameChar != 0) { + result.name += soundNameChar; + *aZoneFileStream >> soundNameChar; + } + } + + int tagCount = 0; + int resultCount = 0; + for (quint32 i = 0; i < result.count; i++) { + aZoneFileStream->skipRawData(12); + + QByteArray tagPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(tagPtr.data(), 4); + + if (tagPtr.toHex() == "ffffffff") { + tagCount++; + } + aZoneFileStream->skipRawData(4); + + QByteArray pathPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pathPtr.data(), 4); + + if (pathPtr.toHex() == "ffffffff") { + resultCount++; + } + + aZoneFileStream->skipRawData(160); + } + + for (int i = 0; i < tagCount; i++) { + // Read in tag? + QString tag; + char tagChar; + *aZoneFileStream >> tagChar; + while (tagChar != 0) { + tag += tagChar; + *aZoneFileStream >> tagChar; + } + } + + for (int i = 0; i < resultCount; i++) { + Sound sound; + + if (aZoneFileStream->device()->peek(12).toHex().contains("ffffffff00000000")) { + aZoneFileStream->skipRawData(12); + } + + aZoneFileStream->skipRawData(8); + + QByteArray aliasPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(aliasPtr.data(), 4); + + QByteArray namePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(namePtr.data(), 4); + + *aZoneFileStream >> sound.dataLength; + + if (aliasPtr.toHex() == "ffffffff") { + // Read in sound alias name + char soundAliasChar; + *aZoneFileStream >> soundAliasChar; + while (soundAliasChar != 0) { + sound.alias += soundAliasChar; + *aZoneFileStream >> soundAliasChar; + } + } + + if (aZoneFileStream->device()->peek(4) == "RIFF") { + sound.path = sound.alias; + sound.alias = ""; + } else if (namePtr.toHex() == "ffffffff") { + // Read in sound file path + char soundPathChar; + *aZoneFileStream >> soundPathChar; + while (soundPathChar != 0) { + sound.path += soundPathChar; + *aZoneFileStream >> soundPathChar; + } + sound.path.replace(",", ""); + } + + if (sound.dataLength) { + QByteArray data(sound.dataLength, Qt::Uninitialized); + aZoneFileStream->readRawData(data.data(), sound.dataLength); + sound.data = data; + } + result.sounds.append(sound); + } + + return result; +} + +void ZoneFile_COD8_360::pParseAsset_ColMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD8_360::pParseAsset_GameMapSP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD8_360::pParseAsset_GameMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD8_360::pParseAsset_LightDef(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD8_360::pParseAsset_UIMap(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD8_360::pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD8_360::pParseAsset_AIType(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD8_360::pParseAsset_FX(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Animation ZoneFile_COD8_360::pParseAsset_Animation(QDataStream *aZoneFileStream) { + Animation result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.dataByteCount + >> result.dataShortCount + >> result.dataIntCount + >> result.randomDataByteCount + >> result.randomDataIntCount + >> result.numframes + >> result.isLooped + >> result.isDelta + >> result.noneRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.normalTranslatedBoneCount + >> result.preciseTranslatedBoneCount + >> result.staticTranslatedBoneCount + >> result.noneTranslatedBoneCount + >> result.totalBoneCount + >> result.otherBoneCount1 + >> result.otherBoneCount2 + >> result.notifyCount + >> result.assetType + >> result.pad + >> result.randomDataShortCount + >> result.indexCount + >> result.frameRate + >> result.frequency + >> result.boneIDsPtr + >> result.dataBytePtr + >> result.dataShortPtr + >> result.dataIntPtr + >> result.randomDataShortPtr + >> result.randomDataBytePtr + >> result.randomDataIntPtr + >> result.longIndiciesPtr + >> result.notificationsPtr + >> result.deltaPartsPtr; + + // Read in x_anim file name + QString xAnimName; + char xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + while (xAnimNameChar != 0) { + result.name += xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + } + + // Parse x_anim index header + QVector sectionLengths; + for (int i = 0; i < result.numframes; i++) { + quint8 sectionlength; + *aZoneFileStream >> sectionlength; + sectionLengths.push_back(sectionlength); + // Skip padding + aZoneFileStream->skipRawData(1); + } + // Skip unknown section + aZoneFileStream->skipRawData(2 * 8); + + return result; +} + +MenuFile ZoneFile_COD8_360::pParseAsset_MenuFile(QDataStream *aZoneFileStream) { + //MENU_FILE + MenuFile result; + + aZoneFileStream->skipRawData(4); // Separator + + // Parse menu def count + *aZoneFileStream >> result.menuCount; + + // Clearly misparsed, never have this much + if (result.menuCount > 1000) { + qDebug() << "Failure reported when parsing menu file."; + return result; + } + for (uint i = 0; i < result.menuCount; i++) { + Menu menu; + + aZoneFileStream->skipRawData(4); // Separator + + // Read in x_anim file name + char menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + while (menuFilepathChar != 0) { + menu.filePath += menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + } + aZoneFileStream->skipRawData(4); // Separator + + *aZoneFileStream >> menu.menuNamePtr; + + float menuRectX, menuRectY, menuRectWidth, menuRectHeight; + *aZoneFileStream >> menuRectX >> menuRectY >> menuRectWidth >> menuRectHeight; + menu.rect = QRectF(menuRectX, menuRectY, menuRectWidth, menuRectHeight); + + quint32 hAlignInt, vAlignInt; + *aZoneFileStream >> hAlignInt >> vAlignInt; + menu.hAlign = (MENU_H_ALIGNMENT)hAlignInt; + menu.vAlign = (MENU_V_ALIGNMENT)vAlignInt; + + float rectClientX, rectClientY, rectClientWidth, rectClientHeight; + *aZoneFileStream >> rectClientX >> rectClientY >> rectClientWidth >> rectClientHeight; + menu.clientRect = QRectF(rectClientX, rectClientY, rectClientWidth, rectClientHeight); + + quint32 hClientAlignInt, vClientAlignInt, styleInt, borderInt; + *aZoneFileStream >> hClientAlignInt >> vClientAlignInt >> menu.groupPtr + >> styleInt >> borderInt >> menu.ownerDraw >> menu.ownerDrawFlags + >> menu.borderSize >> menu.staticFlags >> menu.dynamicFlags >> menu.nextTime; + menu.hClientAlign = (MENU_H_ALIGNMENT)hClientAlignInt; + menu.vClientAlign = (MENU_V_ALIGNMENT)vClientAlignInt; + menu.style = (MENU_WINDOW_STYLE)styleInt; + menu.border = (MENU_WINDOW_BORDER)borderInt; + + float foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA, + backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA, + borderColorR, borderColorG, borderColorB, borderColorA, + outlineColorR, outlineColorG, outlineColorB, outlineColorA; + *aZoneFileStream >> foregroundColorR >> foregroundColorG >> foregroundColorB >> foregroundColorA + >> backgroundColorR >> backgroundColorG >> backgroundColorB >> backgroundColorA + >> borderColorR >> borderColorG >> borderColorB >> borderColorA + >> outlineColorR >> outlineColorG >> outlineColorB >> outlineColorA; + + menu.foregroundColor = QColor(foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA); + menu.backgroundColor = QColor(backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA); + menu.borderColor = QColor(borderColorR, borderColorG, borderColorB, borderColorA); + menu.outlineColor = QColor(outlineColorR, outlineColorG, outlineColorB, outlineColorA); + + *aZoneFileStream >> menu.materialPtr >> menu.fontPtr >> menu.fullScreen >> menu.itemCount + >> menu.fontIndex >> menu.cursorItem >> menu.fadeCycle >> menu.fadeClamp + >> menu.fadeAmount >> menu.fadeInAmount >> menu.blurRadius >> menu.onOpenPtr + >> menu.onFocusPtr >> menu.onClosePtr >> menu.onESCPtr >> menu.onKeyPtr + >> menu.visibleExpCount >> menu.expEntryPtr >> menu.allowedBindingPtr + >> menu.soundNamePtr >> menu.imageTrack; + + float focusColorR, focusColorG, focusColorB, focusColorA, + disabledColorR, disabledColorG, disabledColorB, disabledColorA; + *aZoneFileStream >> focusColorR >> focusColorG >> focusColorB >> focusColorA + >> disabledColorR >> disabledColorG >> disabledColorB >> disabledColorA; + menu.focusColor = QColor(focusColorR, focusColorG, focusColorB, focusColorA); + menu.disabledColor = QColor(disabledColorR, disabledColorG, disabledColorB, disabledColorA); + + *aZoneFileStream >> menu.rectXExpCount >> menu.rectXExpPtr >> menu.rectYExpCount >> menu.rectYExpPtr; + + aZoneFileStream->skipRawData(4); // Separator + + char menuDefNameChar; + int menuDefNameLen = 0; + *aZoneFileStream >> menuDefNameChar; + while (menuDefNameChar != 0 && menuDefNameLen < 30) { + menuDefNameLen++; + menu.name += menuDefNameChar; + *aZoneFileStream >> menuDefNameChar; + } + + char defStringChar; + int defStringLen = 0; + *aZoneFileStream >> defStringChar; + while (defStringChar != 0 && defStringLen < 30) { + defStringLen++; + menu.definition += defStringChar; + *aZoneFileStream >> defStringChar; + } + aZoneFileStream->skipRawData(4 * 10); + + *aZoneFileStream >> menu.itemWindowDefNamePtr; + + float itemRectX, itemRectY, itemRectWidth, itemRectHeight; + *aZoneFileStream >> itemRectX >> itemRectY >> itemRectWidth >> itemRectHeight; + menu.itemRect = QRectF(itemRectX, itemRectY, itemRectWidth, itemRectHeight); + + *aZoneFileStream >> menu.itemHAlignment >> menu.itemVAlignment >> menu.itemGroupPtr + >> menu.itemWindowStyle >> menu.itemWindowBorder >> menu.itemOwnerDraw + >> menu.itemOwnerDrawFlags >> menu.itemBorderSize >> menu.itemStaticFlags + >> menu.itemDynamicFlags >> menu.itemNextTime; + + float itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA, + itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA, + itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA, + itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA; + *aZoneFileStream >> itemForegroundColorR >> itemForegroundColorG >> itemForegroundColorB >> itemForegroundColorA + >> itemBackgroundColorR >> itemBackgroundColorG >> itemBackgroundColorB >> itemBackgroundColorA + >> itemBorderColorR >> itemBorderColorG >> itemBorderColorB >> itemBorderColorA + >> itemOutlineColorR >> itemOutlineColorG >> itemOutlineColorB >> itemOutlineColorA; + + menu.itemForegroundColor = QColor(itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA); + menu.itemBackgroundColor = QColor(itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA); + menu.itemBorderColor = QColor(itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA); + menu.itemOutlineColor = QColor(itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA); + + *aZoneFileStream >> menu.itemMaterialPtr; + + float itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight; + *aZoneFileStream >> itemTextRectX >> itemTextRectY >> itemTextRectWidth >> itemTextRectHeight; + menu.itemTextRect = QRectF(itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight); + + quint32 hItemTextAlignInt, vItemTextAlignInt, itemType, fontTypeInt, textStyleInt; + *aZoneFileStream >> hItemTextAlignInt >> vItemTextAlignInt >> itemType >> menu.dataType + >> menu.alignment >> fontTypeInt >> menu.textAlignMode >> menu.textalignx >> menu.textaligny + >> menu.textscale >> textStyleInt >> menu.gameMsgWindowIndex >> menu.gameMsgWindowMode + >> menu.testPtr >> menu.textSavegameInfo >> menu.parentPtr; + menu.itemText_hAlign = (MENU_H_ALIGNMENT)hItemTextAlignInt; + menu.itemText_vAlign = (MENU_V_ALIGNMENT)vItemTextAlignInt; + menu.itemType = (MENU_ITEM_TYPE)itemType; + menu.fontEnum = (MENU_FONT_TYPE)fontTypeInt; + menu.textStyle = (MENU_ITEM_TEXTSTYLE)textStyleInt; + + *aZoneFileStream >> menu.mouseEnterText >> menu.mouseExitText >> menu.mouseEnter >> menu.mouseExit + >> menu.action >> menu.onAccept >> menu.onFocus >> menu.leaveFocus >> menu.dvar >> menu.dvarTest + >> menu.keyHandlerPtr >> menu.enableDvarPtr >> menu.dvarFlags >> menu.focusSoundPtr + >> menu.special >> menu.cursorPos; + + // itemDefData_t typeData; + + // listBoxDef_s *listBox; + + *aZoneFileStream >> menu.startPos >> menu.endPos >> menu.drawPadding; + + *aZoneFileStream >> menu.elementWidth >> menu.elementHeight; + + *aZoneFileStream >> menu.elementStyle >> menu.numColumns; + + //columnInfo_s columnInfo[16]; + + *aZoneFileStream >> menu.doubleClickPtr; + + + *aZoneFileStream >> menu.notselectable >> menu.noScrollBars >> menu.usePaging; + + float itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA, + itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA, + itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA; + *aZoneFileStream >> itemSelectBorderColorR >> itemSelectBorderColorG >> itemSelectBorderColorB >> itemSelectBorderColorA + >> itemDisableColorR >> itemDisableColorG >> itemDisableColorB >> itemDisableColorA + >> itemFocusColorR >> itemFocusColorG >> itemFocusColorB >> itemFocusColorA; + menu.itemSelectBorderColor = QColor(itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA); + menu.itemDisableColor = QColor(itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA); + menu.itemFocusColor = QColor(itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA); + + *aZoneFileStream >> menu.selectIconPtr >> menu.backgroundItemListboxPtr >> menu.highlightTexturePtr; + + // editFieldDef_s *editField; + + *aZoneFileStream >> menu.minVal >> menu.maxVal >> menu.defVal >> menu.range >> menu.maxChars + >> menu.maxCharsGotoNext >> menu.maxPaintChars >> menu.paintOffset; + + // multiDef_s *multi; + + for (int i = 0; i < 32; i++) { + quint32 dvarList; + *aZoneFileStream >> dvarList; + menu.dvarListPtrs.push_back(dvarList); + } + + for (int i = 0; i < 32; i++) { + quint32 dvarStr; + *aZoneFileStream >> dvarStr; + menu.dvarStrPtrs.push_back(dvarStr); + } + + for (int i = 0; i < 32; i++) { + float dvarValue; + *aZoneFileStream >> dvarValue; + menu.dvarValues.push_back(dvarValue); + } + + *aZoneFileStream >> menu.count >> menu.strDef >> menu.enumDvarNamePtr; + aZoneFileStream->skipRawData(4); + //>> menu.dataPtr + *aZoneFileStream >> menu.itemImageTrack; + + qDebug() << aZoneFileStream->device()->pos(); + + //statement_s visibleExp; + //statement_s textExp; + //statement_s materialExp; + //statement_s rectXExp; + //statement_s rectYExp; + //statement_s rectWExp; + //statement_s rectHExp; + //statement_s foreColorAExp; + result.menuDefs << menu; + } + return result; +} + +void ZoneFile_COD8_360::pParseAsset_Weapon(QDataStream *aZoneFileStream) { + //WEAPON_FILE + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD8_360::pParseAsset_D3DBSP(QDataStream *aZoneFileStream) { + //D3DBSP_DUMP + Q_UNUSED(aZoneFileStream); +} + +StringTable ZoneFile_COD8_360::pParseAsset_StringTable(QDataStream *aZoneFileStream) { + StringTable result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.columnCount + >> result.rowCount; + + // Todo fix this + result.columnCount = 0; + result.rowCount = 0; + + aZoneFileStream->skipRawData(4); + + QString stringTableName; + char stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + while (stringTableNameChar != 0) { + result.name += stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + } + + for (quint32 i = 0; i < result.rowCount; i++) { + QByteArray pointerData(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pointerData.data(), 4); + result.tablePointers.push_back(pointerData.toHex()); + + aZoneFileStream->skipRawData(4); + } + + for (const QString &pointerAddr : result.tablePointers) { + QString leadingContent = ""; + if (pointerAddr == "FFFFFFFF") { + char leadingContentChar; + *aZoneFileStream >> leadingContentChar; + while (leadingContentChar != 0) { + leadingContent += leadingContentChar; + *aZoneFileStream >> leadingContentChar; + } + } else { + leadingContent = pointerAddr; + } + + QString content; + char contentChar; + *aZoneFileStream >> contentChar; + while (contentChar != 0) { + content += contentChar; + *aZoneFileStream >> contentChar; + } + result.content[leadingContent] = content; + } + return result; +} + +AssetType ZoneFile_COD8_360::AssetStrToEnum(const QString aAssetType) { + const QString cleanedType = aAssetType.toUpper(); + if (cleanedType == "17000000") { // localized string PARTIALLY VERIFIED + return ASSET_LOCAL_STRING; + } else if (cleanedType == "20000000") { // raw_file PARTIALLY VERIFIED + return ASSET_RAW_FILE; + } else if (cleanedType == "1A000000") { // fx PARTIALLY VERIFIED + return ASSET_EFFECT; + } else if (cleanedType == "09000000") { // loaded_sound PARTIALLY VERIFIED + return ASSET_SOUND; + } else if (cleanedType == "04000000") { // x_anim PARTIALLY VERIFIED + return ASSET_ANIMATION; + } else if (cleanedType == "0C000000") { // collision_map PARTIALLY VERIFIED + return ASSET_COLLISION_MAP; + } else if (cleanedType == "21000000") { // string_table PARTIALLY VERIFIED + return ASSET_STRING_TABLE; + } else if (cleanedType == "15000000") { // menu_file PARTIALLY VERIFIED + return ASSET_MENU; + } else if (cleanedType == "07000000") { // tech set PARTIALLY VERIFIED + return ASSET_TECH_SET; + } else if (cleanedType == "18000000") { // weapon PARTIALLY VERIFIED + return ASSET_WEAPON; + } else if (cleanedType == "11000000") { // gfx map PARTIALLY VERIFIED + return ASSET_GFX_MAP; + } else if (cleanedType == "12000000") { // light_def PARTIALLY VERIFIED + return ASSET_LIGHT_DEF; + } else if (cleanedType == "14000000") { // font PARTIALLY VERIFIED + return ASSET_FONT; + } else if (cleanedType == "05000000") { // xmodel PARTIALLY VERIFIED + return ASSET_MODEL; + } else if (cleanedType == "0D000000") { // d3dbsp PARTIALLY VERIFIED + return ASSET_D3DBSP; + } else if (cleanedType == "06000000") { // image PARTIALLY VERIFIED + return ASSET_IMAGE; + } else if (cleanedType == "0E000000") { // game map sp PARTIALLY VERIFIED + return ASSET_GAME_MAP_SP; + } else if (cleanedType == "0B000000") { // col map sp PARTIALLY VERIFIED + return ASSET_COL_MAP_SP; + } + return ASSET_NONE; +} + +QByteArray ZoneFile_COD8_360::GetBinaryData() { + QByteArray result; + + return result; +} diff --git a/libs/zonefile/360/zonefile_cod8_360.h b/libs/zonefile/360/zonefile_cod8_360.h new file mode 100644 index 0000000..13c419e --- /dev/null +++ b/libs/zonefile/360/zonefile_cod8_360.h @@ -0,0 +1,52 @@ +#ifndef ZONEFILE_COD8_360_H +#define ZONEFILE_COD8_360_H + +#include "zonefile.h" + +class ZoneFile_COD8_360 : public ZoneFile +{ +public: + ZoneFile_COD8_360(); + ~ZoneFile_COD8_360(); + + bool Load(const QByteArray aFileData) override; + AssetType AssetStrToEnum(const QString aAssetType) override; + + QByteArray GetBinaryData() override; + +protected: + void pParseZoneHeader(QDataStream *aZoneFileStream) override; + quint32 pParseZoneSize(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsA(QDataStream *aZoneFileStream) override; + quint32 pParseZoneTagCount(QDataStream *aZoneFileStream) override; + quint32 pParseZoneRecordCount(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsB(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsC(QDataStream *aZoneFileStream) override; + QStringList pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) override; + QStringList pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) override; + AssetMap pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) override; + LocalString pParseAsset_LocalString(QDataStream *aZoneFileStream) override; + RawFile pParseAsset_RawFile(QDataStream *aZoneFileStream) override; + void pParseAsset_PhysPreset(QDataStream *aZoneFileStream) override; + Model pParseAsset_Model(QDataStream *aZoneFileStream) override; + Material pParseAsset_Material(QDataStream *aZoneFileStream) override; + Shader pParseAsset_Shader(QDataStream *aZoneFileStream) override; + TechSet pParseAsset_TechSet(QDataStream *aZoneFileStream) override; + Image pParseAsset_Image(QDataStream *aZoneFileStream) override; + SoundAsset pParseAsset_Sound(QDataStream *aZoneFileStream) override; + void pParseAsset_ColMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapSP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_LightDef(QDataStream *aZoneFileStream) override; + void pParseAsset_UIMap(QDataStream *aZoneFileStream) override; + void pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) override; + void pParseAsset_AIType(QDataStream *aZoneFileStream) override; + void pParseAsset_FX(QDataStream *aZoneFileStream) override; + Animation pParseAsset_Animation(QDataStream *aZoneFileStream) override; + MenuFile pParseAsset_MenuFile(QDataStream *aZoneFileStream) override; + void pParseAsset_Weapon(QDataStream *aZoneFileStream) override; + void pParseAsset_D3DBSP(QDataStream *aZoneFileStream) override; + StringTable pParseAsset_StringTable(QDataStream *aZoneFileStream) override; +}; + +#endif // ZONEFILE_COD8_360_H diff --git a/libs/zonefile/360/zonefile_cod9_360.cpp b/libs/zonefile/360/zonefile_cod9_360.cpp new file mode 100644 index 0000000..5155c1c --- /dev/null +++ b/libs/zonefile/360/zonefile_cod9_360.cpp @@ -0,0 +1,1072 @@ +#include "zonefile_cod9_360.h" + +#include +#include +#include + +ZoneFile_COD9_360::ZoneFile_COD9_360() +{ + +} + +ZoneFile_COD9_360::~ZoneFile_COD9_360() +{ + +} + +bool ZoneFile_COD9_360::Load(const QByteArray aFileData) { + // Open zone file as little endian stream + QDataStream zoneFileStream(aFileData); + zoneFileStream.setByteOrder(QDataStream::BigEndian); + + // Parse data from zone file header + pParseZoneHeader(&zoneFileStream); + SetRecords(pParseZoneIndex(&zoneFileStream, GetRecordCount())); + SetAssetMap(pParseAssets(&zoneFileStream, GetRecords())); + + return true; +} + +void ZoneFile_COD9_360::pParseZoneHeader(QDataStream *aZoneFileStream) { + SetSize(pParseZoneSize(aZoneFileStream)); + pParseZoneUnknownsA(aZoneFileStream); + + SetTagCount(pParseZoneTagCount(aZoneFileStream)); + pParseZoneUnknownsB(aZoneFileStream); + + SetRecordCount(pParseZoneRecordCount(aZoneFileStream)); + + quint32 tagCount = GetTagCount(); + if (tagCount) { + pParseZoneUnknownsC(aZoneFileStream); + SetTags(pParseZoneTags(aZoneFileStream, tagCount)); + } else { + aZoneFileStream->skipRawData(4); + } +} + +quint32 ZoneFile_COD9_360::pParseZoneSize(QDataStream *aZoneFileStream) { + quint32 zoneFileSize; + *aZoneFileStream >> zoneFileSize; + if (zoneFileSize <= 0) { + qDebug() << "Tried to open empty zone file!"; + exit(-1); + } + zoneFileSize += 36; + return zoneFileSize; +} + +/* + ParseZoneUnknownsA() + + Parses the 1st section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD9_360::pParseZoneUnknownsA(QDataStream *aZoneFileStream) { + // Byte 4-7, 8-11, 12-15: unknown + QByteArray unknown1(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown1.data(), 4); + + QByteArray unknown2(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown2.data(), 4); + + QByteArray unknown3(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown3.data(), 4); + + // Byte 16-19, 20-23: empty/unknown + QByteArray unknown4(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown4.data(), 4); + + QByteArray unknown5(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown5.data(), 4); + + // Byte 24-27: somehow related to the filesize, but smaller value + QByteArray unknown6(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown6.data(), 4); + + // Byte 28-31, 32-35: unknown + QByteArray unknown7(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown7.data(), 4); + + QByteArray unknown8(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown8.data(), 4); +} + +/* + ParseZoneTagCount() + + Parses the number of string tags in the zone index +*/ +quint32 ZoneFile_COD9_360::pParseZoneTagCount(QDataStream *aZoneFileStream) { + quint32 tagCount; + *aZoneFileStream >> tagCount; + return tagCount; +} + +/* + ParseZoneRecordCount() + + Parses the number of records in the zone index +*/ +quint32 ZoneFile_COD9_360::pParseZoneRecordCount(QDataStream *aZoneFileStream) { + quint32 recordCount; + *aZoneFileStream >> recordCount; + return recordCount; +} + +/* + ParseZoneUnknownsB() + + Parses the 2nd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD9_360::pParseZoneUnknownsB(QDataStream *aZoneFileStream) { + // Byte 44-47: Unknown/empty? + QByteArray unknown9(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown9.data(), 4); +} + +/* + pParseZoneUnknownsC() + + Parses the 3rd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD9_360::pParseZoneUnknownsC(QDataStream *aZoneFileStream) { + // Byte 40-43: Unknown/empty? + QByteArray unknown10(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown10.data(), 4); + + // Byte 44-47: Unknown/empty? + QByteArray unknown11(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown11.data(), 4); +} + +/* + ParseZoneTags() + + Parses the string tags ate the start of zone file +*/ +QStringList ZoneFile_COD9_360::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) { + QStringList tags; + + // Byte 48-51: Repeated separators? ÿÿÿÿ x i + aZoneFileStream->skipRawData(4 * (tagCount - 1)); + + // Parse tags/strings before index + QString zoneTag; + char zoneTagChar; + for (quint32 i = 0; i < tagCount; i++) { + *aZoneFileStream >> zoneTagChar; + while (zoneTagChar != 0) { + zoneTag += zoneTagChar; + *aZoneFileStream >> zoneTagChar; + } + tags << zoneTag; + zoneTag.clear(); + } + return tags; +} + +/* + ParseZoneIndex() + + Parse the binary zone index data and populate table +*/ +QStringList ZoneFile_COD9_360::pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) { + QStringList result; + + // Don't parse if no records + if (!recordCount) { return result; } + + if (aZoneFileStream->device()->peek(4).toHex().contains("ffff")) { + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 2); + } + + // Parse index & map found asset types + for (quint32 i = 0; i <= recordCount; i++) { + // Skip record start + QByteArray rawAssetType(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rawAssetType.data(), 4); + result << rawAssetType.toHex(); + + // Skip separator + aZoneFileStream->skipRawData(4); + } + return result; +} + +AssetMap ZoneFile_COD9_360::pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) { + AssetMap result; + + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 8); + + for (int i = 0; i < assetOrder.size(); i++) { + const QString typeHex = assetOrder[i]; + const AssetType typeStr = AssetStrToEnum(typeHex); + + if (typeStr == ASSET_LOCAL_STRING) { // localized string asset + result.localStrings << pParseAsset_LocalString(aZoneFileStream); + } else if (typeStr == ASSET_RAW_FILE) { // gsc + auto rawFile = pParseAsset_RawFile(aZoneFileStream); + if (rawFile.length) { + result.rawFiles << rawFile; + } + } else if (typeStr == ASSET_PHYS_PRESET) { // physpreset + pParseAsset_PhysPreset(aZoneFileStream); + } else if (typeStr == ASSET_MODEL) { // xmodel + result.models << pParseAsset_Model(aZoneFileStream); + } else if (typeStr == ASSET_MATERIAL) { // material + pParseAsset_Material(aZoneFileStream); + } else if (typeStr == ASSET_SHADER) { // pixelshader + pParseAsset_Shader(aZoneFileStream); + } else if (typeStr == ASSET_TECH_SET) { // techset include + result.techSets << pParseAsset_TechSet(aZoneFileStream); + } else if (typeStr == ASSET_IMAGE) { // image + result.images << pParseAsset_Image(aZoneFileStream); + } else if (typeStr == ASSET_SOUND) { // loaded_sound + result.sounds << pParseAsset_Sound(aZoneFileStream); + } else if (typeStr == ASSET_COLLISION_MAP) { // col_map_mp + pParseAsset_ColMapMP(aZoneFileStream); + } else if (typeStr == ASSET_MP_MAP) { // game_map_sp + pParseAsset_GameMapSP(aZoneFileStream); + } else if (typeStr == ASSET_SP_MAP) { // game_map_mp + pParseAsset_GameMapMP(aZoneFileStream); + } else if (typeStr == ASSET_LIGHT_DEF) { // lightdef + pParseAsset_LightDef(aZoneFileStream); + } else if (typeStr == ASSET_UI_MAP) { // ui_map + pParseAsset_UIMap(aZoneFileStream); + } else if (typeStr == ASSET_SND_DRIVER_GLOBALS) { // snddriverglobals + pParseAsset_SNDDriverGlobals(aZoneFileStream); + } else if (typeStr == ASSET_AI_TYPE) { // aitype + pParseAsset_AIType(aZoneFileStream); + } else if (typeStr == ASSET_EFFECT) { // aitype + pParseAsset_FX(aZoneFileStream); + } else if (typeStr == ASSET_ANIMATION) { // aitype + result.animations << pParseAsset_Animation(aZoneFileStream); + } else if (typeStr == ASSET_STRING_TABLE) { // string_table + result.stringTables << pParseAsset_StringTable(aZoneFileStream); + } else if (typeStr == ASSET_MENU) { // string_table + result.menuFiles << pParseAsset_MenuFile(aZoneFileStream); + } else if (typeStr == ASSET_WEAPON) { // string_table + pParseAsset_Weapon(aZoneFileStream); + } else if (typeStr == ASSET_D3DBSP) { // string_table + pParseAsset_D3DBSP(aZoneFileStream); + } + } + return result; +} + +LocalString ZoneFile_COD9_360::pParseAsset_LocalString(QDataStream *aZoneFileStream) { + LocalString result; + + quint32 stringPtr, aliasPtr; + *aZoneFileStream >> stringPtr >> aliasPtr; + if (stringPtr == 4294967295) { + // Parse local string asset contents + QString localStr; + char localStrChar; + *aZoneFileStream >> localStrChar; + while (localStrChar != 0) { + result.string += localStrChar; + *aZoneFileStream >> localStrChar; + } + } else { + result.string = "String Ptr: " + QString::number(stringPtr); + } + + if (aliasPtr == 4294967295) { + // Parse rawfile name + QString aliasName; + char aliasNameChar; + *aZoneFileStream >> aliasNameChar; + while (aliasNameChar != 0) { + result.alias += aliasNameChar; + *aZoneFileStream >> aliasNameChar; + } + } else { + result.string = "Alias Ptr: " + QString::number(aliasPtr); + } + + return result; +} + +RawFile ZoneFile_COD9_360::pParseAsset_RawFile(QDataStream *aZoneFileStream) { + RawFile result; + + // Skip start separator FF FF FF FF (pointer?) + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.length; + + // Skip unknown 4 byte data + aZoneFileStream->skipRawData(4); + + // Parse rawfile path + char scriptPathChar; + *aZoneFileStream >> scriptPathChar; + while (scriptPathChar != 0) { + result.path += scriptPathChar; + *aZoneFileStream >> scriptPathChar; + } + result.path.replace(",", ""); + const QStringList pathParts = result.path.split('/'); + if (pathParts.size() == 0) { + qDebug() << "Failed to parse ff path! " << result.path; + exit(-1); + } + + // Parse gsc contents + char rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + while (rawFileContentsChar != 0 && rawFileContentsChar != -1) { + result.contents += rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + } + return result; +} + +void ZoneFile_COD9_360::pParseAsset_PhysPreset(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Model ZoneFile_COD9_360::pParseAsset_Model(QDataStream *aZoneFileStream) { + Model result; + + *aZoneFileStream >> result.namePtr >> result.tagCount >> result.rootTagCount + >> result.surfCount >> result.unknownCount >> result.boneNamePtr + >> result.parentListPtr >> result.quatsPtr >> result.transPtr + >> result.partClassPtr >> result.baseMatPtr + >> result.surfsPtr >> result.materialHandlesPtr; + + // Parse XModelLodInfo + for (int i = 1; i <= 4; i++) { + quint32 intDist; + *aZoneFileStream >> intDist; + + std::memcpy(&result.lodInfo[i].dist, &intDist, sizeof(result.lodInfo[i].dist)); + *aZoneFileStream >> result.lodInfo[i].numsurfs >> result.lodInfo[i].surfIndex; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.lodInfo[i].partBits[0] + >> result.lodInfo[i].partBits[1] + >> result.lodInfo[i].partBits[2] + >> result.lodInfo[i].partBits[3]; + } + + *aZoneFileStream >> result.collSurfsPtr >> result.numCollSurfs >> result.contents >> result.boneInfoPtr; + + quint32 intRadius, intMins[3], intMaxs[3]; + *aZoneFileStream >> intRadius >> intMins[0] >> intMins[1] + >> intMins[2] >> intMaxs[0] >> intMaxs[1] >> intMaxs[2]; + + std::memcpy(&result.radius, &intRadius, sizeof(result.radius)); + + std::memcpy(&result.mins[0], &intMins[0], sizeof(result.mins[0])); + std::memcpy(&result.mins[1], &intMins[1], sizeof(result.mins[1])); + std::memcpy(&result.mins[2], &intMins[2], sizeof(result.mins[2])); + + std::memcpy(&result.maxs[0], &intMaxs[0], sizeof(result.maxs[0])); + std::memcpy(&result.maxs[1], &intMaxs[1], sizeof(result.maxs[2])); + std::memcpy(&result.maxs[2], &intMaxs[2], sizeof(result.maxs[3])); + + *aZoneFileStream >> result.numLods >> result.collLod >> result.streamInfoPtr + >> result.memUsage >> result.flags >> result.physPresetPtr >> result.physGeomsPtr; + + // Parse model name + char modelNameChar; + *aZoneFileStream >> modelNameChar; + while (modelNameChar == 0) { + *aZoneFileStream >> modelNameChar; + } + while (modelNameChar != 0) { + result.modelName += modelNameChar; + *aZoneFileStream >> modelNameChar; + } + return result; +} + +Material ZoneFile_COD9_360::pParseAsset_Material(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); + + return Material(); +} + +Shader ZoneFile_COD9_360::pParseAsset_Shader(QDataStream *aZoneFileStream) { + Shader result = Shader(); + + quint8 minorVersion, majorVersion; + *aZoneFileStream >> minorVersion >> majorVersion; + + quint32 magic; + *aZoneFileStream >> magic; + + // Verify .fxc magic + if (magic != 65534 && magic != 65535) { return result; } + + SHADER_TYPE type = SHADER_NONE; + quint16 rawShaderType; + *aZoneFileStream >> rawShaderType; + if (rawShaderType == 65535) { // Pixel shader + type = SHADER_PIXEL; + } else if (rawShaderType == 65534) { // Vertex shader + type = SHADER_VERTEX; + } + Q_UNUSED(type); + + while (true) { + quint32 instructionToken; + *aZoneFileStream >> instructionToken; + + SHADER_OPCODE opCode = (SHADER_OPCODE)(instructionToken & 0xffff); + + int size; + if (opCode == OPCODE_End) { + break; + } else if (opCode == OPCODE_Comment) { + size = (int)((instructionToken >> 16) & 0x7FFF); + } else { + size = (int)((instructionToken >> 24) & 0x0f); + } + Q_UNUSED(size); + } + + + return result; +} + +TechSet ZoneFile_COD9_360::pParseAsset_TechSet(QDataStream *aZoneFileStream) { + TechSet result; + + for (int i = 1; i <= 62; i++) { + quint32 ptr; + *aZoneFileStream >> ptr; + + result.pointers << ptr; + } + qDebug() << aZoneFileStream->device()->pos(); + + // Parse techset name + char techSetNameChar; + *aZoneFileStream >> techSetNameChar; + while (techSetNameChar != 0) { + result.name += techSetNameChar; + *aZoneFileStream >> techSetNameChar; + } + result.name.replace(",", ""); + + return result; +} + +Image ZoneFile_COD9_360::pParseAsset_Image(QDataStream *aZoneFileStream) { + Image result; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknowna >> result.unknownb + >> result.unknownc >> result.unknownd + >> result.unknowne >> result.unknownf + >> result.unknowng; + + aZoneFileStream->skipRawData(15 * 4); + *aZoneFileStream >> result.unknownh >> result.unknowni; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknownj; + + aZoneFileStream->skipRawData(4); + + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + result.materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + result.materialName.replace(",", ""); + + if (result.unknowna) { + *aZoneFileStream >> result.unknownk; + *aZoneFileStream >> result.unknownl; + *aZoneFileStream >> result.unknownm; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown1; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown2 >> result.unknown3 + >> result.size1 >> result.size2 + >> result.unknown4 >> result.unknown5; + + aZoneFileStream->skipRawData(4); + + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + result.name += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + + *aZoneFileStream >> result.unknown6 >> result.unknown7; + + QByteArray compressionData(8, Qt::Uninitialized); + aZoneFileStream->readRawData(compressionData.data(), 8); + if (compressionData.contains("DXT1")) { + result.compression = COMPRESSION_DXT1; + } else if (compressionData.contains("DXT3")) { + result.compression = COMPRESSION_DXT3; + } else if (compressionData.contains("DXT5")) { + result.compression = COMPRESSION_DXT5; + } else { + result.compression = COMPRESSION_NONE; + } + + *aZoneFileStream >> result.unknown8 >> result.unknown9; + } + + return result; +} + +SoundAsset ZoneFile_COD9_360::pParseAsset_Sound(QDataStream *aZoneFileStream) { + SoundAsset result; + + qDebug() << aZoneFileStream->device()->pos(); + + QByteArray rootNamePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rootNamePtr.data(), 4); + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.count; + + if (rootNamePtr.toHex() == "ffffffff") { + // Read in sound file name + char soundNameChar; + *aZoneFileStream >> soundNameChar; + while (soundNameChar != 0) { + result.name += soundNameChar; + *aZoneFileStream >> soundNameChar; + } + } + + int tagCount = 0; + int resultCount = 0; + for (quint32 i = 0; i < result.count; i++) { + aZoneFileStream->skipRawData(12); + + QByteArray tagPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(tagPtr.data(), 4); + + if (tagPtr.toHex() == "ffffffff") { + tagCount++; + } + aZoneFileStream->skipRawData(4); + + QByteArray pathPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pathPtr.data(), 4); + + if (pathPtr.toHex() == "ffffffff") { + resultCount++; + } + + aZoneFileStream->skipRawData(160); + } + + for (int i = 0; i < tagCount; i++) { + // Read in tag? + QString tag; + char tagChar; + *aZoneFileStream >> tagChar; + while (tagChar != 0) { + tag += tagChar; + *aZoneFileStream >> tagChar; + } + } + + for (int i = 0; i < resultCount; i++) { + Sound sound; + + if (aZoneFileStream->device()->peek(12).toHex().contains("ffffffff00000000")) { + aZoneFileStream->skipRawData(12); + } + + aZoneFileStream->skipRawData(8); + + QByteArray aliasPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(aliasPtr.data(), 4); + + QByteArray namePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(namePtr.data(), 4); + + *aZoneFileStream >> sound.dataLength; + + if (aliasPtr.toHex() == "ffffffff") { + // Read in sound alias name + char soundAliasChar; + *aZoneFileStream >> soundAliasChar; + while (soundAliasChar != 0) { + sound.alias += soundAliasChar; + *aZoneFileStream >> soundAliasChar; + } + } + + if (aZoneFileStream->device()->peek(4) == "RIFF") { + sound.path = sound.alias; + sound.alias = ""; + } else if (namePtr.toHex() == "ffffffff") { + // Read in sound file path + char soundPathChar; + *aZoneFileStream >> soundPathChar; + while (soundPathChar != 0) { + sound.path += soundPathChar; + *aZoneFileStream >> soundPathChar; + } + sound.path.replace(",", ""); + } + + if (sound.dataLength) { + QByteArray data(sound.dataLength, Qt::Uninitialized); + aZoneFileStream->readRawData(data.data(), sound.dataLength); + sound.data = data; + } + result.sounds.append(sound); + } + + return result; +} + +void ZoneFile_COD9_360::pParseAsset_ColMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD9_360::pParseAsset_GameMapSP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD9_360::pParseAsset_GameMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD9_360::pParseAsset_LightDef(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD9_360::pParseAsset_UIMap(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD9_360::pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD9_360::pParseAsset_AIType(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD9_360::pParseAsset_FX(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Animation ZoneFile_COD9_360::pParseAsset_Animation(QDataStream *aZoneFileStream) { + Animation result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.dataByteCount + >> result.dataShortCount + >> result.dataIntCount + >> result.randomDataByteCount + >> result.randomDataIntCount + >> result.numframes + >> result.isLooped + >> result.isDelta + >> result.noneRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.normalTranslatedBoneCount + >> result.preciseTranslatedBoneCount + >> result.staticTranslatedBoneCount + >> result.noneTranslatedBoneCount + >> result.totalBoneCount + >> result.otherBoneCount1 + >> result.otherBoneCount2 + >> result.notifyCount + >> result.assetType + >> result.pad + >> result.randomDataShortCount + >> result.indexCount + >> result.frameRate + >> result.frequency + >> result.boneIDsPtr + >> result.dataBytePtr + >> result.dataShortPtr + >> result.dataIntPtr + >> result.randomDataShortPtr + >> result.randomDataBytePtr + >> result.randomDataIntPtr + >> result.longIndiciesPtr + >> result.notificationsPtr + >> result.deltaPartsPtr; + + // Read in x_anim file name + QString xAnimName; + char xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + while (xAnimNameChar != 0) { + result.name += xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + } + + // Parse x_anim index header + QVector sectionLengths; + for (int i = 0; i < result.numframes; i++) { + quint8 sectionlength; + *aZoneFileStream >> sectionlength; + sectionLengths.push_back(sectionlength); + // Skip padding + aZoneFileStream->skipRawData(1); + } + // Skip unknown section + aZoneFileStream->skipRawData(2 * 8); + + return result; +} + +MenuFile ZoneFile_COD9_360::pParseAsset_MenuFile(QDataStream *aZoneFileStream) { + //MENU_FILE + MenuFile result; + + aZoneFileStream->skipRawData(4); // Separator + + // Parse menu def count + *aZoneFileStream >> result.menuCount; + + // Clearly misparsed, never have this much + if (result.menuCount > 1000) { + qDebug() << "Failure reported when parsing menu file."; + return result; + } + for (uint i = 0; i < result.menuCount; i++) { + Menu menu; + + aZoneFileStream->skipRawData(4); // Separator + + // Read in x_anim file name + char menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + while (menuFilepathChar != 0) { + menu.filePath += menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + } + aZoneFileStream->skipRawData(4); // Separator + + *aZoneFileStream >> menu.menuNamePtr; + + float menuRectX, menuRectY, menuRectWidth, menuRectHeight; + *aZoneFileStream >> menuRectX >> menuRectY >> menuRectWidth >> menuRectHeight; + menu.rect = QRectF(menuRectX, menuRectY, menuRectWidth, menuRectHeight); + + quint32 hAlignInt, vAlignInt; + *aZoneFileStream >> hAlignInt >> vAlignInt; + menu.hAlign = (MENU_H_ALIGNMENT)hAlignInt; + menu.vAlign = (MENU_V_ALIGNMENT)vAlignInt; + + float rectClientX, rectClientY, rectClientWidth, rectClientHeight; + *aZoneFileStream >> rectClientX >> rectClientY >> rectClientWidth >> rectClientHeight; + menu.clientRect = QRectF(rectClientX, rectClientY, rectClientWidth, rectClientHeight); + + quint32 hClientAlignInt, vClientAlignInt, styleInt, borderInt; + *aZoneFileStream >> hClientAlignInt >> vClientAlignInt >> menu.groupPtr + >> styleInt >> borderInt >> menu.ownerDraw >> menu.ownerDrawFlags + >> menu.borderSize >> menu.staticFlags >> menu.dynamicFlags >> menu.nextTime; + menu.hClientAlign = (MENU_H_ALIGNMENT)hClientAlignInt; + menu.vClientAlign = (MENU_V_ALIGNMENT)vClientAlignInt; + menu.style = (MENU_WINDOW_STYLE)styleInt; + menu.border = (MENU_WINDOW_BORDER)borderInt; + + float foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA, + backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA, + borderColorR, borderColorG, borderColorB, borderColorA, + outlineColorR, outlineColorG, outlineColorB, outlineColorA; + *aZoneFileStream >> foregroundColorR >> foregroundColorG >> foregroundColorB >> foregroundColorA + >> backgroundColorR >> backgroundColorG >> backgroundColorB >> backgroundColorA + >> borderColorR >> borderColorG >> borderColorB >> borderColorA + >> outlineColorR >> outlineColorG >> outlineColorB >> outlineColorA; + + menu.foregroundColor = QColor(foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA); + menu.backgroundColor = QColor(backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA); + menu.borderColor = QColor(borderColorR, borderColorG, borderColorB, borderColorA); + menu.outlineColor = QColor(outlineColorR, outlineColorG, outlineColorB, outlineColorA); + + *aZoneFileStream >> menu.materialPtr >> menu.fontPtr >> menu.fullScreen >> menu.itemCount + >> menu.fontIndex >> menu.cursorItem >> menu.fadeCycle >> menu.fadeClamp + >> menu.fadeAmount >> menu.fadeInAmount >> menu.blurRadius >> menu.onOpenPtr + >> menu.onFocusPtr >> menu.onClosePtr >> menu.onESCPtr >> menu.onKeyPtr + >> menu.visibleExpCount >> menu.expEntryPtr >> menu.allowedBindingPtr + >> menu.soundNamePtr >> menu.imageTrack; + + float focusColorR, focusColorG, focusColorB, focusColorA, + disabledColorR, disabledColorG, disabledColorB, disabledColorA; + *aZoneFileStream >> focusColorR >> focusColorG >> focusColorB >> focusColorA + >> disabledColorR >> disabledColorG >> disabledColorB >> disabledColorA; + menu.focusColor = QColor(focusColorR, focusColorG, focusColorB, focusColorA); + menu.disabledColor = QColor(disabledColorR, disabledColorG, disabledColorB, disabledColorA); + + *aZoneFileStream >> menu.rectXExpCount >> menu.rectXExpPtr >> menu.rectYExpCount >> menu.rectYExpPtr; + + aZoneFileStream->skipRawData(4); // Separator + + char menuDefNameChar; + int menuDefNameLen = 0; + *aZoneFileStream >> menuDefNameChar; + while (menuDefNameChar != 0 && menuDefNameLen < 30) { + menuDefNameLen++; + menu.name += menuDefNameChar; + *aZoneFileStream >> menuDefNameChar; + } + + char defStringChar; + int defStringLen = 0; + *aZoneFileStream >> defStringChar; + while (defStringChar != 0 && defStringLen < 30) { + defStringLen++; + menu.definition += defStringChar; + *aZoneFileStream >> defStringChar; + } + aZoneFileStream->skipRawData(4 * 10); + + *aZoneFileStream >> menu.itemWindowDefNamePtr; + + float itemRectX, itemRectY, itemRectWidth, itemRectHeight; + *aZoneFileStream >> itemRectX >> itemRectY >> itemRectWidth >> itemRectHeight; + menu.itemRect = QRectF(itemRectX, itemRectY, itemRectWidth, itemRectHeight); + + *aZoneFileStream >> menu.itemHAlignment >> menu.itemVAlignment >> menu.itemGroupPtr + >> menu.itemWindowStyle >> menu.itemWindowBorder >> menu.itemOwnerDraw + >> menu.itemOwnerDrawFlags >> menu.itemBorderSize >> menu.itemStaticFlags + >> menu.itemDynamicFlags >> menu.itemNextTime; + + float itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA, + itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA, + itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA, + itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA; + *aZoneFileStream >> itemForegroundColorR >> itemForegroundColorG >> itemForegroundColorB >> itemForegroundColorA + >> itemBackgroundColorR >> itemBackgroundColorG >> itemBackgroundColorB >> itemBackgroundColorA + >> itemBorderColorR >> itemBorderColorG >> itemBorderColorB >> itemBorderColorA + >> itemOutlineColorR >> itemOutlineColorG >> itemOutlineColorB >> itemOutlineColorA; + + menu.itemForegroundColor = QColor(itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA); + menu.itemBackgroundColor = QColor(itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA); + menu.itemBorderColor = QColor(itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA); + menu.itemOutlineColor = QColor(itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA); + + *aZoneFileStream >> menu.itemMaterialPtr; + + float itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight; + *aZoneFileStream >> itemTextRectX >> itemTextRectY >> itemTextRectWidth >> itemTextRectHeight; + menu.itemTextRect = QRectF(itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight); + + quint32 hItemTextAlignInt, vItemTextAlignInt, itemType, fontTypeInt, textStyleInt; + *aZoneFileStream >> hItemTextAlignInt >> vItemTextAlignInt >> itemType >> menu.dataType + >> menu.alignment >> fontTypeInt >> menu.textAlignMode >> menu.textalignx >> menu.textaligny + >> menu.textscale >> textStyleInt >> menu.gameMsgWindowIndex >> menu.gameMsgWindowMode + >> menu.testPtr >> menu.textSavegameInfo >> menu.parentPtr; + menu.itemText_hAlign = (MENU_H_ALIGNMENT)hItemTextAlignInt; + menu.itemText_vAlign = (MENU_V_ALIGNMENT)vItemTextAlignInt; + menu.itemType = (MENU_ITEM_TYPE)itemType; + menu.fontEnum = (MENU_FONT_TYPE)fontTypeInt; + menu.textStyle = (MENU_ITEM_TEXTSTYLE)textStyleInt; + + *aZoneFileStream >> menu.mouseEnterText >> menu.mouseExitText >> menu.mouseEnter >> menu.mouseExit + >> menu.action >> menu.onAccept >> menu.onFocus >> menu.leaveFocus >> menu.dvar >> menu.dvarTest + >> menu.keyHandlerPtr >> menu.enableDvarPtr >> menu.dvarFlags >> menu.focusSoundPtr + >> menu.special >> menu.cursorPos; + + // itemDefData_t typeData; + + // listBoxDef_s *listBox; + + *aZoneFileStream >> menu.startPos >> menu.endPos >> menu.drawPadding; + + *aZoneFileStream >> menu.elementWidth >> menu.elementHeight; + + *aZoneFileStream >> menu.elementStyle >> menu.numColumns; + + //columnInfo_s columnInfo[16]; + + *aZoneFileStream >> menu.doubleClickPtr; + + + *aZoneFileStream >> menu.notselectable >> menu.noScrollBars >> menu.usePaging; + + float itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA, + itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA, + itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA; + *aZoneFileStream >> itemSelectBorderColorR >> itemSelectBorderColorG >> itemSelectBorderColorB >> itemSelectBorderColorA + >> itemDisableColorR >> itemDisableColorG >> itemDisableColorB >> itemDisableColorA + >> itemFocusColorR >> itemFocusColorG >> itemFocusColorB >> itemFocusColorA; + menu.itemSelectBorderColor = QColor(itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA); + menu.itemDisableColor = QColor(itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA); + menu.itemFocusColor = QColor(itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA); + + *aZoneFileStream >> menu.selectIconPtr >> menu.backgroundItemListboxPtr >> menu.highlightTexturePtr; + + // editFieldDef_s *editField; + + *aZoneFileStream >> menu.minVal >> menu.maxVal >> menu.defVal >> menu.range >> menu.maxChars + >> menu.maxCharsGotoNext >> menu.maxPaintChars >> menu.paintOffset; + + // multiDef_s *multi; + + for (int i = 0; i < 32; i++) { + quint32 dvarList; + *aZoneFileStream >> dvarList; + menu.dvarListPtrs.push_back(dvarList); + } + + for (int i = 0; i < 32; i++) { + quint32 dvarStr; + *aZoneFileStream >> dvarStr; + menu.dvarStrPtrs.push_back(dvarStr); + } + + for (int i = 0; i < 32; i++) { + float dvarValue; + *aZoneFileStream >> dvarValue; + menu.dvarValues.push_back(dvarValue); + } + + *aZoneFileStream >> menu.count >> menu.strDef >> menu.enumDvarNamePtr; + aZoneFileStream->skipRawData(4); + //>> menu.dataPtr + *aZoneFileStream >> menu.itemImageTrack; + + qDebug() << aZoneFileStream->device()->pos(); + + //statement_s visibleExp; + //statement_s textExp; + //statement_s materialExp; + //statement_s rectXExp; + //statement_s rectYExp; + //statement_s rectWExp; + //statement_s rectHExp; + //statement_s foreColorAExp; + result.menuDefs << menu; + } + return result; +} + +void ZoneFile_COD9_360::pParseAsset_Weapon(QDataStream *aZoneFileStream) { + //WEAPON_FILE + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD9_360::pParseAsset_D3DBSP(QDataStream *aZoneFileStream) { + //D3DBSP_DUMP + Q_UNUSED(aZoneFileStream); +} + +StringTable ZoneFile_COD9_360::pParseAsset_StringTable(QDataStream *aZoneFileStream) { + StringTable result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.columnCount + >> result.rowCount; + + // Todo fix this + result.columnCount = 0; + result.rowCount = 0; + + aZoneFileStream->skipRawData(4); + + QString stringTableName; + char stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + while (stringTableNameChar != 0) { + result.name += stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + } + + for (quint32 i = 0; i < result.rowCount; i++) { + QByteArray pointerData(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pointerData.data(), 4); + result.tablePointers.push_back(pointerData.toHex()); + + aZoneFileStream->skipRawData(4); + } + + for (const QString &pointerAddr : result.tablePointers) { + QString leadingContent = ""; + if (pointerAddr == "FFFFFFFF") { + char leadingContentChar; + *aZoneFileStream >> leadingContentChar; + while (leadingContentChar != 0) { + leadingContent += leadingContentChar; + *aZoneFileStream >> leadingContentChar; + } + } else { + leadingContent = pointerAddr; + } + + QString content; + char contentChar; + *aZoneFileStream >> contentChar; + while (contentChar != 0) { + content += contentChar; + *aZoneFileStream >> contentChar; + } + result.content[leadingContent] = content; + } + return result; +} + +AssetType ZoneFile_COD9_360::AssetStrToEnum(const QString aAssetType) { + const QString cleanedType = aAssetType.toUpper(); + if (cleanedType == "17000000") { // localized string PARTIALLY VERIFIED + return ASSET_LOCAL_STRING; + } else if (cleanedType == "20000000") { // raw_file PARTIALLY VERIFIED + return ASSET_RAW_FILE; + } else if (cleanedType == "1A000000") { // fx PARTIALLY VERIFIED + return ASSET_EFFECT; + } else if (cleanedType == "09000000") { // loaded_sound PARTIALLY VERIFIED + return ASSET_SOUND; + } else if (cleanedType == "04000000") { // x_anim PARTIALLY VERIFIED + return ASSET_ANIMATION; + } else if (cleanedType == "0C000000") { // collision_map PARTIALLY VERIFIED + return ASSET_COLLISION_MAP; + } else if (cleanedType == "21000000") { // string_table PARTIALLY VERIFIED + return ASSET_STRING_TABLE; + } else if (cleanedType == "15000000") { // menu_file PARTIALLY VERIFIED + return ASSET_MENU; + } else if (cleanedType == "07000000") { // tech set PARTIALLY VERIFIED + return ASSET_TECH_SET; + } else if (cleanedType == "18000000") { // weapon PARTIALLY VERIFIED + return ASSET_WEAPON; + } else if (cleanedType == "11000000") { // gfx map PARTIALLY VERIFIED + return ASSET_GFX_MAP; + } else if (cleanedType == "12000000") { // light_def PARTIALLY VERIFIED + return ASSET_LIGHT_DEF; + } else if (cleanedType == "14000000") { // font PARTIALLY VERIFIED + return ASSET_FONT; + } else if (cleanedType == "05000000") { // xmodel PARTIALLY VERIFIED + return ASSET_MODEL; + } else if (cleanedType == "0D000000") { // d3dbsp PARTIALLY VERIFIED + return ASSET_D3DBSP; + } else if (cleanedType == "06000000") { // image PARTIALLY VERIFIED + return ASSET_IMAGE; + } else if (cleanedType == "0E000000") { // game map sp PARTIALLY VERIFIED + return ASSET_GAME_MAP_SP; + } else if (cleanedType == "0B000000") { // col map sp PARTIALLY VERIFIED + return ASSET_COL_MAP_SP; + } + return ASSET_NONE; +} + +QByteArray ZoneFile_COD9_360::GetBinaryData() { + QByteArray result; + + return result; +} diff --git a/libs/zonefile/360/zonefile_cod9_360.h b/libs/zonefile/360/zonefile_cod9_360.h new file mode 100644 index 0000000..f52fcde --- /dev/null +++ b/libs/zonefile/360/zonefile_cod9_360.h @@ -0,0 +1,52 @@ +#ifndef ZONEFILE_COD9_360_H +#define ZONEFILE_COD9_360_H + +#include "zonefile.h" + +class ZoneFile_COD9_360 : public ZoneFile +{ +public: + ZoneFile_COD9_360(); + ~ZoneFile_COD9_360(); + + bool Load(const QByteArray aFileData) override; + AssetType AssetStrToEnum(const QString aAssetType) override; + + QByteArray GetBinaryData() override; + +protected: + void pParseZoneHeader(QDataStream *aZoneFileStream) override; + quint32 pParseZoneSize(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsA(QDataStream *aZoneFileStream) override; + quint32 pParseZoneTagCount(QDataStream *aZoneFileStream) override; + quint32 pParseZoneRecordCount(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsB(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsC(QDataStream *aZoneFileStream) override; + QStringList pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) override; + QStringList pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) override; + AssetMap pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) override; + LocalString pParseAsset_LocalString(QDataStream *aZoneFileStream) override; + RawFile pParseAsset_RawFile(QDataStream *aZoneFileStream) override; + void pParseAsset_PhysPreset(QDataStream *aZoneFileStream) override; + Model pParseAsset_Model(QDataStream *aZoneFileStream) override; + Material pParseAsset_Material(QDataStream *aZoneFileStream) override; + Shader pParseAsset_Shader(QDataStream *aZoneFileStream) override; + TechSet pParseAsset_TechSet(QDataStream *aZoneFileStream) override; + Image pParseAsset_Image(QDataStream *aZoneFileStream) override; + SoundAsset pParseAsset_Sound(QDataStream *aZoneFileStream) override; + void pParseAsset_ColMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapSP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_LightDef(QDataStream *aZoneFileStream) override; + void pParseAsset_UIMap(QDataStream *aZoneFileStream) override; + void pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) override; + void pParseAsset_AIType(QDataStream *aZoneFileStream) override; + void pParseAsset_FX(QDataStream *aZoneFileStream) override; + Animation pParseAsset_Animation(QDataStream *aZoneFileStream) override; + MenuFile pParseAsset_MenuFile(QDataStream *aZoneFileStream) override; + void pParseAsset_Weapon(QDataStream *aZoneFileStream) override; + void pParseAsset_D3DBSP(QDataStream *aZoneFileStream) override; + StringTable pParseAsset_StringTable(QDataStream *aZoneFileStream) override; +}; + +#endif // ZONEFILE_COD9_360_H diff --git a/libs/zonefile/PC/zonefile_cod10_pc.cpp b/libs/zonefile/PC/zonefile_cod10_pc.cpp new file mode 100644 index 0000000..650d772 --- /dev/null +++ b/libs/zonefile/PC/zonefile_cod10_pc.cpp @@ -0,0 +1,1072 @@ +#include "zonefile_cod10_pc.h" + +#include +#include +#include + +ZoneFile_COD10_PC::ZoneFile_COD10_PC() +{ + +} + +ZoneFile_COD10_PC::~ZoneFile_COD10_PC() +{ + +} + +bool ZoneFile_COD10_PC::Load(const QByteArray aFileData) { + // Open zone file as little endian stream + QDataStream zoneFileStream(aFileData); + zoneFileStream.setByteOrder(QDataStream::LittleEndian); + + // Parse data from zone file header + pParseZoneHeader(&zoneFileStream); + SetRecords(pParseZoneIndex(&zoneFileStream, GetRecordCount())); + SetAssetMap(pParseAssets(&zoneFileStream, GetRecords())); + + return true; +} + +void ZoneFile_COD10_PC::pParseZoneHeader(QDataStream *aZoneFileStream) { + SetSize(pParseZoneSize(aZoneFileStream)); + pParseZoneUnknownsA(aZoneFileStream); + + SetTagCount(pParseZoneTagCount(aZoneFileStream)); + pParseZoneUnknownsB(aZoneFileStream); + + SetRecordCount(pParseZoneRecordCount(aZoneFileStream)); + + quint32 tagCount = GetTagCount(); + if (tagCount) { + pParseZoneUnknownsC(aZoneFileStream); + SetTags(pParseZoneTags(aZoneFileStream, tagCount)); + } else { + aZoneFileStream->skipRawData(4); + } +} + +quint32 ZoneFile_COD10_PC::pParseZoneSize(QDataStream *aZoneFileStream) { + quint32 zoneFileSize; + *aZoneFileStream >> zoneFileSize; + if (zoneFileSize <= 0) { + qDebug() << "Tried to open empty zone file!"; + exit(-1); + } + zoneFileSize += 36; + return zoneFileSize; +} + +/* + ParseZoneUnknownsA() + + Parses the 1st section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD10_PC::pParseZoneUnknownsA(QDataStream *aZoneFileStream) { + // Byte 4-7, 8-11, 12-15: unknown + QByteArray unknown1(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown1.data(), 4); + + QByteArray unknown2(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown2.data(), 4); + + QByteArray unknown3(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown3.data(), 4); + + // Byte 16-19, 20-23: empty/unknown + QByteArray unknown4(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown4.data(), 4); + + QByteArray unknown5(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown5.data(), 4); + + // Byte 24-27: somehow related to the filesize, but smaller value + QByteArray unknown6(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown6.data(), 4); + + // Byte 28-31, 32-35: unknown + QByteArray unknown7(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown7.data(), 4); + + QByteArray unknown8(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown8.data(), 4); +} + +/* + ParseZoneTagCount() + + Parses the number of string tags in the zone index +*/ +quint32 ZoneFile_COD10_PC::pParseZoneTagCount(QDataStream *aZoneFileStream) { + quint32 tagCount; + *aZoneFileStream >> tagCount; + return tagCount; +} + +/* + ParseZoneRecordCount() + + Parses the number of records in the zone index +*/ +quint32 ZoneFile_COD10_PC::pParseZoneRecordCount(QDataStream *aZoneFileStream) { + quint32 recordCount; + *aZoneFileStream >> recordCount; + return recordCount; +} + +/* + ParseZoneUnknownsB() + + Parses the 2nd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD10_PC::pParseZoneUnknownsB(QDataStream *aZoneFileStream) { + // Byte 44-47: Unknown/empty? + QByteArray unknown9(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown9.data(), 4); +} + +/* + pParseZoneUnknownsC() + + Parses the 3rd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD10_PC::pParseZoneUnknownsC(QDataStream *aZoneFileStream) { + // Byte 40-43: Unknown/empty? + QByteArray unknown10(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown10.data(), 4); + + // Byte 44-47: Unknown/empty? + QByteArray unknown11(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown11.data(), 4); +} + +/* + ParseZoneTags() + + Parses the string tags ate the start of zone file +*/ +QStringList ZoneFile_COD10_PC::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) { + QStringList tags; + + // Byte 48-51: Repeated separators? ÿÿÿÿ x i + aZoneFileStream->skipRawData(4 * (tagCount - 1)); + + // Parse tags/strings before index + QString zoneTag; + char zoneTagChar; + for (quint32 i = 0; i < tagCount; i++) { + *aZoneFileStream >> zoneTagChar; + while (zoneTagChar != 0) { + zoneTag += zoneTagChar; + *aZoneFileStream >> zoneTagChar; + } + tags << zoneTag; + zoneTag.clear(); + } + return tags; +} + +/* + ParseZoneIndex() + + Parse the binary zone index data and populate table +*/ +QStringList ZoneFile_COD10_PC::pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) { + QStringList result; + + // Don't parse if no records + if (!recordCount) { return result; } + + if (aZoneFileStream->device()->peek(4).toHex().contains("ffff")) { + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 2); + } + + // Parse index & map found asset types + for (quint32 i = 0; i <= recordCount; i++) { + // Skip record start + QByteArray rawAssetType(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rawAssetType.data(), 4); + result << rawAssetType.toHex(); + + // Skip separator + aZoneFileStream->skipRawData(4); + } + return result; +} + +AssetMap ZoneFile_COD10_PC::pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) { + AssetMap result; + + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 8); + + for (int i = 0; i < assetOrder.size(); i++) { + const QString typeHex = assetOrder[i]; + const AssetType typeStr = AssetStrToEnum(typeHex); + + if (typeStr == ASSET_LOCAL_STRING) { // localized string asset + result.localStrings << pParseAsset_LocalString(aZoneFileStream); + } else if (typeStr == ASSET_RAW_FILE) { // gsc + auto rawFile = pParseAsset_RawFile(aZoneFileStream); + if (rawFile.length) { + result.rawFiles << rawFile; + } + } else if (typeStr == ASSET_PHYS_PRESET) { // physpreset + pParseAsset_PhysPreset(aZoneFileStream); + } else if (typeStr == ASSET_MODEL) { // xmodel + result.models << pParseAsset_Model(aZoneFileStream); + } else if (typeStr == ASSET_MATERIAL) { // material + pParseAsset_Material(aZoneFileStream); + } else if (typeStr == ASSET_SHADER) { // pixelshader + pParseAsset_Shader(aZoneFileStream); + } else if (typeStr == ASSET_TECH_SET) { // techset include + result.techSets << pParseAsset_TechSet(aZoneFileStream); + } else if (typeStr == ASSET_IMAGE) { // image + result.images << pParseAsset_Image(aZoneFileStream); + } else if (typeStr == ASSET_SOUND) { // loaded_sound + result.sounds << pParseAsset_Sound(aZoneFileStream); + } else if (typeStr == ASSET_COLLISION_MAP) { // col_map_mp + pParseAsset_ColMapMP(aZoneFileStream); + } else if (typeStr == ASSET_MP_MAP) { // game_map_sp + pParseAsset_GameMapSP(aZoneFileStream); + } else if (typeStr == ASSET_SP_MAP) { // game_map_mp + pParseAsset_GameMapMP(aZoneFileStream); + } else if (typeStr == ASSET_LIGHT_DEF) { // lightdef + pParseAsset_LightDef(aZoneFileStream); + } else if (typeStr == ASSET_UI_MAP) { // ui_map + pParseAsset_UIMap(aZoneFileStream); + } else if (typeStr == ASSET_SND_DRIVER_GLOBALS) { // snddriverglobals + pParseAsset_SNDDriverGlobals(aZoneFileStream); + } else if (typeStr == ASSET_AI_TYPE) { // aitype + pParseAsset_AIType(aZoneFileStream); + } else if (typeStr == ASSET_EFFECT) { // aitype + pParseAsset_FX(aZoneFileStream); + } else if (typeStr == ASSET_ANIMATION) { // aitype + result.animations << pParseAsset_Animation(aZoneFileStream); + } else if (typeStr == ASSET_STRING_TABLE) { // string_table + result.stringTables << pParseAsset_StringTable(aZoneFileStream); + } else if (typeStr == ASSET_MENU) { // string_table + result.menuFiles << pParseAsset_MenuFile(aZoneFileStream); + } else if (typeStr == ASSET_WEAPON) { // string_table + pParseAsset_Weapon(aZoneFileStream); + } else if (typeStr == ASSET_D3DBSP) { // string_table + pParseAsset_D3DBSP(aZoneFileStream); + } + } + return result; +} + +LocalString ZoneFile_COD10_PC::pParseAsset_LocalString(QDataStream *aZoneFileStream) { + LocalString result; + + quint32 stringPtr, aliasPtr; + *aZoneFileStream >> stringPtr >> aliasPtr; + if (stringPtr == 4294967295) { + // Parse local string asset contents + QString localStr; + char localStrChar; + *aZoneFileStream >> localStrChar; + while (localStrChar != 0) { + result.string += localStrChar; + *aZoneFileStream >> localStrChar; + } + } else { + result.string = "String Ptr: " + QString::number(stringPtr); + } + + if (aliasPtr == 4294967295) { + // Parse rawfile name + QString aliasName; + char aliasNameChar; + *aZoneFileStream >> aliasNameChar; + while (aliasNameChar != 0) { + result.alias += aliasNameChar; + *aZoneFileStream >> aliasNameChar; + } + } else { + result.string = "Alias Ptr: " + QString::number(aliasPtr); + } + + return result; +} + +RawFile ZoneFile_COD10_PC::pParseAsset_RawFile(QDataStream *aZoneFileStream) { + RawFile result; + + // Skip start separator FF FF FF FF (pointer?) + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.length; + + // Skip unknown 4 byte data + aZoneFileStream->skipRawData(4); + + // Parse rawfile path + char scriptPathChar; + *aZoneFileStream >> scriptPathChar; + while (scriptPathChar != 0) { + result.path += scriptPathChar; + *aZoneFileStream >> scriptPathChar; + } + result.path.replace(",", ""); + const QStringList pathParts = result.path.split('/'); + if (pathParts.size() == 0) { + qDebug() << "Failed to parse ff path! " << result.path; + exit(-1); + } + + // Parse gsc contents + char rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + while (rawFileContentsChar != 0 && rawFileContentsChar != -1) { + result.contents += rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + } + return result; +} + +void ZoneFile_COD10_PC::pParseAsset_PhysPreset(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Model ZoneFile_COD10_PC::pParseAsset_Model(QDataStream *aZoneFileStream) { + Model result; + + *aZoneFileStream >> result.namePtr >> result.tagCount >> result.rootTagCount + >> result.surfCount >> result.unknownCount >> result.boneNamePtr + >> result.parentListPtr >> result.quatsPtr >> result.transPtr + >> result.partClassPtr >> result.baseMatPtr + >> result.surfsPtr >> result.materialHandlesPtr; + + // Parse XModelLodInfo + for (int i = 1; i <= 4; i++) { + quint32 intDist; + *aZoneFileStream >> intDist; + + std::memcpy(&result.lodInfo[i].dist, &intDist, sizeof(result.lodInfo[i].dist)); + *aZoneFileStream >> result.lodInfo[i].numsurfs >> result.lodInfo[i].surfIndex; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.lodInfo[i].partBits[0] + >> result.lodInfo[i].partBits[1] + >> result.lodInfo[i].partBits[2] + >> result.lodInfo[i].partBits[3]; + } + + *aZoneFileStream >> result.collSurfsPtr >> result.numCollSurfs >> result.contents >> result.boneInfoPtr; + + quint32 intRadius, intMins[3], intMaxs[3]; + *aZoneFileStream >> intRadius >> intMins[0] >> intMins[1] + >> intMins[2] >> intMaxs[0] >> intMaxs[1] >> intMaxs[2]; + + std::memcpy(&result.radius, &intRadius, sizeof(result.radius)); + + std::memcpy(&result.mins[0], &intMins[0], sizeof(result.mins[0])); + std::memcpy(&result.mins[1], &intMins[1], sizeof(result.mins[1])); + std::memcpy(&result.mins[2], &intMins[2], sizeof(result.mins[2])); + + std::memcpy(&result.maxs[0], &intMaxs[0], sizeof(result.maxs[0])); + std::memcpy(&result.maxs[1], &intMaxs[1], sizeof(result.maxs[2])); + std::memcpy(&result.maxs[2], &intMaxs[2], sizeof(result.maxs[3])); + + *aZoneFileStream >> result.numLods >> result.collLod >> result.streamInfoPtr + >> result.memUsage >> result.flags >> result.physPresetPtr >> result.physGeomsPtr; + + // Parse model name + char modelNameChar; + *aZoneFileStream >> modelNameChar; + while (modelNameChar == 0) { + *aZoneFileStream >> modelNameChar; + } + while (modelNameChar != 0) { + result.modelName += modelNameChar; + *aZoneFileStream >> modelNameChar; + } + return result; +} + +Material ZoneFile_COD10_PC::pParseAsset_Material(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); + + return Material(); +} + +Shader ZoneFile_COD10_PC::pParseAsset_Shader(QDataStream *aZoneFileStream) { + Shader result = Shader(); + + quint8 minorVersion, majorVersion; + *aZoneFileStream >> minorVersion >> majorVersion; + + quint32 magic; + *aZoneFileStream >> magic; + + // Verify .fxc magic + if (magic != 65534 && magic != 65535) { return result; } + + SHADER_TYPE type = SHADER_NONE; + quint16 rawShaderType; + *aZoneFileStream >> rawShaderType; + if (rawShaderType == 65535) { // Pixel shader + type = SHADER_PIXEL; + } else if (rawShaderType == 65534) { // Vertex shader + type = SHADER_VERTEX; + } + Q_UNUSED(type); + + while (true) { + quint32 instructionToken; + *aZoneFileStream >> instructionToken; + + SHADER_OPCODE opCode = (SHADER_OPCODE)(instructionToken & 0xffff); + + int size; + if (opCode == OPCODE_End) { + break; + } else if (opCode == OPCODE_Comment) { + size = (int)((instructionToken >> 16) & 0x7FFF); + } else { + size = (int)((instructionToken >> 24) & 0x0f); + } + Q_UNUSED(size); + } + + + return result; +} + +TechSet ZoneFile_COD10_PC::pParseAsset_TechSet(QDataStream *aZoneFileStream) { + TechSet result; + + for (int i = 1; i <= 62; i++) { + quint32 ptr; + *aZoneFileStream >> ptr; + + result.pointers << ptr; + } + qDebug() << aZoneFileStream->device()->pos(); + + // Parse techset name + char techSetNameChar; + *aZoneFileStream >> techSetNameChar; + while (techSetNameChar != 0) { + result.name += techSetNameChar; + *aZoneFileStream >> techSetNameChar; + } + result.name.replace(",", ""); + + return result; +} + +Image ZoneFile_COD10_PC::pParseAsset_Image(QDataStream *aZoneFileStream) { + Image result; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknowna >> result.unknownb + >> result.unknownc >> result.unknownd + >> result.unknowne >> result.unknownf + >> result.unknowng; + + aZoneFileStream->skipRawData(15 * 4); + *aZoneFileStream >> result.unknownh >> result.unknowni; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknownj; + + aZoneFileStream->skipRawData(4); + + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + result.materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + result.materialName.replace(",", ""); + + if (result.unknowna) { + *aZoneFileStream >> result.unknownk; + *aZoneFileStream >> result.unknownl; + *aZoneFileStream >> result.unknownm; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown1; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown2 >> result.unknown3 + >> result.size1 >> result.size2 + >> result.unknown4 >> result.unknown5; + + aZoneFileStream->skipRawData(4); + + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + result.name += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + + *aZoneFileStream >> result.unknown6 >> result.unknown7; + + QByteArray compressionData(8, Qt::Uninitialized); + aZoneFileStream->readRawData(compressionData.data(), 8); + if (compressionData.contains("DXT1")) { + result.compression = COMPRESSION_DXT1; + } else if (compressionData.contains("DXT3")) { + result.compression = COMPRESSION_DXT3; + } else if (compressionData.contains("DXT5")) { + result.compression = COMPRESSION_DXT5; + } else { + result.compression = COMPRESSION_NONE; + } + + *aZoneFileStream >> result.unknown8 >> result.unknown9; + } + + return result; +} + +SoundAsset ZoneFile_COD10_PC::pParseAsset_Sound(QDataStream *aZoneFileStream) { + SoundAsset result; + + qDebug() << aZoneFileStream->device()->pos(); + + QByteArray rootNamePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rootNamePtr.data(), 4); + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.count; + + if (rootNamePtr.toHex() == "ffffffff") { + // Read in sound file name + char soundNameChar; + *aZoneFileStream >> soundNameChar; + while (soundNameChar != 0) { + result.name += soundNameChar; + *aZoneFileStream >> soundNameChar; + } + } + + int tagCount = 0; + int resultCount = 0; + for (quint32 i = 0; i < result.count; i++) { + aZoneFileStream->skipRawData(12); + + QByteArray tagPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(tagPtr.data(), 4); + + if (tagPtr.toHex() == "ffffffff") { + tagCount++; + } + aZoneFileStream->skipRawData(4); + + QByteArray pathPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pathPtr.data(), 4); + + if (pathPtr.toHex() == "ffffffff") { + resultCount++; + } + + aZoneFileStream->skipRawData(160); + } + + for (int i = 0; i < tagCount; i++) { + // Read in tag? + QString tag; + char tagChar; + *aZoneFileStream >> tagChar; + while (tagChar != 0) { + tag += tagChar; + *aZoneFileStream >> tagChar; + } + } + + for (int i = 0; i < resultCount; i++) { + Sound sound; + + if (aZoneFileStream->device()->peek(12).toHex().contains("ffffffff00000000")) { + aZoneFileStream->skipRawData(12); + } + + aZoneFileStream->skipRawData(8); + + QByteArray aliasPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(aliasPtr.data(), 4); + + QByteArray namePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(namePtr.data(), 4); + + *aZoneFileStream >> sound.dataLength; + + if (aliasPtr.toHex() == "ffffffff") { + // Read in sound alias name + char soundAliasChar; + *aZoneFileStream >> soundAliasChar; + while (soundAliasChar != 0) { + sound.alias += soundAliasChar; + *aZoneFileStream >> soundAliasChar; + } + } + + if (aZoneFileStream->device()->peek(4) == "RIFF") { + sound.path = sound.alias; + sound.alias = ""; + } else if (namePtr.toHex() == "ffffffff") { + // Read in sound file path + char soundPathChar; + *aZoneFileStream >> soundPathChar; + while (soundPathChar != 0) { + sound.path += soundPathChar; + *aZoneFileStream >> soundPathChar; + } + sound.path.replace(",", ""); + } + + if (sound.dataLength) { + QByteArray data(sound.dataLength, Qt::Uninitialized); + aZoneFileStream->readRawData(data.data(), sound.dataLength); + sound.data = data; + } + result.sounds.append(sound); + } + + return result; +} + +void ZoneFile_COD10_PC::pParseAsset_ColMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD10_PC::pParseAsset_GameMapSP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD10_PC::pParseAsset_GameMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD10_PC::pParseAsset_LightDef(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD10_PC::pParseAsset_UIMap(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD10_PC::pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD10_PC::pParseAsset_AIType(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD10_PC::pParseAsset_FX(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Animation ZoneFile_COD10_PC::pParseAsset_Animation(QDataStream *aZoneFileStream) { + Animation result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.dataByteCount + >> result.dataShortCount + >> result.dataIntCount + >> result.randomDataByteCount + >> result.randomDataIntCount + >> result.numframes + >> result.isLooped + >> result.isDelta + >> result.noneRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.normalTranslatedBoneCount + >> result.preciseTranslatedBoneCount + >> result.staticTranslatedBoneCount + >> result.noneTranslatedBoneCount + >> result.totalBoneCount + >> result.otherBoneCount1 + >> result.otherBoneCount2 + >> result.notifyCount + >> result.assetType + >> result.pad + >> result.randomDataShortCount + >> result.indexCount + >> result.frameRate + >> result.frequency + >> result.boneIDsPtr + >> result.dataBytePtr + >> result.dataShortPtr + >> result.dataIntPtr + >> result.randomDataShortPtr + >> result.randomDataBytePtr + >> result.randomDataIntPtr + >> result.longIndiciesPtr + >> result.notificationsPtr + >> result.deltaPartsPtr; + + // Read in x_anim file name + QString xAnimName; + char xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + while (xAnimNameChar != 0) { + result.name += xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + } + + // Parse x_anim index header + QVector sectionLengths; + for (int i = 0; i < result.numframes; i++) { + quint8 sectionlength; + *aZoneFileStream >> sectionlength; + sectionLengths.push_back(sectionlength); + // Skip padding + aZoneFileStream->skipRawData(1); + } + // Skip unknown section + aZoneFileStream->skipRawData(2 * 8); + + return result; +} + +MenuFile ZoneFile_COD10_PC::pParseAsset_MenuFile(QDataStream *aZoneFileStream) { + //MENU_FILE + MenuFile result; + + aZoneFileStream->skipRawData(4); // Separator + + // Parse menu def count + *aZoneFileStream >> result.menuCount; + + // Clearly misparsed, never have this much + if (result.menuCount > 1000) { + qDebug() << "Failure reported when parsing menu file."; + return result; + } + for (uint i = 0; i < result.menuCount; i++) { + Menu menu; + + aZoneFileStream->skipRawData(4); // Separator + + // Read in x_anim file name + char menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + while (menuFilepathChar != 0) { + menu.filePath += menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + } + aZoneFileStream->skipRawData(4); // Separator + + *aZoneFileStream >> menu.menuNamePtr; + + float menuRectX, menuRectY, menuRectWidth, menuRectHeight; + *aZoneFileStream >> menuRectX >> menuRectY >> menuRectWidth >> menuRectHeight; + menu.rect = QRectF(menuRectX, menuRectY, menuRectWidth, menuRectHeight); + + quint32 hAlignInt, vAlignInt; + *aZoneFileStream >> hAlignInt >> vAlignInt; + menu.hAlign = (MENU_H_ALIGNMENT)hAlignInt; + menu.vAlign = (MENU_V_ALIGNMENT)vAlignInt; + + float rectClientX, rectClientY, rectClientWidth, rectClientHeight; + *aZoneFileStream >> rectClientX >> rectClientY >> rectClientWidth >> rectClientHeight; + menu.clientRect = QRectF(rectClientX, rectClientY, rectClientWidth, rectClientHeight); + + quint32 hClientAlignInt, vClientAlignInt, styleInt, borderInt; + *aZoneFileStream >> hClientAlignInt >> vClientAlignInt >> menu.groupPtr + >> styleInt >> borderInt >> menu.ownerDraw >> menu.ownerDrawFlags + >> menu.borderSize >> menu.staticFlags >> menu.dynamicFlags >> menu.nextTime; + menu.hClientAlign = (MENU_H_ALIGNMENT)hClientAlignInt; + menu.vClientAlign = (MENU_V_ALIGNMENT)vClientAlignInt; + menu.style = (MENU_WINDOW_STYLE)styleInt; + menu.border = (MENU_WINDOW_BORDER)borderInt; + + float foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA, + backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA, + borderColorR, borderColorG, borderColorB, borderColorA, + outlineColorR, outlineColorG, outlineColorB, outlineColorA; + *aZoneFileStream >> foregroundColorR >> foregroundColorG >> foregroundColorB >> foregroundColorA + >> backgroundColorR >> backgroundColorG >> backgroundColorB >> backgroundColorA + >> borderColorR >> borderColorG >> borderColorB >> borderColorA + >> outlineColorR >> outlineColorG >> outlineColorB >> outlineColorA; + + menu.foregroundColor = QColor(foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA); + menu.backgroundColor = QColor(backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA); + menu.borderColor = QColor(borderColorR, borderColorG, borderColorB, borderColorA); + menu.outlineColor = QColor(outlineColorR, outlineColorG, outlineColorB, outlineColorA); + + *aZoneFileStream >> menu.materialPtr >> menu.fontPtr >> menu.fullScreen >> menu.itemCount + >> menu.fontIndex >> menu.cursorItem >> menu.fadeCycle >> menu.fadeClamp + >> menu.fadeAmount >> menu.fadeInAmount >> menu.blurRadius >> menu.onOpenPtr + >> menu.onFocusPtr >> menu.onClosePtr >> menu.onESCPtr >> menu.onKeyPtr + >> menu.visibleExpCount >> menu.expEntryPtr >> menu.allowedBindingPtr + >> menu.soundNamePtr >> menu.imageTrack; + + float focusColorR, focusColorG, focusColorB, focusColorA, + disabledColorR, disabledColorG, disabledColorB, disabledColorA; + *aZoneFileStream >> focusColorR >> focusColorG >> focusColorB >> focusColorA + >> disabledColorR >> disabledColorG >> disabledColorB >> disabledColorA; + menu.focusColor = QColor(focusColorR, focusColorG, focusColorB, focusColorA); + menu.disabledColor = QColor(disabledColorR, disabledColorG, disabledColorB, disabledColorA); + + *aZoneFileStream >> menu.rectXExpCount >> menu.rectXExpPtr >> menu.rectYExpCount >> menu.rectYExpPtr; + + aZoneFileStream->skipRawData(4); // Separator + + char menuDefNameChar; + int menuDefNameLen = 0; + *aZoneFileStream >> menuDefNameChar; + while (menuDefNameChar != 0 && menuDefNameLen < 30) { + menuDefNameLen++; + menu.name += menuDefNameChar; + *aZoneFileStream >> menuDefNameChar; + } + + char defStringChar; + int defStringLen = 0; + *aZoneFileStream >> defStringChar; + while (defStringChar != 0 && defStringLen < 30) { + defStringLen++; + menu.definition += defStringChar; + *aZoneFileStream >> defStringChar; + } + aZoneFileStream->skipRawData(4 * 10); + + *aZoneFileStream >> menu.itemWindowDefNamePtr; + + float itemRectX, itemRectY, itemRectWidth, itemRectHeight; + *aZoneFileStream >> itemRectX >> itemRectY >> itemRectWidth >> itemRectHeight; + menu.itemRect = QRectF(itemRectX, itemRectY, itemRectWidth, itemRectHeight); + + *aZoneFileStream >> menu.itemHAlignment >> menu.itemVAlignment >> menu.itemGroupPtr + >> menu.itemWindowStyle >> menu.itemWindowBorder >> menu.itemOwnerDraw + >> menu.itemOwnerDrawFlags >> menu.itemBorderSize >> menu.itemStaticFlags + >> menu.itemDynamicFlags >> menu.itemNextTime; + + float itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA, + itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA, + itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA, + itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA; + *aZoneFileStream >> itemForegroundColorR >> itemForegroundColorG >> itemForegroundColorB >> itemForegroundColorA + >> itemBackgroundColorR >> itemBackgroundColorG >> itemBackgroundColorB >> itemBackgroundColorA + >> itemBorderColorR >> itemBorderColorG >> itemBorderColorB >> itemBorderColorA + >> itemOutlineColorR >> itemOutlineColorG >> itemOutlineColorB >> itemOutlineColorA; + + menu.itemForegroundColor = QColor(itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA); + menu.itemBackgroundColor = QColor(itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA); + menu.itemBorderColor = QColor(itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA); + menu.itemOutlineColor = QColor(itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA); + + *aZoneFileStream >> menu.itemMaterialPtr; + + float itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight; + *aZoneFileStream >> itemTextRectX >> itemTextRectY >> itemTextRectWidth >> itemTextRectHeight; + menu.itemTextRect = QRectF(itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight); + + quint32 hItemTextAlignInt, vItemTextAlignInt, itemType, fontTypeInt, textStyleInt; + *aZoneFileStream >> hItemTextAlignInt >> vItemTextAlignInt >> itemType >> menu.dataType + >> menu.alignment >> fontTypeInt >> menu.textAlignMode >> menu.textalignx >> menu.textaligny + >> menu.textscale >> textStyleInt >> menu.gameMsgWindowIndex >> menu.gameMsgWindowMode + >> menu.testPtr >> menu.textSavegameInfo >> menu.parentPtr; + menu.itemText_hAlign = (MENU_H_ALIGNMENT)hItemTextAlignInt; + menu.itemText_vAlign = (MENU_V_ALIGNMENT)vItemTextAlignInt; + menu.itemType = (MENU_ITEM_TYPE)itemType; + menu.fontEnum = (MENU_FONT_TYPE)fontTypeInt; + menu.textStyle = (MENU_ITEM_TEXTSTYLE)textStyleInt; + + *aZoneFileStream >> menu.mouseEnterText >> menu.mouseExitText >> menu.mouseEnter >> menu.mouseExit + >> menu.action >> menu.onAccept >> menu.onFocus >> menu.leaveFocus >> menu.dvar >> menu.dvarTest + >> menu.keyHandlerPtr >> menu.enableDvarPtr >> menu.dvarFlags >> menu.focusSoundPtr + >> menu.special >> menu.cursorPos; + + // itemDefData_t typeData; + + // listBoxDef_s *listBox; + + *aZoneFileStream >> menu.startPos >> menu.endPos >> menu.drawPadding; + + *aZoneFileStream >> menu.elementWidth >> menu.elementHeight; + + *aZoneFileStream >> menu.elementStyle >> menu.numColumns; + + //columnInfo_s columnInfo[16]; + + *aZoneFileStream >> menu.doubleClickPtr; + + + *aZoneFileStream >> menu.notselectable >> menu.noScrollBars >> menu.usePaging; + + float itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA, + itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA, + itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA; + *aZoneFileStream >> itemSelectBorderColorR >> itemSelectBorderColorG >> itemSelectBorderColorB >> itemSelectBorderColorA + >> itemDisableColorR >> itemDisableColorG >> itemDisableColorB >> itemDisableColorA + >> itemFocusColorR >> itemFocusColorG >> itemFocusColorB >> itemFocusColorA; + menu.itemSelectBorderColor = QColor(itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA); + menu.itemDisableColor = QColor(itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA); + menu.itemFocusColor = QColor(itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA); + + *aZoneFileStream >> menu.selectIconPtr >> menu.backgroundItemListboxPtr >> menu.highlightTexturePtr; + + // editFieldDef_s *editField; + + *aZoneFileStream >> menu.minVal >> menu.maxVal >> menu.defVal >> menu.range >> menu.maxChars + >> menu.maxCharsGotoNext >> menu.maxPaintChars >> menu.paintOffset; + + // multiDef_s *multi; + + for (int i = 0; i < 32; i++) { + quint32 dvarList; + *aZoneFileStream >> dvarList; + menu.dvarListPtrs.push_back(dvarList); + } + + for (int i = 0; i < 32; i++) { + quint32 dvarStr; + *aZoneFileStream >> dvarStr; + menu.dvarStrPtrs.push_back(dvarStr); + } + + for (int i = 0; i < 32; i++) { + float dvarValue; + *aZoneFileStream >> dvarValue; + menu.dvarValues.push_back(dvarValue); + } + + *aZoneFileStream >> menu.count >> menu.strDef >> menu.enumDvarNamePtr; + aZoneFileStream->skipRawData(4); + //>> menu.dataPtr + *aZoneFileStream >> menu.itemImageTrack; + + qDebug() << aZoneFileStream->device()->pos(); + + //statement_s visibleExp; + //statement_s textExp; + //statement_s materialExp; + //statement_s rectXExp; + //statement_s rectYExp; + //statement_s rectWExp; + //statement_s rectHExp; + //statement_s foreColorAExp; + result.menuDefs << menu; + } + return result; +} + +void ZoneFile_COD10_PC::pParseAsset_Weapon(QDataStream *aZoneFileStream) { + //WEAPON_FILE + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD10_PC::pParseAsset_D3DBSP(QDataStream *aZoneFileStream) { + //D3DBSP_DUMP + Q_UNUSED(aZoneFileStream); +} + +StringTable ZoneFile_COD10_PC::pParseAsset_StringTable(QDataStream *aZoneFileStream) { + StringTable result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.columnCount + >> result.rowCount; + + // Todo fix this + result.columnCount = 0; + result.rowCount = 0; + + aZoneFileStream->skipRawData(4); + + QString stringTableName; + char stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + while (stringTableNameChar != 0) { + result.name += stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + } + + for (quint32 i = 0; i < result.rowCount; i++) { + QByteArray pointerData(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pointerData.data(), 4); + result.tablePointers.push_back(pointerData.toHex()); + + aZoneFileStream->skipRawData(4); + } + + for (const QString &pointerAddr : result.tablePointers) { + QString leadingContent = ""; + if (pointerAddr == "FFFFFFFF") { + char leadingContentChar; + *aZoneFileStream >> leadingContentChar; + while (leadingContentChar != 0) { + leadingContent += leadingContentChar; + *aZoneFileStream >> leadingContentChar; + } + } else { + leadingContent = pointerAddr; + } + + QString content; + char contentChar; + *aZoneFileStream >> contentChar; + while (contentChar != 0) { + content += contentChar; + *aZoneFileStream >> contentChar; + } + result.content[leadingContent] = content; + } + return result; +} + +AssetType ZoneFile_COD10_PC::AssetStrToEnum(const QString aAssetType) { + const QString cleanedType = aAssetType.toUpper(); + if (cleanedType == "17000000") { // localized string PARTIALLY VERIFIED + return ASSET_LOCAL_STRING; + } else if (cleanedType == "20000000") { // raw_file PARTIALLY VERIFIED + return ASSET_RAW_FILE; + } else if (cleanedType == "1A000000") { // fx PARTIALLY VERIFIED + return ASSET_EFFECT; + } else if (cleanedType == "09000000") { // loaded_sound PARTIALLY VERIFIED + return ASSET_SOUND; + } else if (cleanedType == "04000000") { // x_anim PARTIALLY VERIFIED + return ASSET_ANIMATION; + } else if (cleanedType == "0C000000") { // collision_map PARTIALLY VERIFIED + return ASSET_COLLISION_MAP; + } else if (cleanedType == "21000000") { // string_table PARTIALLY VERIFIED + return ASSET_STRING_TABLE; + } else if (cleanedType == "15000000") { // menu_file PARTIALLY VERIFIED + return ASSET_MENU; + } else if (cleanedType == "07000000") { // tech set PARTIALLY VERIFIED + return ASSET_TECH_SET; + } else if (cleanedType == "18000000") { // weapon PARTIALLY VERIFIED + return ASSET_WEAPON; + } else if (cleanedType == "11000000") { // gfx map PARTIALLY VERIFIED + return ASSET_GFX_MAP; + } else if (cleanedType == "12000000") { // light_def PARTIALLY VERIFIED + return ASSET_LIGHT_DEF; + } else if (cleanedType == "14000000") { // font PARTIALLY VERIFIED + return ASSET_FONT; + } else if (cleanedType == "05000000") { // xmodel PARTIALLY VERIFIED + return ASSET_MODEL; + } else if (cleanedType == "0D000000") { // d3dbsp PARTIALLY VERIFIED + return ASSET_D3DBSP; + } else if (cleanedType == "06000000") { // image PARTIALLY VERIFIED + return ASSET_IMAGE; + } else if (cleanedType == "0E000000") { // game map sp PARTIALLY VERIFIED + return ASSET_GAME_MAP_SP; + } else if (cleanedType == "0B000000") { // col map sp PARTIALLY VERIFIED + return ASSET_COL_MAP_SP; + } + return ASSET_NONE; +} + +QByteArray ZoneFile_COD10_PC::GetBinaryData() { + QByteArray result; + + return result; +} diff --git a/libs/zonefile/PC/zonefile_cod10_pc.h b/libs/zonefile/PC/zonefile_cod10_pc.h new file mode 100644 index 0000000..8443654 --- /dev/null +++ b/libs/zonefile/PC/zonefile_cod10_pc.h @@ -0,0 +1,52 @@ +#ifndef ZONEFILE_COD10_PC_H +#define ZONEFILE_COD10_PC_H + +#include "zonefile.h" + +class ZoneFile_COD10_PC : public ZoneFile +{ +public: + ZoneFile_COD10_PC(); + ~ZoneFile_COD10_PC(); + + bool Load(const QByteArray aFileData) override; + AssetType AssetStrToEnum(const QString aAssetType) override; + + QByteArray GetBinaryData() override; + +protected: + void pParseZoneHeader(QDataStream *aZoneFileStream) override; + quint32 pParseZoneSize(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsA(QDataStream *aZoneFileStream) override; + quint32 pParseZoneTagCount(QDataStream *aZoneFileStream) override; + quint32 pParseZoneRecordCount(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsB(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsC(QDataStream *aZoneFileStream) override; + QStringList pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) override; + QStringList pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) override; + AssetMap pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) override; + LocalString pParseAsset_LocalString(QDataStream *aZoneFileStream) override; + RawFile pParseAsset_RawFile(QDataStream *aZoneFileStream) override; + void pParseAsset_PhysPreset(QDataStream *aZoneFileStream) override; + Model pParseAsset_Model(QDataStream *aZoneFileStream) override; + Material pParseAsset_Material(QDataStream *aZoneFileStream) override; + Shader pParseAsset_Shader(QDataStream *aZoneFileStream) override; + TechSet pParseAsset_TechSet(QDataStream *aZoneFileStream) override; + Image pParseAsset_Image(QDataStream *aZoneFileStream) override; + SoundAsset pParseAsset_Sound(QDataStream *aZoneFileStream) override; + void pParseAsset_ColMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapSP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_LightDef(QDataStream *aZoneFileStream) override; + void pParseAsset_UIMap(QDataStream *aZoneFileStream) override; + void pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) override; + void pParseAsset_AIType(QDataStream *aZoneFileStream) override; + void pParseAsset_FX(QDataStream *aZoneFileStream) override; + Animation pParseAsset_Animation(QDataStream *aZoneFileStream) override; + MenuFile pParseAsset_MenuFile(QDataStream *aZoneFileStream) override; + void pParseAsset_Weapon(QDataStream *aZoneFileStream) override; + void pParseAsset_D3DBSP(QDataStream *aZoneFileStream) override; + StringTable pParseAsset_StringTable(QDataStream *aZoneFileStream) override; +}; + +#endif // ZONEFILE_COD10_PC_H diff --git a/libs/zonefile/PC/zonefile_cod11_pc.cpp b/libs/zonefile/PC/zonefile_cod11_pc.cpp new file mode 100644 index 0000000..516d83a --- /dev/null +++ b/libs/zonefile/PC/zonefile_cod11_pc.cpp @@ -0,0 +1,1072 @@ +#include "zonefile_cod11_pc.h" + +#include +#include +#include + +ZoneFile_COD11_PC::ZoneFile_COD11_PC() +{ + +} + +ZoneFile_COD11_PC::~ZoneFile_COD11_PC() +{ + +} + +bool ZoneFile_COD11_PC::Load(const QByteArray aFileData) { + // Open zone file as little endian stream + QDataStream zoneFileStream(aFileData); + zoneFileStream.setByteOrder(QDataStream::LittleEndian); + + // Parse data from zone file header + pParseZoneHeader(&zoneFileStream); + SetRecords(pParseZoneIndex(&zoneFileStream, GetRecordCount())); + SetAssetMap(pParseAssets(&zoneFileStream, GetRecords())); + + return true; +} + +void ZoneFile_COD11_PC::pParseZoneHeader(QDataStream *aZoneFileStream) { + SetSize(pParseZoneSize(aZoneFileStream)); + pParseZoneUnknownsA(aZoneFileStream); + + SetTagCount(pParseZoneTagCount(aZoneFileStream)); + pParseZoneUnknownsB(aZoneFileStream); + + SetRecordCount(pParseZoneRecordCount(aZoneFileStream)); + + quint32 tagCount = GetTagCount(); + if (tagCount) { + pParseZoneUnknownsC(aZoneFileStream); + SetTags(pParseZoneTags(aZoneFileStream, tagCount)); + } else { + aZoneFileStream->skipRawData(4); + } +} + +quint32 ZoneFile_COD11_PC::pParseZoneSize(QDataStream *aZoneFileStream) { + quint32 zoneFileSize; + *aZoneFileStream >> zoneFileSize; + if (zoneFileSize <= 0) { + qDebug() << "Tried to open empty zone file!"; + exit(-1); + } + zoneFileSize += 36; + return zoneFileSize; +} + +/* + ParseZoneUnknownsA() + + Parses the 1st section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD11_PC::pParseZoneUnknownsA(QDataStream *aZoneFileStream) { + // Byte 4-7, 8-11, 12-15: unknown + QByteArray unknown1(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown1.data(), 4); + + QByteArray unknown2(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown2.data(), 4); + + QByteArray unknown3(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown3.data(), 4); + + // Byte 16-19, 20-23: empty/unknown + QByteArray unknown4(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown4.data(), 4); + + QByteArray unknown5(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown5.data(), 4); + + // Byte 24-27: somehow related to the filesize, but smaller value + QByteArray unknown6(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown6.data(), 4); + + // Byte 28-31, 32-35: unknown + QByteArray unknown7(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown7.data(), 4); + + QByteArray unknown8(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown8.data(), 4); +} + +/* + ParseZoneTagCount() + + Parses the number of string tags in the zone index +*/ +quint32 ZoneFile_COD11_PC::pParseZoneTagCount(QDataStream *aZoneFileStream) { + quint32 tagCount; + *aZoneFileStream >> tagCount; + return tagCount; +} + +/* + ParseZoneRecordCount() + + Parses the number of records in the zone index +*/ +quint32 ZoneFile_COD11_PC::pParseZoneRecordCount(QDataStream *aZoneFileStream) { + quint32 recordCount; + *aZoneFileStream >> recordCount; + return recordCount; +} + +/* + ParseZoneUnknownsB() + + Parses the 2nd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD11_PC::pParseZoneUnknownsB(QDataStream *aZoneFileStream) { + // Byte 44-47: Unknown/empty? + QByteArray unknown9(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown9.data(), 4); +} + +/* + pParseZoneUnknownsC() + + Parses the 3rd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD11_PC::pParseZoneUnknownsC(QDataStream *aZoneFileStream) { + // Byte 40-43: Unknown/empty? + QByteArray unknown10(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown10.data(), 4); + + // Byte 44-47: Unknown/empty? + QByteArray unknown11(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown11.data(), 4); +} + +/* + ParseZoneTags() + + Parses the string tags ate the start of zone file +*/ +QStringList ZoneFile_COD11_PC::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) { + QStringList tags; + + // Byte 48-51: Repeated separators? ÿÿÿÿ x i + aZoneFileStream->skipRawData(4 * (tagCount - 1)); + + // Parse tags/strings before index + QString zoneTag; + char zoneTagChar; + for (quint32 i = 0; i < tagCount; i++) { + *aZoneFileStream >> zoneTagChar; + while (zoneTagChar != 0) { + zoneTag += zoneTagChar; + *aZoneFileStream >> zoneTagChar; + } + tags << zoneTag; + zoneTag.clear(); + } + return tags; +} + +/* + ParseZoneIndex() + + Parse the binary zone index data and populate table +*/ +QStringList ZoneFile_COD11_PC::pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) { + QStringList result; + + // Don't parse if no records + if (!recordCount) { return result; } + + if (aZoneFileStream->device()->peek(4).toHex().contains("ffff")) { + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 2); + } + + // Parse index & map found asset types + for (quint32 i = 0; i <= recordCount; i++) { + // Skip record start + QByteArray rawAssetType(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rawAssetType.data(), 4); + result << rawAssetType.toHex(); + + // Skip separator + aZoneFileStream->skipRawData(4); + } + return result; +} + +AssetMap ZoneFile_COD11_PC::pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) { + AssetMap result; + + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 8); + + for (int i = 0; i < assetOrder.size(); i++) { + const QString typeHex = assetOrder[i]; + const AssetType typeStr = AssetStrToEnum(typeHex); + + if (typeStr == ASSET_LOCAL_STRING) { // localized string asset + result.localStrings << pParseAsset_LocalString(aZoneFileStream); + } else if (typeStr == ASSET_RAW_FILE) { // gsc + auto rawFile = pParseAsset_RawFile(aZoneFileStream); + if (rawFile.length) { + result.rawFiles << rawFile; + } + } else if (typeStr == ASSET_PHYS_PRESET) { // physpreset + pParseAsset_PhysPreset(aZoneFileStream); + } else if (typeStr == ASSET_MODEL) { // xmodel + result.models << pParseAsset_Model(aZoneFileStream); + } else if (typeStr == ASSET_MATERIAL) { // material + pParseAsset_Material(aZoneFileStream); + } else if (typeStr == ASSET_SHADER) { // pixelshader + pParseAsset_Shader(aZoneFileStream); + } else if (typeStr == ASSET_TECH_SET) { // techset include + result.techSets << pParseAsset_TechSet(aZoneFileStream); + } else if (typeStr == ASSET_IMAGE) { // image + result.images << pParseAsset_Image(aZoneFileStream); + } else if (typeStr == ASSET_SOUND) { // loaded_sound + result.sounds << pParseAsset_Sound(aZoneFileStream); + } else if (typeStr == ASSET_COLLISION_MAP) { // col_map_mp + pParseAsset_ColMapMP(aZoneFileStream); + } else if (typeStr == ASSET_MP_MAP) { // game_map_sp + pParseAsset_GameMapSP(aZoneFileStream); + } else if (typeStr == ASSET_SP_MAP) { // game_map_mp + pParseAsset_GameMapMP(aZoneFileStream); + } else if (typeStr == ASSET_LIGHT_DEF) { // lightdef + pParseAsset_LightDef(aZoneFileStream); + } else if (typeStr == ASSET_UI_MAP) { // ui_map + pParseAsset_UIMap(aZoneFileStream); + } else if (typeStr == ASSET_SND_DRIVER_GLOBALS) { // snddriverglobals + pParseAsset_SNDDriverGlobals(aZoneFileStream); + } else if (typeStr == ASSET_AI_TYPE) { // aitype + pParseAsset_AIType(aZoneFileStream); + } else if (typeStr == ASSET_EFFECT) { // aitype + pParseAsset_FX(aZoneFileStream); + } else if (typeStr == ASSET_ANIMATION) { // aitype + result.animations << pParseAsset_Animation(aZoneFileStream); + } else if (typeStr == ASSET_STRING_TABLE) { // string_table + result.stringTables << pParseAsset_StringTable(aZoneFileStream); + } else if (typeStr == ASSET_MENU) { // string_table + result.menuFiles << pParseAsset_MenuFile(aZoneFileStream); + } else if (typeStr == ASSET_WEAPON) { // string_table + pParseAsset_Weapon(aZoneFileStream); + } else if (typeStr == ASSET_D3DBSP) { // string_table + pParseAsset_D3DBSP(aZoneFileStream); + } + } + return result; +} + +LocalString ZoneFile_COD11_PC::pParseAsset_LocalString(QDataStream *aZoneFileStream) { + LocalString result; + + quint32 stringPtr, aliasPtr; + *aZoneFileStream >> stringPtr >> aliasPtr; + if (stringPtr == 4294967295) { + // Parse local string asset contents + QString localStr; + char localStrChar; + *aZoneFileStream >> localStrChar; + while (localStrChar != 0) { + result.string += localStrChar; + *aZoneFileStream >> localStrChar; + } + } else { + result.string = "String Ptr: " + QString::number(stringPtr); + } + + if (aliasPtr == 4294967295) { + // Parse rawfile name + QString aliasName; + char aliasNameChar; + *aZoneFileStream >> aliasNameChar; + while (aliasNameChar != 0) { + result.alias += aliasNameChar; + *aZoneFileStream >> aliasNameChar; + } + } else { + result.string = "Alias Ptr: " + QString::number(aliasPtr); + } + + return result; +} + +RawFile ZoneFile_COD11_PC::pParseAsset_RawFile(QDataStream *aZoneFileStream) { + RawFile result; + + // Skip start separator FF FF FF FF (pointer?) + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.length; + + // Skip unknown 4 byte data + aZoneFileStream->skipRawData(4); + + // Parse rawfile path + char scriptPathChar; + *aZoneFileStream >> scriptPathChar; + while (scriptPathChar != 0) { + result.path += scriptPathChar; + *aZoneFileStream >> scriptPathChar; + } + result.path.replace(",", ""); + const QStringList pathParts = result.path.split('/'); + if (pathParts.size() == 0) { + qDebug() << "Failed to parse ff path! " << result.path; + exit(-1); + } + + // Parse gsc contents + char rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + while (rawFileContentsChar != 0 && rawFileContentsChar != -1) { + result.contents += rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + } + return result; +} + +void ZoneFile_COD11_PC::pParseAsset_PhysPreset(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Model ZoneFile_COD11_PC::pParseAsset_Model(QDataStream *aZoneFileStream) { + Model result; + + *aZoneFileStream >> result.namePtr >> result.tagCount >> result.rootTagCount + >> result.surfCount >> result.unknownCount >> result.boneNamePtr + >> result.parentListPtr >> result.quatsPtr >> result.transPtr + >> result.partClassPtr >> result.baseMatPtr + >> result.surfsPtr >> result.materialHandlesPtr; + + // Parse XModelLodInfo + for (int i = 1; i <= 4; i++) { + quint32 intDist; + *aZoneFileStream >> intDist; + + std::memcpy(&result.lodInfo[i].dist, &intDist, sizeof(result.lodInfo[i].dist)); + *aZoneFileStream >> result.lodInfo[i].numsurfs >> result.lodInfo[i].surfIndex; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.lodInfo[i].partBits[0] + >> result.lodInfo[i].partBits[1] + >> result.lodInfo[i].partBits[2] + >> result.lodInfo[i].partBits[3]; + } + + *aZoneFileStream >> result.collSurfsPtr >> result.numCollSurfs >> result.contents >> result.boneInfoPtr; + + quint32 intRadius, intMins[3], intMaxs[3]; + *aZoneFileStream >> intRadius >> intMins[0] >> intMins[1] + >> intMins[2] >> intMaxs[0] >> intMaxs[1] >> intMaxs[2]; + + std::memcpy(&result.radius, &intRadius, sizeof(result.radius)); + + std::memcpy(&result.mins[0], &intMins[0], sizeof(result.mins[0])); + std::memcpy(&result.mins[1], &intMins[1], sizeof(result.mins[1])); + std::memcpy(&result.mins[2], &intMins[2], sizeof(result.mins[2])); + + std::memcpy(&result.maxs[0], &intMaxs[0], sizeof(result.maxs[0])); + std::memcpy(&result.maxs[1], &intMaxs[1], sizeof(result.maxs[2])); + std::memcpy(&result.maxs[2], &intMaxs[2], sizeof(result.maxs[3])); + + *aZoneFileStream >> result.numLods >> result.collLod >> result.streamInfoPtr + >> result.memUsage >> result.flags >> result.physPresetPtr >> result.physGeomsPtr; + + // Parse model name + char modelNameChar; + *aZoneFileStream >> modelNameChar; + while (modelNameChar == 0) { + *aZoneFileStream >> modelNameChar; + } + while (modelNameChar != 0) { + result.modelName += modelNameChar; + *aZoneFileStream >> modelNameChar; + } + return result; +} + +Material ZoneFile_COD11_PC::pParseAsset_Material(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); + + return Material(); +} + +Shader ZoneFile_COD11_PC::pParseAsset_Shader(QDataStream *aZoneFileStream) { + Shader result = Shader(); + + quint8 minorVersion, majorVersion; + *aZoneFileStream >> minorVersion >> majorVersion; + + quint32 magic; + *aZoneFileStream >> magic; + + // Verify .fxc magic + if (magic != 65534 && magic != 65535) { return result; } + + SHADER_TYPE type = SHADER_NONE; + quint16 rawShaderType; + *aZoneFileStream >> rawShaderType; + if (rawShaderType == 65535) { // Pixel shader + type = SHADER_PIXEL; + } else if (rawShaderType == 65534) { // Vertex shader + type = SHADER_VERTEX; + } + Q_UNUSED(type); + + while (true) { + quint32 instructionToken; + *aZoneFileStream >> instructionToken; + + SHADER_OPCODE opCode = (SHADER_OPCODE)(instructionToken & 0xffff); + + int size; + if (opCode == OPCODE_End) { + break; + } else if (opCode == OPCODE_Comment) { + size = (int)((instructionToken >> 16) & 0x7FFF); + } else { + size = (int)((instructionToken >> 24) & 0x0f); + } + Q_UNUSED(size); + } + + + return result; +} + +TechSet ZoneFile_COD11_PC::pParseAsset_TechSet(QDataStream *aZoneFileStream) { + TechSet result; + + for (int i = 1; i <= 62; i++) { + quint32 ptr; + *aZoneFileStream >> ptr; + + result.pointers << ptr; + } + qDebug() << aZoneFileStream->device()->pos(); + + // Parse techset name + char techSetNameChar; + *aZoneFileStream >> techSetNameChar; + while (techSetNameChar != 0) { + result.name += techSetNameChar; + *aZoneFileStream >> techSetNameChar; + } + result.name.replace(",", ""); + + return result; +} + +Image ZoneFile_COD11_PC::pParseAsset_Image(QDataStream *aZoneFileStream) { + Image result; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknowna >> result.unknownb + >> result.unknownc >> result.unknownd + >> result.unknowne >> result.unknownf + >> result.unknowng; + + aZoneFileStream->skipRawData(15 * 4); + *aZoneFileStream >> result.unknownh >> result.unknowni; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknownj; + + aZoneFileStream->skipRawData(4); + + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + result.materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + result.materialName.replace(",", ""); + + if (result.unknowna) { + *aZoneFileStream >> result.unknownk; + *aZoneFileStream >> result.unknownl; + *aZoneFileStream >> result.unknownm; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown1; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown2 >> result.unknown3 + >> result.size1 >> result.size2 + >> result.unknown4 >> result.unknown5; + + aZoneFileStream->skipRawData(4); + + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + result.name += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + + *aZoneFileStream >> result.unknown6 >> result.unknown7; + + QByteArray compressionData(8, Qt::Uninitialized); + aZoneFileStream->readRawData(compressionData.data(), 8); + if (compressionData.contains("DXT1")) { + result.compression = COMPRESSION_DXT1; + } else if (compressionData.contains("DXT3")) { + result.compression = COMPRESSION_DXT3; + } else if (compressionData.contains("DXT5")) { + result.compression = COMPRESSION_DXT5; + } else { + result.compression = COMPRESSION_NONE; + } + + *aZoneFileStream >> result.unknown8 >> result.unknown9; + } + + return result; +} + +SoundAsset ZoneFile_COD11_PC::pParseAsset_Sound(QDataStream *aZoneFileStream) { + SoundAsset result; + + qDebug() << aZoneFileStream->device()->pos(); + + QByteArray rootNamePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rootNamePtr.data(), 4); + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.count; + + if (rootNamePtr.toHex() == "ffffffff") { + // Read in sound file name + char soundNameChar; + *aZoneFileStream >> soundNameChar; + while (soundNameChar != 0) { + result.name += soundNameChar; + *aZoneFileStream >> soundNameChar; + } + } + + int tagCount = 0; + int resultCount = 0; + for (quint32 i = 0; i < result.count; i++) { + aZoneFileStream->skipRawData(12); + + QByteArray tagPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(tagPtr.data(), 4); + + if (tagPtr.toHex() == "ffffffff") { + tagCount++; + } + aZoneFileStream->skipRawData(4); + + QByteArray pathPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pathPtr.data(), 4); + + if (pathPtr.toHex() == "ffffffff") { + resultCount++; + } + + aZoneFileStream->skipRawData(160); + } + + for (int i = 0; i < tagCount; i++) { + // Read in tag? + QString tag; + char tagChar; + *aZoneFileStream >> tagChar; + while (tagChar != 0) { + tag += tagChar; + *aZoneFileStream >> tagChar; + } + } + + for (int i = 0; i < resultCount; i++) { + Sound sound; + + if (aZoneFileStream->device()->peek(12).toHex().contains("ffffffff00000000")) { + aZoneFileStream->skipRawData(12); + } + + aZoneFileStream->skipRawData(8); + + QByteArray aliasPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(aliasPtr.data(), 4); + + QByteArray namePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(namePtr.data(), 4); + + *aZoneFileStream >> sound.dataLength; + + if (aliasPtr.toHex() == "ffffffff") { + // Read in sound alias name + char soundAliasChar; + *aZoneFileStream >> soundAliasChar; + while (soundAliasChar != 0) { + sound.alias += soundAliasChar; + *aZoneFileStream >> soundAliasChar; + } + } + + if (aZoneFileStream->device()->peek(4) == "RIFF") { + sound.path = sound.alias; + sound.alias = ""; + } else if (namePtr.toHex() == "ffffffff") { + // Read in sound file path + char soundPathChar; + *aZoneFileStream >> soundPathChar; + while (soundPathChar != 0) { + sound.path += soundPathChar; + *aZoneFileStream >> soundPathChar; + } + sound.path.replace(",", ""); + } + + if (sound.dataLength) { + QByteArray data(sound.dataLength, Qt::Uninitialized); + aZoneFileStream->readRawData(data.data(), sound.dataLength); + sound.data = data; + } + result.sounds.append(sound); + } + + return result; +} + +void ZoneFile_COD11_PC::pParseAsset_ColMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD11_PC::pParseAsset_GameMapSP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD11_PC::pParseAsset_GameMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD11_PC::pParseAsset_LightDef(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD11_PC::pParseAsset_UIMap(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD11_PC::pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD11_PC::pParseAsset_AIType(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD11_PC::pParseAsset_FX(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Animation ZoneFile_COD11_PC::pParseAsset_Animation(QDataStream *aZoneFileStream) { + Animation result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.dataByteCount + >> result.dataShortCount + >> result.dataIntCount + >> result.randomDataByteCount + >> result.randomDataIntCount + >> result.numframes + >> result.isLooped + >> result.isDelta + >> result.noneRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.normalTranslatedBoneCount + >> result.preciseTranslatedBoneCount + >> result.staticTranslatedBoneCount + >> result.noneTranslatedBoneCount + >> result.totalBoneCount + >> result.otherBoneCount1 + >> result.otherBoneCount2 + >> result.notifyCount + >> result.assetType + >> result.pad + >> result.randomDataShortCount + >> result.indexCount + >> result.frameRate + >> result.frequency + >> result.boneIDsPtr + >> result.dataBytePtr + >> result.dataShortPtr + >> result.dataIntPtr + >> result.randomDataShortPtr + >> result.randomDataBytePtr + >> result.randomDataIntPtr + >> result.longIndiciesPtr + >> result.notificationsPtr + >> result.deltaPartsPtr; + + // Read in x_anim file name + QString xAnimName; + char xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + while (xAnimNameChar != 0) { + result.name += xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + } + + // Parse x_anim index header + QVector sectionLengths; + for (int i = 0; i < result.numframes; i++) { + quint8 sectionlength; + *aZoneFileStream >> sectionlength; + sectionLengths.push_back(sectionlength); + // Skip padding + aZoneFileStream->skipRawData(1); + } + // Skip unknown section + aZoneFileStream->skipRawData(2 * 8); + + return result; +} + +MenuFile ZoneFile_COD11_PC::pParseAsset_MenuFile(QDataStream *aZoneFileStream) { + //MENU_FILE + MenuFile result; + + aZoneFileStream->skipRawData(4); // Separator + + // Parse menu def count + *aZoneFileStream >> result.menuCount; + + // Clearly misparsed, never have this much + if (result.menuCount > 1000) { + qDebug() << "Failure reported when parsing menu file."; + return result; + } + for (uint i = 0; i < result.menuCount; i++) { + Menu menu; + + aZoneFileStream->skipRawData(4); // Separator + + // Read in x_anim file name + char menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + while (menuFilepathChar != 0) { + menu.filePath += menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + } + aZoneFileStream->skipRawData(4); // Separator + + *aZoneFileStream >> menu.menuNamePtr; + + float menuRectX, menuRectY, menuRectWidth, menuRectHeight; + *aZoneFileStream >> menuRectX >> menuRectY >> menuRectWidth >> menuRectHeight; + menu.rect = QRectF(menuRectX, menuRectY, menuRectWidth, menuRectHeight); + + quint32 hAlignInt, vAlignInt; + *aZoneFileStream >> hAlignInt >> vAlignInt; + menu.hAlign = (MENU_H_ALIGNMENT)hAlignInt; + menu.vAlign = (MENU_V_ALIGNMENT)vAlignInt; + + float rectClientX, rectClientY, rectClientWidth, rectClientHeight; + *aZoneFileStream >> rectClientX >> rectClientY >> rectClientWidth >> rectClientHeight; + menu.clientRect = QRectF(rectClientX, rectClientY, rectClientWidth, rectClientHeight); + + quint32 hClientAlignInt, vClientAlignInt, styleInt, borderInt; + *aZoneFileStream >> hClientAlignInt >> vClientAlignInt >> menu.groupPtr + >> styleInt >> borderInt >> menu.ownerDraw >> menu.ownerDrawFlags + >> menu.borderSize >> menu.staticFlags >> menu.dynamicFlags >> menu.nextTime; + menu.hClientAlign = (MENU_H_ALIGNMENT)hClientAlignInt; + menu.vClientAlign = (MENU_V_ALIGNMENT)vClientAlignInt; + menu.style = (MENU_WINDOW_STYLE)styleInt; + menu.border = (MENU_WINDOW_BORDER)borderInt; + + float foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA, + backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA, + borderColorR, borderColorG, borderColorB, borderColorA, + outlineColorR, outlineColorG, outlineColorB, outlineColorA; + *aZoneFileStream >> foregroundColorR >> foregroundColorG >> foregroundColorB >> foregroundColorA + >> backgroundColorR >> backgroundColorG >> backgroundColorB >> backgroundColorA + >> borderColorR >> borderColorG >> borderColorB >> borderColorA + >> outlineColorR >> outlineColorG >> outlineColorB >> outlineColorA; + + menu.foregroundColor = QColor(foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA); + menu.backgroundColor = QColor(backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA); + menu.borderColor = QColor(borderColorR, borderColorG, borderColorB, borderColorA); + menu.outlineColor = QColor(outlineColorR, outlineColorG, outlineColorB, outlineColorA); + + *aZoneFileStream >> menu.materialPtr >> menu.fontPtr >> menu.fullScreen >> menu.itemCount + >> menu.fontIndex >> menu.cursorItem >> menu.fadeCycle >> menu.fadeClamp + >> menu.fadeAmount >> menu.fadeInAmount >> menu.blurRadius >> menu.onOpenPtr + >> menu.onFocusPtr >> menu.onClosePtr >> menu.onESCPtr >> menu.onKeyPtr + >> menu.visibleExpCount >> menu.expEntryPtr >> menu.allowedBindingPtr + >> menu.soundNamePtr >> menu.imageTrack; + + float focusColorR, focusColorG, focusColorB, focusColorA, + disabledColorR, disabledColorG, disabledColorB, disabledColorA; + *aZoneFileStream >> focusColorR >> focusColorG >> focusColorB >> focusColorA + >> disabledColorR >> disabledColorG >> disabledColorB >> disabledColorA; + menu.focusColor = QColor(focusColorR, focusColorG, focusColorB, focusColorA); + menu.disabledColor = QColor(disabledColorR, disabledColorG, disabledColorB, disabledColorA); + + *aZoneFileStream >> menu.rectXExpCount >> menu.rectXExpPtr >> menu.rectYExpCount >> menu.rectYExpPtr; + + aZoneFileStream->skipRawData(4); // Separator + + char menuDefNameChar; + int menuDefNameLen = 0; + *aZoneFileStream >> menuDefNameChar; + while (menuDefNameChar != 0 && menuDefNameLen < 30) { + menuDefNameLen++; + menu.name += menuDefNameChar; + *aZoneFileStream >> menuDefNameChar; + } + + char defStringChar; + int defStringLen = 0; + *aZoneFileStream >> defStringChar; + while (defStringChar != 0 && defStringLen < 30) { + defStringLen++; + menu.definition += defStringChar; + *aZoneFileStream >> defStringChar; + } + aZoneFileStream->skipRawData(4 * 10); + + *aZoneFileStream >> menu.itemWindowDefNamePtr; + + float itemRectX, itemRectY, itemRectWidth, itemRectHeight; + *aZoneFileStream >> itemRectX >> itemRectY >> itemRectWidth >> itemRectHeight; + menu.itemRect = QRectF(itemRectX, itemRectY, itemRectWidth, itemRectHeight); + + *aZoneFileStream >> menu.itemHAlignment >> menu.itemVAlignment >> menu.itemGroupPtr + >> menu.itemWindowStyle >> menu.itemWindowBorder >> menu.itemOwnerDraw + >> menu.itemOwnerDrawFlags >> menu.itemBorderSize >> menu.itemStaticFlags + >> menu.itemDynamicFlags >> menu.itemNextTime; + + float itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA, + itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA, + itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA, + itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA; + *aZoneFileStream >> itemForegroundColorR >> itemForegroundColorG >> itemForegroundColorB >> itemForegroundColorA + >> itemBackgroundColorR >> itemBackgroundColorG >> itemBackgroundColorB >> itemBackgroundColorA + >> itemBorderColorR >> itemBorderColorG >> itemBorderColorB >> itemBorderColorA + >> itemOutlineColorR >> itemOutlineColorG >> itemOutlineColorB >> itemOutlineColorA; + + menu.itemForegroundColor = QColor(itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA); + menu.itemBackgroundColor = QColor(itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA); + menu.itemBorderColor = QColor(itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA); + menu.itemOutlineColor = QColor(itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA); + + *aZoneFileStream >> menu.itemMaterialPtr; + + float itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight; + *aZoneFileStream >> itemTextRectX >> itemTextRectY >> itemTextRectWidth >> itemTextRectHeight; + menu.itemTextRect = QRectF(itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight); + + quint32 hItemTextAlignInt, vItemTextAlignInt, itemType, fontTypeInt, textStyleInt; + *aZoneFileStream >> hItemTextAlignInt >> vItemTextAlignInt >> itemType >> menu.dataType + >> menu.alignment >> fontTypeInt >> menu.textAlignMode >> menu.textalignx >> menu.textaligny + >> menu.textscale >> textStyleInt >> menu.gameMsgWindowIndex >> menu.gameMsgWindowMode + >> menu.testPtr >> menu.textSavegameInfo >> menu.parentPtr; + menu.itemText_hAlign = (MENU_H_ALIGNMENT)hItemTextAlignInt; + menu.itemText_vAlign = (MENU_V_ALIGNMENT)vItemTextAlignInt; + menu.itemType = (MENU_ITEM_TYPE)itemType; + menu.fontEnum = (MENU_FONT_TYPE)fontTypeInt; + menu.textStyle = (MENU_ITEM_TEXTSTYLE)textStyleInt; + + *aZoneFileStream >> menu.mouseEnterText >> menu.mouseExitText >> menu.mouseEnter >> menu.mouseExit + >> menu.action >> menu.onAccept >> menu.onFocus >> menu.leaveFocus >> menu.dvar >> menu.dvarTest + >> menu.keyHandlerPtr >> menu.enableDvarPtr >> menu.dvarFlags >> menu.focusSoundPtr + >> menu.special >> menu.cursorPos; + + // itemDefData_t typeData; + + // listBoxDef_s *listBox; + + *aZoneFileStream >> menu.startPos >> menu.endPos >> menu.drawPadding; + + *aZoneFileStream >> menu.elementWidth >> menu.elementHeight; + + *aZoneFileStream >> menu.elementStyle >> menu.numColumns; + + //columnInfo_s columnInfo[16]; + + *aZoneFileStream >> menu.doubleClickPtr; + + + *aZoneFileStream >> menu.notselectable >> menu.noScrollBars >> menu.usePaging; + + float itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA, + itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA, + itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA; + *aZoneFileStream >> itemSelectBorderColorR >> itemSelectBorderColorG >> itemSelectBorderColorB >> itemSelectBorderColorA + >> itemDisableColorR >> itemDisableColorG >> itemDisableColorB >> itemDisableColorA + >> itemFocusColorR >> itemFocusColorG >> itemFocusColorB >> itemFocusColorA; + menu.itemSelectBorderColor = QColor(itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA); + menu.itemDisableColor = QColor(itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA); + menu.itemFocusColor = QColor(itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA); + + *aZoneFileStream >> menu.selectIconPtr >> menu.backgroundItemListboxPtr >> menu.highlightTexturePtr; + + // editFieldDef_s *editField; + + *aZoneFileStream >> menu.minVal >> menu.maxVal >> menu.defVal >> menu.range >> menu.maxChars + >> menu.maxCharsGotoNext >> menu.maxPaintChars >> menu.paintOffset; + + // multiDef_s *multi; + + for (int i = 0; i < 32; i++) { + quint32 dvarList; + *aZoneFileStream >> dvarList; + menu.dvarListPtrs.push_back(dvarList); + } + + for (int i = 0; i < 32; i++) { + quint32 dvarStr; + *aZoneFileStream >> dvarStr; + menu.dvarStrPtrs.push_back(dvarStr); + } + + for (int i = 0; i < 32; i++) { + float dvarValue; + *aZoneFileStream >> dvarValue; + menu.dvarValues.push_back(dvarValue); + } + + *aZoneFileStream >> menu.count >> menu.strDef >> menu.enumDvarNamePtr; + aZoneFileStream->skipRawData(4); + //>> menu.dataPtr + *aZoneFileStream >> menu.itemImageTrack; + + qDebug() << aZoneFileStream->device()->pos(); + + //statement_s visibleExp; + //statement_s textExp; + //statement_s materialExp; + //statement_s rectXExp; + //statement_s rectYExp; + //statement_s rectWExp; + //statement_s rectHExp; + //statement_s foreColorAExp; + result.menuDefs << menu; + } + return result; +} + +void ZoneFile_COD11_PC::pParseAsset_Weapon(QDataStream *aZoneFileStream) { + //WEAPON_FILE + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD11_PC::pParseAsset_D3DBSP(QDataStream *aZoneFileStream) { + //D3DBSP_DUMP + Q_UNUSED(aZoneFileStream); +} + +StringTable ZoneFile_COD11_PC::pParseAsset_StringTable(QDataStream *aZoneFileStream) { + StringTable result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.columnCount + >> result.rowCount; + + // Todo fix this + result.columnCount = 0; + result.rowCount = 0; + + aZoneFileStream->skipRawData(4); + + QString stringTableName; + char stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + while (stringTableNameChar != 0) { + result.name += stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + } + + for (quint32 i = 0; i < result.rowCount; i++) { + QByteArray pointerData(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pointerData.data(), 4); + result.tablePointers.push_back(pointerData.toHex()); + + aZoneFileStream->skipRawData(4); + } + + for (const QString &pointerAddr : result.tablePointers) { + QString leadingContent = ""; + if (pointerAddr == "FFFFFFFF") { + char leadingContentChar; + *aZoneFileStream >> leadingContentChar; + while (leadingContentChar != 0) { + leadingContent += leadingContentChar; + *aZoneFileStream >> leadingContentChar; + } + } else { + leadingContent = pointerAddr; + } + + QString content; + char contentChar; + *aZoneFileStream >> contentChar; + while (contentChar != 0) { + content += contentChar; + *aZoneFileStream >> contentChar; + } + result.content[leadingContent] = content; + } + return result; +} + +AssetType ZoneFile_COD11_PC::AssetStrToEnum(const QString aAssetType) { + const QString cleanedType = aAssetType.toUpper(); + if (cleanedType == "17000000") { // localized string PARTIALLY VERIFIED + return ASSET_LOCAL_STRING; + } else if (cleanedType == "20000000") { // raw_file PARTIALLY VERIFIED + return ASSET_RAW_FILE; + } else if (cleanedType == "1A000000") { // fx PARTIALLY VERIFIED + return ASSET_EFFECT; + } else if (cleanedType == "09000000") { // loaded_sound PARTIALLY VERIFIED + return ASSET_SOUND; + } else if (cleanedType == "04000000") { // x_anim PARTIALLY VERIFIED + return ASSET_ANIMATION; + } else if (cleanedType == "0C000000") { // collision_map PARTIALLY VERIFIED + return ASSET_COLLISION_MAP; + } else if (cleanedType == "21000000") { // string_table PARTIALLY VERIFIED + return ASSET_STRING_TABLE; + } else if (cleanedType == "15000000") { // menu_file PARTIALLY VERIFIED + return ASSET_MENU; + } else if (cleanedType == "07000000") { // tech set PARTIALLY VERIFIED + return ASSET_TECH_SET; + } else if (cleanedType == "18000000") { // weapon PARTIALLY VERIFIED + return ASSET_WEAPON; + } else if (cleanedType == "11000000") { // gfx map PARTIALLY VERIFIED + return ASSET_GFX_MAP; + } else if (cleanedType == "12000000") { // light_def PARTIALLY VERIFIED + return ASSET_LIGHT_DEF; + } else if (cleanedType == "14000000") { // font PARTIALLY VERIFIED + return ASSET_FONT; + } else if (cleanedType == "05000000") { // xmodel PARTIALLY VERIFIED + return ASSET_MODEL; + } else if (cleanedType == "0D000000") { // d3dbsp PARTIALLY VERIFIED + return ASSET_D3DBSP; + } else if (cleanedType == "06000000") { // image PARTIALLY VERIFIED + return ASSET_IMAGE; + } else if (cleanedType == "0E000000") { // game map sp PARTIALLY VERIFIED + return ASSET_GAME_MAP_SP; + } else if (cleanedType == "0B000000") { // col map sp PARTIALLY VERIFIED + return ASSET_COL_MAP_SP; + } + return ASSET_NONE; +} + +QByteArray ZoneFile_COD11_PC::GetBinaryData() { + QByteArray result; + + return result; +} diff --git a/libs/zonefile/PC/zonefile_cod11_pc.h b/libs/zonefile/PC/zonefile_cod11_pc.h new file mode 100644 index 0000000..27f0003 --- /dev/null +++ b/libs/zonefile/PC/zonefile_cod11_pc.h @@ -0,0 +1,52 @@ +#ifndef ZONEFILE_COD11_H +#define ZONEFILE_COD11_H + +#include "zonefile.h" + +class ZoneFile_COD11_PC : public ZoneFile +{ +public: + ZoneFile_COD11_PC(); + ~ZoneFile_COD11_PC(); + + bool Load(const QByteArray aFileData) override; + AssetType AssetStrToEnum(const QString aAssetType) override; + + QByteArray GetBinaryData() override; + +protected: + void pParseZoneHeader(QDataStream *aZoneFileStream) override; + quint32 pParseZoneSize(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsA(QDataStream *aZoneFileStream) override; + quint32 pParseZoneTagCount(QDataStream *aZoneFileStream) override; + quint32 pParseZoneRecordCount(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsB(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsC(QDataStream *aZoneFileStream) override; + QStringList pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) override; + QStringList pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) override; + AssetMap pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) override; + LocalString pParseAsset_LocalString(QDataStream *aZoneFileStream) override; + RawFile pParseAsset_RawFile(QDataStream *aZoneFileStream) override; + void pParseAsset_PhysPreset(QDataStream *aZoneFileStream) override; + Model pParseAsset_Model(QDataStream *aZoneFileStream) override; + Material pParseAsset_Material(QDataStream *aZoneFileStream) override; + Shader pParseAsset_Shader(QDataStream *aZoneFileStream) override; + TechSet pParseAsset_TechSet(QDataStream *aZoneFileStream) override; + Image pParseAsset_Image(QDataStream *aZoneFileStream) override; + SoundAsset pParseAsset_Sound(QDataStream *aZoneFileStream) override; + void pParseAsset_ColMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapSP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_LightDef(QDataStream *aZoneFileStream) override; + void pParseAsset_UIMap(QDataStream *aZoneFileStream) override; + void pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) override; + void pParseAsset_AIType(QDataStream *aZoneFileStream) override; + void pParseAsset_FX(QDataStream *aZoneFileStream) override; + Animation pParseAsset_Animation(QDataStream *aZoneFileStream) override; + MenuFile pParseAsset_MenuFile(QDataStream *aZoneFileStream) override; + void pParseAsset_Weapon(QDataStream *aZoneFileStream) override; + void pParseAsset_D3DBSP(QDataStream *aZoneFileStream) override; + StringTable pParseAsset_StringTable(QDataStream *aZoneFileStream) override; +}; + +#endif // ZONEFILE_COD11_H diff --git a/libs/zonefile/PC/zonefile_cod12_pc.cpp b/libs/zonefile/PC/zonefile_cod12_pc.cpp new file mode 100644 index 0000000..28dcb7d --- /dev/null +++ b/libs/zonefile/PC/zonefile_cod12_pc.cpp @@ -0,0 +1,1207 @@ +#include "zonefile_cod12_pc.h" + +#include +#include +#include + +ZoneFile_COD12_PC::ZoneFile_COD12_PC() +{ + +} + +ZoneFile_COD12_PC::~ZoneFile_COD12_PC() +{ + +} + +bool ZoneFile_COD12_PC::Load(const QByteArray aFileData) { + // Open zone file as little endian stream + QDataStream zoneFileStream(aFileData); + zoneFileStream.setByteOrder(QDataStream::LittleEndian); + + // Parse data from zone file header + pParseZoneHeader(&zoneFileStream); + SetRecords(pParseZoneIndex(&zoneFileStream, GetRecordCount())); + SetAssetMap(pParseAssets(&zoneFileStream, GetRecords())); + + return true; +} + +void ZoneFile_COD12_PC::pParseZoneHeader(QDataStream *aZoneFileStream) { + quint32 tagCount = pParseZoneTagCount(aZoneFileStream); + SetTagCount(tagCount); + + aZoneFileStream->skipRawData(7 * 4); + + quint32 recordCount = pParseZoneRecordCount(aZoneFileStream) - 1; + SetRecordCount(recordCount); + + aZoneFileStream->skipRawData(5 * 4); + + if (tagCount) { + SetTags(pParseZoneTags(aZoneFileStream, tagCount)); + } +} + +quint32 ZoneFile_COD12_PC::pParseZoneSize(QDataStream *aZoneFileStream) { + quint32 zoneFileSize; + *aZoneFileStream >> zoneFileSize; + if (zoneFileSize <= 0) { + qDebug() << "Tried to open empty zone file!"; + exit(-1); + } + zoneFileSize += 36; + return zoneFileSize; +} + +/* + ParseZoneUnknownsA() + + Parses the 1st section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD12_PC::pParseZoneUnknownsA(QDataStream *aZoneFileStream) { + // Byte 4-7, 8-11, 12-15: unknown + QByteArray unknown1(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown1.data(), 4); + + QByteArray unknown2(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown2.data(), 4); + + QByteArray unknown3(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown3.data(), 4); + + // Byte 16-19, 20-23: empty/unknown + QByteArray unknown4(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown4.data(), 4); + + QByteArray unknown5(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown5.data(), 4); + + // Byte 24-27: somehow related to the filesize, but smaller value + QByteArray unknown6(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown6.data(), 4); + + // Byte 28-31, 32-35: unknown + QByteArray unknown7(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown7.data(), 4); + + QByteArray unknown8(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown8.data(), 4); +} + +/* + ParseZoneTagCount() + + Parses the number of string tags in the zone index +*/ +quint32 ZoneFile_COD12_PC::pParseZoneTagCount(QDataStream *aZoneFileStream) { + quint32 tagCount; + *aZoneFileStream >> tagCount; + return tagCount; +} + +/* + ParseZoneRecordCount() + + Parses the number of records in the zone index +*/ +quint32 ZoneFile_COD12_PC::pParseZoneRecordCount(QDataStream *aZoneFileStream) { + quint32 recordCount; + *aZoneFileStream >> recordCount; + return recordCount; +} + +/* + ParseZoneUnknownsB() + + Parses the 2nd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD12_PC::pParseZoneUnknownsB(QDataStream *aZoneFileStream) { + // Byte 44-47: Unknown/empty? + QByteArray unknown9(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown9.data(), 4); +} + +/* + pParseZoneUnknownsC() + + Parses the 3rd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD12_PC::pParseZoneUnknownsC(QDataStream *aZoneFileStream) { + // Byte 40-43: Unknown/empty? + QByteArray unknown10(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown10.data(), 4); + + // Byte 44-47: Unknown/empty? + QByteArray unknown11(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown11.data(), 4); +} + +/* + ParseZoneTags() + + Parses the string tags ate the start of zone file +*/ +QStringList ZoneFile_COD12_PC::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) { + QStringList tags; + + // Byte 48-51: Repeated separators? ÿÿÿÿ x i + aZoneFileStream->skipRawData(8 * (tagCount - 1)); + + // Parse tags/strings before index + QString zoneTag; + char zoneTagChar; + for (quint32 i = 0; i < tagCount; i++) { + if (aZoneFileStream->device()->peek(8).toHex().contains("00000000")) { + break; + } + + *aZoneFileStream >> zoneTagChar; + while (zoneTagChar != 0) { + zoneTag += zoneTagChar; + *aZoneFileStream >> zoneTagChar; + } + tags << zoneTag; + zoneTag.clear(); + } + return tags; +} + +/* + ParseZoneIndex() + + Parse the binary zone index data and populate table +*/ +QStringList ZoneFile_COD12_PC::pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) { + QStringList result; + + // Don't parse if no records + if (!recordCount) { return result; } + + // Parse index & map found asset types + for (quint32 i = 0; i <= recordCount; i++) { + // Skip record start + QByteArray rawAssetType(8, Qt::Uninitialized); + aZoneFileStream->readRawData(rawAssetType.data(), 8); + result << rawAssetType.toHex(); + + // Skip separator + aZoneFileStream->skipRawData(8); + } + return result; +} + +AssetMap ZoneFile_COD12_PC::pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) { + AssetMap result; + + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 8); + + for (int i = 0; i < assetOrder.size(); i++) { + const QString typeHex = assetOrder[i]; + const AssetType typeStr = AssetStrToEnum(typeHex); + + if (typeStr == ASSET_LOCAL_STRING) { // localized string asset + result.localStrings << pParseAsset_LocalString(aZoneFileStream); + } else if (typeStr == ASSET_RAW_FILE) { // raw file + auto rawFile = pParseAsset_RawFile(aZoneFileStream); + if (rawFile.length) { + result.rawFiles << rawFile; + } + } else if (typeStr == ASSET_SCRIPT_PARSE_TREE) { // gsc + auto gscFile = pParseAsset_GSCFile(aZoneFileStream); + if (gscFile.length) { + result.gscFiles << gscFile; + } + } else if (typeStr == ASSET_PHYS_PRESET) { // physpreset + pParseAsset_PhysPreset(aZoneFileStream); + } else if (typeStr == ASSET_MODEL) { // xmodel + result.models << pParseAsset_Model(aZoneFileStream); + } else if (typeStr == ASSET_MATERIAL) { // material + pParseAsset_Material(aZoneFileStream); + } else if (typeStr == ASSET_SHADER) { // pixelshader + pParseAsset_Shader(aZoneFileStream); + } else if (typeStr == ASSET_TECH_SET) { // techset include + result.techSets << pParseAsset_TechSet(aZoneFileStream); + } else if (typeStr == ASSET_IMAGE) { // image + result.images << pParseAsset_Image(aZoneFileStream); + } else if (typeStr == ASSET_SOUND) { // loaded_sound + result.sounds << pParseAsset_Sound(aZoneFileStream); + } else if (typeStr == ASSET_COLLISION_MAP) { // col_map_mp + pParseAsset_ColMapMP(aZoneFileStream); + } else if (typeStr == ASSET_MP_MAP) { // game_map_sp + pParseAsset_GameMapSP(aZoneFileStream); + } else if (typeStr == ASSET_SP_MAP) { // game_map_mp + pParseAsset_GameMapMP(aZoneFileStream); + } else if (typeStr == ASSET_LIGHT_DEF) { // lightdef + pParseAsset_LightDef(aZoneFileStream); + } else if (typeStr == ASSET_UI_MAP) { // ui_map + pParseAsset_UIMap(aZoneFileStream); + } else if (typeStr == ASSET_SND_DRIVER_GLOBALS) { // snddriverglobals + pParseAsset_SNDDriverGlobals(aZoneFileStream); + } else if (typeStr == ASSET_AI_TYPE) { // aitype + pParseAsset_AIType(aZoneFileStream); + } else if (typeStr == ASSET_EFFECT) { // aitype + pParseAsset_FX(aZoneFileStream); + } else if (typeStr == ASSET_ANIMATION) { // aitype + result.animations << pParseAsset_Animation(aZoneFileStream); + } else if (typeStr == ASSET_STRING_TABLE) { // string_table + result.stringTables << pParseAsset_StringTable(aZoneFileStream); + } else if (typeStr == ASSET_MENU) { // string_table + result.menuFiles << pParseAsset_MenuFile(aZoneFileStream); + } else if (typeStr == ASSET_WEAPON) { // string_table + pParseAsset_Weapon(aZoneFileStream); + } else if (typeStr == ASSET_D3DBSP) { // string_table + pParseAsset_D3DBSP(aZoneFileStream); + } + } + return result; +} + +LocalString ZoneFile_COD12_PC::pParseAsset_LocalString(QDataStream *aZoneFileStream) { + LocalString result; + + quint32 stringPtr, aliasPtr; + *aZoneFileStream >> stringPtr >> aliasPtr; + if (stringPtr == 4294967295) { + // Parse local string asset contents + QString localStr; + char localStrChar; + *aZoneFileStream >> localStrChar; + while (localStrChar != 0) { + result.string += localStrChar; + *aZoneFileStream >> localStrChar; + } + } else { + result.string = "String Ptr: " + QString::number(stringPtr); + } + + if (aliasPtr == 4294967295) { + // Parse rawfile name + QString aliasName; + char aliasNameChar; + *aZoneFileStream >> aliasNameChar; + while (aliasNameChar != 0) { + result.alias += aliasNameChar; + *aZoneFileStream >> aliasNameChar; + } + } else { + result.string = "Alias Ptr: " + QString::number(aliasPtr); + } + + return result; +} + +RawFile ZoneFile_COD12_PC::pParseAsset_RawFile(QDataStream *aZoneFileStream) { + RawFile result; + + // Skip start separator FF FF FF FF (pointer?) + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.length; + + // Skip unknown 4 byte data + aZoneFileStream->skipRawData(4); + + // Parse rawfile path + char scriptPathChar; + *aZoneFileStream >> scriptPathChar; + while (scriptPathChar != 0) { + result.path += scriptPathChar; + *aZoneFileStream >> scriptPathChar; + } + result.path.replace(",", ""); + const QStringList pathParts = result.path.split('/'); + if (pathParts.size() == 0) { + qDebug() << "Failed to parse ff path! " << result.path; + exit(-1); + } + + // Parse gsc contents + char rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + while (rawFileContentsChar != 0 && rawFileContentsChar != -1) { + result.contents += rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + } + return result; +} + +GscFile ZoneFile_COD12_PC::pParseAsset_GSCFile(QDataStream *aZoneFileStream) { + GscFile result; + + // Skip start separator FF FF FF FF (pointer?) + aZoneFileStream->skipRawData(8); + + *aZoneFileStream >> result.length; + + // Skip unknown 4 byte data + aZoneFileStream->skipRawData(8); + + // Parse rawfile path + char scriptPathChar; + *aZoneFileStream >> scriptPathChar; + while (scriptPathChar != 0) { + result.path += scriptPathChar; + *aZoneFileStream >> scriptPathChar; + } + const QStringList pathParts = result.path.split('/'); + if (pathParts.size() == 0) { + qDebug() << "Failed to parse ff path! " << result.path; + exit(-1); + } + + // Parse gsc contents + char rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + while (rawFileContentsChar != 0 && rawFileContentsChar != -1) { + result.contents += rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + } + return result; +} + +void ZoneFile_COD12_PC::pParseAsset_PhysPreset(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Model ZoneFile_COD12_PC::pParseAsset_Model(QDataStream *aZoneFileStream) { + Model result; + + *aZoneFileStream >> result.namePtr >> result.tagCount >> result.rootTagCount + >> result.surfCount >> result.unknownCount >> result.boneNamePtr + >> result.parentListPtr >> result.quatsPtr >> result.transPtr + >> result.partClassPtr >> result.baseMatPtr + >> result.surfsPtr >> result.materialHandlesPtr; + + // Parse XModelLodInfo + for (int i = 1; i <= 4; i++) { + quint32 intDist; + *aZoneFileStream >> intDist; + + std::memcpy(&result.lodInfo[i].dist, &intDist, sizeof(result.lodInfo[i].dist)); + *aZoneFileStream >> result.lodInfo[i].numsurfs >> result.lodInfo[i].surfIndex; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.lodInfo[i].partBits[0] + >> result.lodInfo[i].partBits[1] + >> result.lodInfo[i].partBits[2] + >> result.lodInfo[i].partBits[3]; + } + + *aZoneFileStream >> result.collSurfsPtr >> result.numCollSurfs >> result.contents >> result.boneInfoPtr; + + quint32 intRadius, intMins[3], intMaxs[3]; + *aZoneFileStream >> intRadius >> intMins[0] >> intMins[1] + >> intMins[2] >> intMaxs[0] >> intMaxs[1] >> intMaxs[2]; + + std::memcpy(&result.radius, &intRadius, sizeof(result.radius)); + + std::memcpy(&result.mins[0], &intMins[0], sizeof(result.mins[0])); + std::memcpy(&result.mins[1], &intMins[1], sizeof(result.mins[1])); + std::memcpy(&result.mins[2], &intMins[2], sizeof(result.mins[2])); + + std::memcpy(&result.maxs[0], &intMaxs[0], sizeof(result.maxs[0])); + std::memcpy(&result.maxs[1], &intMaxs[1], sizeof(result.maxs[2])); + std::memcpy(&result.maxs[2], &intMaxs[2], sizeof(result.maxs[3])); + + *aZoneFileStream >> result.numLods >> result.collLod >> result.streamInfoPtr + >> result.memUsage >> result.flags >> result.physPresetPtr >> result.physGeomsPtr; + + // Parse model name + char modelNameChar; + *aZoneFileStream >> modelNameChar; + while (modelNameChar == 0) { + *aZoneFileStream >> modelNameChar; + } + while (modelNameChar != 0) { + result.modelName += modelNameChar; + *aZoneFileStream >> modelNameChar; + } + return result; +} + +Material ZoneFile_COD12_PC::pParseAsset_Material(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); + + return Material(); +} + +Shader ZoneFile_COD12_PC::pParseAsset_Shader(QDataStream *aZoneFileStream) { + Shader result = Shader(); + + quint8 minorVersion, majorVersion; + *aZoneFileStream >> minorVersion >> majorVersion; + + quint32 magic; + *aZoneFileStream >> magic; + + // Verify .fxc magic + if (magic != 65534 && magic != 65535) { return result; } + + SHADER_TYPE type = SHADER_NONE; + quint16 rawShaderType; + *aZoneFileStream >> rawShaderType; + if (rawShaderType == 65535) { // Pixel shader + type = SHADER_PIXEL; + } else if (rawShaderType == 65534) { // Vertex shader + type = SHADER_VERTEX; + } + Q_UNUSED(type); + + while (true) { + quint32 instructionToken; + *aZoneFileStream >> instructionToken; + + SHADER_OPCODE opCode = (SHADER_OPCODE)(instructionToken & 0xffff); + + int size; + if (opCode == OPCODE_End) { + break; + } else if (opCode == OPCODE_Comment) { + size = (int)((instructionToken >> 16) & 0x7FFF); + } else { + size = (int)((instructionToken >> 24) & 0x0f); + } + Q_UNUSED(size); + } + + + return result; +} + +TechSet ZoneFile_COD12_PC::pParseAsset_TechSet(QDataStream *aZoneFileStream) { + TechSet result; + + for (int i = 1; i <= 62; i++) { + quint32 ptr; + *aZoneFileStream >> ptr; + + result.pointers << ptr; + } + qDebug() << aZoneFileStream->device()->pos(); + + // Parse techset name + char techSetNameChar; + *aZoneFileStream >> techSetNameChar; + while (techSetNameChar != 0) { + result.name += techSetNameChar; + *aZoneFileStream >> techSetNameChar; + } + result.name.replace(",", ""); + + return result; +} + +Image ZoneFile_COD12_PC::pParseAsset_Image(QDataStream *aZoneFileStream) { + Image result; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknowna >> result.unknownb + >> result.unknownc >> result.unknownd + >> result.unknowne >> result.unknownf + >> result.unknowng; + + aZoneFileStream->skipRawData(15 * 4); + *aZoneFileStream >> result.unknownh >> result.unknowni; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknownj; + + aZoneFileStream->skipRawData(4); + + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + result.materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + result.materialName.replace(",", ""); + + if (result.unknowna) { + *aZoneFileStream >> result.unknownk; + *aZoneFileStream >> result.unknownl; + *aZoneFileStream >> result.unknownm; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown1; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown2 >> result.unknown3 + >> result.size1 >> result.size2 + >> result.unknown4 >> result.unknown5; + + aZoneFileStream->skipRawData(4); + + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + result.name += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + + *aZoneFileStream >> result.unknown6 >> result.unknown7; + + QByteArray compressionData(8, Qt::Uninitialized); + aZoneFileStream->readRawData(compressionData.data(), 8); + if (compressionData.contains("DXT1")) { + result.compression = COMPRESSION_DXT1; + } else if (compressionData.contains("DXT3")) { + result.compression = COMPRESSION_DXT3; + } else if (compressionData.contains("DXT5")) { + result.compression = COMPRESSION_DXT5; + } else { + result.compression = COMPRESSION_NONE; + } + + *aZoneFileStream >> result.unknown8 >> result.unknown9; + } + + return result; +} + +SoundAsset ZoneFile_COD12_PC::pParseAsset_Sound(QDataStream *aZoneFileStream) { + SoundAsset result; + return result; + + qDebug() << aZoneFileStream->device()->pos(); + + QByteArray rootNamePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rootNamePtr.data(), 4); + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.count; + + if (rootNamePtr.toHex() == "ffffffff") { + // Read in sound file name + char soundNameChar; + *aZoneFileStream >> soundNameChar; + while (soundNameChar != 0) { + result.name += soundNameChar; + *aZoneFileStream >> soundNameChar; + } + } + + int tagCount = 0; + int resultCount = 0; + for (quint32 i = 0; i < result.count; i++) { + aZoneFileStream->skipRawData(12); + + QByteArray tagPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(tagPtr.data(), 4); + + if (tagPtr.toHex() == "ffffffff") { + tagCount++; + } + aZoneFileStream->skipRawData(4); + + QByteArray pathPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pathPtr.data(), 4); + + if (pathPtr.toHex() == "ffffffff") { + resultCount++; + } + + aZoneFileStream->skipRawData(160); + } + + for (int i = 0; i < tagCount; i++) { + // Read in tag? + QString tag; + char tagChar; + *aZoneFileStream >> tagChar; + while (tagChar != 0) { + tag += tagChar; + *aZoneFileStream >> tagChar; + } + } + + for (int i = 0; i < resultCount; i++) { + Sound sound; + + if (aZoneFileStream->device()->peek(12).toHex().contains("ffffffff00000000")) { + aZoneFileStream->skipRawData(12); + } + + aZoneFileStream->skipRawData(8); + + QByteArray aliasPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(aliasPtr.data(), 4); + + QByteArray namePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(namePtr.data(), 4); + + *aZoneFileStream >> sound.dataLength; + + if (aliasPtr.toHex() == "ffffffff") { + // Read in sound alias name + char soundAliasChar; + *aZoneFileStream >> soundAliasChar; + while (soundAliasChar != 0) { + sound.alias += soundAliasChar; + *aZoneFileStream >> soundAliasChar; + } + } + + if (aZoneFileStream->device()->peek(4) == "RIFF") { + sound.path = sound.alias; + sound.alias = ""; + } else if (namePtr.toHex() == "ffffffff") { + // Read in sound file path + char soundPathChar; + *aZoneFileStream >> soundPathChar; + while (soundPathChar != 0) { + sound.path += soundPathChar; + *aZoneFileStream >> soundPathChar; + } + sound.path.replace(",", ""); + } + + if (sound.dataLength) { + QByteArray data(sound.dataLength, Qt::Uninitialized); + aZoneFileStream->readRawData(data.data(), sound.dataLength); + sound.data = data; + } + result.sounds.append(sound); + } + + return result; +} + +void ZoneFile_COD12_PC::pParseAsset_ColMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD12_PC::pParseAsset_GameMapSP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD12_PC::pParseAsset_GameMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD12_PC::pParseAsset_LightDef(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD12_PC::pParseAsset_UIMap(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD12_PC::pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD12_PC::pParseAsset_AIType(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD12_PC::pParseAsset_FX(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Animation ZoneFile_COD12_PC::pParseAsset_Animation(QDataStream *aZoneFileStream) { + Animation result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.dataByteCount + >> result.dataShortCount + >> result.dataIntCount + >> result.randomDataByteCount + >> result.randomDataIntCount + >> result.numframes + >> result.isLooped + >> result.isDelta + >> result.noneRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.normalTranslatedBoneCount + >> result.preciseTranslatedBoneCount + >> result.staticTranslatedBoneCount + >> result.noneTranslatedBoneCount + >> result.totalBoneCount + >> result.otherBoneCount1 + >> result.otherBoneCount2 + >> result.notifyCount + >> result.assetType + >> result.pad + >> result.randomDataShortCount + >> result.indexCount + >> result.frameRate + >> result.frequency + >> result.boneIDsPtr + >> result.dataBytePtr + >> result.dataShortPtr + >> result.dataIntPtr + >> result.randomDataShortPtr + >> result.randomDataBytePtr + >> result.randomDataIntPtr + >> result.longIndiciesPtr + >> result.notificationsPtr + >> result.deltaPartsPtr; + + // Read in x_anim file name + QString xAnimName; + char xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + while (xAnimNameChar != 0) { + result.name += xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + } + + // Parse x_anim index header + QVector sectionLengths; + for (int i = 0; i < result.numframes; i++) { + quint8 sectionlength; + *aZoneFileStream >> sectionlength; + sectionLengths.push_back(sectionlength); + // Skip padding + aZoneFileStream->skipRawData(1); + } + // Skip unknown section + aZoneFileStream->skipRawData(2 * 8); + + return result; +} + +MenuFile ZoneFile_COD12_PC::pParseAsset_MenuFile(QDataStream *aZoneFileStream) { + //MENU_FILE + MenuFile result; + + aZoneFileStream->skipRawData(4); // Separator + + // Parse menu def count + *aZoneFileStream >> result.menuCount; + + // Clearly misparsed, never have this much + if (result.menuCount > 1000) { + qDebug() << "Failure reported when parsing menu file."; + return result; + } + for (uint i = 0; i < result.menuCount; i++) { + Menu menu; + + aZoneFileStream->skipRawData(4); // Separator + + // Read in x_anim file name + char menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + while (menuFilepathChar != 0) { + menu.filePath += menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + } + aZoneFileStream->skipRawData(4); // Separator + + *aZoneFileStream >> menu.menuNamePtr; + + float menuRectX, menuRectY, menuRectWidth, menuRectHeight; + *aZoneFileStream >> menuRectX >> menuRectY >> menuRectWidth >> menuRectHeight; + menu.rect = QRectF(menuRectX, menuRectY, menuRectWidth, menuRectHeight); + + quint32 hAlignInt, vAlignInt; + *aZoneFileStream >> hAlignInt >> vAlignInt; + menu.hAlign = (MENU_H_ALIGNMENT)hAlignInt; + menu.vAlign = (MENU_V_ALIGNMENT)vAlignInt; + + float rectClientX, rectClientY, rectClientWidth, rectClientHeight; + *aZoneFileStream >> rectClientX >> rectClientY >> rectClientWidth >> rectClientHeight; + menu.clientRect = QRectF(rectClientX, rectClientY, rectClientWidth, rectClientHeight); + + quint32 hClientAlignInt, vClientAlignInt, styleInt, borderInt; + *aZoneFileStream >> hClientAlignInt >> vClientAlignInt >> menu.groupPtr + >> styleInt >> borderInt >> menu.ownerDraw >> menu.ownerDrawFlags + >> menu.borderSize >> menu.staticFlags >> menu.dynamicFlags >> menu.nextTime; + menu.hClientAlign = (MENU_H_ALIGNMENT)hClientAlignInt; + menu.vClientAlign = (MENU_V_ALIGNMENT)vClientAlignInt; + menu.style = (MENU_WINDOW_STYLE)styleInt; + menu.border = (MENU_WINDOW_BORDER)borderInt; + + float foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA, + backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA, + borderColorR, borderColorG, borderColorB, borderColorA, + outlineColorR, outlineColorG, outlineColorB, outlineColorA; + *aZoneFileStream >> foregroundColorR >> foregroundColorG >> foregroundColorB >> foregroundColorA + >> backgroundColorR >> backgroundColorG >> backgroundColorB >> backgroundColorA + >> borderColorR >> borderColorG >> borderColorB >> borderColorA + >> outlineColorR >> outlineColorG >> outlineColorB >> outlineColorA; + + menu.foregroundColor = QColor(foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA); + menu.backgroundColor = QColor(backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA); + menu.borderColor = QColor(borderColorR, borderColorG, borderColorB, borderColorA); + menu.outlineColor = QColor(outlineColorR, outlineColorG, outlineColorB, outlineColorA); + + *aZoneFileStream >> menu.materialPtr >> menu.fontPtr >> menu.fullScreen >> menu.itemCount + >> menu.fontIndex >> menu.cursorItem >> menu.fadeCycle >> menu.fadeClamp + >> menu.fadeAmount >> menu.fadeInAmount >> menu.blurRadius >> menu.onOpenPtr + >> menu.onFocusPtr >> menu.onClosePtr >> menu.onESCPtr >> menu.onKeyPtr + >> menu.visibleExpCount >> menu.expEntryPtr >> menu.allowedBindingPtr + >> menu.soundNamePtr >> menu.imageTrack; + + float focusColorR, focusColorG, focusColorB, focusColorA, + disabledColorR, disabledColorG, disabledColorB, disabledColorA; + *aZoneFileStream >> focusColorR >> focusColorG >> focusColorB >> focusColorA + >> disabledColorR >> disabledColorG >> disabledColorB >> disabledColorA; + menu.focusColor = QColor(focusColorR, focusColorG, focusColorB, focusColorA); + menu.disabledColor = QColor(disabledColorR, disabledColorG, disabledColorB, disabledColorA); + + *aZoneFileStream >> menu.rectXExpCount >> menu.rectXExpPtr >> menu.rectYExpCount >> menu.rectYExpPtr; + + aZoneFileStream->skipRawData(4); // Separator + + char menuDefNameChar; + int menuDefNameLen = 0; + *aZoneFileStream >> menuDefNameChar; + while (menuDefNameChar != 0 && menuDefNameLen < 30) { + menuDefNameLen++; + menu.name += menuDefNameChar; + *aZoneFileStream >> menuDefNameChar; + } + + char defStringChar; + int defStringLen = 0; + *aZoneFileStream >> defStringChar; + while (defStringChar != 0 && defStringLen < 30) { + defStringLen++; + menu.definition += defStringChar; + *aZoneFileStream >> defStringChar; + } + aZoneFileStream->skipRawData(4 * 10); + + *aZoneFileStream >> menu.itemWindowDefNamePtr; + + float itemRectX, itemRectY, itemRectWidth, itemRectHeight; + *aZoneFileStream >> itemRectX >> itemRectY >> itemRectWidth >> itemRectHeight; + menu.itemRect = QRectF(itemRectX, itemRectY, itemRectWidth, itemRectHeight); + + *aZoneFileStream >> menu.itemHAlignment >> menu.itemVAlignment >> menu.itemGroupPtr + >> menu.itemWindowStyle >> menu.itemWindowBorder >> menu.itemOwnerDraw + >> menu.itemOwnerDrawFlags >> menu.itemBorderSize >> menu.itemStaticFlags + >> menu.itemDynamicFlags >> menu.itemNextTime; + + float itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA, + itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA, + itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA, + itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA; + *aZoneFileStream >> itemForegroundColorR >> itemForegroundColorG >> itemForegroundColorB >> itemForegroundColorA + >> itemBackgroundColorR >> itemBackgroundColorG >> itemBackgroundColorB >> itemBackgroundColorA + >> itemBorderColorR >> itemBorderColorG >> itemBorderColorB >> itemBorderColorA + >> itemOutlineColorR >> itemOutlineColorG >> itemOutlineColorB >> itemOutlineColorA; + + menu.itemForegroundColor = QColor(itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA); + menu.itemBackgroundColor = QColor(itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA); + menu.itemBorderColor = QColor(itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA); + menu.itemOutlineColor = QColor(itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA); + + *aZoneFileStream >> menu.itemMaterialPtr; + + float itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight; + *aZoneFileStream >> itemTextRectX >> itemTextRectY >> itemTextRectWidth >> itemTextRectHeight; + menu.itemTextRect = QRectF(itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight); + + quint32 hItemTextAlignInt, vItemTextAlignInt, itemType, fontTypeInt, textStyleInt; + *aZoneFileStream >> hItemTextAlignInt >> vItemTextAlignInt >> itemType >> menu.dataType + >> menu.alignment >> fontTypeInt >> menu.textAlignMode >> menu.textalignx >> menu.textaligny + >> menu.textscale >> textStyleInt >> menu.gameMsgWindowIndex >> menu.gameMsgWindowMode + >> menu.testPtr >> menu.textSavegameInfo >> menu.parentPtr; + menu.itemText_hAlign = (MENU_H_ALIGNMENT)hItemTextAlignInt; + menu.itemText_vAlign = (MENU_V_ALIGNMENT)vItemTextAlignInt; + menu.itemType = (MENU_ITEM_TYPE)itemType; + menu.fontEnum = (MENU_FONT_TYPE)fontTypeInt; + menu.textStyle = (MENU_ITEM_TEXTSTYLE)textStyleInt; + + *aZoneFileStream >> menu.mouseEnterText >> menu.mouseExitText >> menu.mouseEnter >> menu.mouseExit + >> menu.action >> menu.onAccept >> menu.onFocus >> menu.leaveFocus >> menu.dvar >> menu.dvarTest + >> menu.keyHandlerPtr >> menu.enableDvarPtr >> menu.dvarFlags >> menu.focusSoundPtr + >> menu.special >> menu.cursorPos; + + // itemDefData_t typeData; + + // listBoxDef_s *listBox; + + *aZoneFileStream >> menu.startPos >> menu.endPos >> menu.drawPadding; + + *aZoneFileStream >> menu.elementWidth >> menu.elementHeight; + + *aZoneFileStream >> menu.elementStyle >> menu.numColumns; + + //columnInfo_s columnInfo[16]; + + *aZoneFileStream >> menu.doubleClickPtr; + + + *aZoneFileStream >> menu.notselectable >> menu.noScrollBars >> menu.usePaging; + + float itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA, + itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA, + itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA; + *aZoneFileStream >> itemSelectBorderColorR >> itemSelectBorderColorG >> itemSelectBorderColorB >> itemSelectBorderColorA + >> itemDisableColorR >> itemDisableColorG >> itemDisableColorB >> itemDisableColorA + >> itemFocusColorR >> itemFocusColorG >> itemFocusColorB >> itemFocusColorA; + menu.itemSelectBorderColor = QColor(itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA); + menu.itemDisableColor = QColor(itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA); + menu.itemFocusColor = QColor(itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA); + + *aZoneFileStream >> menu.selectIconPtr >> menu.backgroundItemListboxPtr >> menu.highlightTexturePtr; + + // editFieldDef_s *editField; + + *aZoneFileStream >> menu.minVal >> menu.maxVal >> menu.defVal >> menu.range >> menu.maxChars + >> menu.maxCharsGotoNext >> menu.maxPaintChars >> menu.paintOffset; + + // multiDef_s *multi; + + for (int i = 0; i < 32; i++) { + quint32 dvarList; + *aZoneFileStream >> dvarList; + menu.dvarListPtrs.push_back(dvarList); + } + + for (int i = 0; i < 32; i++) { + quint32 dvarStr; + *aZoneFileStream >> dvarStr; + menu.dvarStrPtrs.push_back(dvarStr); + } + + for (int i = 0; i < 32; i++) { + float dvarValue; + *aZoneFileStream >> dvarValue; + menu.dvarValues.push_back(dvarValue); + } + + *aZoneFileStream >> menu.count >> menu.strDef >> menu.enumDvarNamePtr; + aZoneFileStream->skipRawData(4); + //>> menu.dataPtr + *aZoneFileStream >> menu.itemImageTrack; + + qDebug() << aZoneFileStream->device()->pos(); + + //statement_s visibleExp; + //statement_s textExp; + //statement_s materialExp; + //statement_s rectXExp; + //statement_s rectYExp; + //statement_s rectWExp; + //statement_s rectHExp; + //statement_s foreColorAExp; + result.menuDefs << menu; + } + return result; +} + +void ZoneFile_COD12_PC::pParseAsset_Weapon(QDataStream *aZoneFileStream) { + //WEAPON_FILE + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD12_PC::pParseAsset_D3DBSP(QDataStream *aZoneFileStream) { + //D3DBSP_DUMP + Q_UNUSED(aZoneFileStream); +} + +StringTable ZoneFile_COD12_PC::pParseAsset_StringTable(QDataStream *aZoneFileStream) { + StringTable result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.columnCount + >> result.rowCount; + + // Todo fix this + result.columnCount = 0; + result.rowCount = 0; + + aZoneFileStream->skipRawData(4); + + QString stringTableName; + char stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + while (stringTableNameChar != 0) { + result.name += stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + } + + for (quint32 i = 0; i < result.rowCount; i++) { + QByteArray pointerData(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pointerData.data(), 4); + result.tablePointers.push_back(pointerData.toHex()); + + aZoneFileStream->skipRawData(4); + } + + for (const QString &pointerAddr : result.tablePointers) { + QString leadingContent = ""; + if (pointerAddr == "FFFFFFFF") { + char leadingContentChar; + *aZoneFileStream >> leadingContentChar; + while (leadingContentChar != 0) { + leadingContent += leadingContentChar; + *aZoneFileStream >> leadingContentChar; + } + } else { + leadingContent = pointerAddr; + } + + QString content; + char contentChar; + *aZoneFileStream >> contentChar; + while (contentChar != 0) { + content += contentChar; + *aZoneFileStream >> contentChar; + } + result.content[leadingContent] = content; + } + return result; +} + +AssetType ZoneFile_COD12_PC::AssetStrToEnum(const QString aAssetType) { + const QString cleanedType = aAssetType.toUpper(); + if (cleanedType == "0000000000000000") { + return ASSET_PHYS_PRESET; + } else if (cleanedType == "0100000000000000") { + return ASSET_PHYS_CONSTRAINTS; + } else if (cleanedType == "0200000000000000") { + return ASSET_DESTRUCTIBLE_DEF; + } else if (cleanedType == "0300000000000000") { + return ASSET_ANIMATION; + } else if (cleanedType == "0400000000000000") { + return ASSET_MODEL; + } else if (cleanedType == "0500000000000000") { + return ASSET_MODEL_MESH; + } else if (cleanedType == "0600000000000000") { + return ASSET_MATERIAL; + } else if (cleanedType == "0700000000000000") { + return ASSET_COMPUTE_SHADER_SET; + } else if (cleanedType == "0800000000000000") { + return ASSET_TECH_SET; + } else if (cleanedType == "0900000000000000") { + return ASSET_IMAGE; + } else if (cleanedType == "0A00000000000000") { + return ASSET_SOUND; + } else if (cleanedType == "1100000000000000") { + return ASSET_LIGHT_DEF; + } else if (cleanedType == "1500000000000000") { + return ASSET_FONT_ICON; + } else if (cleanedType == "1700000000000000") { + return ASSET_WEAPON; + } else if (cleanedType == "1C00000000000000") { + return ASSET_PLAYER_SOUNDS_TABLE; + } else if (cleanedType == "1D00000000000000") { + return ASSET_PLAYER_FX_TABLE; + } else if (cleanedType == "1E00000000000000") { + return ASSET_SHARED_WEAPON_SOUNDS; + } else if (cleanedType == "1F00000000000000") { + return ASSET_ATTACHMENT; + } else if (cleanedType == "2000000000000000") { + return ASSET_ATTACHMENT_UNIQUE; + } else if (cleanedType == "2100000000000000") { + return ASSET_WEAPON_CAMO; + } else if (cleanedType == "2200000000000000") { + return ASSET_CUSTOMIZATION_TABLE; + } else if (cleanedType == "2300000000000000") { + return ASSET_CUSTOMIZATION_TABLE_FEIMAGES; + } else if (cleanedType == "2400000000000000") { + return ASSET_CUSTOMIZATION_TABLE_COLOR; + }else if (cleanedType == "2600000000000000") { + return ASSET_EFFECT; + } else if (cleanedType == "2F00000000000000") { + return ASSET_RAW_FILE; + } else if (cleanedType == "3000000000000000") { + return ASSET_STRING_TABLE; + } else if (cleanedType == "3100000000000000") { + return ASSET_STRUCTURED_TABLE; + } else if (cleanedType == "3200000000000000") { + return ASSET_LEADERBOARD_DEF; + } else if (cleanedType == "3300000000000000") { + return ASSET_DDL; + } else if (cleanedType == "3600000000000000") { + return ASSET_SCRIPT_PARSE_TREE; + } else if (cleanedType == "3700000000000000") { + return ASSET_KEY_VALUE_PAIRS; + } else if (cleanedType == "3800000000000000") { + return ASSET_VEHICLE; + } else if (cleanedType == "3A00000000000000") { + return ASSET_VEHICLE_TRACER; + } else if (cleanedType == "3C00000000000000") { + return ASSET_SURFACE_FX_TABLE; + } else if (cleanedType == "3D00000000000000") { + return ASSET_SURFACE_SOUND_DEF; + } else if (cleanedType == "3E00000000000000") { + return ASSET_FOOTSTEP_TABLE; + } else if (cleanedType == "3F00000000000000") { + return ASSET_ENTITY_FX_IMPACTS; + } else if (cleanedType == "4000000000000000") { + return ASSET_ENTITY_SOUND_IMPACTS; + } else if (cleanedType == "4200000000000000") { + return ASSET_VEHICLE_FX_DEF; + } else if (cleanedType == "4300000000000000") { + return ASSET_VEHICLE_SOUND_DEF; + } else if (cleanedType == "4500000000000000") { + return ASSET_SCRIPT_BUNDLE; + } else if (cleanedType == "4600000000000000") { + return ASSET_SCRIPT_BUNDLE_LIST; + } else if (cleanedType == "4700000000000000") { + return ASSET_RUMBLE; + } else if (cleanedType == "4A00000000000000") { + return ASSET_AIM_TABLE; + } else if (cleanedType == "4B00000000000000") { + return ASSET_ANIM_SELECTOR_TABLE; + } else if (cleanedType == "4C00000000000000") { + return ASSET_ANIM_MAPPING_TABLE; + } else if (cleanedType == "4D00000000000000") { + return ASSET_ANIM_STATE_MACHINE; + } else if (cleanedType == "4E00000000000000") { + return ASSET_BEHAVIOR_TREE; + } else if (cleanedType == "4F00000000000000") { + return ASSET_BEHAVIOR_STATE_MACHINE; + } else if (cleanedType == "5100000000000000") { + return ASSET_S_ANIM; + } else if (cleanedType == "5200000000000000") { + return ASSET_LIGHT_DEF; + } else if (cleanedType == "5300000000000000") { + return ASSET_BIT_FIELD; + } else if (cleanedType == "5400000000000000") { + return ASSET_SURFACE_SOUND_DEF; + } else if (cleanedType == "5500000000000000") { + return ASSET_SURFACE_FX_TABLE; + } else if (cleanedType == "5600000000000000") { + return ASSET_RUMBLE; + } else if (cleanedType == "5900000000000000") { + return ASSET_AIM_TABLE; + } else if (cleanedType == "5A00000000000000") { + return ASSET_MAP_TABLE; + } else if (cleanedType == "5B00000000000000") { + return ASSET_MAP_TABLE_LOADING_IMAGES; + } else if (cleanedType == "5C00000000000000") { + return ASSET_MEDAL; + } else if (cleanedType == "5D00000000000000") { + return ASSET_MEDAL_TABLE; + } else if (cleanedType == "5E00000000000000") { + return ASSET_OBJECTIVE; + } else if (cleanedType == "5F00000000000000") { + return ASSET_OBJECTIVE_LIST; + } else if (cleanedType == "6400000000000000") { + return ASSET_LASER; + } else if (cleanedType == "6500000000000000") { + return ASSET_BEAM; + } else if (cleanedType == "6600000000000000") { + return ASSET_STREAMER_HINT; + } else if (cleanedType == "1B00000000000000") { + return ASSET_CG_MEDIA_TABLE; + } + + return ASSET_NONE; +} + +QByteArray ZoneFile_COD12_PC::GetBinaryData() { + QByteArray result; + + return result; +} diff --git a/libs/zonefile/PC/zonefile_cod12_pc.h b/libs/zonefile/PC/zonefile_cod12_pc.h new file mode 100644 index 0000000..5d246a1 --- /dev/null +++ b/libs/zonefile/PC/zonefile_cod12_pc.h @@ -0,0 +1,53 @@ +#ifndef ZONEFILE_COD12_PC_H +#define ZONEFILE_COD12_PC_H + +#include "zonefile.h" + +class ZoneFile_COD12_PC : public ZoneFile +{ +public: + ZoneFile_COD12_PC(); + ~ZoneFile_COD12_PC(); + + bool Load(const QByteArray aFileData) override; + AssetType AssetStrToEnum(const QString aAssetType) override; + + QByteArray GetBinaryData() override; + +protected: + void pParseZoneHeader(QDataStream *aZoneFileStream) override; + quint32 pParseZoneSize(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsA(QDataStream *aZoneFileStream) override; + quint32 pParseZoneTagCount(QDataStream *aZoneFileStream) override; + quint32 pParseZoneRecordCount(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsB(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsC(QDataStream *aZoneFileStream) override; + QStringList pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) override; + QStringList pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) override; + AssetMap pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) override; + LocalString pParseAsset_LocalString(QDataStream *aZoneFileStream) override; + RawFile pParseAsset_RawFile(QDataStream *aZoneFileStream) override; + GscFile pParseAsset_GSCFile(QDataStream *aZoneFileStream) ; + void pParseAsset_PhysPreset(QDataStream *aZoneFileStream) override; + Model pParseAsset_Model(QDataStream *aZoneFileStream) override; + Material pParseAsset_Material(QDataStream *aZoneFileStream) override; + Shader pParseAsset_Shader(QDataStream *aZoneFileStream) override; + TechSet pParseAsset_TechSet(QDataStream *aZoneFileStream) override; + Image pParseAsset_Image(QDataStream *aZoneFileStream) override; + SoundAsset pParseAsset_Sound(QDataStream *aZoneFileStream) override; + void pParseAsset_ColMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapSP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_LightDef(QDataStream *aZoneFileStream) override; + void pParseAsset_UIMap(QDataStream *aZoneFileStream) override; + void pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) override; + void pParseAsset_AIType(QDataStream *aZoneFileStream) override; + void pParseAsset_FX(QDataStream *aZoneFileStream) override; + Animation pParseAsset_Animation(QDataStream *aZoneFileStream) override; + MenuFile pParseAsset_MenuFile(QDataStream *aZoneFileStream) override; + void pParseAsset_Weapon(QDataStream *aZoneFileStream) override; + void pParseAsset_D3DBSP(QDataStream *aZoneFileStream) override; + StringTable pParseAsset_StringTable(QDataStream *aZoneFileStream) override; +}; + +#endif // ZONEFILE_COD12_PC_H diff --git a/libs/zonefile/PC/zonefile_cod4_pc.cpp b/libs/zonefile/PC/zonefile_cod4_pc.cpp new file mode 100644 index 0000000..6359151 --- /dev/null +++ b/libs/zonefile/PC/zonefile_cod4_pc.cpp @@ -0,0 +1,1140 @@ +#include "zonefile_cod4_pc.h" + +#include +#include +#include + +ZoneFile_COD4_PC::ZoneFile_COD4_PC() + : ZoneFile() { + +} + +ZoneFile_COD4_PC::~ZoneFile_COD4_PC() { + +} + +bool ZoneFile_COD4_PC::Load(const QByteArray aFileData) { + // Open zone file as little endian stream + QDataStream zoneFileStream(aFileData); + zoneFileStream.setByteOrder(QDataStream::LittleEndian); + + + // Parse data from zone file header + pParseZoneHeader(&zoneFileStream); + SetRecords(pParseZoneIndex(&zoneFileStream, GetRecordCount())); + SetAssetMap(pParseAssets(&zoneFileStream, GetRecords())); + + return true; +} + +void ZoneFile_COD4_PC::pParseZoneHeader(QDataStream *aZoneFileStream) { + SetSize(pParseZoneSize(aZoneFileStream)); + pParseZoneUnknownsA(aZoneFileStream); + + SetTagCount(pParseZoneTagCount(aZoneFileStream)); + pParseZoneUnknownsB(aZoneFileStream); + + SetRecordCount(pParseZoneRecordCount(aZoneFileStream)); + + quint32 tagCount = GetTagCount(); + if (tagCount) { + pParseZoneUnknownsC(aZoneFileStream); + SetTags(pParseZoneTags(aZoneFileStream, tagCount)); + } else { + aZoneFileStream->skipRawData(4); + } +} + +quint32 ZoneFile_COD4_PC::pParseZoneSize(QDataStream *aZoneFileStream) { + quint32 zoneFileSize; + *aZoneFileStream >> zoneFileSize; + if (zoneFileSize <= 0) { + qDebug() << "Tried to open empty zone file!"; + exit(-1); + } + zoneFileSize += 36; + return zoneFileSize; +} + +/* + ParseZoneUnknownsA() + + Parses the 1st section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD4_PC::pParseZoneUnknownsA(QDataStream *aZoneFileStream) { + // Byte 4-7, 8-11, 12-15: unknown + QByteArray unknown1(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown1.data(), 4); + + QByteArray unknown2(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown2.data(), 4); + + QByteArray unknown3(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown3.data(), 4); + + // Byte 16-19, 20-23: empty/unknown + QByteArray unknown4(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown4.data(), 4); + + QByteArray unknown5(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown5.data(), 4); + + // Byte 24-27: somehow related to the filesize, but smaller value + QByteArray unknown6(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown6.data(), 4); + + // Byte 28-31, 32-35: unknown + QByteArray unknown7(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown7.data(), 4); + + QByteArray unknown8(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown8.data(), 4); +} + +/* + ParseZoneTagCount() + + Parses the number of string tags in the zone index +*/ +quint32 ZoneFile_COD4_PC::pParseZoneTagCount(QDataStream *aZoneFileStream) { + quint32 tagCount; + *aZoneFileStream >> tagCount; + return tagCount; +} + +/* + ParseZoneRecordCount() + + Parses the number of records in the zone index +*/ +quint32 ZoneFile_COD4_PC::pParseZoneRecordCount(QDataStream *aZoneFileStream) { + quint32 recordCount; + *aZoneFileStream >> recordCount; + return recordCount; +} + +/* + ParseZoneUnknownsB() + + Parses the 2nd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD4_PC::pParseZoneUnknownsB(QDataStream *aZoneFileStream) { + // Byte 44-47: Unknown/empty? + QByteArray unknown9(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown9.data(), 4); +} + +/* + pParseZoneUnknownsC() + + Parses the 3rd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD4_PC::pParseZoneUnknownsC(QDataStream *aZoneFileStream) { + // Byte 40-43: Unknown/empty? + QByteArray unknown10(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown10.data(), 4); + + // Byte 44-47: Unknown/empty? + QByteArray unknown11(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown11.data(), 4); +} + +/* + ParseZoneTags() + + Parses the string tags ate the start of zone file +*/ +QStringList ZoneFile_COD4_PC::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) { + QStringList tags; + + // Byte 48-51: Repeated separators? ÿÿÿÿ x i + aZoneFileStream->skipRawData(4 * (tagCount - 1)); + + // Parse tags/strings before index + QString zoneTag; + char zoneTagChar; + for (quint32 i = 0; i < tagCount; i++) { + *aZoneFileStream >> zoneTagChar; + while (zoneTagChar != 0) { + zoneTag += zoneTagChar; + *aZoneFileStream >> zoneTagChar; + } + tags << zoneTag; + zoneTag.clear(); + } + return tags; +} + +/* + ParseZoneIndex() + + Parse the binary zone index data and populate table +*/ +QStringList ZoneFile_COD4_PC::pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) { + QStringList result; + + // Don't parse if no records + if (!recordCount) { return result; } + + if (aZoneFileStream->device()->peek(4).toHex().contains("ffff")) { + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 2); + } + + // Parse index & map found asset types + for (quint32 i = 0; i <= recordCount; i++) { + // Skip record start + QByteArray rawAssetType(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rawAssetType.data(), 4); + result << rawAssetType.toHex(); + + // Skip separator + aZoneFileStream->skipRawData(4); + } + return result; +} + +AssetMap ZoneFile_COD4_PC::pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) { + AssetMap result; + + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 8); + + for (int i = 0; i < assetOrder.size(); i++) { + const QString typeHex = assetOrder[i]; + const AssetType typeStr = AssetStrToEnum(typeHex); + + if (typeStr == ASSET_LOCAL_STRING) { // localized string asset + result.localStrings << pParseAsset_LocalString(aZoneFileStream); + } else if (typeStr == ASSET_RAW_FILE) { // gsc + auto rawFile = pParseAsset_RawFile(aZoneFileStream); + if (rawFile.length) { + result.rawFiles << rawFile; + } + } else if (typeStr == ASSET_PHYS_PRESET) { // physpreset + pParseAsset_PhysPreset(aZoneFileStream); + } else if (typeStr == ASSET_MODEL) { // xmodel + result.models << pParseAsset_Model(aZoneFileStream); + } else if (typeStr == ASSET_MATERIAL) { // material + pParseAsset_Material(aZoneFileStream); + } else if (typeStr == ASSET_SHADER) { // pixelshader + pParseAsset_Shader(aZoneFileStream); + } else if (typeStr == ASSET_TECH_SET) { // techset include + result.techSets << pParseAsset_TechSet(aZoneFileStream); + } else if (typeStr == ASSET_IMAGE) { // image + result.images << pParseAsset_Image(aZoneFileStream); + } else if (typeStr == ASSET_SOUND) { // loaded_sound + result.sounds << pParseAsset_Sound(aZoneFileStream); + } else if (typeStr == ASSET_COLLISION_MAP) { // col_map_mp + pParseAsset_ColMapMP(aZoneFileStream); + } else if (typeStr == ASSET_MP_MAP) { // game_map_sp + pParseAsset_GameMapSP(aZoneFileStream); + } else if (typeStr == ASSET_SP_MAP) { // game_map_mp + pParseAsset_GameMapMP(aZoneFileStream); + } else if (typeStr == ASSET_LIGHT_DEF) { // lightdef + pParseAsset_LightDef(aZoneFileStream); + } else if (typeStr == ASSET_UI_MAP) { // ui_map + pParseAsset_UIMap(aZoneFileStream); + } else if (typeStr == ASSET_SND_DRIVER_GLOBALS) { // snddriverglobals + pParseAsset_SNDDriverGlobals(aZoneFileStream); + } else if (typeStr == ASSET_AI_TYPE) { // aitype + pParseAsset_AIType(aZoneFileStream); + } else if (typeStr == ASSET_EFFECT) { // aitype + pParseAsset_FX(aZoneFileStream); + } else if (typeStr == ASSET_ANIMATION) { // aitype + result.animations << pParseAsset_Animation(aZoneFileStream); + } else if (typeStr == ASSET_STRING_TABLE) { // string_table + result.stringTables << pParseAsset_StringTable(aZoneFileStream); + } else if (typeStr == ASSET_MENU) { // string_table + result.menuFiles << pParseAsset_MenuFile(aZoneFileStream); + } else if (typeStr == ASSET_WEAPON) { // string_table + pParseAsset_Weapon(aZoneFileStream); + } else if (typeStr == ASSET_D3DBSP) { // string_table + pParseAsset_D3DBSP(aZoneFileStream); + } + } + return result; +} + +LocalString ZoneFile_COD4_PC::pParseAsset_LocalString(QDataStream *aZoneFileStream) { + LocalString result; + + quint32 stringPtr, aliasPtr; + *aZoneFileStream >> stringPtr >> aliasPtr; + if (stringPtr == 4294967295) { + // Parse local string asset contents + QString localStr; + char localStrChar; + *aZoneFileStream >> localStrChar; + while (localStrChar != 0) { + result.string += localStrChar; + *aZoneFileStream >> localStrChar; + } + } else { + result.string = "String Ptr: " + QString::number(stringPtr); + } + + if (aliasPtr == 4294967295) { + // Parse rawfile name + QString aliasName; + char aliasNameChar; + *aZoneFileStream >> aliasNameChar; + while (aliasNameChar != 0) { + result.alias += aliasNameChar; + *aZoneFileStream >> aliasNameChar; + } + } else { + result.string = "Alias Ptr: " + QString::number(aliasPtr); + } + + return result; +} + +RawFile ZoneFile_COD4_PC::pParseAsset_RawFile(QDataStream *aZoneFileStream) { + RawFile result; + + // Skip start separator FF FF FF FF (pointer?) + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.length; + + // Skip unknown 4 byte data + aZoneFileStream->skipRawData(4); + + // Parse rawfile path + char scriptPathChar; + *aZoneFileStream >> scriptPathChar; + while (scriptPathChar != 0) { + result.path += scriptPathChar; + *aZoneFileStream >> scriptPathChar; + } + result.path.replace(",", ""); + + const QStringList pathParts = result.path.split('/'); + if (pathParts.size() == 0) { + qDebug() << "Failed to parse ff path! " << result.path; + exit(-1); + } + if (result.path.contains(".bik")) { + qDebug() << "rawFileLength: " << result.length; + QByteArray bikData(result.length, Qt::Uninitialized); + aZoneFileStream->readRawData(bikData.data(), result.length); + + //QFile bikFile(QDir::currentPath() + "/" + rawFilePath.split('/').last()); + //qDebug() << bikFile.fileName(); + //if (!bikFile.open(QIODevice::WriteOnly)) { + // qWarning() << "Failed to open .bik file for writing!"; + // return; + //} + //qDebug() << QString("%1: %2").arg(rawFilePath).arg(bikFile.fileName()); + //bikFile.write(bikData); + } else { + // Parse gsc contents + char rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + while (rawFileContentsChar != 0 && rawFileContentsChar != -1) { + result.contents += rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + } + } + return result; +} + +void ZoneFile_COD4_PC::pParseAsset_PhysPreset(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Model ZoneFile_COD4_PC::pParseAsset_Model(QDataStream *aZoneFileStream) { + Model result; + + *aZoneFileStream >> result.namePtr >> result.tagCount >> result.rootTagCount + >> result.surfCount >> result.unknownCount >> result.boneNamePtr + >> result.parentListPtr >> result.quatsPtr >> result.transPtr + >> result.partClassPtr >> result.baseMatPtr + >> result.surfsPtr >> result.materialHandlesPtr; + + // Parse XModelLodInfo + for (int i = 1; i <= 4; i++) { + quint32 intDist; + *aZoneFileStream >> intDist; + + std::memcpy(&result.lodInfo[i].dist, &intDist, sizeof(result.lodInfo[i].dist)); + *aZoneFileStream >> result.lodInfo[i].numsurfs >> result.lodInfo[i].surfIndex; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.lodInfo[i].partBits[0] + >> result.lodInfo[i].partBits[1] + >> result.lodInfo[i].partBits[2] + >> result.lodInfo[i].partBits[3]; + } + + *aZoneFileStream >> result.collSurfsPtr >> result.numCollSurfs >> result.contents >> result.boneInfoPtr; + + quint32 intRadius, intMins[3], intMaxs[3]; + *aZoneFileStream >> intRadius >> intMins[0] >> intMins[1] + >> intMins[2] >> intMaxs[0] >> intMaxs[1] >> intMaxs[2]; + + std::memcpy(&result.radius, &intRadius, sizeof(result.radius)); + + std::memcpy(&result.mins[0], &intMins[0], sizeof(result.mins[0])); + std::memcpy(&result.mins[1], &intMins[1], sizeof(result.mins[1])); + std::memcpy(&result.mins[2], &intMins[2], sizeof(result.mins[2])); + + std::memcpy(&result.maxs[0], &intMaxs[0], sizeof(result.maxs[0])); + std::memcpy(&result.maxs[1], &intMaxs[1], sizeof(result.maxs[2])); + std::memcpy(&result.maxs[2], &intMaxs[2], sizeof(result.maxs[3])); + + *aZoneFileStream >> result.numLods >> result.collLod >> result.streamInfoPtr + >> result.memUsage >> result.flags >> result.physPresetPtr >> result.physGeomsPtr; + + // Parse model name + char modelNameChar; + *aZoneFileStream >> modelNameChar; + while (modelNameChar == 0) { + *aZoneFileStream >> modelNameChar; + } + while (modelNameChar != 0) { + result.modelName += modelNameChar; + *aZoneFileStream >> modelNameChar; + } + return result; +} + +Material ZoneFile_COD4_PC::pParseAsset_Material(QDataStream *aZoneFileStream) { + aZoneFileStream->skipRawData(27 * 4); + + qint32 materialNamePtr; + *aZoneFileStream >> materialNamePtr; + if (materialNamePtr == -1) { + QString materialName; + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + } + + aZoneFileStream->skipRawData(3 * 4); + + qint32 compressionPtr, compression, unknownSectionPtr; + *aZoneFileStream >> compressionPtr; + if (compressionPtr == -1) { + *aZoneFileStream >> compression; + + *aZoneFileStream >> unknownSectionPtr; + if (unknownSectionPtr == -2) { + aZoneFileStream->skipRawData(6 * 4); + } + } + + qint32 imageNamePtr; + *aZoneFileStream >> imageNamePtr; + if (imageNamePtr == -1) { + QString imageName; + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + imageName += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + } + + QByteArray compressionData(4, Qt::Uninitialized); + QString compressionStr; + if (compressionPtr == -1) { + aZoneFileStream->skipRawData(2 * 4); + aZoneFileStream->readRawData(compressionData.data(), 4); + aZoneFileStream->skipRawData(4); + compressionStr = QString::fromUtf8(compressionData); + aZoneFileStream->skipRawData(4); + } + aZoneFileStream->skipRawData(4); + + // TODO: Fill out this material + return Material(); +} + +Shader ZoneFile_COD4_PC::pParseAsset_Shader(QDataStream *aZoneFileStream) { + Shader result = Shader(); + + quint8 minorVersion, majorVersion; + *aZoneFileStream >> minorVersion >> majorVersion; + + quint32 magic; + *aZoneFileStream >> magic; + + // Verify .fxc magic + if (magic != 65534 && magic != 65535) { return result; } + + SHADER_TYPE type = SHADER_NONE; + quint16 rawShaderType; + *aZoneFileStream >> rawShaderType; + if (rawShaderType == 65535) { // Pixel shader + type = SHADER_PIXEL; + } else if (rawShaderType == 65534) { // Vertex shader + type = SHADER_VERTEX; + } + Q_UNUSED(type); + + while (true) { + quint32 instructionToken; + *aZoneFileStream >> instructionToken; + + SHADER_OPCODE opCode = (SHADER_OPCODE)(instructionToken & 0xffff); + + int size; + if (opCode == OPCODE_End) { + break; + } else if (opCode == OPCODE_Comment) { + size = (int)((instructionToken >> 16) & 0x7FFF); + } else { + size = (int)((instructionToken >> 24) & 0x0f); + } + Q_UNUSED(size); + } + + + return result; +} + +TechSet ZoneFile_COD4_PC::pParseAsset_TechSet(QDataStream *aZoneFileStream) { + TechSet result; + + for (int i = 1; i <= 62; i++) { + quint32 ptr; + *aZoneFileStream >> ptr; + + result.pointers << ptr; + } + qDebug() << aZoneFileStream->device()->pos(); + + // Parse techset name + char techSetNameChar; + *aZoneFileStream >> techSetNameChar; + while (techSetNameChar != 0) { + result.name += techSetNameChar; + *aZoneFileStream >> techSetNameChar; + } + result.name.replace(",", ""); + + return result; +} + +Image ZoneFile_COD4_PC::pParseAsset_Image(QDataStream *aZoneFileStream) { + Image result; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknowna >> result.unknownb + >> result.unknownc >> result.unknownd + >> result.unknowne >> result.unknownf + >> result.unknowng; + + aZoneFileStream->skipRawData(15 * 4); + *aZoneFileStream >> result.unknownh >> result.unknowni; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknownj; + + aZoneFileStream->skipRawData(4); + + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + result.materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + result.materialName.replace(",", ""); + + if (result.unknowna) { + *aZoneFileStream >> result.unknownk; + *aZoneFileStream >> result.unknownl; + *aZoneFileStream >> result.unknownm; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown1; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown2 >> result.unknown3 + >> result.size1 >> result.size2 + >> result.unknown4 >> result.unknown5; + + aZoneFileStream->skipRawData(4); + + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + result.name += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + + *aZoneFileStream >> result.unknown6 >> result.unknown7; + + QByteArray compressionData(8, Qt::Uninitialized); + aZoneFileStream->readRawData(compressionData.data(), 8); + if (compressionData.contains("DXT1")) { + result.compression = COMPRESSION_DXT1; + } else if (compressionData.contains("DXT3")) { + result.compression = COMPRESSION_DXT3; + } else if (compressionData.contains("DXT5")) { + result.compression = COMPRESSION_DXT5; + } else { + result.compression = COMPRESSION_NONE; + } + + *aZoneFileStream >> result.unknown8 >> result.unknown9; + } + + return result; +} + +SoundAsset ZoneFile_COD4_PC::pParseAsset_Sound(QDataStream *aZoneFileStream) { + SoundAsset result; + + qDebug() << aZoneFileStream->device()->pos(); + + QByteArray rootNamePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rootNamePtr.data(), 4); + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.count; + + if (rootNamePtr.toHex() == "ffffffff") { + // Read in sound file name + char soundNameChar; + *aZoneFileStream >> soundNameChar; + while (soundNameChar != 0) { + result.name += soundNameChar; + *aZoneFileStream >> soundNameChar; + } + } + + int tagCount = 0; + int resultCount = 0; + for (quint32 i = 0; i < result.count; i++) { + aZoneFileStream->skipRawData(12); + + QByteArray tagPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(tagPtr.data(), 4); + + if (tagPtr.toHex() == "ffffffff") { + tagCount++; + } + aZoneFileStream->skipRawData(4); + + QByteArray pathPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pathPtr.data(), 4); + + if (pathPtr.toHex() == "ffffffff") { + resultCount++; + } + + aZoneFileStream->skipRawData(160); + } + + for (int i = 0; i < tagCount; i++) { + // Read in tag? + QString tag; + char tagChar; + *aZoneFileStream >> tagChar; + while (tagChar != 0) { + tag += tagChar; + *aZoneFileStream >> tagChar; + } + } + + for (int i = 0; i < resultCount; i++) { + Sound sound; + + if (aZoneFileStream->device()->peek(12).toHex().contains("ffffffff00000000")) { + aZoneFileStream->skipRawData(12); + } + + aZoneFileStream->skipRawData(8); + + QByteArray aliasPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(aliasPtr.data(), 4); + + QByteArray namePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(namePtr.data(), 4); + + *aZoneFileStream >> sound.dataLength; + + if (aliasPtr.toHex() == "ffffffff") { + // Read in sound alias name + char soundAliasChar; + *aZoneFileStream >> soundAliasChar; + while (soundAliasChar != 0) { + sound.alias += soundAliasChar; + *aZoneFileStream >> soundAliasChar; + } + } + + if (aZoneFileStream->device()->peek(4) == "RIFF") { + sound.path = sound.alias; + sound.alias = ""; + } else if (namePtr.toHex() == "ffffffff") { + // Read in sound file path + char soundPathChar; + *aZoneFileStream >> soundPathChar; + while (soundPathChar != 0) { + sound.path += soundPathChar; + *aZoneFileStream >> soundPathChar; + } + sound.path.replace(",", ""); + } + + if (sound.dataLength) { + QByteArray data(sound.dataLength, Qt::Uninitialized); + aZoneFileStream->readRawData(data.data(), sound.dataLength); + sound.data = data; + } + result.sounds.append(sound); + } + + return result; +} + +void ZoneFile_COD4_PC::pParseAsset_ColMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD4_PC::pParseAsset_GameMapSP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD4_PC::pParseAsset_GameMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD4_PC::pParseAsset_LightDef(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD4_PC::pParseAsset_UIMap(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD4_PC::pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD4_PC::pParseAsset_AIType(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD4_PC::pParseAsset_FX(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Animation ZoneFile_COD4_PC::pParseAsset_Animation(QDataStream *aZoneFileStream) { + Animation result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.dataByteCount + >> result.dataShortCount + >> result.dataIntCount + >> result.randomDataByteCount + >> result.randomDataIntCount + >> result.numframes + >> result.isLooped + >> result.isDelta + >> result.noneRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.normalTranslatedBoneCount + >> result.preciseTranslatedBoneCount + >> result.staticTranslatedBoneCount + >> result.noneTranslatedBoneCount + >> result.totalBoneCount + >> result.otherBoneCount1 + >> result.otherBoneCount2 + >> result.notifyCount + >> result.assetType + >> result.pad + >> result.randomDataShortCount + >> result.indexCount + >> result.frameRate + >> result.frequency + >> result.boneIDsPtr + >> result.dataBytePtr + >> result.dataShortPtr + >> result.dataIntPtr + >> result.randomDataShortPtr + >> result.randomDataBytePtr + >> result.randomDataIntPtr + >> result.longIndiciesPtr + >> result.notificationsPtr + >> result.deltaPartsPtr; + + // Read in x_anim file name + QString xAnimName; + char xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + while (xAnimNameChar != 0) { + result.name += xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + } + + // Parse x_anim index header + QVector sectionLengths; + for (int i = 0; i < result.numframes; i++) { + quint8 sectionlength; + *aZoneFileStream >> sectionlength; + sectionLengths.push_back(sectionlength); + // Skip padding + aZoneFileStream->skipRawData(1); + } + // Skip unknown section + aZoneFileStream->skipRawData(2 * 8); + + return result; +} + +MenuFile ZoneFile_COD4_PC::pParseAsset_MenuFile(QDataStream *aZoneFileStream) { + //MENU_FILE + MenuFile result; + + aZoneFileStream->skipRawData(4); // Separator + + // Parse menu def count + *aZoneFileStream >> result.menuCount; + + // Clearly misparsed, never have this much + if (result.menuCount > 1000) { + qDebug() << "Failure reported when parsing menu file."; + return result; + } + for (uint i = 0; i < result.menuCount; i++) { + Menu menu; + + aZoneFileStream->skipRawData(4); // Separator + + // Read in x_anim file name + char menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + while (menuFilepathChar != 0) { + menu.filePath += menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + } + aZoneFileStream->skipRawData(4); // Separator + + *aZoneFileStream >> menu.menuNamePtr; + + float menuRectX, menuRectY, menuRectWidth, menuRectHeight; + *aZoneFileStream >> menuRectX >> menuRectY >> menuRectWidth >> menuRectHeight; + menu.rect = QRectF(menuRectX, menuRectY, menuRectWidth, menuRectHeight); + + quint32 hAlignInt, vAlignInt; + *aZoneFileStream >> hAlignInt >> vAlignInt; + menu.hAlign = (MENU_H_ALIGNMENT)hAlignInt; + menu.vAlign = (MENU_V_ALIGNMENT)vAlignInt; + + float rectClientX, rectClientY, rectClientWidth, rectClientHeight; + *aZoneFileStream >> rectClientX >> rectClientY >> rectClientWidth >> rectClientHeight; + menu.clientRect = QRectF(rectClientX, rectClientY, rectClientWidth, rectClientHeight); + + quint32 hClientAlignInt, vClientAlignInt, styleInt, borderInt; + *aZoneFileStream >> hClientAlignInt >> vClientAlignInt >> menu.groupPtr + >> styleInt >> borderInt >> menu.ownerDraw >> menu.ownerDrawFlags + >> menu.borderSize >> menu.staticFlags >> menu.dynamicFlags >> menu.nextTime; + menu.hClientAlign = (MENU_H_ALIGNMENT)hClientAlignInt; + menu.vClientAlign = (MENU_V_ALIGNMENT)vClientAlignInt; + menu.style = (MENU_WINDOW_STYLE)styleInt; + menu.border = (MENU_WINDOW_BORDER)borderInt; + + float foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA, + backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA, + borderColorR, borderColorG, borderColorB, borderColorA, + outlineColorR, outlineColorG, outlineColorB, outlineColorA; + *aZoneFileStream >> foregroundColorR >> foregroundColorG >> foregroundColorB >> foregroundColorA + >> backgroundColorR >> backgroundColorG >> backgroundColorB >> backgroundColorA + >> borderColorR >> borderColorG >> borderColorB >> borderColorA + >> outlineColorR >> outlineColorG >> outlineColorB >> outlineColorA; + + menu.foregroundColor = QColor(foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA); + menu.backgroundColor = QColor(backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA); + menu.borderColor = QColor(borderColorR, borderColorG, borderColorB, borderColorA); + menu.outlineColor = QColor(outlineColorR, outlineColorG, outlineColorB, outlineColorA); + + *aZoneFileStream >> menu.materialPtr >> menu.fontPtr >> menu.fullScreen >> menu.itemCount + >> menu.fontIndex >> menu.cursorItem >> menu.fadeCycle >> menu.fadeClamp + >> menu.fadeAmount >> menu.fadeInAmount >> menu.blurRadius >> menu.onOpenPtr + >> menu.onFocusPtr >> menu.onClosePtr >> menu.onESCPtr >> menu.onKeyPtr + >> menu.visibleExpCount >> menu.expEntryPtr >> menu.allowedBindingPtr + >> menu.soundNamePtr >> menu.imageTrack; + + float focusColorR, focusColorG, focusColorB, focusColorA, + disabledColorR, disabledColorG, disabledColorB, disabledColorA; + *aZoneFileStream >> focusColorR >> focusColorG >> focusColorB >> focusColorA + >> disabledColorR >> disabledColorG >> disabledColorB >> disabledColorA; + menu.focusColor = QColor(focusColorR, focusColorG, focusColorB, focusColorA); + menu.disabledColor = QColor(disabledColorR, disabledColorG, disabledColorB, disabledColorA); + + *aZoneFileStream >> menu.rectXExpCount >> menu.rectXExpPtr >> menu.rectYExpCount >> menu.rectYExpPtr; + + aZoneFileStream->skipRawData(4); // Separator + + char menuDefNameChar; + int menuDefNameLen = 0; + *aZoneFileStream >> menuDefNameChar; + while (menuDefNameChar != 0 && menuDefNameLen < 30) { + menuDefNameLen++; + menu.name += menuDefNameChar; + *aZoneFileStream >> menuDefNameChar; + } + + char defStringChar; + int defStringLen = 0; + *aZoneFileStream >> defStringChar; + while (defStringChar != 0 && defStringLen < 30) { + defStringLen++; + menu.definition += defStringChar; + *aZoneFileStream >> defStringChar; + } + aZoneFileStream->skipRawData(4 * 10); + + *aZoneFileStream >> menu.itemWindowDefNamePtr; + + float itemRectX, itemRectY, itemRectWidth, itemRectHeight; + *aZoneFileStream >> itemRectX >> itemRectY >> itemRectWidth >> itemRectHeight; + menu.itemRect = QRectF(itemRectX, itemRectY, itemRectWidth, itemRectHeight); + + *aZoneFileStream >> menu.itemHAlignment >> menu.itemVAlignment >> menu.itemGroupPtr + >> menu.itemWindowStyle >> menu.itemWindowBorder >> menu.itemOwnerDraw + >> menu.itemOwnerDrawFlags >> menu.itemBorderSize >> menu.itemStaticFlags + >> menu.itemDynamicFlags >> menu.itemNextTime; + + float itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA, + itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA, + itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA, + itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA; + *aZoneFileStream >> itemForegroundColorR >> itemForegroundColorG >> itemForegroundColorB >> itemForegroundColorA + >> itemBackgroundColorR >> itemBackgroundColorG >> itemBackgroundColorB >> itemBackgroundColorA + >> itemBorderColorR >> itemBorderColorG >> itemBorderColorB >> itemBorderColorA + >> itemOutlineColorR >> itemOutlineColorG >> itemOutlineColorB >> itemOutlineColorA; + + menu.itemForegroundColor = QColor(itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA); + menu.itemBackgroundColor = QColor(itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA); + menu.itemBorderColor = QColor(itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA); + menu.itemOutlineColor = QColor(itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA); + + *aZoneFileStream >> menu.itemMaterialPtr; + + float itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight; + *aZoneFileStream >> itemTextRectX >> itemTextRectY >> itemTextRectWidth >> itemTextRectHeight; + menu.itemTextRect = QRectF(itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight); + + quint32 hItemTextAlignInt, vItemTextAlignInt, itemType, fontTypeInt, textStyleInt; + *aZoneFileStream >> hItemTextAlignInt >> vItemTextAlignInt >> itemType >> menu.dataType + >> menu.alignment >> fontTypeInt >> menu.textAlignMode >> menu.textalignx >> menu.textaligny + >> menu.textscale >> textStyleInt >> menu.gameMsgWindowIndex >> menu.gameMsgWindowMode + >> menu.testPtr >> menu.textSavegameInfo >> menu.parentPtr; + menu.itemText_hAlign = (MENU_H_ALIGNMENT)hItemTextAlignInt; + menu.itemText_vAlign = (MENU_V_ALIGNMENT)vItemTextAlignInt; + menu.itemType = (MENU_ITEM_TYPE)itemType; + menu.fontEnum = (MENU_FONT_TYPE)fontTypeInt; + menu.textStyle = (MENU_ITEM_TEXTSTYLE)textStyleInt; + + *aZoneFileStream >> menu.mouseEnterText >> menu.mouseExitText >> menu.mouseEnter >> menu.mouseExit + >> menu.action >> menu.onAccept >> menu.onFocus >> menu.leaveFocus >> menu.dvar >> menu.dvarTest + >> menu.keyHandlerPtr >> menu.enableDvarPtr >> menu.dvarFlags >> menu.focusSoundPtr + >> menu.special >> menu.cursorPos; + + // itemDefData_t typeData; + + // listBoxDef_s *listBox; + + *aZoneFileStream >> menu.startPos >> menu.endPos >> menu.drawPadding; + + *aZoneFileStream >> menu.elementWidth >> menu.elementHeight; + + *aZoneFileStream >> menu.elementStyle >> menu.numColumns; + + //columnInfo_s columnInfo[16]; + + *aZoneFileStream >> menu.doubleClickPtr; + + + *aZoneFileStream >> menu.notselectable >> menu.noScrollBars >> menu.usePaging; + + float itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA, + itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA, + itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA; + *aZoneFileStream >> itemSelectBorderColorR >> itemSelectBorderColorG >> itemSelectBorderColorB >> itemSelectBorderColorA + >> itemDisableColorR >> itemDisableColorG >> itemDisableColorB >> itemDisableColorA + >> itemFocusColorR >> itemFocusColorG >> itemFocusColorB >> itemFocusColorA; + menu.itemSelectBorderColor = QColor(itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA); + menu.itemDisableColor = QColor(itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA); + menu.itemFocusColor = QColor(itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA); + + *aZoneFileStream >> menu.selectIconPtr >> menu.backgroundItemListboxPtr >> menu.highlightTexturePtr; + + // editFieldDef_s *editField; + + *aZoneFileStream >> menu.minVal >> menu.maxVal >> menu.defVal >> menu.range >> menu.maxChars + >> menu.maxCharsGotoNext >> menu.maxPaintChars >> menu.paintOffset; + + // multiDef_s *multi; + + for (int i = 0; i < 32; i++) { + quint32 dvarList; + *aZoneFileStream >> dvarList; + menu.dvarListPtrs.push_back(dvarList); + } + + for (int i = 0; i < 32; i++) { + quint32 dvarStr; + *aZoneFileStream >> dvarStr; + menu.dvarStrPtrs.push_back(dvarStr); + } + + for (int i = 0; i < 32; i++) { + float dvarValue; + *aZoneFileStream >> dvarValue; + menu.dvarValues.push_back(dvarValue); + } + + *aZoneFileStream >> menu.count >> menu.strDef >> menu.enumDvarNamePtr; + aZoneFileStream->skipRawData(4); + //>> menu.dataPtr + *aZoneFileStream >> menu.itemImageTrack; + + qDebug() << aZoneFileStream->device()->pos(); + + //statement_s visibleExp; + //statement_s textExp; + //statement_s materialExp; + //statement_s rectXExp; + //statement_s rectYExp; + //statement_s rectWExp; + //statement_s rectHExp; + //statement_s foreColorAExp; + result.menuDefs << menu; + } + return result; +} + +void ZoneFile_COD4_PC::pParseAsset_Weapon(QDataStream *aZoneFileStream) { + //WEAPON_FILE + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD4_PC::pParseAsset_D3DBSP(QDataStream *aZoneFileStream) { + //D3DBSP_DUMP + Q_UNUSED(aZoneFileStream); +} + +StringTable ZoneFile_COD4_PC::pParseAsset_StringTable(QDataStream *aZoneFileStream) { + StringTable result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.columnCount + >> result.rowCount; + + // Todo fix this + result.columnCount = 0; + result.rowCount = 0; + + aZoneFileStream->skipRawData(4); + + QString stringTableName; + char stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + while (stringTableNameChar != 0) { + result.name += stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + } + + for (quint32 i = 0; i < result.rowCount; i++) { + QByteArray pointerData(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pointerData.data(), 4); + result.tablePointers.push_back(pointerData.toHex()); + + aZoneFileStream->skipRawData(4); + } + + for (const QString &pointerAddr : result.tablePointers) { + QString leadingContent = ""; + if (pointerAddr == "FFFFFFFF") { + char leadingContentChar; + *aZoneFileStream >> leadingContentChar; + while (leadingContentChar != 0) { + leadingContent += leadingContentChar; + *aZoneFileStream >> leadingContentChar; + } + } else { + leadingContent = pointerAddr; + } + + QString content; + char contentChar; + *aZoneFileStream >> contentChar; + while (contentChar != 0) { + content += contentChar; + *aZoneFileStream >> contentChar; + } + result.content[leadingContent] = content; + } + return result; +} + +AssetType ZoneFile_COD4_PC::AssetStrToEnum(const QString aAssetType) { + const QString cleanedType = aAssetType.toUpper(); + if (cleanedType == "17000000") { // localized string PARTIALLY VERIFIED + return ASSET_RAW_FILE; + } else if (cleanedType == "20000000") { // raw_file PARTIALLY VERIFIED + return ASSET_SCRIPT_PARSE_TREE; + } else if (cleanedType == "1A000000") { // fx PARTIALLY VERIFIED + return ASSET_EFFECT; + } else if (cleanedType == "09000000") { // loaded_sound PARTIALLY VERIFIED + return ASSET_SOUND; + } else if (cleanedType == "04000000") { // x_anim PARTIALLY VERIFIED + return ASSET_ANIMATION; + } else if (cleanedType == "0C000000") { // collision_map PARTIALLY VERIFIED + return ASSET_COLLISION_MAP; + } else if (cleanedType == "21000000") { // string_table PARTIALLY VERIFIED + return ASSET_STRING_TABLE; + } else if (cleanedType == "15000000") { // menu_file PARTIALLY VERIFIED + return ASSET_MENU; + } else if (cleanedType == "07000000") { // tech set PARTIALLY VERIFIED + return ASSET_TECH_SET; + } else if (cleanedType == "18000000") { // weapon PARTIALLY VERIFIED + return ASSET_WEAPON; + } else if (cleanedType == "11000000") { // gfx map PARTIALLY VERIFIED + return ASSET_GFX_MAP; + } else if (cleanedType == "12000000") { // light_def PARTIALLY VERIFIED + return ASSET_LIGHT_DEF; + } else if (cleanedType == "14000000") { // font PARTIALLY VERIFIED + return ASSET_FONT; + } else if (cleanedType == "05000000") { // xmodel PARTIALLY VERIFIED + return ASSET_MODEL; + } else if (cleanedType == "0D000000") { // d3dbsp PARTIALLY VERIFIED + return ASSET_D3DBSP; + } else if (cleanedType == "06000000") { // image PARTIALLY VERIFIED + return ASSET_IMAGE; + } else if (cleanedType == "0E000000") { // game map sp PARTIALLY VERIFIED + return ASSET_GAME_MAP_SP; + } else if (cleanedType == "0B000000") { // col map sp PARTIALLY VERIFIED + return ASSET_COL_MAP_SP; + } else if (cleanedType == "01000000") { // physics preset PARTIALLY VERIFIED + return ASSET_PHYS_PRESET; + } else if (cleanedType == "03000000") { // destructible def PARTIALLY VERIFIED + return ASSET_DESTRUCTIBLE; + } + return ASSET_NONE; +} + +QByteArray ZoneFile_COD4_PC::GetBinaryData() { + QByteArray result; + + return result; +} diff --git a/libs/zonefile/PC/zonefile_cod4_pc.h b/libs/zonefile/PC/zonefile_cod4_pc.h new file mode 100644 index 0000000..be47e4f --- /dev/null +++ b/libs/zonefile/PC/zonefile_cod4_pc.h @@ -0,0 +1,54 @@ +#ifndef ZONEFILE_COD4_PC_H +#define ZONEFILE_COD4_PC_H + +#include + +#include "zonefile.h" + +class ZoneFile_COD4_PC : public ZoneFile +{ +public: + ZoneFile_COD4_PC(); + ~ZoneFile_COD4_PC(); + + bool Load(const QByteArray aFileData) override; + AssetType AssetStrToEnum(const QString aAssetType) override; + + QByteArray GetBinaryData() override; + +private: + void pParseZoneHeader(QDataStream *aZoneFileStream) override; + quint32 pParseZoneSize(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsA(QDataStream *aZoneFileStream) override; + quint32 pParseZoneTagCount(QDataStream *aZoneFileStream) override; + quint32 pParseZoneRecordCount(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsB(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsC(QDataStream *aZoneFileStream) override; + QStringList pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) override; + QStringList pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) override; + AssetMap pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) override; + LocalString pParseAsset_LocalString(QDataStream *aZoneFileStream) override; + RawFile pParseAsset_RawFile(QDataStream *aZoneFileStream) override; + void pParseAsset_PhysPreset(QDataStream *aZoneFileStream) override; + Model pParseAsset_Model(QDataStream *aZoneFileStream) override; + Material pParseAsset_Material(QDataStream *aZoneFileStream) override; + Shader pParseAsset_Shader(QDataStream *aZoneFileStream) override; + TechSet pParseAsset_TechSet(QDataStream *aZoneFileStream) override; + Image pParseAsset_Image(QDataStream *aZoneFileStream) override; + SoundAsset pParseAsset_Sound(QDataStream *aZoneFileStream) override; + void pParseAsset_ColMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapSP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_LightDef(QDataStream *aZoneFileStream) override; + void pParseAsset_UIMap(QDataStream *aZoneFileStream) override; + void pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) override; + void pParseAsset_AIType(QDataStream *aZoneFileStream) override; + void pParseAsset_FX(QDataStream *aZoneFileStream) override; + Animation pParseAsset_Animation(QDataStream *aZoneFileStream) override; + MenuFile pParseAsset_MenuFile(QDataStream *aZoneFileStream) override; + void pParseAsset_Weapon(QDataStream *aZoneFileStream) override; + void pParseAsset_D3DBSP(QDataStream *aZoneFileStream) override; + StringTable pParseAsset_StringTable(QDataStream *aZoneFileStream) override; +}; + +#endif // ZONEFILE_COD4_PC_H diff --git a/libs/zonefile/PC/zonefile_cod5_pc.cpp b/libs/zonefile/PC/zonefile_cod5_pc.cpp new file mode 100644 index 0000000..fc93a04 --- /dev/null +++ b/libs/zonefile/PC/zonefile_cod5_pc.cpp @@ -0,0 +1,1140 @@ +#include "zonefile_cod5_pc.h" + +#include +#include +#include + +ZoneFile_COD5_PC::ZoneFile_COD5_PC() + : ZoneFile() { + +} + +ZoneFile_COD5_PC::~ZoneFile_COD5_PC() { + +} + +bool ZoneFile_COD5_PC::Load(const QByteArray aFileData) { + // Open zone file as little endian stream + QDataStream zoneFileStream(aFileData); + zoneFileStream.setByteOrder(QDataStream::LittleEndian); + + + // Parse data from zone file header + pParseZoneHeader(&zoneFileStream); + SetRecords(pParseZoneIndex(&zoneFileStream, GetRecordCount())); + SetAssetMap(pParseAssets(&zoneFileStream, GetRecords())); + + return true; +} + +void ZoneFile_COD5_PC::pParseZoneHeader(QDataStream *aZoneFileStream) { + SetSize(pParseZoneSize(aZoneFileStream)); + pParseZoneUnknownsA(aZoneFileStream); + + SetTagCount(pParseZoneTagCount(aZoneFileStream)); + pParseZoneUnknownsB(aZoneFileStream); + + SetRecordCount(pParseZoneRecordCount(aZoneFileStream)); + + quint32 tagCount = GetTagCount(); + if (tagCount) { + pParseZoneUnknownsC(aZoneFileStream); + SetTags(pParseZoneTags(aZoneFileStream, tagCount)); + } else { + aZoneFileStream->skipRawData(4); + } +} + +quint32 ZoneFile_COD5_PC::pParseZoneSize(QDataStream *aZoneFileStream) { + quint32 zoneFileSize; + *aZoneFileStream >> zoneFileSize; + if (zoneFileSize <= 0) { + qDebug() << "Tried to open empty zone file!"; + exit(-1); + } + zoneFileSize += 36; + return zoneFileSize; +} + +/* + ParseZoneUnknownsA() + + Parses the 1st section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD5_PC::pParseZoneUnknownsA(QDataStream *aZoneFileStream) { + // Byte 4-7, 8-11, 12-15: unknown + QByteArray unknown1(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown1.data(), 4); + + QByteArray unknown2(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown2.data(), 4); + + QByteArray unknown3(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown3.data(), 4); + + // Byte 16-19, 20-23: empty/unknown + QByteArray unknown4(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown4.data(), 4); + + QByteArray unknown5(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown5.data(), 4); + + // Byte 24-27: somehow related to the filesize, but smaller value + QByteArray unknown6(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown6.data(), 4); + + // Byte 28-31, 32-35: unknown + QByteArray unknown7(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown7.data(), 4); + + QByteArray unknown8(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown8.data(), 4); +} + +/* + ParseZoneTagCount() + + Parses the number of string tags in the zone index +*/ +quint32 ZoneFile_COD5_PC::pParseZoneTagCount(QDataStream *aZoneFileStream) { + quint32 tagCount; + *aZoneFileStream >> tagCount; + return tagCount; +} + +/* + ParseZoneRecordCount() + + Parses the number of records in the zone index +*/ +quint32 ZoneFile_COD5_PC::pParseZoneRecordCount(QDataStream *aZoneFileStream) { + quint32 recordCount; + *aZoneFileStream >> recordCount; + return recordCount; +} + +/* + ParseZoneUnknownsB() + + Parses the 2nd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD5_PC::pParseZoneUnknownsB(QDataStream *aZoneFileStream) { + // Byte 44-47: Unknown/empty? + QByteArray unknown9(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown9.data(), 4); +} + +/* + pParseZoneUnknownsC() + + Parses the 3rd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD5_PC::pParseZoneUnknownsC(QDataStream *aZoneFileStream) { + // Byte 40-43: Unknown/empty? + QByteArray unknown10(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown10.data(), 4); + + // Byte 44-47: Unknown/empty? + QByteArray unknown11(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown11.data(), 4); +} + +/* + ParseZoneTags() + + Parses the string tags ate the start of zone file +*/ +QStringList ZoneFile_COD5_PC::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) { + QStringList tags; + + // Byte 48-51: Repeated separators? ÿÿÿÿ x i + aZoneFileStream->skipRawData(4 * (tagCount - 1)); + + // Parse tags/strings before index + QString zoneTag; + char zoneTagChar; + for (quint32 i = 0; i < tagCount; i++) { + *aZoneFileStream >> zoneTagChar; + while (zoneTagChar != 0) { + zoneTag += zoneTagChar; + *aZoneFileStream >> zoneTagChar; + } + tags << zoneTag; + zoneTag.clear(); + } + return tags; +} + +/* + ParseZoneIndex() + + Parse the binary zone index data and populate table +*/ +QStringList ZoneFile_COD5_PC::pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) { + QStringList result; + + // Don't parse if no records + if (!recordCount) { return result; } + + if (aZoneFileStream->device()->peek(4).toHex().contains("ffff")) { + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 2); + } + + // Parse index & map found asset types + for (quint32 i = 0; i <= recordCount; i++) { + // Skip record start + QByteArray rawAssetType(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rawAssetType.data(), 4); + result << rawAssetType.toHex(); + + // Skip separator + aZoneFileStream->skipRawData(4); + } + return result; +} + +AssetMap ZoneFile_COD5_PC::pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) { + AssetMap result; + + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 8); + + for (int i = 0; i < assetOrder.size(); i++) { + const QString typeHex = assetOrder[i]; + const AssetType typeStr = AssetStrToEnum(typeHex); + + if (typeStr == ASSET_LOCAL_STRING) { // localized string asset + result.localStrings << pParseAsset_LocalString(aZoneFileStream); + } else if (typeStr == ASSET_RAW_FILE) { // gsc + auto rawFile = pParseAsset_RawFile(aZoneFileStream); + if (rawFile.length) { + result.rawFiles << rawFile; + } + } else if (typeStr == ASSET_PHYS_PRESET) { // physpreset + pParseAsset_PhysPreset(aZoneFileStream); + } else if (typeStr == ASSET_MODEL) { // xmodel + result.models << pParseAsset_Model(aZoneFileStream); + } else if (typeStr == ASSET_MATERIAL) { // material + pParseAsset_Material(aZoneFileStream); + } else if (typeStr == ASSET_SHADER) { // pixelshader + pParseAsset_Shader(aZoneFileStream); + } else if (typeStr == ASSET_TECH_SET) { // techset include + result.techSets << pParseAsset_TechSet(aZoneFileStream); + } else if (typeStr == ASSET_IMAGE) { // image + result.images << pParseAsset_Image(aZoneFileStream); + } else if (typeStr == ASSET_SOUND) { // loaded_sound + result.sounds << pParseAsset_Sound(aZoneFileStream); + } else if (typeStr == ASSET_COLLISION_MAP) { // col_map_mp + pParseAsset_ColMapMP(aZoneFileStream); + } else if (typeStr == ASSET_MP_MAP) { // game_map_sp + pParseAsset_GameMapSP(aZoneFileStream); + } else if (typeStr == ASSET_SP_MAP) { // game_map_mp + pParseAsset_GameMapMP(aZoneFileStream); + } else if (typeStr == ASSET_LIGHT_DEF) { // lightdef + pParseAsset_LightDef(aZoneFileStream); + } else if (typeStr == ASSET_UI_MAP) { // ui_map + pParseAsset_UIMap(aZoneFileStream); + } else if (typeStr == ASSET_SND_DRIVER_GLOBALS) { // snddriverglobals + pParseAsset_SNDDriverGlobals(aZoneFileStream); + } else if (typeStr == ASSET_AI_TYPE) { // aitype + pParseAsset_AIType(aZoneFileStream); + } else if (typeStr == ASSET_EFFECT) { // aitype + pParseAsset_FX(aZoneFileStream); + } else if (typeStr == ASSET_ANIMATION) { // aitype + result.animations << pParseAsset_Animation(aZoneFileStream); + } else if (typeStr == ASSET_STRING_TABLE) { // string_table + result.stringTables << pParseAsset_StringTable(aZoneFileStream); + } else if (typeStr == ASSET_MENU) { // string_table + result.menuFiles << pParseAsset_MenuFile(aZoneFileStream); + } else if (typeStr == ASSET_WEAPON) { // string_table + pParseAsset_Weapon(aZoneFileStream); + } else if (typeStr == ASSET_D3DBSP) { // string_table + pParseAsset_D3DBSP(aZoneFileStream); + } + } + return result; +} + +LocalString ZoneFile_COD5_PC::pParseAsset_LocalString(QDataStream *aZoneFileStream) { + LocalString result; + + quint32 stringPtr, aliasPtr; + *aZoneFileStream >> stringPtr >> aliasPtr; + if (stringPtr == 4294967295) { + // Parse local string asset contents + QString localStr; + char localStrChar; + *aZoneFileStream >> localStrChar; + while (localStrChar != 0) { + result.string += localStrChar; + *aZoneFileStream >> localStrChar; + } + } else { + result.string = "String Ptr: " + QString::number(stringPtr); + } + + if (aliasPtr == 4294967295) { + // Parse rawfile name + QString aliasName; + char aliasNameChar; + *aZoneFileStream >> aliasNameChar; + while (aliasNameChar != 0) { + result.alias += aliasNameChar; + *aZoneFileStream >> aliasNameChar; + } + } else { + result.string = "Alias Ptr: " + QString::number(aliasPtr); + } + + return result; +} + +RawFile ZoneFile_COD5_PC::pParseAsset_RawFile(QDataStream *aZoneFileStream) { + RawFile result; + + // Skip start separator FF FF FF FF (pointer?) + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.length; + + // Skip unknown 4 byte data + aZoneFileStream->skipRawData(4); + + // Parse rawfile path + char scriptPathChar; + *aZoneFileStream >> scriptPathChar; + while (scriptPathChar != 0) { + result.path += scriptPathChar; + *aZoneFileStream >> scriptPathChar; + } + result.path.replace(",", ""); + + const QStringList pathParts = result.path.split('/'); + if (pathParts.size() == 0) { + qDebug() << "Failed to parse ff path! " << result.path; + exit(-1); + } + if (result.path.contains(".bik")) { + qDebug() << "rawFileLength: " << result.length; + QByteArray bikData(result.length, Qt::Uninitialized); + aZoneFileStream->readRawData(bikData.data(), result.length); + + //QFile bikFile(QDir::currentPath() + "/" + rawFilePath.split('/').last()); + //qDebug() << bikFile.fileName(); + //if (!bikFile.open(QIODevice::WriteOnly)) { + // qWarning() << "Failed to open .bik file for writing!"; + // return; + //} + //qDebug() << QString("%1: %2").arg(rawFilePath).arg(bikFile.fileName()); + //bikFile.write(bikData); + } else { + // Parse gsc contents + char rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + while (rawFileContentsChar != 0 && rawFileContentsChar != -1) { + result.contents += rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + } + } + return result; +} + +void ZoneFile_COD5_PC::pParseAsset_PhysPreset(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Model ZoneFile_COD5_PC::pParseAsset_Model(QDataStream *aZoneFileStream) { + Model result; + + *aZoneFileStream >> result.namePtr >> result.tagCount >> result.rootTagCount + >> result.surfCount >> result.unknownCount >> result.boneNamePtr + >> result.parentListPtr >> result.quatsPtr >> result.transPtr + >> result.partClassPtr >> result.baseMatPtr + >> result.surfsPtr >> result.materialHandlesPtr; + + // Parse XModelLodInfo + for (int i = 1; i <= 4; i++) { + quint32 intDist; + *aZoneFileStream >> intDist; + + std::memcpy(&result.lodInfo[i].dist, &intDist, sizeof(result.lodInfo[i].dist)); + *aZoneFileStream >> result.lodInfo[i].numsurfs >> result.lodInfo[i].surfIndex; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.lodInfo[i].partBits[0] + >> result.lodInfo[i].partBits[1] + >> result.lodInfo[i].partBits[2] + >> result.lodInfo[i].partBits[3]; + } + + *aZoneFileStream >> result.collSurfsPtr >> result.numCollSurfs >> result.contents >> result.boneInfoPtr; + + quint32 intRadius, intMins[3], intMaxs[3]; + *aZoneFileStream >> intRadius >> intMins[0] >> intMins[1] + >> intMins[2] >> intMaxs[0] >> intMaxs[1] >> intMaxs[2]; + + std::memcpy(&result.radius, &intRadius, sizeof(result.radius)); + + std::memcpy(&result.mins[0], &intMins[0], sizeof(result.mins[0])); + std::memcpy(&result.mins[1], &intMins[1], sizeof(result.mins[1])); + std::memcpy(&result.mins[2], &intMins[2], sizeof(result.mins[2])); + + std::memcpy(&result.maxs[0], &intMaxs[0], sizeof(result.maxs[0])); + std::memcpy(&result.maxs[1], &intMaxs[1], sizeof(result.maxs[2])); + std::memcpy(&result.maxs[2], &intMaxs[2], sizeof(result.maxs[3])); + + *aZoneFileStream >> result.numLods >> result.collLod >> result.streamInfoPtr + >> result.memUsage >> result.flags >> result.physPresetPtr >> result.physGeomsPtr; + + // Parse model name + char modelNameChar; + *aZoneFileStream >> modelNameChar; + while (modelNameChar == 0) { + *aZoneFileStream >> modelNameChar; + } + while (modelNameChar != 0) { + result.modelName += modelNameChar; + *aZoneFileStream >> modelNameChar; + } + return result; +} + +Material ZoneFile_COD5_PC::pParseAsset_Material(QDataStream *aZoneFileStream) { + aZoneFileStream->skipRawData(27 * 4); + + qint32 materialNamePtr; + *aZoneFileStream >> materialNamePtr; + if (materialNamePtr == -1) { + QString materialName; + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + } + + aZoneFileStream->skipRawData(3 * 4); + + qint32 compressionPtr, compression, unknownSectionPtr; + *aZoneFileStream >> compressionPtr; + if (compressionPtr == -1) { + *aZoneFileStream >> compression; + + *aZoneFileStream >> unknownSectionPtr; + if (unknownSectionPtr == -2) { + aZoneFileStream->skipRawData(6 * 4); + } + } + + qint32 imageNamePtr; + *aZoneFileStream >> imageNamePtr; + if (imageNamePtr == -1) { + QString imageName; + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + imageName += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + } + + QByteArray compressionData(4, Qt::Uninitialized); + QString compressionStr; + if (compressionPtr == -1) { + aZoneFileStream->skipRawData(2 * 4); + aZoneFileStream->readRawData(compressionData.data(), 4); + aZoneFileStream->skipRawData(4); + compressionStr = QString::fromUtf8(compressionData); + aZoneFileStream->skipRawData(4); + } + aZoneFileStream->skipRawData(4); + + // TODO: Fill out this material + return Material(); +} + +Shader ZoneFile_COD5_PC::pParseAsset_Shader(QDataStream *aZoneFileStream) { + Shader result = Shader(); + + quint8 minorVersion, majorVersion; + *aZoneFileStream >> minorVersion >> majorVersion; + + quint32 magic; + *aZoneFileStream >> magic; + + // Verify .fxc magic + if (magic != 65534 && magic != 65535) { return result; } + + SHADER_TYPE type = SHADER_NONE; + quint16 rawShaderType; + *aZoneFileStream >> rawShaderType; + if (rawShaderType == 65535) { // Pixel shader + type = SHADER_PIXEL; + } else if (rawShaderType == 65534) { // Vertex shader + type = SHADER_VERTEX; + } + Q_UNUSED(type); + + while (true) { + quint32 instructionToken; + *aZoneFileStream >> instructionToken; + + SHADER_OPCODE opCode = (SHADER_OPCODE)(instructionToken & 0xffff); + + int size; + if (opCode == OPCODE_End) { + break; + } else if (opCode == OPCODE_Comment) { + size = (int)((instructionToken >> 16) & 0x7FFF); + } else { + size = (int)((instructionToken >> 24) & 0x0f); + } + Q_UNUSED(size); + } + + + return result; +} + +TechSet ZoneFile_COD5_PC::pParseAsset_TechSet(QDataStream *aZoneFileStream) { + TechSet result; + + for (int i = 1; i <= 62; i++) { + quint32 ptr; + *aZoneFileStream >> ptr; + + result.pointers << ptr; + } + qDebug() << aZoneFileStream->device()->pos(); + + // Parse techset name + char techSetNameChar; + *aZoneFileStream >> techSetNameChar; + while (techSetNameChar != 0) { + result.name += techSetNameChar; + *aZoneFileStream >> techSetNameChar; + } + result.name.replace(",", ""); + + return result; +} + +Image ZoneFile_COD5_PC::pParseAsset_Image(QDataStream *aZoneFileStream) { + Image result; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknowna >> result.unknownb + >> result.unknownc >> result.unknownd + >> result.unknowne >> result.unknownf + >> result.unknowng; + + aZoneFileStream->skipRawData(15 * 4); + *aZoneFileStream >> result.unknownh >> result.unknowni; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknownj; + + aZoneFileStream->skipRawData(4); + + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + result.materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + result.materialName.replace(",", ""); + + if (result.unknowna) { + *aZoneFileStream >> result.unknownk; + *aZoneFileStream >> result.unknownl; + *aZoneFileStream >> result.unknownm; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown1; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown2 >> result.unknown3 + >> result.size1 >> result.size2 + >> result.unknown4 >> result.unknown5; + + aZoneFileStream->skipRawData(4); + + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + result.name += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + + *aZoneFileStream >> result.unknown6 >> result.unknown7; + + QByteArray compressionData(8, Qt::Uninitialized); + aZoneFileStream->readRawData(compressionData.data(), 8); + if (compressionData.contains("DXT1")) { + result.compression = COMPRESSION_DXT1; + } else if (compressionData.contains("DXT3")) { + result.compression = COMPRESSION_DXT3; + } else if (compressionData.contains("DXT5")) { + result.compression = COMPRESSION_DXT5; + } else { + result.compression = COMPRESSION_NONE; + } + + *aZoneFileStream >> result.unknown8 >> result.unknown9; + } + + return result; +} + +SoundAsset ZoneFile_COD5_PC::pParseAsset_Sound(QDataStream *aZoneFileStream) { + SoundAsset result; + + qDebug() << aZoneFileStream->device()->pos(); + + QByteArray rootNamePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rootNamePtr.data(), 4); + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.count; + + if (rootNamePtr.toHex() == "ffffffff") { + // Read in sound file name + char soundNameChar; + *aZoneFileStream >> soundNameChar; + while (soundNameChar != 0) { + result.name += soundNameChar; + *aZoneFileStream >> soundNameChar; + } + } + + int tagCount = 0; + int resultCount = 0; + for (quint32 i = 0; i < result.count; i++) { + aZoneFileStream->skipRawData(12); + + QByteArray tagPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(tagPtr.data(), 4); + + if (tagPtr.toHex() == "ffffffff") { + tagCount++; + } + aZoneFileStream->skipRawData(4); + + QByteArray pathPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pathPtr.data(), 4); + + if (pathPtr.toHex() == "ffffffff") { + resultCount++; + } + + aZoneFileStream->skipRawData(160); + } + + for (int i = 0; i < tagCount; i++) { + // Read in tag? + QString tag; + char tagChar; + *aZoneFileStream >> tagChar; + while (tagChar != 0) { + tag += tagChar; + *aZoneFileStream >> tagChar; + } + } + + for (int i = 0; i < resultCount; i++) { + Sound sound; + + if (aZoneFileStream->device()->peek(12).toHex().contains("ffffffff00000000")) { + aZoneFileStream->skipRawData(12); + } + + aZoneFileStream->skipRawData(8); + + QByteArray aliasPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(aliasPtr.data(), 4); + + QByteArray namePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(namePtr.data(), 4); + + *aZoneFileStream >> sound.dataLength; + + if (aliasPtr.toHex() == "ffffffff") { + // Read in sound alias name + char soundAliasChar; + *aZoneFileStream >> soundAliasChar; + while (soundAliasChar != 0) { + sound.alias += soundAliasChar; + *aZoneFileStream >> soundAliasChar; + } + } + + if (aZoneFileStream->device()->peek(4) == "RIFF") { + sound.path = sound.alias; + sound.alias = ""; + } else if (namePtr.toHex() == "ffffffff") { + // Read in sound file path + char soundPathChar; + *aZoneFileStream >> soundPathChar; + while (soundPathChar != 0) { + sound.path += soundPathChar; + *aZoneFileStream >> soundPathChar; + } + sound.path.replace(",", ""); + } + + if (sound.dataLength) { + QByteArray data(sound.dataLength, Qt::Uninitialized); + aZoneFileStream->readRawData(data.data(), sound.dataLength); + sound.data = data; + } + result.sounds.append(sound); + } + + return result; +} + +void ZoneFile_COD5_PC::pParseAsset_ColMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD5_PC::pParseAsset_GameMapSP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD5_PC::pParseAsset_GameMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD5_PC::pParseAsset_LightDef(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD5_PC::pParseAsset_UIMap(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD5_PC::pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD5_PC::pParseAsset_AIType(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD5_PC::pParseAsset_FX(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Animation ZoneFile_COD5_PC::pParseAsset_Animation(QDataStream *aZoneFileStream) { + Animation result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.dataByteCount + >> result.dataShortCount + >> result.dataIntCount + >> result.randomDataByteCount + >> result.randomDataIntCount + >> result.numframes + >> result.isLooped + >> result.isDelta + >> result.noneRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.normalTranslatedBoneCount + >> result.preciseTranslatedBoneCount + >> result.staticTranslatedBoneCount + >> result.noneTranslatedBoneCount + >> result.totalBoneCount + >> result.otherBoneCount1 + >> result.otherBoneCount2 + >> result.notifyCount + >> result.assetType + >> result.pad + >> result.randomDataShortCount + >> result.indexCount + >> result.frameRate + >> result.frequency + >> result.boneIDsPtr + >> result.dataBytePtr + >> result.dataShortPtr + >> result.dataIntPtr + >> result.randomDataShortPtr + >> result.randomDataBytePtr + >> result.randomDataIntPtr + >> result.longIndiciesPtr + >> result.notificationsPtr + >> result.deltaPartsPtr; + + // Read in x_anim file name + QString xAnimName; + char xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + while (xAnimNameChar != 0) { + result.name += xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + } + + // Parse x_anim index header + QVector sectionLengths; + for (int i = 0; i < result.numframes; i++) { + quint8 sectionlength; + *aZoneFileStream >> sectionlength; + sectionLengths.push_back(sectionlength); + // Skip padding + aZoneFileStream->skipRawData(1); + } + // Skip unknown section + aZoneFileStream->skipRawData(2 * 8); + + return result; +} + +MenuFile ZoneFile_COD5_PC::pParseAsset_MenuFile(QDataStream *aZoneFileStream) { + //MENU_FILE + MenuFile result; + + aZoneFileStream->skipRawData(4); // Separator + + // Parse menu def count + *aZoneFileStream >> result.menuCount; + + // Clearly misparsed, never have this much + if (result.menuCount > 1000) { + qDebug() << "Failure reported when parsing menu file."; + return result; + } + for (uint i = 0; i < result.menuCount; i++) { + Menu menu; + + aZoneFileStream->skipRawData(4); // Separator + + // Read in x_anim file name + char menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + while (menuFilepathChar != 0) { + menu.filePath += menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + } + aZoneFileStream->skipRawData(4); // Separator + + *aZoneFileStream >> menu.menuNamePtr; + + float menuRectX, menuRectY, menuRectWidth, menuRectHeight; + *aZoneFileStream >> menuRectX >> menuRectY >> menuRectWidth >> menuRectHeight; + menu.rect = QRectF(menuRectX, menuRectY, menuRectWidth, menuRectHeight); + + quint32 hAlignInt, vAlignInt; + *aZoneFileStream >> hAlignInt >> vAlignInt; + menu.hAlign = (MENU_H_ALIGNMENT)hAlignInt; + menu.vAlign = (MENU_V_ALIGNMENT)vAlignInt; + + float rectClientX, rectClientY, rectClientWidth, rectClientHeight; + *aZoneFileStream >> rectClientX >> rectClientY >> rectClientWidth >> rectClientHeight; + menu.clientRect = QRectF(rectClientX, rectClientY, rectClientWidth, rectClientHeight); + + quint32 hClientAlignInt, vClientAlignInt, styleInt, borderInt; + *aZoneFileStream >> hClientAlignInt >> vClientAlignInt >> menu.groupPtr + >> styleInt >> borderInt >> menu.ownerDraw >> menu.ownerDrawFlags + >> menu.borderSize >> menu.staticFlags >> menu.dynamicFlags >> menu.nextTime; + menu.hClientAlign = (MENU_H_ALIGNMENT)hClientAlignInt; + menu.vClientAlign = (MENU_V_ALIGNMENT)vClientAlignInt; + menu.style = (MENU_WINDOW_STYLE)styleInt; + menu.border = (MENU_WINDOW_BORDER)borderInt; + + float foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA, + backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA, + borderColorR, borderColorG, borderColorB, borderColorA, + outlineColorR, outlineColorG, outlineColorB, outlineColorA; + *aZoneFileStream >> foregroundColorR >> foregroundColorG >> foregroundColorB >> foregroundColorA + >> backgroundColorR >> backgroundColorG >> backgroundColorB >> backgroundColorA + >> borderColorR >> borderColorG >> borderColorB >> borderColorA + >> outlineColorR >> outlineColorG >> outlineColorB >> outlineColorA; + + menu.foregroundColor = QColor(foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA); + menu.backgroundColor = QColor(backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA); + menu.borderColor = QColor(borderColorR, borderColorG, borderColorB, borderColorA); + menu.outlineColor = QColor(outlineColorR, outlineColorG, outlineColorB, outlineColorA); + + *aZoneFileStream >> menu.materialPtr >> menu.fontPtr >> menu.fullScreen >> menu.itemCount + >> menu.fontIndex >> menu.cursorItem >> menu.fadeCycle >> menu.fadeClamp + >> menu.fadeAmount >> menu.fadeInAmount >> menu.blurRadius >> menu.onOpenPtr + >> menu.onFocusPtr >> menu.onClosePtr >> menu.onESCPtr >> menu.onKeyPtr + >> menu.visibleExpCount >> menu.expEntryPtr >> menu.allowedBindingPtr + >> menu.soundNamePtr >> menu.imageTrack; + + float focusColorR, focusColorG, focusColorB, focusColorA, + disabledColorR, disabledColorG, disabledColorB, disabledColorA; + *aZoneFileStream >> focusColorR >> focusColorG >> focusColorB >> focusColorA + >> disabledColorR >> disabledColorG >> disabledColorB >> disabledColorA; + menu.focusColor = QColor(focusColorR, focusColorG, focusColorB, focusColorA); + menu.disabledColor = QColor(disabledColorR, disabledColorG, disabledColorB, disabledColorA); + + *aZoneFileStream >> menu.rectXExpCount >> menu.rectXExpPtr >> menu.rectYExpCount >> menu.rectYExpPtr; + + aZoneFileStream->skipRawData(4); // Separator + + char menuDefNameChar; + int menuDefNameLen = 0; + *aZoneFileStream >> menuDefNameChar; + while (menuDefNameChar != 0 && menuDefNameLen < 30) { + menuDefNameLen++; + menu.name += menuDefNameChar; + *aZoneFileStream >> menuDefNameChar; + } + + char defStringChar; + int defStringLen = 0; + *aZoneFileStream >> defStringChar; + while (defStringChar != 0 && defStringLen < 30) { + defStringLen++; + menu.definition += defStringChar; + *aZoneFileStream >> defStringChar; + } + aZoneFileStream->skipRawData(4 * 10); + + *aZoneFileStream >> menu.itemWindowDefNamePtr; + + float itemRectX, itemRectY, itemRectWidth, itemRectHeight; + *aZoneFileStream >> itemRectX >> itemRectY >> itemRectWidth >> itemRectHeight; + menu.itemRect = QRectF(itemRectX, itemRectY, itemRectWidth, itemRectHeight); + + *aZoneFileStream >> menu.itemHAlignment >> menu.itemVAlignment >> menu.itemGroupPtr + >> menu.itemWindowStyle >> menu.itemWindowBorder >> menu.itemOwnerDraw + >> menu.itemOwnerDrawFlags >> menu.itemBorderSize >> menu.itemStaticFlags + >> menu.itemDynamicFlags >> menu.itemNextTime; + + float itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA, + itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA, + itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA, + itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA; + *aZoneFileStream >> itemForegroundColorR >> itemForegroundColorG >> itemForegroundColorB >> itemForegroundColorA + >> itemBackgroundColorR >> itemBackgroundColorG >> itemBackgroundColorB >> itemBackgroundColorA + >> itemBorderColorR >> itemBorderColorG >> itemBorderColorB >> itemBorderColorA + >> itemOutlineColorR >> itemOutlineColorG >> itemOutlineColorB >> itemOutlineColorA; + + menu.itemForegroundColor = QColor(itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA); + menu.itemBackgroundColor = QColor(itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA); + menu.itemBorderColor = QColor(itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA); + menu.itemOutlineColor = QColor(itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA); + + *aZoneFileStream >> menu.itemMaterialPtr; + + float itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight; + *aZoneFileStream >> itemTextRectX >> itemTextRectY >> itemTextRectWidth >> itemTextRectHeight; + menu.itemTextRect = QRectF(itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight); + + quint32 hItemTextAlignInt, vItemTextAlignInt, itemType, fontTypeInt, textStyleInt; + *aZoneFileStream >> hItemTextAlignInt >> vItemTextAlignInt >> itemType >> menu.dataType + >> menu.alignment >> fontTypeInt >> menu.textAlignMode >> menu.textalignx >> menu.textaligny + >> menu.textscale >> textStyleInt >> menu.gameMsgWindowIndex >> menu.gameMsgWindowMode + >> menu.testPtr >> menu.textSavegameInfo >> menu.parentPtr; + menu.itemText_hAlign = (MENU_H_ALIGNMENT)hItemTextAlignInt; + menu.itemText_vAlign = (MENU_V_ALIGNMENT)vItemTextAlignInt; + menu.itemType = (MENU_ITEM_TYPE)itemType; + menu.fontEnum = (MENU_FONT_TYPE)fontTypeInt; + menu.textStyle = (MENU_ITEM_TEXTSTYLE)textStyleInt; + + *aZoneFileStream >> menu.mouseEnterText >> menu.mouseExitText >> menu.mouseEnter >> menu.mouseExit + >> menu.action >> menu.onAccept >> menu.onFocus >> menu.leaveFocus >> menu.dvar >> menu.dvarTest + >> menu.keyHandlerPtr >> menu.enableDvarPtr >> menu.dvarFlags >> menu.focusSoundPtr + >> menu.special >> menu.cursorPos; + + // itemDefData_t typeData; + + // listBoxDef_s *listBox; + + *aZoneFileStream >> menu.startPos >> menu.endPos >> menu.drawPadding; + + *aZoneFileStream >> menu.elementWidth >> menu.elementHeight; + + *aZoneFileStream >> menu.elementStyle >> menu.numColumns; + + //columnInfo_s columnInfo[16]; + + *aZoneFileStream >> menu.doubleClickPtr; + + + *aZoneFileStream >> menu.notselectable >> menu.noScrollBars >> menu.usePaging; + + float itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA, + itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA, + itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA; + *aZoneFileStream >> itemSelectBorderColorR >> itemSelectBorderColorG >> itemSelectBorderColorB >> itemSelectBorderColorA + >> itemDisableColorR >> itemDisableColorG >> itemDisableColorB >> itemDisableColorA + >> itemFocusColorR >> itemFocusColorG >> itemFocusColorB >> itemFocusColorA; + menu.itemSelectBorderColor = QColor(itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA); + menu.itemDisableColor = QColor(itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA); + menu.itemFocusColor = QColor(itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA); + + *aZoneFileStream >> menu.selectIconPtr >> menu.backgroundItemListboxPtr >> menu.highlightTexturePtr; + + // editFieldDef_s *editField; + + *aZoneFileStream >> menu.minVal >> menu.maxVal >> menu.defVal >> menu.range >> menu.maxChars + >> menu.maxCharsGotoNext >> menu.maxPaintChars >> menu.paintOffset; + + // multiDef_s *multi; + + for (int i = 0; i < 32; i++) { + quint32 dvarList; + *aZoneFileStream >> dvarList; + menu.dvarListPtrs.push_back(dvarList); + } + + for (int i = 0; i < 32; i++) { + quint32 dvarStr; + *aZoneFileStream >> dvarStr; + menu.dvarStrPtrs.push_back(dvarStr); + } + + for (int i = 0; i < 32; i++) { + float dvarValue; + *aZoneFileStream >> dvarValue; + menu.dvarValues.push_back(dvarValue); + } + + *aZoneFileStream >> menu.count >> menu.strDef >> menu.enumDvarNamePtr; + aZoneFileStream->skipRawData(4); + //>> menu.dataPtr + *aZoneFileStream >> menu.itemImageTrack; + + qDebug() << aZoneFileStream->device()->pos(); + + //statement_s visibleExp; + //statement_s textExp; + //statement_s materialExp; + //statement_s rectXExp; + //statement_s rectYExp; + //statement_s rectWExp; + //statement_s rectHExp; + //statement_s foreColorAExp; + result.menuDefs << menu; + } + return result; +} + +void ZoneFile_COD5_PC::pParseAsset_Weapon(QDataStream *aZoneFileStream) { + //WEAPON_FILE + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD5_PC::pParseAsset_D3DBSP(QDataStream *aZoneFileStream) { + //D3DBSP_DUMP + Q_UNUSED(aZoneFileStream); +} + +StringTable ZoneFile_COD5_PC::pParseAsset_StringTable(QDataStream *aZoneFileStream) { + StringTable result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.columnCount + >> result.rowCount; + + // Todo fix this + result.columnCount = 0; + result.rowCount = 0; + + aZoneFileStream->skipRawData(4); + + QString stringTableName; + char stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + while (stringTableNameChar != 0) { + result.name += stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + } + + for (quint32 i = 0; i < result.rowCount; i++) { + QByteArray pointerData(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pointerData.data(), 4); + result.tablePointers.push_back(pointerData.toHex()); + + aZoneFileStream->skipRawData(4); + } + + for (const QString &pointerAddr : result.tablePointers) { + QString leadingContent = ""; + if (pointerAddr == "FFFFFFFF") { + char leadingContentChar; + *aZoneFileStream >> leadingContentChar; + while (leadingContentChar != 0) { + leadingContent += leadingContentChar; + *aZoneFileStream >> leadingContentChar; + } + } else { + leadingContent = pointerAddr; + } + + QString content; + char contentChar; + *aZoneFileStream >> contentChar; + while (contentChar != 0) { + content += contentChar; + *aZoneFileStream >> contentChar; + } + result.content[leadingContent] = content; + } + return result; +} + +AssetType ZoneFile_COD5_PC::AssetStrToEnum(const QString aAssetType) { + const QString cleanedType = aAssetType.toUpper(); + if (cleanedType == "17000000") { // localized string PARTIALLY VERIFIED + return ASSET_RAW_FILE; + } else if (cleanedType == "20000000") { // raw_file PARTIALLY VERIFIED + return ASSET_SCRIPT_PARSE_TREE; + } else if (cleanedType == "1A000000") { // fx PARTIALLY VERIFIED + return ASSET_EFFECT; + } else if (cleanedType == "09000000") { // loaded_sound PARTIALLY VERIFIED + return ASSET_SOUND; + } else if (cleanedType == "04000000") { // x_anim PARTIALLY VERIFIED + return ASSET_ANIMATION; + } else if (cleanedType == "0C000000") { // collision_map PARTIALLY VERIFIED + return ASSET_COLLISION_MAP; + } else if (cleanedType == "21000000") { // string_table PARTIALLY VERIFIED + return ASSET_STRING_TABLE; + } else if (cleanedType == "15000000") { // menu_file PARTIALLY VERIFIED + return ASSET_MENU; + } else if (cleanedType == "07000000") { // tech set PARTIALLY VERIFIED + return ASSET_TECH_SET; + } else if (cleanedType == "18000000") { // weapon PARTIALLY VERIFIED + return ASSET_WEAPON; + } else if (cleanedType == "11000000") { // gfx map PARTIALLY VERIFIED + return ASSET_GFX_MAP; + } else if (cleanedType == "12000000") { // light_def PARTIALLY VERIFIED + return ASSET_LIGHT_DEF; + } else if (cleanedType == "14000000") { // font PARTIALLY VERIFIED + return ASSET_FONT; + } else if (cleanedType == "05000000") { // xmodel PARTIALLY VERIFIED + return ASSET_MODEL; + } else if (cleanedType == "0D000000") { // d3dbsp PARTIALLY VERIFIED + return ASSET_D3DBSP; + } else if (cleanedType == "06000000") { // image PARTIALLY VERIFIED + return ASSET_IMAGE; + } else if (cleanedType == "0E000000") { // game map sp PARTIALLY VERIFIED + return ASSET_GAME_MAP_SP; + } else if (cleanedType == "0B000000") { // col map sp PARTIALLY VERIFIED + return ASSET_COL_MAP_SP; + } else if (cleanedType == "01000000") { // physics preset PARTIALLY VERIFIED + return ASSET_PHYS_PRESET; + } else if (cleanedType == "03000000") { // destructible def PARTIALLY VERIFIED + return ASSET_DESTRUCTIBLE; + } + return ASSET_NONE; +} + +QByteArray ZoneFile_COD5_PC::GetBinaryData() { + QByteArray result; + + return result; +} diff --git a/libs/zonefile/PC/zonefile_cod5_pc.h b/libs/zonefile/PC/zonefile_cod5_pc.h new file mode 100644 index 0000000..5125441 --- /dev/null +++ b/libs/zonefile/PC/zonefile_cod5_pc.h @@ -0,0 +1,54 @@ +#ifndef ZONEFILE_COD5_PC_H +#define ZONEFILE_COD5_PC_H + +#include + +#include "zonefile.h" + +class ZoneFile_COD5_PC : public ZoneFile +{ +public: + ZoneFile_COD5_PC(); + ~ZoneFile_COD5_PC(); + + bool Load(const QByteArray aFileData) override; + AssetType AssetStrToEnum(const QString aAssetType) override; + + QByteArray GetBinaryData() override; + +private: + void pParseZoneHeader(QDataStream *aZoneFileStream) override; + quint32 pParseZoneSize(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsA(QDataStream *aZoneFileStream) override; + quint32 pParseZoneTagCount(QDataStream *aZoneFileStream) override; + quint32 pParseZoneRecordCount(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsB(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsC(QDataStream *aZoneFileStream) override; + QStringList pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) override; + QStringList pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) override; + AssetMap pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) override; + LocalString pParseAsset_LocalString(QDataStream *aZoneFileStream) override; + RawFile pParseAsset_RawFile(QDataStream *aZoneFileStream) override; + void pParseAsset_PhysPreset(QDataStream *aZoneFileStream) override; + Model pParseAsset_Model(QDataStream *aZoneFileStream) override; + Material pParseAsset_Material(QDataStream *aZoneFileStream) override; + Shader pParseAsset_Shader(QDataStream *aZoneFileStream) override; + TechSet pParseAsset_TechSet(QDataStream *aZoneFileStream) override; + Image pParseAsset_Image(QDataStream *aZoneFileStream) override; + SoundAsset pParseAsset_Sound(QDataStream *aZoneFileStream) override; + void pParseAsset_ColMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapSP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_LightDef(QDataStream *aZoneFileStream) override; + void pParseAsset_UIMap(QDataStream *aZoneFileStream) override; + void pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) override; + void pParseAsset_AIType(QDataStream *aZoneFileStream) override; + void pParseAsset_FX(QDataStream *aZoneFileStream) override; + Animation pParseAsset_Animation(QDataStream *aZoneFileStream) override; + MenuFile pParseAsset_MenuFile(QDataStream *aZoneFileStream) override; + void pParseAsset_Weapon(QDataStream *aZoneFileStream) override; + void pParseAsset_D3DBSP(QDataStream *aZoneFileStream) override; + StringTable pParseAsset_StringTable(QDataStream *aZoneFileStream) override; +}; + +#endif // ZONEFILE_COD5_PC_H diff --git a/libs/zonefile/PC/zonefile_cod6_pc.cpp b/libs/zonefile/PC/zonefile_cod6_pc.cpp new file mode 100644 index 0000000..1b2dfb6 --- /dev/null +++ b/libs/zonefile/PC/zonefile_cod6_pc.cpp @@ -0,0 +1,1140 @@ +#include "zonefile_cod6_pc.h" + +#include +#include +#include + +ZoneFile_COD6_PC::ZoneFile_COD6_PC() + : ZoneFile() { + +} + +ZoneFile_COD6_PC::~ZoneFile_COD6_PC() { + +} + +bool ZoneFile_COD6_PC::Load(const QByteArray aFileData) { + // Open zone file as little endian stream + QDataStream zoneFileStream(aFileData); + zoneFileStream.setByteOrder(QDataStream::LittleEndian); + + + // Parse data from zone file header + pParseZoneHeader(&zoneFileStream); + SetRecords(pParseZoneIndex(&zoneFileStream, GetRecordCount())); + SetAssetMap(pParseAssets(&zoneFileStream, GetRecords())); + + return true; +} + +void ZoneFile_COD6_PC::pParseZoneHeader(QDataStream *aZoneFileStream) { + SetSize(pParseZoneSize(aZoneFileStream)); + pParseZoneUnknownsA(aZoneFileStream); + + SetTagCount(pParseZoneTagCount(aZoneFileStream)); + pParseZoneUnknownsB(aZoneFileStream); + + SetRecordCount(pParseZoneRecordCount(aZoneFileStream)); + + quint32 tagCount = GetTagCount(); + if (tagCount) { + pParseZoneUnknownsC(aZoneFileStream); + SetTags(pParseZoneTags(aZoneFileStream, tagCount)); + } else { + aZoneFileStream->skipRawData(4); + } +} + +quint32 ZoneFile_COD6_PC::pParseZoneSize(QDataStream *aZoneFileStream) { + quint32 zoneFileSize; + *aZoneFileStream >> zoneFileSize; + if (zoneFileSize <= 0) { + qDebug() << "Tried to open empty zone file!"; + exit(-1); + } + zoneFileSize += 36; + return zoneFileSize; +} + +/* + ParseZoneUnknownsA() + + Parses the 1st section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD6_PC::pParseZoneUnknownsA(QDataStream *aZoneFileStream) { + // Byte 4-7, 8-11, 12-15: unknown + QByteArray unknown1(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown1.data(), 4); + + QByteArray unknown2(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown2.data(), 4); + + QByteArray unknown3(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown3.data(), 4); + + // Byte 16-19, 20-23: empty/unknown + QByteArray unknown4(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown4.data(), 4); + + QByteArray unknown5(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown5.data(), 4); + + // Byte 24-27: somehow related to the filesize, but smaller value + QByteArray unknown6(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown6.data(), 4); + + // Byte 28-31, 32-35: unknown + QByteArray unknown7(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown7.data(), 4); + + QByteArray unknown8(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown8.data(), 4); +} + +/* + ParseZoneTagCount() + + Parses the number of string tags in the zone index +*/ +quint32 ZoneFile_COD6_PC::pParseZoneTagCount(QDataStream *aZoneFileStream) { + quint32 tagCount; + *aZoneFileStream >> tagCount; + return tagCount; +} + +/* + ParseZoneRecordCount() + + Parses the number of records in the zone index +*/ +quint32 ZoneFile_COD6_PC::pParseZoneRecordCount(QDataStream *aZoneFileStream) { + quint32 recordCount; + *aZoneFileStream >> recordCount; + return recordCount; +} + +/* + ParseZoneUnknownsB() + + Parses the 2nd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD6_PC::pParseZoneUnknownsB(QDataStream *aZoneFileStream) { + // Byte 44-47: Unknown/empty? + QByteArray unknown9(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown9.data(), 4); +} + +/* + pParseZoneUnknownsC() + + Parses the 3rd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD6_PC::pParseZoneUnknownsC(QDataStream *aZoneFileStream) { + // Byte 40-43: Unknown/empty? + QByteArray unknown10(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown10.data(), 4); + + // Byte 44-47: Unknown/empty? + QByteArray unknown11(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown11.data(), 4); +} + +/* + ParseZoneTags() + + Parses the string tags ate the start of zone file +*/ +QStringList ZoneFile_COD6_PC::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) { + QStringList tags; + + // Byte 48-51: Repeated separators? ÿÿÿÿ x i + aZoneFileStream->skipRawData(4 * (tagCount - 1)); + + // Parse tags/strings before index + QString zoneTag; + char zoneTagChar; + for (quint32 i = 0; i < tagCount; i++) { + *aZoneFileStream >> zoneTagChar; + while (zoneTagChar != 0) { + zoneTag += zoneTagChar; + *aZoneFileStream >> zoneTagChar; + } + tags << zoneTag; + zoneTag.clear(); + } + return tags; +} + +/* + ParseZoneIndex() + + Parse the binary zone index data and populate table +*/ +QStringList ZoneFile_COD6_PC::pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) { + QStringList result; + + // Don't parse if no records + if (!recordCount) { return result; } + + if (aZoneFileStream->device()->peek(4).toHex().contains("ffff")) { + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 2); + } + + // Parse index & map found asset types + for (quint32 i = 0; i <= recordCount; i++) { + // Skip record start + QByteArray rawAssetType(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rawAssetType.data(), 4); + result << rawAssetType.toHex(); + + // Skip separator + aZoneFileStream->skipRawData(4); + } + return result; +} + +AssetMap ZoneFile_COD6_PC::pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) { + AssetMap result; + + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 8); + + for (int i = 0; i < assetOrder.size(); i++) { + const QString typeHex = assetOrder[i]; + const AssetType typeStr = AssetStrToEnum(typeHex); + + if (typeStr == ASSET_LOCAL_STRING) { // localized string asset + result.localStrings << pParseAsset_LocalString(aZoneFileStream); + } else if (typeStr == ASSET_RAW_FILE) { // gsc + auto rawFile = pParseAsset_RawFile(aZoneFileStream); + if (rawFile.length) { + result.rawFiles << rawFile; + } + } else if (typeStr == ASSET_PHYS_PRESET) { // physpreset + pParseAsset_PhysPreset(aZoneFileStream); + } else if (typeStr == ASSET_MODEL) { // xmodel + result.models << pParseAsset_Model(aZoneFileStream); + } else if (typeStr == ASSET_MATERIAL) { // material + pParseAsset_Material(aZoneFileStream); + } else if (typeStr == ASSET_SHADER) { // pixelshader + pParseAsset_Shader(aZoneFileStream); + } else if (typeStr == ASSET_TECH_SET) { // techset include + result.techSets << pParseAsset_TechSet(aZoneFileStream); + } else if (typeStr == ASSET_IMAGE) { // image + result.images << pParseAsset_Image(aZoneFileStream); + } else if (typeStr == ASSET_SOUND) { // loaded_sound + result.sounds << pParseAsset_Sound(aZoneFileStream); + } else if (typeStr == ASSET_COLLISION_MAP) { // col_map_mp + pParseAsset_ColMapMP(aZoneFileStream); + } else if (typeStr == ASSET_MP_MAP) { // game_map_sp + pParseAsset_GameMapSP(aZoneFileStream); + } else if (typeStr == ASSET_SP_MAP) { // game_map_mp + pParseAsset_GameMapMP(aZoneFileStream); + } else if (typeStr == ASSET_LIGHT_DEF) { // lightdef + pParseAsset_LightDef(aZoneFileStream); + } else if (typeStr == ASSET_UI_MAP) { // ui_map + pParseAsset_UIMap(aZoneFileStream); + } else if (typeStr == ASSET_SND_DRIVER_GLOBALS) { // snddriverglobals + pParseAsset_SNDDriverGlobals(aZoneFileStream); + } else if (typeStr == ASSET_AI_TYPE) { // aitype + pParseAsset_AIType(aZoneFileStream); + } else if (typeStr == ASSET_EFFECT) { // aitype + pParseAsset_FX(aZoneFileStream); + } else if (typeStr == ASSET_ANIMATION) { // aitype + result.animations << pParseAsset_Animation(aZoneFileStream); + } else if (typeStr == ASSET_STRING_TABLE) { // string_table + result.stringTables << pParseAsset_StringTable(aZoneFileStream); + } else if (typeStr == ASSET_MENU) { // string_table + result.menuFiles << pParseAsset_MenuFile(aZoneFileStream); + } else if (typeStr == ASSET_WEAPON) { // string_table + pParseAsset_Weapon(aZoneFileStream); + } else if (typeStr == ASSET_D3DBSP) { // string_table + pParseAsset_D3DBSP(aZoneFileStream); + } + } + return result; +} + +LocalString ZoneFile_COD6_PC::pParseAsset_LocalString(QDataStream *aZoneFileStream) { + LocalString result; + + quint32 stringPtr, aliasPtr; + *aZoneFileStream >> stringPtr >> aliasPtr; + if (stringPtr == 4294967295) { + // Parse local string asset contents + QString localStr; + char localStrChar; + *aZoneFileStream >> localStrChar; + while (localStrChar != 0) { + result.string += localStrChar; + *aZoneFileStream >> localStrChar; + } + } else { + result.string = "String Ptr: " + QString::number(stringPtr); + } + + if (aliasPtr == 4294967295) { + // Parse rawfile name + QString aliasName; + char aliasNameChar; + *aZoneFileStream >> aliasNameChar; + while (aliasNameChar != 0) { + result.alias += aliasNameChar; + *aZoneFileStream >> aliasNameChar; + } + } else { + result.string = "Alias Ptr: " + QString::number(aliasPtr); + } + + return result; +} + +RawFile ZoneFile_COD6_PC::pParseAsset_RawFile(QDataStream *aZoneFileStream) { + RawFile result; + + // Skip start separator FF FF FF FF (pointer?) + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.length; + + // Skip unknown 4 byte data + aZoneFileStream->skipRawData(4); + + // Parse rawfile path + char scriptPathChar; + *aZoneFileStream >> scriptPathChar; + while (scriptPathChar != 0) { + result.path += scriptPathChar; + *aZoneFileStream >> scriptPathChar; + } + result.path.replace(",", ""); + + const QStringList pathParts = result.path.split('/'); + if (pathParts.size() == 0) { + qDebug() << "Failed to parse ff path! " << result.path; + exit(-1); + } + if (result.path.contains(".bik")) { + qDebug() << "rawFileLength: " << result.length; + QByteArray bikData(result.length, Qt::Uninitialized); + aZoneFileStream->readRawData(bikData.data(), result.length); + + //QFile bikFile(QDir::currentPath() + "/" + rawFilePath.split('/').last()); + //qDebug() << bikFile.fileName(); + //if (!bikFile.open(QIODevice::WriteOnly)) { + // qWarning() << "Failed to open .bik file for writing!"; + // return; + //} + //qDebug() << QString("%1: %2").arg(rawFilePath).arg(bikFile.fileName()); + //bikFile.write(bikData); + } else { + // Parse gsc contents + char rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + while (rawFileContentsChar != 0 && rawFileContentsChar != -1) { + result.contents += rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + } + } + return result; +} + +void ZoneFile_COD6_PC::pParseAsset_PhysPreset(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Model ZoneFile_COD6_PC::pParseAsset_Model(QDataStream *aZoneFileStream) { + Model result; + + *aZoneFileStream >> result.namePtr >> result.tagCount >> result.rootTagCount + >> result.surfCount >> result.unknownCount >> result.boneNamePtr + >> result.parentListPtr >> result.quatsPtr >> result.transPtr + >> result.partClassPtr >> result.baseMatPtr + >> result.surfsPtr >> result.materialHandlesPtr; + + // Parse XModelLodInfo + for (int i = 1; i <= 4; i++) { + quint32 intDist; + *aZoneFileStream >> intDist; + + std::memcpy(&result.lodInfo[i].dist, &intDist, sizeof(result.lodInfo[i].dist)); + *aZoneFileStream >> result.lodInfo[i].numsurfs >> result.lodInfo[i].surfIndex; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.lodInfo[i].partBits[0] + >> result.lodInfo[i].partBits[1] + >> result.lodInfo[i].partBits[2] + >> result.lodInfo[i].partBits[3]; + } + + *aZoneFileStream >> result.collSurfsPtr >> result.numCollSurfs >> result.contents >> result.boneInfoPtr; + + quint32 intRadius, intMins[3], intMaxs[3]; + *aZoneFileStream >> intRadius >> intMins[0] >> intMins[1] + >> intMins[2] >> intMaxs[0] >> intMaxs[1] >> intMaxs[2]; + + std::memcpy(&result.radius, &intRadius, sizeof(result.radius)); + + std::memcpy(&result.mins[0], &intMins[0], sizeof(result.mins[0])); + std::memcpy(&result.mins[1], &intMins[1], sizeof(result.mins[1])); + std::memcpy(&result.mins[2], &intMins[2], sizeof(result.mins[2])); + + std::memcpy(&result.maxs[0], &intMaxs[0], sizeof(result.maxs[0])); + std::memcpy(&result.maxs[1], &intMaxs[1], sizeof(result.maxs[2])); + std::memcpy(&result.maxs[2], &intMaxs[2], sizeof(result.maxs[3])); + + *aZoneFileStream >> result.numLods >> result.collLod >> result.streamInfoPtr + >> result.memUsage >> result.flags >> result.physPresetPtr >> result.physGeomsPtr; + + // Parse model name + char modelNameChar; + *aZoneFileStream >> modelNameChar; + while (modelNameChar == 0) { + *aZoneFileStream >> modelNameChar; + } + while (modelNameChar != 0) { + result.modelName += modelNameChar; + *aZoneFileStream >> modelNameChar; + } + return result; +} + +Material ZoneFile_COD6_PC::pParseAsset_Material(QDataStream *aZoneFileStream) { + aZoneFileStream->skipRawData(27 * 4); + + qint32 materialNamePtr; + *aZoneFileStream >> materialNamePtr; + if (materialNamePtr == -1) { + QString materialName; + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + } + + aZoneFileStream->skipRawData(3 * 4); + + qint32 compressionPtr, compression, unknownSectionPtr; + *aZoneFileStream >> compressionPtr; + if (compressionPtr == -1) { + *aZoneFileStream >> compression; + + *aZoneFileStream >> unknownSectionPtr; + if (unknownSectionPtr == -2) { + aZoneFileStream->skipRawData(6 * 4); + } + } + + qint32 imageNamePtr; + *aZoneFileStream >> imageNamePtr; + if (imageNamePtr == -1) { + QString imageName; + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + imageName += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + } + + QByteArray compressionData(4, Qt::Uninitialized); + QString compressionStr; + if (compressionPtr == -1) { + aZoneFileStream->skipRawData(2 * 4); + aZoneFileStream->readRawData(compressionData.data(), 4); + aZoneFileStream->skipRawData(4); + compressionStr = QString::fromUtf8(compressionData); + aZoneFileStream->skipRawData(4); + } + aZoneFileStream->skipRawData(4); + + // TODO: Fill out this material + return Material(); +} + +Shader ZoneFile_COD6_PC::pParseAsset_Shader(QDataStream *aZoneFileStream) { + Shader result = Shader(); + + quint8 minorVersion, majorVersion; + *aZoneFileStream >> minorVersion >> majorVersion; + + quint32 magic; + *aZoneFileStream >> magic; + + // Verify .fxc magic + if (magic != 65534 && magic != 65535) { return result; } + + SHADER_TYPE type = SHADER_NONE; + quint16 rawShaderType; + *aZoneFileStream >> rawShaderType; + if (rawShaderType == 65535) { // Pixel shader + type = SHADER_PIXEL; + } else if (rawShaderType == 65534) { // Vertex shader + type = SHADER_VERTEX; + } + Q_UNUSED(type); + + while (true) { + quint32 instructionToken; + *aZoneFileStream >> instructionToken; + + SHADER_OPCODE opCode = (SHADER_OPCODE)(instructionToken & 0xffff); + + int size; + if (opCode == OPCODE_End) { + break; + } else if (opCode == OPCODE_Comment) { + size = (int)((instructionToken >> 16) & 0x7FFF); + } else { + size = (int)((instructionToken >> 24) & 0x0f); + } + Q_UNUSED(size); + } + + + return result; +} + +TechSet ZoneFile_COD6_PC::pParseAsset_TechSet(QDataStream *aZoneFileStream) { + TechSet result; + + for (int i = 1; i <= 62; i++) { + quint32 ptr; + *aZoneFileStream >> ptr; + + result.pointers << ptr; + } + qDebug() << aZoneFileStream->device()->pos(); + + // Parse techset name + char techSetNameChar; + *aZoneFileStream >> techSetNameChar; + while (techSetNameChar != 0) { + result.name += techSetNameChar; + *aZoneFileStream >> techSetNameChar; + } + result.name.replace(",", ""); + + return result; +} + +Image ZoneFile_COD6_PC::pParseAsset_Image(QDataStream *aZoneFileStream) { + Image result; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknowna >> result.unknownb + >> result.unknownc >> result.unknownd + >> result.unknowne >> result.unknownf + >> result.unknowng; + + aZoneFileStream->skipRawData(15 * 4); + *aZoneFileStream >> result.unknownh >> result.unknowni; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknownj; + + aZoneFileStream->skipRawData(4); + + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + result.materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + result.materialName.replace(",", ""); + + if (result.unknowna) { + *aZoneFileStream >> result.unknownk; + *aZoneFileStream >> result.unknownl; + *aZoneFileStream >> result.unknownm; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown1; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown2 >> result.unknown3 + >> result.size1 >> result.size2 + >> result.unknown4 >> result.unknown5; + + aZoneFileStream->skipRawData(4); + + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + result.name += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + + *aZoneFileStream >> result.unknown6 >> result.unknown7; + + QByteArray compressionData(8, Qt::Uninitialized); + aZoneFileStream->readRawData(compressionData.data(), 8); + if (compressionData.contains("DXT1")) { + result.compression = COMPRESSION_DXT1; + } else if (compressionData.contains("DXT3")) { + result.compression = COMPRESSION_DXT3; + } else if (compressionData.contains("DXT5")) { + result.compression = COMPRESSION_DXT5; + } else { + result.compression = COMPRESSION_NONE; + } + + *aZoneFileStream >> result.unknown8 >> result.unknown9; + } + + return result; +} + +SoundAsset ZoneFile_COD6_PC::pParseAsset_Sound(QDataStream *aZoneFileStream) { + SoundAsset result; + + qDebug() << aZoneFileStream->device()->pos(); + + QByteArray rootNamePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rootNamePtr.data(), 4); + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.count; + + if (rootNamePtr.toHex() == "ffffffff") { + // Read in sound file name + char soundNameChar; + *aZoneFileStream >> soundNameChar; + while (soundNameChar != 0) { + result.name += soundNameChar; + *aZoneFileStream >> soundNameChar; + } + } + + int tagCount = 0; + int resultCount = 0; + for (quint32 i = 0; i < result.count; i++) { + aZoneFileStream->skipRawData(12); + + QByteArray tagPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(tagPtr.data(), 4); + + if (tagPtr.toHex() == "ffffffff") { + tagCount++; + } + aZoneFileStream->skipRawData(4); + + QByteArray pathPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pathPtr.data(), 4); + + if (pathPtr.toHex() == "ffffffff") { + resultCount++; + } + + aZoneFileStream->skipRawData(160); + } + + for (int i = 0; i < tagCount; i++) { + // Read in tag? + QString tag; + char tagChar; + *aZoneFileStream >> tagChar; + while (tagChar != 0) { + tag += tagChar; + *aZoneFileStream >> tagChar; + } + } + + for (int i = 0; i < resultCount; i++) { + Sound sound; + + if (aZoneFileStream->device()->peek(12).toHex().contains("ffffffff00000000")) { + aZoneFileStream->skipRawData(12); + } + + aZoneFileStream->skipRawData(8); + + QByteArray aliasPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(aliasPtr.data(), 4); + + QByteArray namePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(namePtr.data(), 4); + + *aZoneFileStream >> sound.dataLength; + + if (aliasPtr.toHex() == "ffffffff") { + // Read in sound alias name + char soundAliasChar; + *aZoneFileStream >> soundAliasChar; + while (soundAliasChar != 0) { + sound.alias += soundAliasChar; + *aZoneFileStream >> soundAliasChar; + } + } + + if (aZoneFileStream->device()->peek(4) == "RIFF") { + sound.path = sound.alias; + sound.alias = ""; + } else if (namePtr.toHex() == "ffffffff") { + // Read in sound file path + char soundPathChar; + *aZoneFileStream >> soundPathChar; + while (soundPathChar != 0) { + sound.path += soundPathChar; + *aZoneFileStream >> soundPathChar; + } + sound.path.replace(",", ""); + } + + if (sound.dataLength) { + QByteArray data(sound.dataLength, Qt::Uninitialized); + aZoneFileStream->readRawData(data.data(), sound.dataLength); + sound.data = data; + } + result.sounds.append(sound); + } + + return result; +} + +void ZoneFile_COD6_PC::pParseAsset_ColMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD6_PC::pParseAsset_GameMapSP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD6_PC::pParseAsset_GameMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD6_PC::pParseAsset_LightDef(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD6_PC::pParseAsset_UIMap(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD6_PC::pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD6_PC::pParseAsset_AIType(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD6_PC::pParseAsset_FX(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Animation ZoneFile_COD6_PC::pParseAsset_Animation(QDataStream *aZoneFileStream) { + Animation result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.dataByteCount + >> result.dataShortCount + >> result.dataIntCount + >> result.randomDataByteCount + >> result.randomDataIntCount + >> result.numframes + >> result.isLooped + >> result.isDelta + >> result.noneRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.normalTranslatedBoneCount + >> result.preciseTranslatedBoneCount + >> result.staticTranslatedBoneCount + >> result.noneTranslatedBoneCount + >> result.totalBoneCount + >> result.otherBoneCount1 + >> result.otherBoneCount2 + >> result.notifyCount + >> result.assetType + >> result.pad + >> result.randomDataShortCount + >> result.indexCount + >> result.frameRate + >> result.frequency + >> result.boneIDsPtr + >> result.dataBytePtr + >> result.dataShortPtr + >> result.dataIntPtr + >> result.randomDataShortPtr + >> result.randomDataBytePtr + >> result.randomDataIntPtr + >> result.longIndiciesPtr + >> result.notificationsPtr + >> result.deltaPartsPtr; + + // Read in x_anim file name + QString xAnimName; + char xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + while (xAnimNameChar != 0) { + result.name += xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + } + + // Parse x_anim index header + QVector sectionLengths; + for (int i = 0; i < result.numframes; i++) { + quint8 sectionlength; + *aZoneFileStream >> sectionlength; + sectionLengths.push_back(sectionlength); + // Skip padding + aZoneFileStream->skipRawData(1); + } + // Skip unknown section + aZoneFileStream->skipRawData(2 * 8); + + return result; +} + +MenuFile ZoneFile_COD6_PC::pParseAsset_MenuFile(QDataStream *aZoneFileStream) { + //MENU_FILE + MenuFile result; + + aZoneFileStream->skipRawData(4); // Separator + + // Parse menu def count + *aZoneFileStream >> result.menuCount; + + // Clearly misparsed, never have this much + if (result.menuCount > 1000) { + qDebug() << "Failure reported when parsing menu file."; + return result; + } + for (uint i = 0; i < result.menuCount; i++) { + Menu menu; + + aZoneFileStream->skipRawData(4); // Separator + + // Read in x_anim file name + char menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + while (menuFilepathChar != 0) { + menu.filePath += menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + } + aZoneFileStream->skipRawData(4); // Separator + + *aZoneFileStream >> menu.menuNamePtr; + + float menuRectX, menuRectY, menuRectWidth, menuRectHeight; + *aZoneFileStream >> menuRectX >> menuRectY >> menuRectWidth >> menuRectHeight; + menu.rect = QRectF(menuRectX, menuRectY, menuRectWidth, menuRectHeight); + + quint32 hAlignInt, vAlignInt; + *aZoneFileStream >> hAlignInt >> vAlignInt; + menu.hAlign = (MENU_H_ALIGNMENT)hAlignInt; + menu.vAlign = (MENU_V_ALIGNMENT)vAlignInt; + + float rectClientX, rectClientY, rectClientWidth, rectClientHeight; + *aZoneFileStream >> rectClientX >> rectClientY >> rectClientWidth >> rectClientHeight; + menu.clientRect = QRectF(rectClientX, rectClientY, rectClientWidth, rectClientHeight); + + quint32 hClientAlignInt, vClientAlignInt, styleInt, borderInt; + *aZoneFileStream >> hClientAlignInt >> vClientAlignInt >> menu.groupPtr + >> styleInt >> borderInt >> menu.ownerDraw >> menu.ownerDrawFlags + >> menu.borderSize >> menu.staticFlags >> menu.dynamicFlags >> menu.nextTime; + menu.hClientAlign = (MENU_H_ALIGNMENT)hClientAlignInt; + menu.vClientAlign = (MENU_V_ALIGNMENT)vClientAlignInt; + menu.style = (MENU_WINDOW_STYLE)styleInt; + menu.border = (MENU_WINDOW_BORDER)borderInt; + + float foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA, + backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA, + borderColorR, borderColorG, borderColorB, borderColorA, + outlineColorR, outlineColorG, outlineColorB, outlineColorA; + *aZoneFileStream >> foregroundColorR >> foregroundColorG >> foregroundColorB >> foregroundColorA + >> backgroundColorR >> backgroundColorG >> backgroundColorB >> backgroundColorA + >> borderColorR >> borderColorG >> borderColorB >> borderColorA + >> outlineColorR >> outlineColorG >> outlineColorB >> outlineColorA; + + menu.foregroundColor = QColor(foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA); + menu.backgroundColor = QColor(backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA); + menu.borderColor = QColor(borderColorR, borderColorG, borderColorB, borderColorA); + menu.outlineColor = QColor(outlineColorR, outlineColorG, outlineColorB, outlineColorA); + + *aZoneFileStream >> menu.materialPtr >> menu.fontPtr >> menu.fullScreen >> menu.itemCount + >> menu.fontIndex >> menu.cursorItem >> menu.fadeCycle >> menu.fadeClamp + >> menu.fadeAmount >> menu.fadeInAmount >> menu.blurRadius >> menu.onOpenPtr + >> menu.onFocusPtr >> menu.onClosePtr >> menu.onESCPtr >> menu.onKeyPtr + >> menu.visibleExpCount >> menu.expEntryPtr >> menu.allowedBindingPtr + >> menu.soundNamePtr >> menu.imageTrack; + + float focusColorR, focusColorG, focusColorB, focusColorA, + disabledColorR, disabledColorG, disabledColorB, disabledColorA; + *aZoneFileStream >> focusColorR >> focusColorG >> focusColorB >> focusColorA + >> disabledColorR >> disabledColorG >> disabledColorB >> disabledColorA; + menu.focusColor = QColor(focusColorR, focusColorG, focusColorB, focusColorA); + menu.disabledColor = QColor(disabledColorR, disabledColorG, disabledColorB, disabledColorA); + + *aZoneFileStream >> menu.rectXExpCount >> menu.rectXExpPtr >> menu.rectYExpCount >> menu.rectYExpPtr; + + aZoneFileStream->skipRawData(4); // Separator + + char menuDefNameChar; + int menuDefNameLen = 0; + *aZoneFileStream >> menuDefNameChar; + while (menuDefNameChar != 0 && menuDefNameLen < 30) { + menuDefNameLen++; + menu.name += menuDefNameChar; + *aZoneFileStream >> menuDefNameChar; + } + + char defStringChar; + int defStringLen = 0; + *aZoneFileStream >> defStringChar; + while (defStringChar != 0 && defStringLen < 30) { + defStringLen++; + menu.definition += defStringChar; + *aZoneFileStream >> defStringChar; + } + aZoneFileStream->skipRawData(4 * 10); + + *aZoneFileStream >> menu.itemWindowDefNamePtr; + + float itemRectX, itemRectY, itemRectWidth, itemRectHeight; + *aZoneFileStream >> itemRectX >> itemRectY >> itemRectWidth >> itemRectHeight; + menu.itemRect = QRectF(itemRectX, itemRectY, itemRectWidth, itemRectHeight); + + *aZoneFileStream >> menu.itemHAlignment >> menu.itemVAlignment >> menu.itemGroupPtr + >> menu.itemWindowStyle >> menu.itemWindowBorder >> menu.itemOwnerDraw + >> menu.itemOwnerDrawFlags >> menu.itemBorderSize >> menu.itemStaticFlags + >> menu.itemDynamicFlags >> menu.itemNextTime; + + float itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA, + itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA, + itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA, + itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA; + *aZoneFileStream >> itemForegroundColorR >> itemForegroundColorG >> itemForegroundColorB >> itemForegroundColorA + >> itemBackgroundColorR >> itemBackgroundColorG >> itemBackgroundColorB >> itemBackgroundColorA + >> itemBorderColorR >> itemBorderColorG >> itemBorderColorB >> itemBorderColorA + >> itemOutlineColorR >> itemOutlineColorG >> itemOutlineColorB >> itemOutlineColorA; + + menu.itemForegroundColor = QColor(itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA); + menu.itemBackgroundColor = QColor(itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA); + menu.itemBorderColor = QColor(itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA); + menu.itemOutlineColor = QColor(itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA); + + *aZoneFileStream >> menu.itemMaterialPtr; + + float itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight; + *aZoneFileStream >> itemTextRectX >> itemTextRectY >> itemTextRectWidth >> itemTextRectHeight; + menu.itemTextRect = QRectF(itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight); + + quint32 hItemTextAlignInt, vItemTextAlignInt, itemType, fontTypeInt, textStyleInt; + *aZoneFileStream >> hItemTextAlignInt >> vItemTextAlignInt >> itemType >> menu.dataType + >> menu.alignment >> fontTypeInt >> menu.textAlignMode >> menu.textalignx >> menu.textaligny + >> menu.textscale >> textStyleInt >> menu.gameMsgWindowIndex >> menu.gameMsgWindowMode + >> menu.testPtr >> menu.textSavegameInfo >> menu.parentPtr; + menu.itemText_hAlign = (MENU_H_ALIGNMENT)hItemTextAlignInt; + menu.itemText_vAlign = (MENU_V_ALIGNMENT)vItemTextAlignInt; + menu.itemType = (MENU_ITEM_TYPE)itemType; + menu.fontEnum = (MENU_FONT_TYPE)fontTypeInt; + menu.textStyle = (MENU_ITEM_TEXTSTYLE)textStyleInt; + + *aZoneFileStream >> menu.mouseEnterText >> menu.mouseExitText >> menu.mouseEnter >> menu.mouseExit + >> menu.action >> menu.onAccept >> menu.onFocus >> menu.leaveFocus >> menu.dvar >> menu.dvarTest + >> menu.keyHandlerPtr >> menu.enableDvarPtr >> menu.dvarFlags >> menu.focusSoundPtr + >> menu.special >> menu.cursorPos; + + // itemDefData_t typeData; + + // listBoxDef_s *listBox; + + *aZoneFileStream >> menu.startPos >> menu.endPos >> menu.drawPadding; + + *aZoneFileStream >> menu.elementWidth >> menu.elementHeight; + + *aZoneFileStream >> menu.elementStyle >> menu.numColumns; + + //columnInfo_s columnInfo[16]; + + *aZoneFileStream >> menu.doubleClickPtr; + + + *aZoneFileStream >> menu.notselectable >> menu.noScrollBars >> menu.usePaging; + + float itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA, + itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA, + itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA; + *aZoneFileStream >> itemSelectBorderColorR >> itemSelectBorderColorG >> itemSelectBorderColorB >> itemSelectBorderColorA + >> itemDisableColorR >> itemDisableColorG >> itemDisableColorB >> itemDisableColorA + >> itemFocusColorR >> itemFocusColorG >> itemFocusColorB >> itemFocusColorA; + menu.itemSelectBorderColor = QColor(itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA); + menu.itemDisableColor = QColor(itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA); + menu.itemFocusColor = QColor(itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA); + + *aZoneFileStream >> menu.selectIconPtr >> menu.backgroundItemListboxPtr >> menu.highlightTexturePtr; + + // editFieldDef_s *editField; + + *aZoneFileStream >> menu.minVal >> menu.maxVal >> menu.defVal >> menu.range >> menu.maxChars + >> menu.maxCharsGotoNext >> menu.maxPaintChars >> menu.paintOffset; + + // multiDef_s *multi; + + for (int i = 0; i < 32; i++) { + quint32 dvarList; + *aZoneFileStream >> dvarList; + menu.dvarListPtrs.push_back(dvarList); + } + + for (int i = 0; i < 32; i++) { + quint32 dvarStr; + *aZoneFileStream >> dvarStr; + menu.dvarStrPtrs.push_back(dvarStr); + } + + for (int i = 0; i < 32; i++) { + float dvarValue; + *aZoneFileStream >> dvarValue; + menu.dvarValues.push_back(dvarValue); + } + + *aZoneFileStream >> menu.count >> menu.strDef >> menu.enumDvarNamePtr; + aZoneFileStream->skipRawData(4); + //>> menu.dataPtr + *aZoneFileStream >> menu.itemImageTrack; + + qDebug() << aZoneFileStream->device()->pos(); + + //statement_s visibleExp; + //statement_s textExp; + //statement_s materialExp; + //statement_s rectXExp; + //statement_s rectYExp; + //statement_s rectWExp; + //statement_s rectHExp; + //statement_s foreColorAExp; + result.menuDefs << menu; + } + return result; +} + +void ZoneFile_COD6_PC::pParseAsset_Weapon(QDataStream *aZoneFileStream) { + //WEAPON_FILE + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD6_PC::pParseAsset_D3DBSP(QDataStream *aZoneFileStream) { + //D3DBSP_DUMP + Q_UNUSED(aZoneFileStream); +} + +StringTable ZoneFile_COD6_PC::pParseAsset_StringTable(QDataStream *aZoneFileStream) { + StringTable result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.columnCount + >> result.rowCount; + + // Todo fix this + result.columnCount = 0; + result.rowCount = 0; + + aZoneFileStream->skipRawData(4); + + QString stringTableName; + char stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + while (stringTableNameChar != 0) { + result.name += stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + } + + for (quint32 i = 0; i < result.rowCount; i++) { + QByteArray pointerData(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pointerData.data(), 4); + result.tablePointers.push_back(pointerData.toHex()); + + aZoneFileStream->skipRawData(4); + } + + for (const QString &pointerAddr : result.tablePointers) { + QString leadingContent = ""; + if (pointerAddr == "FFFFFFFF") { + char leadingContentChar; + *aZoneFileStream >> leadingContentChar; + while (leadingContentChar != 0) { + leadingContent += leadingContentChar; + *aZoneFileStream >> leadingContentChar; + } + } else { + leadingContent = pointerAddr; + } + + QString content; + char contentChar; + *aZoneFileStream >> contentChar; + while (contentChar != 0) { + content += contentChar; + *aZoneFileStream >> contentChar; + } + result.content[leadingContent] = content; + } + return result; +} + +AssetType ZoneFile_COD6_PC::AssetStrToEnum(const QString aAssetType) { + const QString cleanedType = aAssetType.toUpper(); + if (cleanedType == "17000000") { // localized string PARTIALLY VERIFIED + return ASSET_RAW_FILE; + } else if (cleanedType == "20000000") { // raw_file PARTIALLY VERIFIED + return ASSET_SCRIPT_PARSE_TREE; + } else if (cleanedType == "1A000000") { // fx PARTIALLY VERIFIED + return ASSET_EFFECT; + } else if (cleanedType == "09000000") { // loaded_sound PARTIALLY VERIFIED + return ASSET_SOUND; + } else if (cleanedType == "04000000") { // x_anim PARTIALLY VERIFIED + return ASSET_ANIMATION; + } else if (cleanedType == "0C000000") { // collision_map PARTIALLY VERIFIED + return ASSET_COLLISION_MAP; + } else if (cleanedType == "21000000") { // string_table PARTIALLY VERIFIED + return ASSET_STRING_TABLE; + } else if (cleanedType == "15000000") { // menu_file PARTIALLY VERIFIED + return ASSET_MENU; + } else if (cleanedType == "07000000") { // tech set PARTIALLY VERIFIED + return ASSET_TECH_SET; + } else if (cleanedType == "18000000") { // weapon PARTIALLY VERIFIED + return ASSET_WEAPON; + } else if (cleanedType == "11000000") { // gfx map PARTIALLY VERIFIED + return ASSET_GFX_MAP; + } else if (cleanedType == "12000000") { // light_def PARTIALLY VERIFIED + return ASSET_LIGHT_DEF; + } else if (cleanedType == "14000000") { // font PARTIALLY VERIFIED + return ASSET_FONT; + } else if (cleanedType == "05000000") { // xmodel PARTIALLY VERIFIED + return ASSET_MODEL; + } else if (cleanedType == "0D000000") { // d3dbsp PARTIALLY VERIFIED + return ASSET_D3DBSP; + } else if (cleanedType == "06000000") { // image PARTIALLY VERIFIED + return ASSET_IMAGE; + } else if (cleanedType == "0E000000") { // game map sp PARTIALLY VERIFIED + return ASSET_GAME_MAP_SP; + } else if (cleanedType == "0B000000") { // col map sp PARTIALLY VERIFIED + return ASSET_COL_MAP_SP; + } else if (cleanedType == "01000000") { // physics preset PARTIALLY VERIFIED + return ASSET_PHYS_PRESET; + } else if (cleanedType == "03000000") { // destructible def PARTIALLY VERIFIED + return ASSET_DESTRUCTIBLE; + } + return ASSET_NONE; +} + +QByteArray ZoneFile_COD6_PC::GetBinaryData() { + QByteArray result; + + return result; +} diff --git a/libs/zonefile/PC/zonefile_cod6_pc.h b/libs/zonefile/PC/zonefile_cod6_pc.h new file mode 100644 index 0000000..4ecfed3 --- /dev/null +++ b/libs/zonefile/PC/zonefile_cod6_pc.h @@ -0,0 +1,54 @@ +#ifndef ZONEFILE_COD6_PC_H +#define ZONEFILE_COD6_PC_H + +#include + +#include "zonefile.h" + +class ZoneFile_COD6_PC : public ZoneFile +{ +public: + ZoneFile_COD6_PC(); + ~ZoneFile_COD6_PC(); + + bool Load(const QByteArray aFileData) override; + AssetType AssetStrToEnum(const QString aAssetType) override; + + QByteArray GetBinaryData() override; + +private: + void pParseZoneHeader(QDataStream *aZoneFileStream) override; + quint32 pParseZoneSize(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsA(QDataStream *aZoneFileStream) override; + quint32 pParseZoneTagCount(QDataStream *aZoneFileStream) override; + quint32 pParseZoneRecordCount(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsB(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsC(QDataStream *aZoneFileStream) override; + QStringList pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) override; + QStringList pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) override; + AssetMap pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) override; + LocalString pParseAsset_LocalString(QDataStream *aZoneFileStream) override; + RawFile pParseAsset_RawFile(QDataStream *aZoneFileStream) override; + void pParseAsset_PhysPreset(QDataStream *aZoneFileStream) override; + Model pParseAsset_Model(QDataStream *aZoneFileStream) override; + Material pParseAsset_Material(QDataStream *aZoneFileStream) override; + Shader pParseAsset_Shader(QDataStream *aZoneFileStream) override; + TechSet pParseAsset_TechSet(QDataStream *aZoneFileStream) override; + Image pParseAsset_Image(QDataStream *aZoneFileStream) override; + SoundAsset pParseAsset_Sound(QDataStream *aZoneFileStream) override; + void pParseAsset_ColMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapSP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_LightDef(QDataStream *aZoneFileStream) override; + void pParseAsset_UIMap(QDataStream *aZoneFileStream) override; + void pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) override; + void pParseAsset_AIType(QDataStream *aZoneFileStream) override; + void pParseAsset_FX(QDataStream *aZoneFileStream) override; + Animation pParseAsset_Animation(QDataStream *aZoneFileStream) override; + MenuFile pParseAsset_MenuFile(QDataStream *aZoneFileStream) override; + void pParseAsset_Weapon(QDataStream *aZoneFileStream) override; + void pParseAsset_D3DBSP(QDataStream *aZoneFileStream) override; + StringTable pParseAsset_StringTable(QDataStream *aZoneFileStream) override; +}; + +#endif // ZONEFILE_COD6_PC_H diff --git a/libs/zonefile/PC/zonefile_cod7_pc.cpp b/libs/zonefile/PC/zonefile_cod7_pc.cpp new file mode 100644 index 0000000..9d491fa --- /dev/null +++ b/libs/zonefile/PC/zonefile_cod7_pc.cpp @@ -0,0 +1,1077 @@ +#include "zonefile_cod7_pc.h" + +#include +#include +#include + +ZoneFile_COD7_PC::ZoneFile_COD7_PC() +{ + +} + +ZoneFile_COD7_PC::~ZoneFile_COD7_PC() +{ + +} + +bool ZoneFile_COD7_PC::Load(const QByteArray aFileData) { + // Open zone file as little endian stream + QDataStream zoneFileStream(aFileData); + zoneFileStream.setByteOrder(QDataStream::LittleEndian); + + // Parse data from zone file header + pParseZoneHeader(&zoneFileStream); + zoneFileStream.device()->seek(zoneFileStream.device()->pos() - 1); + SetRecords(pParseZoneIndex(&zoneFileStream, GetRecordCount())); + SetAssetMap(pParseAssets(&zoneFileStream, GetRecords())); + + return true; +} + +void ZoneFile_COD7_PC::pParseZoneHeader(QDataStream *aZoneFileStream) { + quint32 size = pParseZoneSize(aZoneFileStream); + SetSize(size); + + pParseZoneUnknownsA(aZoneFileStream); + + quint32 tagCount = pParseZoneTagCount(aZoneFileStream); + SetTagCount(tagCount); + + pParseZoneUnknownsB(aZoneFileStream); + + quint32 recordCount = pParseZoneRecordCount(aZoneFileStream); + SetRecordCount(recordCount); + + if (tagCount) { + pParseZoneUnknownsC(aZoneFileStream); + SetTags(pParseZoneTags(aZoneFileStream, tagCount)); + } else { + aZoneFileStream->skipRawData(4); + } +} + +quint32 ZoneFile_COD7_PC::pParseZoneSize(QDataStream *aZoneFileStream) { + quint32 zoneFileSize; + *aZoneFileStream >> zoneFileSize; + if (zoneFileSize <= 0) { + qDebug() << "Tried to open empty zone file!"; + exit(-1); + } + zoneFileSize += 36; + return zoneFileSize; +} + +/* + ParseZoneUnknownsA() + + Parses the 1st section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD7_PC::pParseZoneUnknownsA(QDataStream *aZoneFileStream) { + // Byte 4-7, 8-11, 12-15: unknown + QByteArray unknown1(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown1.data(), 4); + + QByteArray unknown2(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown2.data(), 4); + + QByteArray unknown3(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown3.data(), 4); + + // Byte 16-19, 20-23: empty/unknown + QByteArray unknown4(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown4.data(), 4); + + QByteArray unknown5(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown5.data(), 4); + + // Byte 24-27: somehow related to the filesize, but smaller value + QByteArray unknown6(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown6.data(), 4); + + // Byte 28-31, 32-35: unknown + QByteArray unknown7(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown7.data(), 4); + + QByteArray unknown8(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown8.data(), 4); +} + +/* + ParseZoneTagCount() + + Parses the number of string tags in the zone index +*/ +quint32 ZoneFile_COD7_PC::pParseZoneTagCount(QDataStream *aZoneFileStream) { + quint32 tagCount; + *aZoneFileStream >> tagCount; + return tagCount; +} + +/* + ParseZoneRecordCount() + + Parses the number of records in the zone index +*/ +quint32 ZoneFile_COD7_PC::pParseZoneRecordCount(QDataStream *aZoneFileStream) { + quint32 recordCount; + *aZoneFileStream >> recordCount; + return recordCount; +} + +/* + ParseZoneUnknownsB() + + Parses the 2nd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD7_PC::pParseZoneUnknownsB(QDataStream *aZoneFileStream) { + // Byte 44-47: Unknown/empty? + QByteArray unknown9(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown9.data(), 4); +} + +/* + pParseZoneUnknownsC() + + Parses the 3rd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD7_PC::pParseZoneUnknownsC(QDataStream *aZoneFileStream) { + // Byte 40-43: Unknown/empty? + QByteArray unknown10(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown10.data(), 4); + + // Byte 44-47: Unknown/empty? + QByteArray unknown11(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown11.data(), 4); +} + +/* + ParseZoneTags() + + Parses the string tags ate the start of zone file +*/ +QStringList ZoneFile_COD7_PC::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) { + QStringList tags; + + // Byte 48-51: Repeated separators? ÿÿÿÿ x i + aZoneFileStream->skipRawData(4 * (tagCount - 1)); + + // Parse tags/strings before index + QString zoneTag; + char zoneTagChar; + for (quint32 i = 0; i < tagCount; i++) { + *aZoneFileStream >> zoneTagChar; + while (zoneTagChar != 0) { + zoneTag += zoneTagChar; + *aZoneFileStream >> zoneTagChar; + } + tags << zoneTag; + zoneTag.clear(); + } + return tags; +} + +/* + ParseZoneIndex() + + Parse the binary zone index data and populate table +*/ +QStringList ZoneFile_COD7_PC::pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) { + QStringList result; + + // Don't parse if no records + if (!recordCount) { return result; } + + if (aZoneFileStream->device()->peek(4).toHex().contains("ffff")) { + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 2); + } + + // Parse index & map found asset types + for (quint32 i = 0; i <= recordCount; i++) { + // Skip record start + QByteArray rawAssetType(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rawAssetType.data(), 4); + result << rawAssetType.toHex(); + + // Skip separator + aZoneFileStream->skipRawData(4); + } + return result; +} + +AssetMap ZoneFile_COD7_PC::pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) { + AssetMap result; + + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 8); + + for (int i = 0; i < assetOrder.size(); i++) { + const QString typeHex = assetOrder[i]; + const AssetType typeStr = AssetStrToEnum(typeHex); + + if (typeStr == ASSET_LOCAL_STRING) { // localized string asset + result.localStrings << pParseAsset_LocalString(aZoneFileStream); + } else if (typeStr == ASSET_RAW_FILE) { // gsc + auto rawFile = pParseAsset_RawFile(aZoneFileStream); + if (rawFile.length) { + result.rawFiles << rawFile; + } + } else if (typeStr == ASSET_PHYS_PRESET) { // physpreset + pParseAsset_PhysPreset(aZoneFileStream); + } else if (typeStr == ASSET_MODEL) { // xmodel + result.models << pParseAsset_Model(aZoneFileStream); + } else if (typeStr == ASSET_MATERIAL) { // material + pParseAsset_Material(aZoneFileStream); + } else if (typeStr == ASSET_SHADER) { // pixelshader + pParseAsset_Shader(aZoneFileStream); + } else if (typeStr == ASSET_TECH_SET) { // techset include + result.techSets << pParseAsset_TechSet(aZoneFileStream); + } else if (typeStr == ASSET_IMAGE) { // image + result.images << pParseAsset_Image(aZoneFileStream); + } else if (typeStr == ASSET_SOUND) { // loaded_sound + result.sounds << pParseAsset_Sound(aZoneFileStream); + } else if (typeStr == ASSET_COLLISION_MAP) { // col_map_mp + pParseAsset_ColMapMP(aZoneFileStream); + } else if (typeStr == ASSET_MP_MAP) { // game_map_sp + pParseAsset_GameMapSP(aZoneFileStream); + } else if (typeStr == ASSET_SP_MAP) { // game_map_mp + pParseAsset_GameMapMP(aZoneFileStream); + } else if (typeStr == ASSET_LIGHT_DEF) { // lightdef + pParseAsset_LightDef(aZoneFileStream); + } else if (typeStr == ASSET_UI_MAP) { // ui_map + pParseAsset_UIMap(aZoneFileStream); + } else if (typeStr == ASSET_SND_DRIVER_GLOBALS) { // snddriverglobals + pParseAsset_SNDDriverGlobals(aZoneFileStream); + } else if (typeStr == ASSET_AI_TYPE) { // aitype + pParseAsset_AIType(aZoneFileStream); + } else if (typeStr == ASSET_EFFECT) { // aitype + pParseAsset_FX(aZoneFileStream); + } else if (typeStr == ASSET_ANIMATION) { // aitype + result.animations << pParseAsset_Animation(aZoneFileStream); + } else if (typeStr == ASSET_STRING_TABLE) { // string_table + result.stringTables << pParseAsset_StringTable(aZoneFileStream); + } else if (typeStr == ASSET_MENU) { // string_table + result.menuFiles << pParseAsset_MenuFile(aZoneFileStream); + } else if (typeStr == ASSET_WEAPON) { // string_table + pParseAsset_Weapon(aZoneFileStream); + } else if (typeStr == ASSET_D3DBSP) { // string_table + pParseAsset_D3DBSP(aZoneFileStream); + } + } + return result; +} + +LocalString ZoneFile_COD7_PC::pParseAsset_LocalString(QDataStream *aZoneFileStream) { + LocalString result; + + quint32 stringPtr, aliasPtr; + *aZoneFileStream >> stringPtr >> aliasPtr; + if (stringPtr == 4294967295) { + // Parse local string asset contents + QString localStr; + char localStrChar; + *aZoneFileStream >> localStrChar; + while (localStrChar != 0) { + result.string += localStrChar; + *aZoneFileStream >> localStrChar; + } + } else { + result.string = "String Ptr: " + QString::number(stringPtr); + } + + if (aliasPtr == 4294967295) { + // Parse rawfile name + QString aliasName; + char aliasNameChar; + *aZoneFileStream >> aliasNameChar; + while (aliasNameChar != 0) { + result.alias += aliasNameChar; + *aZoneFileStream >> aliasNameChar; + } + } else { + result.string = "Alias Ptr: " + QString::number(aliasPtr); + } + + return result; +} + +RawFile ZoneFile_COD7_PC::pParseAsset_RawFile(QDataStream *aZoneFileStream) { + RawFile result; + + // Skip start separator FF FF FF FF (pointer?) + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.length; + + // Skip unknown 4 byte data + aZoneFileStream->skipRawData(4); + + // Parse rawfile path + char scriptPathChar; + *aZoneFileStream >> scriptPathChar; + while (scriptPathChar != 0) { + result.path += scriptPathChar; + *aZoneFileStream >> scriptPathChar; + } + result.path.replace(",", ""); + const QStringList pathParts = result.path.split('/'); + if (pathParts.size() == 0) { + qDebug() << "Failed to parse ff path! " << result.path; + exit(-1); + } + + // Parse gsc contents + char rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + while (rawFileContentsChar != 0 && rawFileContentsChar != -1) { + result.contents += rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + } + return result; +} + +void ZoneFile_COD7_PC::pParseAsset_PhysPreset(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Model ZoneFile_COD7_PC::pParseAsset_Model(QDataStream *aZoneFileStream) { + Model result; + + *aZoneFileStream >> result.namePtr >> result.tagCount >> result.rootTagCount + >> result.surfCount >> result.unknownCount >> result.boneNamePtr + >> result.parentListPtr >> result.quatsPtr >> result.transPtr + >> result.partClassPtr >> result.baseMatPtr + >> result.surfsPtr >> result.materialHandlesPtr; + + // Parse XModelLodInfo + for (int i = 1; i <= 4; i++) { + quint32 intDist; + *aZoneFileStream >> intDist; + + std::memcpy(&result.lodInfo[i].dist, &intDist, sizeof(result.lodInfo[i].dist)); + *aZoneFileStream >> result.lodInfo[i].numsurfs >> result.lodInfo[i].surfIndex; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.lodInfo[i].partBits[0] + >> result.lodInfo[i].partBits[1] + >> result.lodInfo[i].partBits[2] + >> result.lodInfo[i].partBits[3]; + } + + *aZoneFileStream >> result.collSurfsPtr >> result.numCollSurfs >> result.contents >> result.boneInfoPtr; + + quint32 intRadius, intMins[3], intMaxs[3]; + *aZoneFileStream >> intRadius >> intMins[0] >> intMins[1] + >> intMins[2] >> intMaxs[0] >> intMaxs[1] >> intMaxs[2]; + + std::memcpy(&result.radius, &intRadius, sizeof(result.radius)); + + std::memcpy(&result.mins[0], &intMins[0], sizeof(result.mins[0])); + std::memcpy(&result.mins[1], &intMins[1], sizeof(result.mins[1])); + std::memcpy(&result.mins[2], &intMins[2], sizeof(result.mins[2])); + + std::memcpy(&result.maxs[0], &intMaxs[0], sizeof(result.maxs[0])); + std::memcpy(&result.maxs[1], &intMaxs[1], sizeof(result.maxs[2])); + std::memcpy(&result.maxs[2], &intMaxs[2], sizeof(result.maxs[3])); + + *aZoneFileStream >> result.numLods >> result.collLod >> result.streamInfoPtr + >> result.memUsage >> result.flags >> result.physPresetPtr >> result.physGeomsPtr; + + // Parse model name + char modelNameChar; + *aZoneFileStream >> modelNameChar; + while (modelNameChar == 0) { + *aZoneFileStream >> modelNameChar; + } + while (modelNameChar != 0) { + result.modelName += modelNameChar; + *aZoneFileStream >> modelNameChar; + } + return result; +} + +Material ZoneFile_COD7_PC::pParseAsset_Material(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); + + return Material(); +} + +Shader ZoneFile_COD7_PC::pParseAsset_Shader(QDataStream *aZoneFileStream) { + Shader result = Shader(); + + quint8 minorVersion, majorVersion; + *aZoneFileStream >> minorVersion >> majorVersion; + + quint32 magic; + *aZoneFileStream >> magic; + + // Verify .fxc magic + if (magic != 65534 && magic != 65535) { return result; } + + SHADER_TYPE type = SHADER_NONE; + quint16 rawShaderType; + *aZoneFileStream >> rawShaderType; + if (rawShaderType == 65535) { // Pixel shader + type = SHADER_PIXEL; + } else if (rawShaderType == 65534) { // Vertex shader + type = SHADER_VERTEX; + } + Q_UNUSED(type); + + while (true) { + quint32 instructionToken; + *aZoneFileStream >> instructionToken; + + SHADER_OPCODE opCode = (SHADER_OPCODE)(instructionToken & 0xffff); + + int size; + if (opCode == OPCODE_End) { + break; + } else if (opCode == OPCODE_Comment) { + size = (int)((instructionToken >> 16) & 0x7FFF); + } else { + size = (int)((instructionToken >> 24) & 0x0f); + } + Q_UNUSED(size); + } + + + return result; +} + +TechSet ZoneFile_COD7_PC::pParseAsset_TechSet(QDataStream *aZoneFileStream) { + TechSet result; + + for (int i = 1; i <= 62; i++) { + quint32 ptr; + *aZoneFileStream >> ptr; + + result.pointers << ptr; + } + qDebug() << aZoneFileStream->device()->pos(); + + // Parse techset name + char techSetNameChar; + *aZoneFileStream >> techSetNameChar; + while (techSetNameChar != 0) { + result.name += techSetNameChar; + *aZoneFileStream >> techSetNameChar; + } + result.name.replace(",", ""); + + return result; +} + +Image ZoneFile_COD7_PC::pParseAsset_Image(QDataStream *aZoneFileStream) { + Image result; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknowna >> result.unknownb + >> result.unknownc >> result.unknownd + >> result.unknowne >> result.unknownf + >> result.unknowng; + + aZoneFileStream->skipRawData(15 * 4); + *aZoneFileStream >> result.unknownh >> result.unknowni; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknownj; + + aZoneFileStream->skipRawData(4); + + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + result.materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + result.materialName.replace(",", ""); + + if (result.unknowna) { + *aZoneFileStream >> result.unknownk; + *aZoneFileStream >> result.unknownl; + *aZoneFileStream >> result.unknownm; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown1; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown2 >> result.unknown3 + >> result.size1 >> result.size2 + >> result.unknown4 >> result.unknown5; + + aZoneFileStream->skipRawData(4); + + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + result.name += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + + *aZoneFileStream >> result.unknown6 >> result.unknown7; + + QByteArray compressionData(8, Qt::Uninitialized); + aZoneFileStream->readRawData(compressionData.data(), 8); + if (compressionData.contains("DXT1")) { + result.compression = COMPRESSION_DXT1; + } else if (compressionData.contains("DXT3")) { + result.compression = COMPRESSION_DXT3; + } else if (compressionData.contains("DXT5")) { + result.compression = COMPRESSION_DXT5; + } else { + result.compression = COMPRESSION_NONE; + } + + *aZoneFileStream >> result.unknown8 >> result.unknown9; + } + + return result; +} + +SoundAsset ZoneFile_COD7_PC::pParseAsset_Sound(QDataStream *aZoneFileStream) { + SoundAsset result; + + qDebug() << aZoneFileStream->device()->pos(); + + QByteArray rootNamePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rootNamePtr.data(), 4); + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.count; + + if (rootNamePtr.toHex() == "ffffffff") { + // Read in sound file name + char soundNameChar; + *aZoneFileStream >> soundNameChar; + while (soundNameChar != 0) { + result.name += soundNameChar; + *aZoneFileStream >> soundNameChar; + } + } + + int tagCount = 0; + int resultCount = 0; + for (quint32 i = 0; i < result.count; i++) { + aZoneFileStream->skipRawData(12); + + QByteArray tagPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(tagPtr.data(), 4); + + if (tagPtr.toHex() == "ffffffff") { + tagCount++; + } + aZoneFileStream->skipRawData(4); + + QByteArray pathPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pathPtr.data(), 4); + + if (pathPtr.toHex() == "ffffffff") { + resultCount++; + } + + aZoneFileStream->skipRawData(160); + } + + for (int i = 0; i < tagCount; i++) { + // Read in tag? + QString tag; + char tagChar; + *aZoneFileStream >> tagChar; + while (tagChar != 0) { + tag += tagChar; + *aZoneFileStream >> tagChar; + } + } + + for (int i = 0; i < resultCount; i++) { + Sound sound; + + if (aZoneFileStream->device()->peek(12).toHex().contains("ffffffff00000000")) { + aZoneFileStream->skipRawData(12); + } + + aZoneFileStream->skipRawData(8); + + QByteArray aliasPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(aliasPtr.data(), 4); + + QByteArray namePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(namePtr.data(), 4); + + *aZoneFileStream >> sound.dataLength; + + if (aliasPtr.toHex() == "ffffffff") { + // Read in sound alias name + char soundAliasChar; + *aZoneFileStream >> soundAliasChar; + while (soundAliasChar != 0) { + sound.alias += soundAliasChar; + *aZoneFileStream >> soundAliasChar; + } + } + + if (aZoneFileStream->device()->peek(4) == "RIFF") { + sound.path = sound.alias; + sound.alias = ""; + } else if (namePtr.toHex() == "ffffffff") { + // Read in sound file path + char soundPathChar; + *aZoneFileStream >> soundPathChar; + while (soundPathChar != 0) { + sound.path += soundPathChar; + *aZoneFileStream >> soundPathChar; + } + sound.path.replace(",", ""); + } + + if (sound.dataLength) { + QByteArray data(sound.dataLength, Qt::Uninitialized); + aZoneFileStream->readRawData(data.data(), sound.dataLength); + sound.data = data; + } + result.sounds.append(sound); + } + + return result; +} + +void ZoneFile_COD7_PC::pParseAsset_ColMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD7_PC::pParseAsset_GameMapSP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD7_PC::pParseAsset_GameMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD7_PC::pParseAsset_LightDef(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD7_PC::pParseAsset_UIMap(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD7_PC::pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD7_PC::pParseAsset_AIType(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD7_PC::pParseAsset_FX(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Animation ZoneFile_COD7_PC::pParseAsset_Animation(QDataStream *aZoneFileStream) { + Animation result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.dataByteCount + >> result.dataShortCount + >> result.dataIntCount + >> result.randomDataByteCount + >> result.randomDataIntCount + >> result.numframes + >> result.isLooped + >> result.isDelta + >> result.noneRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.normalTranslatedBoneCount + >> result.preciseTranslatedBoneCount + >> result.staticTranslatedBoneCount + >> result.noneTranslatedBoneCount + >> result.totalBoneCount + >> result.otherBoneCount1 + >> result.otherBoneCount2 + >> result.notifyCount + >> result.assetType + >> result.pad + >> result.randomDataShortCount + >> result.indexCount + >> result.frameRate + >> result.frequency + >> result.boneIDsPtr + >> result.dataBytePtr + >> result.dataShortPtr + >> result.dataIntPtr + >> result.randomDataShortPtr + >> result.randomDataBytePtr + >> result.randomDataIntPtr + >> result.longIndiciesPtr + >> result.notificationsPtr + >> result.deltaPartsPtr; + + // Read in x_anim file name + QString xAnimName; + char xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + while (xAnimNameChar != 0) { + result.name += xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + } + + // Parse x_anim index header + QVector sectionLengths; + for (int i = 0; i < result.numframes; i++) { + quint8 sectionlength; + *aZoneFileStream >> sectionlength; + sectionLengths.push_back(sectionlength); + // Skip padding + aZoneFileStream->skipRawData(1); + } + // Skip unknown section + aZoneFileStream->skipRawData(2 * 8); + + return result; +} + +MenuFile ZoneFile_COD7_PC::pParseAsset_MenuFile(QDataStream *aZoneFileStream) { + //MENU_FILE + MenuFile result; + + aZoneFileStream->skipRawData(4); // Separator + + // Parse menu def count + *aZoneFileStream >> result.menuCount; + + // Clearly misparsed, never have this much + if (result.menuCount > 1000) { + qDebug() << "Failure reported when parsing menu file."; + return result; + } + for (uint i = 0; i < result.menuCount; i++) { + Menu menu; + + aZoneFileStream->skipRawData(4); // Separator + + // Read in x_anim file name + char menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + while (menuFilepathChar != 0) { + menu.filePath += menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + } + aZoneFileStream->skipRawData(4); // Separator + + *aZoneFileStream >> menu.menuNamePtr; + + float menuRectX, menuRectY, menuRectWidth, menuRectHeight; + *aZoneFileStream >> menuRectX >> menuRectY >> menuRectWidth >> menuRectHeight; + menu.rect = QRectF(menuRectX, menuRectY, menuRectWidth, menuRectHeight); + + quint32 hAlignInt, vAlignInt; + *aZoneFileStream >> hAlignInt >> vAlignInt; + menu.hAlign = (MENU_H_ALIGNMENT)hAlignInt; + menu.vAlign = (MENU_V_ALIGNMENT)vAlignInt; + + float rectClientX, rectClientY, rectClientWidth, rectClientHeight; + *aZoneFileStream >> rectClientX >> rectClientY >> rectClientWidth >> rectClientHeight; + menu.clientRect = QRectF(rectClientX, rectClientY, rectClientWidth, rectClientHeight); + + quint32 hClientAlignInt, vClientAlignInt, styleInt, borderInt; + *aZoneFileStream >> hClientAlignInt >> vClientAlignInt >> menu.groupPtr + >> styleInt >> borderInt >> menu.ownerDraw >> menu.ownerDrawFlags + >> menu.borderSize >> menu.staticFlags >> menu.dynamicFlags >> menu.nextTime; + menu.hClientAlign = (MENU_H_ALIGNMENT)hClientAlignInt; + menu.vClientAlign = (MENU_V_ALIGNMENT)vClientAlignInt; + menu.style = (MENU_WINDOW_STYLE)styleInt; + menu.border = (MENU_WINDOW_BORDER)borderInt; + + float foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA, + backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA, + borderColorR, borderColorG, borderColorB, borderColorA, + outlineColorR, outlineColorG, outlineColorB, outlineColorA; + *aZoneFileStream >> foregroundColorR >> foregroundColorG >> foregroundColorB >> foregroundColorA + >> backgroundColorR >> backgroundColorG >> backgroundColorB >> backgroundColorA + >> borderColorR >> borderColorG >> borderColorB >> borderColorA + >> outlineColorR >> outlineColorG >> outlineColorB >> outlineColorA; + + menu.foregroundColor = QColor(foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA); + menu.backgroundColor = QColor(backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA); + menu.borderColor = QColor(borderColorR, borderColorG, borderColorB, borderColorA); + menu.outlineColor = QColor(outlineColorR, outlineColorG, outlineColorB, outlineColorA); + + *aZoneFileStream >> menu.materialPtr >> menu.fontPtr >> menu.fullScreen >> menu.itemCount + >> menu.fontIndex >> menu.cursorItem >> menu.fadeCycle >> menu.fadeClamp + >> menu.fadeAmount >> menu.fadeInAmount >> menu.blurRadius >> menu.onOpenPtr + >> menu.onFocusPtr >> menu.onClosePtr >> menu.onESCPtr >> menu.onKeyPtr + >> menu.visibleExpCount >> menu.expEntryPtr >> menu.allowedBindingPtr + >> menu.soundNamePtr >> menu.imageTrack; + + float focusColorR, focusColorG, focusColorB, focusColorA, + disabledColorR, disabledColorG, disabledColorB, disabledColorA; + *aZoneFileStream >> focusColorR >> focusColorG >> focusColorB >> focusColorA + >> disabledColorR >> disabledColorG >> disabledColorB >> disabledColorA; + menu.focusColor = QColor(focusColorR, focusColorG, focusColorB, focusColorA); + menu.disabledColor = QColor(disabledColorR, disabledColorG, disabledColorB, disabledColorA); + + *aZoneFileStream >> menu.rectXExpCount >> menu.rectXExpPtr >> menu.rectYExpCount >> menu.rectYExpPtr; + + aZoneFileStream->skipRawData(4); // Separator + + char menuDefNameChar; + int menuDefNameLen = 0; + *aZoneFileStream >> menuDefNameChar; + while (menuDefNameChar != 0 && menuDefNameLen < 30) { + menuDefNameLen++; + menu.name += menuDefNameChar; + *aZoneFileStream >> menuDefNameChar; + } + + char defStringChar; + int defStringLen = 0; + *aZoneFileStream >> defStringChar; + while (defStringChar != 0 && defStringLen < 30) { + defStringLen++; + menu.definition += defStringChar; + *aZoneFileStream >> defStringChar; + } + aZoneFileStream->skipRawData(4 * 10); + + *aZoneFileStream >> menu.itemWindowDefNamePtr; + + float itemRectX, itemRectY, itemRectWidth, itemRectHeight; + *aZoneFileStream >> itemRectX >> itemRectY >> itemRectWidth >> itemRectHeight; + menu.itemRect = QRectF(itemRectX, itemRectY, itemRectWidth, itemRectHeight); + + *aZoneFileStream >> menu.itemHAlignment >> menu.itemVAlignment >> menu.itemGroupPtr + >> menu.itemWindowStyle >> menu.itemWindowBorder >> menu.itemOwnerDraw + >> menu.itemOwnerDrawFlags >> menu.itemBorderSize >> menu.itemStaticFlags + >> menu.itemDynamicFlags >> menu.itemNextTime; + + float itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA, + itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA, + itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA, + itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA; + *aZoneFileStream >> itemForegroundColorR >> itemForegroundColorG >> itemForegroundColorB >> itemForegroundColorA + >> itemBackgroundColorR >> itemBackgroundColorG >> itemBackgroundColorB >> itemBackgroundColorA + >> itemBorderColorR >> itemBorderColorG >> itemBorderColorB >> itemBorderColorA + >> itemOutlineColorR >> itemOutlineColorG >> itemOutlineColorB >> itemOutlineColorA; + + menu.itemForegroundColor = QColor(itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA); + menu.itemBackgroundColor = QColor(itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA); + menu.itemBorderColor = QColor(itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA); + menu.itemOutlineColor = QColor(itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA); + + *aZoneFileStream >> menu.itemMaterialPtr; + + float itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight; + *aZoneFileStream >> itemTextRectX >> itemTextRectY >> itemTextRectWidth >> itemTextRectHeight; + menu.itemTextRect = QRectF(itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight); + + quint32 hItemTextAlignInt, vItemTextAlignInt, itemType, fontTypeInt, textStyleInt; + *aZoneFileStream >> hItemTextAlignInt >> vItemTextAlignInt >> itemType >> menu.dataType + >> menu.alignment >> fontTypeInt >> menu.textAlignMode >> menu.textalignx >> menu.textaligny + >> menu.textscale >> textStyleInt >> menu.gameMsgWindowIndex >> menu.gameMsgWindowMode + >> menu.testPtr >> menu.textSavegameInfo >> menu.parentPtr; + menu.itemText_hAlign = (MENU_H_ALIGNMENT)hItemTextAlignInt; + menu.itemText_vAlign = (MENU_V_ALIGNMENT)vItemTextAlignInt; + menu.itemType = (MENU_ITEM_TYPE)itemType; + menu.fontEnum = (MENU_FONT_TYPE)fontTypeInt; + menu.textStyle = (MENU_ITEM_TEXTSTYLE)textStyleInt; + + *aZoneFileStream >> menu.mouseEnterText >> menu.mouseExitText >> menu.mouseEnter >> menu.mouseExit + >> menu.action >> menu.onAccept >> menu.onFocus >> menu.leaveFocus >> menu.dvar >> menu.dvarTest + >> menu.keyHandlerPtr >> menu.enableDvarPtr >> menu.dvarFlags >> menu.focusSoundPtr + >> menu.special >> menu.cursorPos; + + // itemDefData_t typeData; + + // listBoxDef_s *listBox; + + *aZoneFileStream >> menu.startPos >> menu.endPos >> menu.drawPadding; + + *aZoneFileStream >> menu.elementWidth >> menu.elementHeight; + + *aZoneFileStream >> menu.elementStyle >> menu.numColumns; + + //columnInfo_s columnInfo[16]; + + *aZoneFileStream >> menu.doubleClickPtr; + + + *aZoneFileStream >> menu.notselectable >> menu.noScrollBars >> menu.usePaging; + + float itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA, + itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA, + itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA; + *aZoneFileStream >> itemSelectBorderColorR >> itemSelectBorderColorG >> itemSelectBorderColorB >> itemSelectBorderColorA + >> itemDisableColorR >> itemDisableColorG >> itemDisableColorB >> itemDisableColorA + >> itemFocusColorR >> itemFocusColorG >> itemFocusColorB >> itemFocusColorA; + menu.itemSelectBorderColor = QColor(itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA); + menu.itemDisableColor = QColor(itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA); + menu.itemFocusColor = QColor(itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA); + + *aZoneFileStream >> menu.selectIconPtr >> menu.backgroundItemListboxPtr >> menu.highlightTexturePtr; + + // editFieldDef_s *editField; + + *aZoneFileStream >> menu.minVal >> menu.maxVal >> menu.defVal >> menu.range >> menu.maxChars + >> menu.maxCharsGotoNext >> menu.maxPaintChars >> menu.paintOffset; + + // multiDef_s *multi; + + for (int i = 0; i < 32; i++) { + quint32 dvarList; + *aZoneFileStream >> dvarList; + menu.dvarListPtrs.push_back(dvarList); + } + + for (int i = 0; i < 32; i++) { + quint32 dvarStr; + *aZoneFileStream >> dvarStr; + menu.dvarStrPtrs.push_back(dvarStr); + } + + for (int i = 0; i < 32; i++) { + float dvarValue; + *aZoneFileStream >> dvarValue; + menu.dvarValues.push_back(dvarValue); + } + + *aZoneFileStream >> menu.count >> menu.strDef >> menu.enumDvarNamePtr; + aZoneFileStream->skipRawData(4); + //>> menu.dataPtr + *aZoneFileStream >> menu.itemImageTrack; + + qDebug() << aZoneFileStream->device()->pos(); + + //statement_s visibleExp; + //statement_s textExp; + //statement_s materialExp; + //statement_s rectXExp; + //statement_s rectYExp; + //statement_s rectWExp; + //statement_s rectHExp; + //statement_s foreColorAExp; + result.menuDefs << menu; + } + return result; +} + +void ZoneFile_COD7_PC::pParseAsset_Weapon(QDataStream *aZoneFileStream) { + //WEAPON_FILE + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD7_PC::pParseAsset_D3DBSP(QDataStream *aZoneFileStream) { + //D3DBSP_DUMP + Q_UNUSED(aZoneFileStream); +} + +StringTable ZoneFile_COD7_PC::pParseAsset_StringTable(QDataStream *aZoneFileStream) { + StringTable result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.columnCount + >> result.rowCount; + + // Todo fix this + result.columnCount = 0; + result.rowCount = 0; + + aZoneFileStream->skipRawData(4); + + QString stringTableName; + char stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + while (stringTableNameChar != 0) { + result.name += stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + } + + for (quint32 i = 0; i < result.rowCount; i++) { + QByteArray pointerData(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pointerData.data(), 4); + result.tablePointers.push_back(pointerData.toHex()); + + aZoneFileStream->skipRawData(4); + } + + for (const QString &pointerAddr : result.tablePointers) { + QString leadingContent = ""; + if (pointerAddr == "FFFFFFFF") { + char leadingContentChar; + *aZoneFileStream >> leadingContentChar; + while (leadingContentChar != 0) { + leadingContent += leadingContentChar; + *aZoneFileStream >> leadingContentChar; + } + } else { + leadingContent = pointerAddr; + } + + QString content; + char contentChar; + *aZoneFileStream >> contentChar; + while (contentChar != 0) { + content += contentChar; + *aZoneFileStream >> contentChar; + } + result.content[leadingContent] = content; + } + return result; +} + +AssetType ZoneFile_COD7_PC::AssetStrToEnum(const QString aAssetType) { + const QString cleanedType = aAssetType.toUpper(); + if (cleanedType == "17000000") { // localized string PARTIALLY VERIFIED + return ASSET_LOCAL_STRING; + } else if (cleanedType == "20000000") { // raw_file PARTIALLY VERIFIED + return ASSET_RAW_FILE; + } else if (cleanedType == "1A000000") { // fx PARTIALLY VERIFIED + return ASSET_EFFECT; + } else if (cleanedType == "09000000") { // loaded_sound PARTIALLY VERIFIED + return ASSET_SOUND; + } else if (cleanedType == "04000000") { // x_anim PARTIALLY VERIFIED + return ASSET_ANIMATION; + } else if (cleanedType == "0C000000") { // collision_map PARTIALLY VERIFIED + return ASSET_COLLISION_MAP; + } else if (cleanedType == "21000000") { // string_table PARTIALLY VERIFIED + return ASSET_STRING_TABLE; + } else if (cleanedType == "15000000") { // menu_file PARTIALLY VERIFIED + return ASSET_MENU; + } else if (cleanedType == "07000000") { // tech set PARTIALLY VERIFIED + return ASSET_TECH_SET; + } else if (cleanedType == "18000000") { // weapon PARTIALLY VERIFIED + return ASSET_WEAPON; + } else if (cleanedType == "11000000") { // gfx map PARTIALLY VERIFIED + return ASSET_GFX_MAP; + } else if (cleanedType == "12000000") { // light_def PARTIALLY VERIFIED + return ASSET_LIGHT_DEF; + } else if (cleanedType == "14000000") { // font PARTIALLY VERIFIED + return ASSET_FONT; + } else if (cleanedType == "05000000") { // xmodel PARTIALLY VERIFIED + return ASSET_MODEL; + } else if (cleanedType == "0D000000") { // d3dbsp PARTIALLY VERIFIED + return ASSET_D3DBSP; + } else if (cleanedType == "06000000") { // image PARTIALLY VERIFIED + return ASSET_IMAGE; + } else if (cleanedType == "0E000000") { // game map sp PARTIALLY VERIFIED + return ASSET_GAME_MAP_SP; + } else if (cleanedType == "0B000000") { // col map sp PARTIALLY VERIFIED + return ASSET_COL_MAP_SP; + } + return ASSET_NONE; +} + +QByteArray ZoneFile_COD7_PC::GetBinaryData() { + QByteArray result; + + return result; +} diff --git a/libs/zonefile/PC/zonefile_cod7_pc.h b/libs/zonefile/PC/zonefile_cod7_pc.h new file mode 100644 index 0000000..dec60e4 --- /dev/null +++ b/libs/zonefile/PC/zonefile_cod7_pc.h @@ -0,0 +1,52 @@ +#ifndef ZONEFILE_COD7_PC_H +#define ZONEFILE_COD7_PC_H + +#include "zonefile.h" + +class ZoneFile_COD7_PC : public ZoneFile +{ +public: + ZoneFile_COD7_PC(); + ~ZoneFile_COD7_PC(); + + bool Load(const QByteArray aFileData) override; + AssetType AssetStrToEnum(const QString aAssetType) override; + + QByteArray GetBinaryData() override; + +protected: + void pParseZoneHeader(QDataStream *aZoneFileStream) override; + quint32 pParseZoneSize(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsA(QDataStream *aZoneFileStream) override; + quint32 pParseZoneTagCount(QDataStream *aZoneFileStream) override; + quint32 pParseZoneRecordCount(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsB(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsC(QDataStream *aZoneFileStream) override; + QStringList pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) override; + QStringList pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) override; + AssetMap pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) override; + LocalString pParseAsset_LocalString(QDataStream *aZoneFileStream) override; + RawFile pParseAsset_RawFile(QDataStream *aZoneFileStream) override; + void pParseAsset_PhysPreset(QDataStream *aZoneFileStream) override; + Model pParseAsset_Model(QDataStream *aZoneFileStream) override; + Material pParseAsset_Material(QDataStream *aZoneFileStream) override; + Shader pParseAsset_Shader(QDataStream *aZoneFileStream) override; + TechSet pParseAsset_TechSet(QDataStream *aZoneFileStream) override; + Image pParseAsset_Image(QDataStream *aZoneFileStream) override; + SoundAsset pParseAsset_Sound(QDataStream *aZoneFileStream) override; + void pParseAsset_ColMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapSP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_LightDef(QDataStream *aZoneFileStream) override; + void pParseAsset_UIMap(QDataStream *aZoneFileStream) override; + void pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) override; + void pParseAsset_AIType(QDataStream *aZoneFileStream) override; + void pParseAsset_FX(QDataStream *aZoneFileStream) override; + Animation pParseAsset_Animation(QDataStream *aZoneFileStream) override; + MenuFile pParseAsset_MenuFile(QDataStream *aZoneFileStream) override; + void pParseAsset_Weapon(QDataStream *aZoneFileStream) override; + void pParseAsset_D3DBSP(QDataStream *aZoneFileStream) override; + StringTable pParseAsset_StringTable(QDataStream *aZoneFileStream) override; +}; + +#endif // ZONEFILE_COD7_PC_H diff --git a/libs/zonefile/PC/zonefile_cod8_pc.cpp b/libs/zonefile/PC/zonefile_cod8_pc.cpp new file mode 100644 index 0000000..1d62c80 --- /dev/null +++ b/libs/zonefile/PC/zonefile_cod8_pc.cpp @@ -0,0 +1,1077 @@ +#include "zonefile_cod8_pc.h" + +#include +#include +#include + +ZoneFile_COD8_PC::ZoneFile_COD8_PC() +{ + +} + +ZoneFile_COD8_PC::~ZoneFile_COD8_PC() +{ + +} + +bool ZoneFile_COD8_PC::Load(const QByteArray aFileData) { + // Open zone file as little endian stream + QDataStream zoneFileStream(aFileData); + zoneFileStream.setByteOrder(QDataStream::LittleEndian); + + // Parse data from zone file header + pParseZoneHeader(&zoneFileStream); + zoneFileStream.device()->seek(zoneFileStream.device()->pos() - 1); + SetRecords(pParseZoneIndex(&zoneFileStream, GetRecordCount())); + SetAssetMap(pParseAssets(&zoneFileStream, GetRecords())); + + return true; +} + +void ZoneFile_COD8_PC::pParseZoneHeader(QDataStream *aZoneFileStream) { + quint32 size = pParseZoneSize(aZoneFileStream); + SetSize(size); + + pParseZoneUnknownsA(aZoneFileStream); + + quint32 tagCount = pParseZoneTagCount(aZoneFileStream); + SetTagCount(tagCount); + + pParseZoneUnknownsB(aZoneFileStream); + + quint32 recordCount = pParseZoneRecordCount(aZoneFileStream); + SetRecordCount(recordCount); + + if (tagCount) { + pParseZoneUnknownsC(aZoneFileStream); + SetTags(pParseZoneTags(aZoneFileStream, tagCount)); + } else { + aZoneFileStream->skipRawData(4); + } +} + +quint32 ZoneFile_COD8_PC::pParseZoneSize(QDataStream *aZoneFileStream) { + quint32 zoneFileSize; + *aZoneFileStream >> zoneFileSize; + if (zoneFileSize <= 0) { + qDebug() << "Tried to open empty zone file!"; + exit(-1); + } + zoneFileSize += 36; + return zoneFileSize; +} + +/* + ParseZoneUnknownsA() + + Parses the 1st section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD8_PC::pParseZoneUnknownsA(QDataStream *aZoneFileStream) { + // Byte 4-7, 8-11, 12-15: unknown + QByteArray unknown1(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown1.data(), 4); + + QByteArray unknown2(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown2.data(), 4); + + QByteArray unknown3(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown3.data(), 4); + + // Byte 16-19, 20-23: empty/unknown + QByteArray unknown4(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown4.data(), 4); + + QByteArray unknown5(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown5.data(), 4); + + // Byte 24-27: somehow related to the filesize, but smaller value + QByteArray unknown6(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown6.data(), 4); + + // Byte 28-31, 32-35: unknown + QByteArray unknown7(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown7.data(), 4); + + QByteArray unknown8(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown8.data(), 4); +} + +/* + ParseZoneTagCount() + + Parses the number of string tags in the zone index +*/ +quint32 ZoneFile_COD8_PC::pParseZoneTagCount(QDataStream *aZoneFileStream) { + quint32 tagCount; + *aZoneFileStream >> tagCount; + return tagCount; +} + +/* + ParseZoneRecordCount() + + Parses the number of records in the zone index +*/ +quint32 ZoneFile_COD8_PC::pParseZoneRecordCount(QDataStream *aZoneFileStream) { + quint32 recordCount; + *aZoneFileStream >> recordCount; + return recordCount; +} + +/* + ParseZoneUnknownsB() + + Parses the 2nd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD8_PC::pParseZoneUnknownsB(QDataStream *aZoneFileStream) { + // Byte 44-47: Unknown/empty? + QByteArray unknown9(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown9.data(), 4); +} + +/* + pParseZoneUnknownsC() + + Parses the 3rd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD8_PC::pParseZoneUnknownsC(QDataStream *aZoneFileStream) { + // Byte 40-43: Unknown/empty? + QByteArray unknown10(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown10.data(), 4); + + // Byte 44-47: Unknown/empty? + QByteArray unknown11(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown11.data(), 4); +} + +/* + ParseZoneTags() + + Parses the string tags ate the start of zone file +*/ +QStringList ZoneFile_COD8_PC::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) { + QStringList tags; + + // Byte 48-51: Repeated separators? ÿÿÿÿ x i + aZoneFileStream->skipRawData(4 * (tagCount - 1)); + + // Parse tags/strings before index + QString zoneTag; + char zoneTagChar; + for (quint32 i = 0; i < tagCount; i++) { + *aZoneFileStream >> zoneTagChar; + while (zoneTagChar != 0) { + zoneTag += zoneTagChar; + *aZoneFileStream >> zoneTagChar; + } + tags << zoneTag; + zoneTag.clear(); + } + return tags; +} + +/* + ParseZoneIndex() + + Parse the binary zone index data and populate table +*/ +QStringList ZoneFile_COD8_PC::pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) { + QStringList result; + + // Don't parse if no records + if (!recordCount) { return result; } + + if (aZoneFileStream->device()->peek(4).toHex().contains("ffff")) { + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 2); + } + + // Parse index & map found asset types + for (quint32 i = 0; i <= recordCount; i++) { + // Skip record start + QByteArray rawAssetType(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rawAssetType.data(), 4); + result << rawAssetType.toHex(); + + // Skip separator + aZoneFileStream->skipRawData(4); + } + return result; +} + +AssetMap ZoneFile_COD8_PC::pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) { + AssetMap result; + + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 8); + + for (int i = 0; i < assetOrder.size(); i++) { + const QString typeHex = assetOrder[i]; + const AssetType typeStr = AssetStrToEnum(typeHex); + + if (typeStr == ASSET_LOCAL_STRING) { // localized string asset + result.localStrings << pParseAsset_LocalString(aZoneFileStream); + } else if (typeStr == ASSET_RAW_FILE) { // gsc + auto rawFile = pParseAsset_RawFile(aZoneFileStream); + if (rawFile.length) { + result.rawFiles << rawFile; + } + } else if (typeStr == ASSET_PHYS_PRESET) { // physpreset + pParseAsset_PhysPreset(aZoneFileStream); + } else if (typeStr == ASSET_MODEL) { // xmodel + result.models << pParseAsset_Model(aZoneFileStream); + } else if (typeStr == ASSET_MATERIAL) { // material + pParseAsset_Material(aZoneFileStream); + } else if (typeStr == ASSET_SHADER) { // pixelshader + pParseAsset_Shader(aZoneFileStream); + } else if (typeStr == ASSET_TECH_SET) { // techset include + result.techSets << pParseAsset_TechSet(aZoneFileStream); + } else if (typeStr == ASSET_IMAGE) { // image + result.images << pParseAsset_Image(aZoneFileStream); + } else if (typeStr == ASSET_SOUND) { // loaded_sound + result.sounds << pParseAsset_Sound(aZoneFileStream); + } else if (typeStr == ASSET_COLLISION_MAP) { // col_map_mp + pParseAsset_ColMapMP(aZoneFileStream); + } else if (typeStr == ASSET_MP_MAP) { // game_map_sp + pParseAsset_GameMapSP(aZoneFileStream); + } else if (typeStr == ASSET_SP_MAP) { // game_map_mp + pParseAsset_GameMapMP(aZoneFileStream); + } else if (typeStr == ASSET_LIGHT_DEF) { // lightdef + pParseAsset_LightDef(aZoneFileStream); + } else if (typeStr == ASSET_UI_MAP) { // ui_map + pParseAsset_UIMap(aZoneFileStream); + } else if (typeStr == ASSET_SND_DRIVER_GLOBALS) { // snddriverglobals + pParseAsset_SNDDriverGlobals(aZoneFileStream); + } else if (typeStr == ASSET_AI_TYPE) { // aitype + pParseAsset_AIType(aZoneFileStream); + } else if (typeStr == ASSET_EFFECT) { // aitype + pParseAsset_FX(aZoneFileStream); + } else if (typeStr == ASSET_ANIMATION) { // aitype + result.animations << pParseAsset_Animation(aZoneFileStream); + } else if (typeStr == ASSET_STRING_TABLE) { // string_table + result.stringTables << pParseAsset_StringTable(aZoneFileStream); + } else if (typeStr == ASSET_MENU) { // string_table + result.menuFiles << pParseAsset_MenuFile(aZoneFileStream); + } else if (typeStr == ASSET_WEAPON) { // string_table + pParseAsset_Weapon(aZoneFileStream); + } else if (typeStr == ASSET_D3DBSP) { // string_table + pParseAsset_D3DBSP(aZoneFileStream); + } + } + return result; +} + +LocalString ZoneFile_COD8_PC::pParseAsset_LocalString(QDataStream *aZoneFileStream) { + LocalString result; + + quint32 stringPtr, aliasPtr; + *aZoneFileStream >> stringPtr >> aliasPtr; + if (stringPtr == 4294967295) { + // Parse local string asset contents + QString localStr; + char localStrChar; + *aZoneFileStream >> localStrChar; + while (localStrChar != 0) { + result.string += localStrChar; + *aZoneFileStream >> localStrChar; + } + } else { + result.string = "String Ptr: " + QString::number(stringPtr); + } + + if (aliasPtr == 4294967295) { + // Parse rawfile name + QString aliasName; + char aliasNameChar; + *aZoneFileStream >> aliasNameChar; + while (aliasNameChar != 0) { + result.alias += aliasNameChar; + *aZoneFileStream >> aliasNameChar; + } + } else { + result.string = "Alias Ptr: " + QString::number(aliasPtr); + } + + return result; +} + +RawFile ZoneFile_COD8_PC::pParseAsset_RawFile(QDataStream *aZoneFileStream) { + RawFile result; + + // Skip start separator FF FF FF FF (pointer?) + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.length; + + // Skip unknown 4 byte data + aZoneFileStream->skipRawData(4); + + // Parse rawfile path + char scriptPathChar; + *aZoneFileStream >> scriptPathChar; + while (scriptPathChar != 0) { + result.path += scriptPathChar; + *aZoneFileStream >> scriptPathChar; + } + result.path.replace(",", ""); + const QStringList pathParts = result.path.split('/'); + if (pathParts.size() == 0) { + qDebug() << "Failed to parse ff path! " << result.path; + exit(-1); + } + + // Parse gsc contents + char rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + while (rawFileContentsChar != 0 && rawFileContentsChar != -1) { + result.contents += rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + } + return result; +} + +void ZoneFile_COD8_PC::pParseAsset_PhysPreset(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Model ZoneFile_COD8_PC::pParseAsset_Model(QDataStream *aZoneFileStream) { + Model result; + + *aZoneFileStream >> result.namePtr >> result.tagCount >> result.rootTagCount + >> result.surfCount >> result.unknownCount >> result.boneNamePtr + >> result.parentListPtr >> result.quatsPtr >> result.transPtr + >> result.partClassPtr >> result.baseMatPtr + >> result.surfsPtr >> result.materialHandlesPtr; + + // Parse XModelLodInfo + for (int i = 1; i <= 4; i++) { + quint32 intDist; + *aZoneFileStream >> intDist; + + std::memcpy(&result.lodInfo[i].dist, &intDist, sizeof(result.lodInfo[i].dist)); + *aZoneFileStream >> result.lodInfo[i].numsurfs >> result.lodInfo[i].surfIndex; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.lodInfo[i].partBits[0] + >> result.lodInfo[i].partBits[1] + >> result.lodInfo[i].partBits[2] + >> result.lodInfo[i].partBits[3]; + } + + *aZoneFileStream >> result.collSurfsPtr >> result.numCollSurfs >> result.contents >> result.boneInfoPtr; + + quint32 intRadius, intMins[3], intMaxs[3]; + *aZoneFileStream >> intRadius >> intMins[0] >> intMins[1] + >> intMins[2] >> intMaxs[0] >> intMaxs[1] >> intMaxs[2]; + + std::memcpy(&result.radius, &intRadius, sizeof(result.radius)); + + std::memcpy(&result.mins[0], &intMins[0], sizeof(result.mins[0])); + std::memcpy(&result.mins[1], &intMins[1], sizeof(result.mins[1])); + std::memcpy(&result.mins[2], &intMins[2], sizeof(result.mins[2])); + + std::memcpy(&result.maxs[0], &intMaxs[0], sizeof(result.maxs[0])); + std::memcpy(&result.maxs[1], &intMaxs[1], sizeof(result.maxs[2])); + std::memcpy(&result.maxs[2], &intMaxs[2], sizeof(result.maxs[3])); + + *aZoneFileStream >> result.numLods >> result.collLod >> result.streamInfoPtr + >> result.memUsage >> result.flags >> result.physPresetPtr >> result.physGeomsPtr; + + // Parse model name + char modelNameChar; + *aZoneFileStream >> modelNameChar; + while (modelNameChar == 0) { + *aZoneFileStream >> modelNameChar; + } + while (modelNameChar != 0) { + result.modelName += modelNameChar; + *aZoneFileStream >> modelNameChar; + } + return result; +} + +Material ZoneFile_COD8_PC::pParseAsset_Material(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); + + return Material(); +} + +Shader ZoneFile_COD8_PC::pParseAsset_Shader(QDataStream *aZoneFileStream) { + Shader result = Shader(); + + quint8 minorVersion, majorVersion; + *aZoneFileStream >> minorVersion >> majorVersion; + + quint32 magic; + *aZoneFileStream >> magic; + + // Verify .fxc magic + if (magic != 65534 && magic != 65535) { return result; } + + SHADER_TYPE type = SHADER_NONE; + quint16 rawShaderType; + *aZoneFileStream >> rawShaderType; + if (rawShaderType == 65535) { // Pixel shader + type = SHADER_PIXEL; + } else if (rawShaderType == 65534) { // Vertex shader + type = SHADER_VERTEX; + } + Q_UNUSED(type); + + while (true) { + quint32 instructionToken; + *aZoneFileStream >> instructionToken; + + SHADER_OPCODE opCode = (SHADER_OPCODE)(instructionToken & 0xffff); + + int size; + if (opCode == OPCODE_End) { + break; + } else if (opCode == OPCODE_Comment) { + size = (int)((instructionToken >> 16) & 0x7FFF); + } else { + size = (int)((instructionToken >> 24) & 0x0f); + } + Q_UNUSED(size); + } + + + return result; +} + +TechSet ZoneFile_COD8_PC::pParseAsset_TechSet(QDataStream *aZoneFileStream) { + TechSet result; + + for (int i = 1; i <= 62; i++) { + quint32 ptr; + *aZoneFileStream >> ptr; + + result.pointers << ptr; + } + qDebug() << aZoneFileStream->device()->pos(); + + // Parse techset name + char techSetNameChar; + *aZoneFileStream >> techSetNameChar; + while (techSetNameChar != 0) { + result.name += techSetNameChar; + *aZoneFileStream >> techSetNameChar; + } + result.name.replace(",", ""); + + return result; +} + +Image ZoneFile_COD8_PC::pParseAsset_Image(QDataStream *aZoneFileStream) { + Image result; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknowna >> result.unknownb + >> result.unknownc >> result.unknownd + >> result.unknowne >> result.unknownf + >> result.unknowng; + + aZoneFileStream->skipRawData(15 * 4); + *aZoneFileStream >> result.unknownh >> result.unknowni; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknownj; + + aZoneFileStream->skipRawData(4); + + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + result.materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + result.materialName.replace(",", ""); + + if (result.unknowna) { + *aZoneFileStream >> result.unknownk; + *aZoneFileStream >> result.unknownl; + *aZoneFileStream >> result.unknownm; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown1; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown2 >> result.unknown3 + >> result.size1 >> result.size2 + >> result.unknown4 >> result.unknown5; + + aZoneFileStream->skipRawData(4); + + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + result.name += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + + *aZoneFileStream >> result.unknown6 >> result.unknown7; + + QByteArray compressionData(8, Qt::Uninitialized); + aZoneFileStream->readRawData(compressionData.data(), 8); + if (compressionData.contains("DXT1")) { + result.compression = COMPRESSION_DXT1; + } else if (compressionData.contains("DXT3")) { + result.compression = COMPRESSION_DXT3; + } else if (compressionData.contains("DXT5")) { + result.compression = COMPRESSION_DXT5; + } else { + result.compression = COMPRESSION_NONE; + } + + *aZoneFileStream >> result.unknown8 >> result.unknown9; + } + + return result; +} + +SoundAsset ZoneFile_COD8_PC::pParseAsset_Sound(QDataStream *aZoneFileStream) { + SoundAsset result; + + qDebug() << aZoneFileStream->device()->pos(); + + QByteArray rootNamePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rootNamePtr.data(), 4); + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.count; + + if (rootNamePtr.toHex() == "ffffffff") { + // Read in sound file name + char soundNameChar; + *aZoneFileStream >> soundNameChar; + while (soundNameChar != 0) { + result.name += soundNameChar; + *aZoneFileStream >> soundNameChar; + } + } + + int tagCount = 0; + int resultCount = 0; + for (quint32 i = 0; i < result.count; i++) { + aZoneFileStream->skipRawData(12); + + QByteArray tagPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(tagPtr.data(), 4); + + if (tagPtr.toHex() == "ffffffff") { + tagCount++; + } + aZoneFileStream->skipRawData(4); + + QByteArray pathPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pathPtr.data(), 4); + + if (pathPtr.toHex() == "ffffffff") { + resultCount++; + } + + aZoneFileStream->skipRawData(160); + } + + for (int i = 0; i < tagCount; i++) { + // Read in tag? + QString tag; + char tagChar; + *aZoneFileStream >> tagChar; + while (tagChar != 0) { + tag += tagChar; + *aZoneFileStream >> tagChar; + } + } + + for (int i = 0; i < resultCount; i++) { + Sound sound; + + if (aZoneFileStream->device()->peek(12).toHex().contains("ffffffff00000000")) { + aZoneFileStream->skipRawData(12); + } + + aZoneFileStream->skipRawData(8); + + QByteArray aliasPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(aliasPtr.data(), 4); + + QByteArray namePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(namePtr.data(), 4); + + *aZoneFileStream >> sound.dataLength; + + if (aliasPtr.toHex() == "ffffffff") { + // Read in sound alias name + char soundAliasChar; + *aZoneFileStream >> soundAliasChar; + while (soundAliasChar != 0) { + sound.alias += soundAliasChar; + *aZoneFileStream >> soundAliasChar; + } + } + + if (aZoneFileStream->device()->peek(4) == "RIFF") { + sound.path = sound.alias; + sound.alias = ""; + } else if (namePtr.toHex() == "ffffffff") { + // Read in sound file path + char soundPathChar; + *aZoneFileStream >> soundPathChar; + while (soundPathChar != 0) { + sound.path += soundPathChar; + *aZoneFileStream >> soundPathChar; + } + sound.path.replace(",", ""); + } + + if (sound.dataLength) { + QByteArray data(sound.dataLength, Qt::Uninitialized); + aZoneFileStream->readRawData(data.data(), sound.dataLength); + sound.data = data; + } + result.sounds.append(sound); + } + + return result; +} + +void ZoneFile_COD8_PC::pParseAsset_ColMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD8_PC::pParseAsset_GameMapSP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD8_PC::pParseAsset_GameMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD8_PC::pParseAsset_LightDef(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD8_PC::pParseAsset_UIMap(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD8_PC::pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD8_PC::pParseAsset_AIType(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD8_PC::pParseAsset_FX(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Animation ZoneFile_COD8_PC::pParseAsset_Animation(QDataStream *aZoneFileStream) { + Animation result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.dataByteCount + >> result.dataShortCount + >> result.dataIntCount + >> result.randomDataByteCount + >> result.randomDataIntCount + >> result.numframes + >> result.isLooped + >> result.isDelta + >> result.noneRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.normalTranslatedBoneCount + >> result.preciseTranslatedBoneCount + >> result.staticTranslatedBoneCount + >> result.noneTranslatedBoneCount + >> result.totalBoneCount + >> result.otherBoneCount1 + >> result.otherBoneCount2 + >> result.notifyCount + >> result.assetType + >> result.pad + >> result.randomDataShortCount + >> result.indexCount + >> result.frameRate + >> result.frequency + >> result.boneIDsPtr + >> result.dataBytePtr + >> result.dataShortPtr + >> result.dataIntPtr + >> result.randomDataShortPtr + >> result.randomDataBytePtr + >> result.randomDataIntPtr + >> result.longIndiciesPtr + >> result.notificationsPtr + >> result.deltaPartsPtr; + + // Read in x_anim file name + QString xAnimName; + char xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + while (xAnimNameChar != 0) { + result.name += xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + } + + // Parse x_anim index header + QVector sectionLengths; + for (int i = 0; i < result.numframes; i++) { + quint8 sectionlength; + *aZoneFileStream >> sectionlength; + sectionLengths.push_back(sectionlength); + // Skip padding + aZoneFileStream->skipRawData(1); + } + // Skip unknown section + aZoneFileStream->skipRawData(2 * 8); + + return result; +} + +MenuFile ZoneFile_COD8_PC::pParseAsset_MenuFile(QDataStream *aZoneFileStream) { + //MENU_FILE + MenuFile result; + + aZoneFileStream->skipRawData(4); // Separator + + // Parse menu def count + *aZoneFileStream >> result.menuCount; + + // Clearly misparsed, never have this much + if (result.menuCount > 1000) { + qDebug() << "Failure reported when parsing menu file."; + return result; + } + for (uint i = 0; i < result.menuCount; i++) { + Menu menu; + + aZoneFileStream->skipRawData(4); // Separator + + // Read in x_anim file name + char menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + while (menuFilepathChar != 0) { + menu.filePath += menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + } + aZoneFileStream->skipRawData(4); // Separator + + *aZoneFileStream >> menu.menuNamePtr; + + float menuRectX, menuRectY, menuRectWidth, menuRectHeight; + *aZoneFileStream >> menuRectX >> menuRectY >> menuRectWidth >> menuRectHeight; + menu.rect = QRectF(menuRectX, menuRectY, menuRectWidth, menuRectHeight); + + quint32 hAlignInt, vAlignInt; + *aZoneFileStream >> hAlignInt >> vAlignInt; + menu.hAlign = (MENU_H_ALIGNMENT)hAlignInt; + menu.vAlign = (MENU_V_ALIGNMENT)vAlignInt; + + float rectClientX, rectClientY, rectClientWidth, rectClientHeight; + *aZoneFileStream >> rectClientX >> rectClientY >> rectClientWidth >> rectClientHeight; + menu.clientRect = QRectF(rectClientX, rectClientY, rectClientWidth, rectClientHeight); + + quint32 hClientAlignInt, vClientAlignInt, styleInt, borderInt; + *aZoneFileStream >> hClientAlignInt >> vClientAlignInt >> menu.groupPtr + >> styleInt >> borderInt >> menu.ownerDraw >> menu.ownerDrawFlags + >> menu.borderSize >> menu.staticFlags >> menu.dynamicFlags >> menu.nextTime; + menu.hClientAlign = (MENU_H_ALIGNMENT)hClientAlignInt; + menu.vClientAlign = (MENU_V_ALIGNMENT)vClientAlignInt; + menu.style = (MENU_WINDOW_STYLE)styleInt; + menu.border = (MENU_WINDOW_BORDER)borderInt; + + float foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA, + backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA, + borderColorR, borderColorG, borderColorB, borderColorA, + outlineColorR, outlineColorG, outlineColorB, outlineColorA; + *aZoneFileStream >> foregroundColorR >> foregroundColorG >> foregroundColorB >> foregroundColorA + >> backgroundColorR >> backgroundColorG >> backgroundColorB >> backgroundColorA + >> borderColorR >> borderColorG >> borderColorB >> borderColorA + >> outlineColorR >> outlineColorG >> outlineColorB >> outlineColorA; + + menu.foregroundColor = QColor(foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA); + menu.backgroundColor = QColor(backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA); + menu.borderColor = QColor(borderColorR, borderColorG, borderColorB, borderColorA); + menu.outlineColor = QColor(outlineColorR, outlineColorG, outlineColorB, outlineColorA); + + *aZoneFileStream >> menu.materialPtr >> menu.fontPtr >> menu.fullScreen >> menu.itemCount + >> menu.fontIndex >> menu.cursorItem >> menu.fadeCycle >> menu.fadeClamp + >> menu.fadeAmount >> menu.fadeInAmount >> menu.blurRadius >> menu.onOpenPtr + >> menu.onFocusPtr >> menu.onClosePtr >> menu.onESCPtr >> menu.onKeyPtr + >> menu.visibleExpCount >> menu.expEntryPtr >> menu.allowedBindingPtr + >> menu.soundNamePtr >> menu.imageTrack; + + float focusColorR, focusColorG, focusColorB, focusColorA, + disabledColorR, disabledColorG, disabledColorB, disabledColorA; + *aZoneFileStream >> focusColorR >> focusColorG >> focusColorB >> focusColorA + >> disabledColorR >> disabledColorG >> disabledColorB >> disabledColorA; + menu.focusColor = QColor(focusColorR, focusColorG, focusColorB, focusColorA); + menu.disabledColor = QColor(disabledColorR, disabledColorG, disabledColorB, disabledColorA); + + *aZoneFileStream >> menu.rectXExpCount >> menu.rectXExpPtr >> menu.rectYExpCount >> menu.rectYExpPtr; + + aZoneFileStream->skipRawData(4); // Separator + + char menuDefNameChar; + int menuDefNameLen = 0; + *aZoneFileStream >> menuDefNameChar; + while (menuDefNameChar != 0 && menuDefNameLen < 30) { + menuDefNameLen++; + menu.name += menuDefNameChar; + *aZoneFileStream >> menuDefNameChar; + } + + char defStringChar; + int defStringLen = 0; + *aZoneFileStream >> defStringChar; + while (defStringChar != 0 && defStringLen < 30) { + defStringLen++; + menu.definition += defStringChar; + *aZoneFileStream >> defStringChar; + } + aZoneFileStream->skipRawData(4 * 10); + + *aZoneFileStream >> menu.itemWindowDefNamePtr; + + float itemRectX, itemRectY, itemRectWidth, itemRectHeight; + *aZoneFileStream >> itemRectX >> itemRectY >> itemRectWidth >> itemRectHeight; + menu.itemRect = QRectF(itemRectX, itemRectY, itemRectWidth, itemRectHeight); + + *aZoneFileStream >> menu.itemHAlignment >> menu.itemVAlignment >> menu.itemGroupPtr + >> menu.itemWindowStyle >> menu.itemWindowBorder >> menu.itemOwnerDraw + >> menu.itemOwnerDrawFlags >> menu.itemBorderSize >> menu.itemStaticFlags + >> menu.itemDynamicFlags >> menu.itemNextTime; + + float itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA, + itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA, + itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA, + itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA; + *aZoneFileStream >> itemForegroundColorR >> itemForegroundColorG >> itemForegroundColorB >> itemForegroundColorA + >> itemBackgroundColorR >> itemBackgroundColorG >> itemBackgroundColorB >> itemBackgroundColorA + >> itemBorderColorR >> itemBorderColorG >> itemBorderColorB >> itemBorderColorA + >> itemOutlineColorR >> itemOutlineColorG >> itemOutlineColorB >> itemOutlineColorA; + + menu.itemForegroundColor = QColor(itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA); + menu.itemBackgroundColor = QColor(itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA); + menu.itemBorderColor = QColor(itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA); + menu.itemOutlineColor = QColor(itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA); + + *aZoneFileStream >> menu.itemMaterialPtr; + + float itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight; + *aZoneFileStream >> itemTextRectX >> itemTextRectY >> itemTextRectWidth >> itemTextRectHeight; + menu.itemTextRect = QRectF(itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight); + + quint32 hItemTextAlignInt, vItemTextAlignInt, itemType, fontTypeInt, textStyleInt; + *aZoneFileStream >> hItemTextAlignInt >> vItemTextAlignInt >> itemType >> menu.dataType + >> menu.alignment >> fontTypeInt >> menu.textAlignMode >> menu.textalignx >> menu.textaligny + >> menu.textscale >> textStyleInt >> menu.gameMsgWindowIndex >> menu.gameMsgWindowMode + >> menu.testPtr >> menu.textSavegameInfo >> menu.parentPtr; + menu.itemText_hAlign = (MENU_H_ALIGNMENT)hItemTextAlignInt; + menu.itemText_vAlign = (MENU_V_ALIGNMENT)vItemTextAlignInt; + menu.itemType = (MENU_ITEM_TYPE)itemType; + menu.fontEnum = (MENU_FONT_TYPE)fontTypeInt; + menu.textStyle = (MENU_ITEM_TEXTSTYLE)textStyleInt; + + *aZoneFileStream >> menu.mouseEnterText >> menu.mouseExitText >> menu.mouseEnter >> menu.mouseExit + >> menu.action >> menu.onAccept >> menu.onFocus >> menu.leaveFocus >> menu.dvar >> menu.dvarTest + >> menu.keyHandlerPtr >> menu.enableDvarPtr >> menu.dvarFlags >> menu.focusSoundPtr + >> menu.special >> menu.cursorPos; + + // itemDefData_t typeData; + + // listBoxDef_s *listBox; + + *aZoneFileStream >> menu.startPos >> menu.endPos >> menu.drawPadding; + + *aZoneFileStream >> menu.elementWidth >> menu.elementHeight; + + *aZoneFileStream >> menu.elementStyle >> menu.numColumns; + + //columnInfo_s columnInfo[16]; + + *aZoneFileStream >> menu.doubleClickPtr; + + + *aZoneFileStream >> menu.notselectable >> menu.noScrollBars >> menu.usePaging; + + float itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA, + itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA, + itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA; + *aZoneFileStream >> itemSelectBorderColorR >> itemSelectBorderColorG >> itemSelectBorderColorB >> itemSelectBorderColorA + >> itemDisableColorR >> itemDisableColorG >> itemDisableColorB >> itemDisableColorA + >> itemFocusColorR >> itemFocusColorG >> itemFocusColorB >> itemFocusColorA; + menu.itemSelectBorderColor = QColor(itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA); + menu.itemDisableColor = QColor(itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA); + menu.itemFocusColor = QColor(itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA); + + *aZoneFileStream >> menu.selectIconPtr >> menu.backgroundItemListboxPtr >> menu.highlightTexturePtr; + + // editFieldDef_s *editField; + + *aZoneFileStream >> menu.minVal >> menu.maxVal >> menu.defVal >> menu.range >> menu.maxChars + >> menu.maxCharsGotoNext >> menu.maxPaintChars >> menu.paintOffset; + + // multiDef_s *multi; + + for (int i = 0; i < 32; i++) { + quint32 dvarList; + *aZoneFileStream >> dvarList; + menu.dvarListPtrs.push_back(dvarList); + } + + for (int i = 0; i < 32; i++) { + quint32 dvarStr; + *aZoneFileStream >> dvarStr; + menu.dvarStrPtrs.push_back(dvarStr); + } + + for (int i = 0; i < 32; i++) { + float dvarValue; + *aZoneFileStream >> dvarValue; + menu.dvarValues.push_back(dvarValue); + } + + *aZoneFileStream >> menu.count >> menu.strDef >> menu.enumDvarNamePtr; + aZoneFileStream->skipRawData(4); + //>> menu.dataPtr + *aZoneFileStream >> menu.itemImageTrack; + + qDebug() << aZoneFileStream->device()->pos(); + + //statement_s visibleExp; + //statement_s textExp; + //statement_s materialExp; + //statement_s rectXExp; + //statement_s rectYExp; + //statement_s rectWExp; + //statement_s rectHExp; + //statement_s foreColorAExp; + result.menuDefs << menu; + } + return result; +} + +void ZoneFile_COD8_PC::pParseAsset_Weapon(QDataStream *aZoneFileStream) { + //WEAPON_FILE + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD8_PC::pParseAsset_D3DBSP(QDataStream *aZoneFileStream) { + //D3DBSP_DUMP + Q_UNUSED(aZoneFileStream); +} + +StringTable ZoneFile_COD8_PC::pParseAsset_StringTable(QDataStream *aZoneFileStream) { + StringTable result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.columnCount + >> result.rowCount; + + // Todo fix this + result.columnCount = 0; + result.rowCount = 0; + + aZoneFileStream->skipRawData(4); + + QString stringTableName; + char stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + while (stringTableNameChar != 0) { + result.name += stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + } + + for (quint32 i = 0; i < result.rowCount; i++) { + QByteArray pointerData(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pointerData.data(), 4); + result.tablePointers.push_back(pointerData.toHex()); + + aZoneFileStream->skipRawData(4); + } + + for (const QString &pointerAddr : result.tablePointers) { + QString leadingContent = ""; + if (pointerAddr == "FFFFFFFF") { + char leadingContentChar; + *aZoneFileStream >> leadingContentChar; + while (leadingContentChar != 0) { + leadingContent += leadingContentChar; + *aZoneFileStream >> leadingContentChar; + } + } else { + leadingContent = pointerAddr; + } + + QString content; + char contentChar; + *aZoneFileStream >> contentChar; + while (contentChar != 0) { + content += contentChar; + *aZoneFileStream >> contentChar; + } + result.content[leadingContent] = content; + } + return result; +} + +AssetType ZoneFile_COD8_PC::AssetStrToEnum(const QString aAssetType) { + const QString cleanedType = aAssetType.toUpper(); + if (cleanedType == "17000000") { // localized string PARTIALLY VERIFIED + return ASSET_LOCAL_STRING; + } else if (cleanedType == "20000000") { // raw_file PARTIALLY VERIFIED + return ASSET_RAW_FILE; + } else if (cleanedType == "1A000000") { // fx PARTIALLY VERIFIED + return ASSET_EFFECT; + } else if (cleanedType == "09000000") { // loaded_sound PARTIALLY VERIFIED + return ASSET_SOUND; + } else if (cleanedType == "04000000") { // x_anim PARTIALLY VERIFIED + return ASSET_ANIMATION; + } else if (cleanedType == "0C000000") { // collision_map PARTIALLY VERIFIED + return ASSET_COLLISION_MAP; + } else if (cleanedType == "21000000") { // string_table PARTIALLY VERIFIED + return ASSET_STRING_TABLE; + } else if (cleanedType == "15000000") { // menu_file PARTIALLY VERIFIED + return ASSET_MENU; + } else if (cleanedType == "07000000") { // tech set PARTIALLY VERIFIED + return ASSET_TECH_SET; + } else if (cleanedType == "18000000") { // weapon PARTIALLY VERIFIED + return ASSET_WEAPON; + } else if (cleanedType == "11000000") { // gfx map PARTIALLY VERIFIED + return ASSET_GFX_MAP; + } else if (cleanedType == "12000000") { // light_def PARTIALLY VERIFIED + return ASSET_LIGHT_DEF; + } else if (cleanedType == "14000000") { // font PARTIALLY VERIFIED + return ASSET_FONT; + } else if (cleanedType == "05000000") { // xmodel PARTIALLY VERIFIED + return ASSET_MODEL; + } else if (cleanedType == "0D000000") { // d3dbsp PARTIALLY VERIFIED + return ASSET_D3DBSP; + } else if (cleanedType == "06000000") { // image PARTIALLY VERIFIED + return ASSET_IMAGE; + } else if (cleanedType == "0E000000") { // game map sp PARTIALLY VERIFIED + return ASSET_GAME_MAP_SP; + } else if (cleanedType == "0B000000") { // col map sp PARTIALLY VERIFIED + return ASSET_COL_MAP_SP; + } + return ASSET_NONE; +} + +QByteArray ZoneFile_COD8_PC::GetBinaryData() { + QByteArray result; + + return result; +} diff --git a/libs/zonefile/PC/zonefile_cod8_pc.h b/libs/zonefile/PC/zonefile_cod8_pc.h new file mode 100644 index 0000000..5ba5f15 --- /dev/null +++ b/libs/zonefile/PC/zonefile_cod8_pc.h @@ -0,0 +1,52 @@ +#ifndef ZONEFILE_COD7_PC_H +#define ZONEFILE_COD7_PC_H + +#include "zonefile.h" + +class ZoneFile_COD8_PC : public ZoneFile +{ +public: + ZoneFile_COD8_PC(); + ~ZoneFile_COD8_PC(); + + bool Load(const QByteArray aFileData) override; + AssetType AssetStrToEnum(const QString aAssetType) override; + + QByteArray GetBinaryData() override; + +protected: + void pParseZoneHeader(QDataStream *aZoneFileStream) override; + quint32 pParseZoneSize(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsA(QDataStream *aZoneFileStream) override; + quint32 pParseZoneTagCount(QDataStream *aZoneFileStream) override; + quint32 pParseZoneRecordCount(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsB(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsC(QDataStream *aZoneFileStream) override; + QStringList pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) override; + QStringList pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) override; + AssetMap pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) override; + LocalString pParseAsset_LocalString(QDataStream *aZoneFileStream) override; + RawFile pParseAsset_RawFile(QDataStream *aZoneFileStream) override; + void pParseAsset_PhysPreset(QDataStream *aZoneFileStream) override; + Model pParseAsset_Model(QDataStream *aZoneFileStream) override; + Material pParseAsset_Material(QDataStream *aZoneFileStream) override; + Shader pParseAsset_Shader(QDataStream *aZoneFileStream) override; + TechSet pParseAsset_TechSet(QDataStream *aZoneFileStream) override; + Image pParseAsset_Image(QDataStream *aZoneFileStream) override; + SoundAsset pParseAsset_Sound(QDataStream *aZoneFileStream) override; + void pParseAsset_ColMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapSP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_LightDef(QDataStream *aZoneFileStream) override; + void pParseAsset_UIMap(QDataStream *aZoneFileStream) override; + void pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) override; + void pParseAsset_AIType(QDataStream *aZoneFileStream) override; + void pParseAsset_FX(QDataStream *aZoneFileStream) override; + Animation pParseAsset_Animation(QDataStream *aZoneFileStream) override; + MenuFile pParseAsset_MenuFile(QDataStream *aZoneFileStream) override; + void pParseAsset_Weapon(QDataStream *aZoneFileStream) override; + void pParseAsset_D3DBSP(QDataStream *aZoneFileStream) override; + StringTable pParseAsset_StringTable(QDataStream *aZoneFileStream) override; +}; + +#endif // ZONEFILE_COD7_PC_H diff --git a/libs/zonefile/PC/zonefile_cod9_pc.cpp b/libs/zonefile/PC/zonefile_cod9_pc.cpp new file mode 100644 index 0000000..c4a2b83 --- /dev/null +++ b/libs/zonefile/PC/zonefile_cod9_pc.cpp @@ -0,0 +1,1072 @@ +#include "zonefile_cod9_pc.h" + +#include +#include +#include + +ZoneFile_COD9_PC::ZoneFile_COD9_PC() +{ + +} + +ZoneFile_COD9_PC::~ZoneFile_COD9_PC() +{ + +} + +bool ZoneFile_COD9_PC::Load(const QByteArray aFileData) { + // Open zone file as little endian stream + QDataStream zoneFileStream(aFileData); + zoneFileStream.setByteOrder(QDataStream::LittleEndian); + + // Parse data from zone file header + pParseZoneHeader(&zoneFileStream); + SetRecords(pParseZoneIndex(&zoneFileStream, GetRecordCount())); + SetAssetMap(pParseAssets(&zoneFileStream, GetRecords())); + + return true; +} + +void ZoneFile_COD9_PC::pParseZoneHeader(QDataStream *aZoneFileStream) { + SetSize(pParseZoneSize(aZoneFileStream)); + pParseZoneUnknownsA(aZoneFileStream); + + SetTagCount(pParseZoneTagCount(aZoneFileStream)); + pParseZoneUnknownsB(aZoneFileStream); + + SetRecordCount(pParseZoneRecordCount(aZoneFileStream)); + + quint32 tagCount = GetTagCount(); + if (tagCount) { + pParseZoneUnknownsC(aZoneFileStream); + SetTags(pParseZoneTags(aZoneFileStream, tagCount)); + } else { + aZoneFileStream->skipRawData(4); + } +} + +quint32 ZoneFile_COD9_PC::pParseZoneSize(QDataStream *aZoneFileStream) { + quint32 zoneFileSize; + *aZoneFileStream >> zoneFileSize; + if (zoneFileSize <= 0) { + qDebug() << "Tried to open empty zone file!"; + exit(-1); + } + zoneFileSize += 36; + return zoneFileSize; +} + +/* + ParseZoneUnknownsA() + + Parses the 1st section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD9_PC::pParseZoneUnknownsA(QDataStream *aZoneFileStream) { + // Byte 4-7, 8-11, 12-15: unknown + QByteArray unknown1(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown1.data(), 4); + + QByteArray unknown2(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown2.data(), 4); + + QByteArray unknown3(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown3.data(), 4); + + // Byte 16-19, 20-23: empty/unknown + QByteArray unknown4(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown4.data(), 4); + + QByteArray unknown5(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown5.data(), 4); + + // Byte 24-27: somehow related to the filesize, but smaller value + QByteArray unknown6(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown6.data(), 4); + + // Byte 28-31, 32-35: unknown + QByteArray unknown7(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown7.data(), 4); + + QByteArray unknown8(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown8.data(), 4); +} + +/* + ParseZoneTagCount() + + Parses the number of string tags in the zone index +*/ +quint32 ZoneFile_COD9_PC::pParseZoneTagCount(QDataStream *aZoneFileStream) { + quint32 tagCount; + *aZoneFileStream >> tagCount; + return tagCount; +} + +/* + ParseZoneRecordCount() + + Parses the number of records in the zone index +*/ +quint32 ZoneFile_COD9_PC::pParseZoneRecordCount(QDataStream *aZoneFileStream) { + quint32 recordCount; + *aZoneFileStream >> recordCount; + return recordCount; +} + +/* + ParseZoneUnknownsB() + + Parses the 2nd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD9_PC::pParseZoneUnknownsB(QDataStream *aZoneFileStream) { + // Byte 44-47: Unknown/empty? + QByteArray unknown9(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown9.data(), 4); +} + +/* + pParseZoneUnknownsC() + + Parses the 3rd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD9_PC::pParseZoneUnknownsC(QDataStream *aZoneFileStream) { + // Byte 40-43: Unknown/empty? + QByteArray unknown10(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown10.data(), 4); + + // Byte 44-47: Unknown/empty? + QByteArray unknown11(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown11.data(), 4); +} + +/* + ParseZoneTags() + + Parses the string tags ate the start of zone file +*/ +QStringList ZoneFile_COD9_PC::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) { + QStringList tags; + + // Byte 48-51: Repeated separators? ÿÿÿÿ x i + aZoneFileStream->skipRawData(4 * (tagCount - 1)); + + // Parse tags/strings before index + QString zoneTag; + char zoneTagChar; + for (quint32 i = 0; i < tagCount; i++) { + *aZoneFileStream >> zoneTagChar; + while (zoneTagChar != 0) { + zoneTag += zoneTagChar; + *aZoneFileStream >> zoneTagChar; + } + tags << zoneTag; + zoneTag.clear(); + } + return tags; +} + +/* + ParseZoneIndex() + + Parse the binary zone index data and populate table +*/ +QStringList ZoneFile_COD9_PC::pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) { + QStringList result; + + // Don't parse if no records + if (!recordCount) { return result; } + + if (aZoneFileStream->device()->peek(4).toHex().contains("ffff")) { + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 2); + } + + // Parse index & map found asset types + for (quint32 i = 0; i <= recordCount; i++) { + // Skip record start + QByteArray rawAssetType(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rawAssetType.data(), 4); + result << rawAssetType.toHex(); + + // Skip separator + aZoneFileStream->skipRawData(4); + } + return result; +} + +AssetMap ZoneFile_COD9_PC::pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) { + AssetMap result; + + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 8); + + for (int i = 0; i < assetOrder.size(); i++) { + const QString typeHex = assetOrder[i]; + const AssetType typeStr = AssetStrToEnum(typeHex); + + if (typeStr == ASSET_LOCAL_STRING) { // localized string asset + result.localStrings << pParseAsset_LocalString(aZoneFileStream); + } else if (typeStr == ASSET_RAW_FILE) { // gsc + auto rawFile = pParseAsset_RawFile(aZoneFileStream); + if (rawFile.length) { + result.rawFiles << rawFile; + } + } else if (typeStr == ASSET_PHYS_PRESET) { // physpreset + pParseAsset_PhysPreset(aZoneFileStream); + } else if (typeStr == ASSET_MODEL) { // xmodel + result.models << pParseAsset_Model(aZoneFileStream); + } else if (typeStr == ASSET_MATERIAL) { // material + pParseAsset_Material(aZoneFileStream); + } else if (typeStr == ASSET_SHADER) { // pixelshader + pParseAsset_Shader(aZoneFileStream); + } else if (typeStr == ASSET_TECH_SET) { // techset include + result.techSets << pParseAsset_TechSet(aZoneFileStream); + } else if (typeStr == ASSET_IMAGE) { // image + result.images << pParseAsset_Image(aZoneFileStream); + } else if (typeStr == ASSET_SOUND) { // loaded_sound + result.sounds << pParseAsset_Sound(aZoneFileStream); + } else if (typeStr == ASSET_COLLISION_MAP) { // col_map_mp + pParseAsset_ColMapMP(aZoneFileStream); + } else if (typeStr == ASSET_MP_MAP) { // game_map_sp + pParseAsset_GameMapSP(aZoneFileStream); + } else if (typeStr == ASSET_SP_MAP) { // game_map_mp + pParseAsset_GameMapMP(aZoneFileStream); + } else if (typeStr == ASSET_LIGHT_DEF) { // lightdef + pParseAsset_LightDef(aZoneFileStream); + } else if (typeStr == ASSET_UI_MAP) { // ui_map + pParseAsset_UIMap(aZoneFileStream); + } else if (typeStr == ASSET_SND_DRIVER_GLOBALS) { // snddriverglobals + pParseAsset_SNDDriverGlobals(aZoneFileStream); + } else if (typeStr == ASSET_AI_TYPE) { // aitype + pParseAsset_AIType(aZoneFileStream); + } else if (typeStr == ASSET_EFFECT) { // aitype + pParseAsset_FX(aZoneFileStream); + } else if (typeStr == ASSET_ANIMATION) { // aitype + result.animations << pParseAsset_Animation(aZoneFileStream); + } else if (typeStr == ASSET_STRING_TABLE) { // string_table + result.stringTables << pParseAsset_StringTable(aZoneFileStream); + } else if (typeStr == ASSET_MENU) { // string_table + result.menuFiles << pParseAsset_MenuFile(aZoneFileStream); + } else if (typeStr == ASSET_WEAPON) { // string_table + pParseAsset_Weapon(aZoneFileStream); + } else if (typeStr == ASSET_D3DBSP) { // string_table + pParseAsset_D3DBSP(aZoneFileStream); + } + } + return result; +} + +LocalString ZoneFile_COD9_PC::pParseAsset_LocalString(QDataStream *aZoneFileStream) { + LocalString result; + + quint32 stringPtr, aliasPtr; + *aZoneFileStream >> stringPtr >> aliasPtr; + if (stringPtr == 4294967295) { + // Parse local string asset contents + QString localStr; + char localStrChar; + *aZoneFileStream >> localStrChar; + while (localStrChar != 0) { + result.string += localStrChar; + *aZoneFileStream >> localStrChar; + } + } else { + result.string = "String Ptr: " + QString::number(stringPtr); + } + + if (aliasPtr == 4294967295) { + // Parse rawfile name + QString aliasName; + char aliasNameChar; + *aZoneFileStream >> aliasNameChar; + while (aliasNameChar != 0) { + result.alias += aliasNameChar; + *aZoneFileStream >> aliasNameChar; + } + } else { + result.string = "Alias Ptr: " + QString::number(aliasPtr); + } + + return result; +} + +RawFile ZoneFile_COD9_PC::pParseAsset_RawFile(QDataStream *aZoneFileStream) { + RawFile result; + + // Skip start separator FF FF FF FF (pointer?) + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.length; + + // Skip unknown 4 byte data + aZoneFileStream->skipRawData(4); + + // Parse rawfile path + char scriptPathChar; + *aZoneFileStream >> scriptPathChar; + while (scriptPathChar != 0) { + result.path += scriptPathChar; + *aZoneFileStream >> scriptPathChar; + } + result.path.replace(",", ""); + const QStringList pathParts = result.path.split('/'); + if (pathParts.size() == 0) { + qDebug() << "Failed to parse ff path! " << result.path; + exit(-1); + } + + // Parse gsc contents + char rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + while (rawFileContentsChar != 0 && rawFileContentsChar != -1) { + result.contents += rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + } + return result; +} + +void ZoneFile_COD9_PC::pParseAsset_PhysPreset(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Model ZoneFile_COD9_PC::pParseAsset_Model(QDataStream *aZoneFileStream) { + Model result; + + *aZoneFileStream >> result.namePtr >> result.tagCount >> result.rootTagCount + >> result.surfCount >> result.unknownCount >> result.boneNamePtr + >> result.parentListPtr >> result.quatsPtr >> result.transPtr + >> result.partClassPtr >> result.baseMatPtr + >> result.surfsPtr >> result.materialHandlesPtr; + + // Parse XModelLodInfo + for (int i = 1; i <= 4; i++) { + quint32 intDist; + *aZoneFileStream >> intDist; + + std::memcpy(&result.lodInfo[i].dist, &intDist, sizeof(result.lodInfo[i].dist)); + *aZoneFileStream >> result.lodInfo[i].numsurfs >> result.lodInfo[i].surfIndex; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.lodInfo[i].partBits[0] + >> result.lodInfo[i].partBits[1] + >> result.lodInfo[i].partBits[2] + >> result.lodInfo[i].partBits[3]; + } + + *aZoneFileStream >> result.collSurfsPtr >> result.numCollSurfs >> result.contents >> result.boneInfoPtr; + + quint32 intRadius, intMins[3], intMaxs[3]; + *aZoneFileStream >> intRadius >> intMins[0] >> intMins[1] + >> intMins[2] >> intMaxs[0] >> intMaxs[1] >> intMaxs[2]; + + std::memcpy(&result.radius, &intRadius, sizeof(result.radius)); + + std::memcpy(&result.mins[0], &intMins[0], sizeof(result.mins[0])); + std::memcpy(&result.mins[1], &intMins[1], sizeof(result.mins[1])); + std::memcpy(&result.mins[2], &intMins[2], sizeof(result.mins[2])); + + std::memcpy(&result.maxs[0], &intMaxs[0], sizeof(result.maxs[0])); + std::memcpy(&result.maxs[1], &intMaxs[1], sizeof(result.maxs[2])); + std::memcpy(&result.maxs[2], &intMaxs[2], sizeof(result.maxs[3])); + + *aZoneFileStream >> result.numLods >> result.collLod >> result.streamInfoPtr + >> result.memUsage >> result.flags >> result.physPresetPtr >> result.physGeomsPtr; + + // Parse model name + char modelNameChar; + *aZoneFileStream >> modelNameChar; + while (modelNameChar == 0) { + *aZoneFileStream >> modelNameChar; + } + while (modelNameChar != 0) { + result.modelName += modelNameChar; + *aZoneFileStream >> modelNameChar; + } + return result; +} + +Material ZoneFile_COD9_PC::pParseAsset_Material(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); + + return Material(); +} + +Shader ZoneFile_COD9_PC::pParseAsset_Shader(QDataStream *aZoneFileStream) { + Shader result = Shader(); + + quint8 minorVersion, majorVersion; + *aZoneFileStream >> minorVersion >> majorVersion; + + quint32 magic; + *aZoneFileStream >> magic; + + // Verify .fxc magic + if (magic != 65534 && magic != 65535) { return result; } + + SHADER_TYPE type = SHADER_NONE; + quint16 rawShaderType; + *aZoneFileStream >> rawShaderType; + if (rawShaderType == 65535) { // Pixel shader + type = SHADER_PIXEL; + } else if (rawShaderType == 65534) { // Vertex shader + type = SHADER_VERTEX; + } + Q_UNUSED(type); + + while (true) { + quint32 instructionToken; + *aZoneFileStream >> instructionToken; + + SHADER_OPCODE opCode = (SHADER_OPCODE)(instructionToken & 0xffff); + + int size; + if (opCode == OPCODE_End) { + break; + } else if (opCode == OPCODE_Comment) { + size = (int)((instructionToken >> 16) & 0x7FFF); + } else { + size = (int)((instructionToken >> 24) & 0x0f); + } + Q_UNUSED(size); + } + + + return result; +} + +TechSet ZoneFile_COD9_PC::pParseAsset_TechSet(QDataStream *aZoneFileStream) { + TechSet result; + + for (int i = 1; i <= 62; i++) { + quint32 ptr; + *aZoneFileStream >> ptr; + + result.pointers << ptr; + } + qDebug() << aZoneFileStream->device()->pos(); + + // Parse techset name + char techSetNameChar; + *aZoneFileStream >> techSetNameChar; + while (techSetNameChar != 0) { + result.name += techSetNameChar; + *aZoneFileStream >> techSetNameChar; + } + result.name.replace(",", ""); + + return result; +} + +Image ZoneFile_COD9_PC::pParseAsset_Image(QDataStream *aZoneFileStream) { + Image result; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknowna >> result.unknownb + >> result.unknownc >> result.unknownd + >> result.unknowne >> result.unknownf + >> result.unknowng; + + aZoneFileStream->skipRawData(15 * 4); + *aZoneFileStream >> result.unknownh >> result.unknowni; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknownj; + + aZoneFileStream->skipRawData(4); + + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + result.materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + result.materialName.replace(",", ""); + + if (result.unknowna) { + *aZoneFileStream >> result.unknownk; + *aZoneFileStream >> result.unknownl; + *aZoneFileStream >> result.unknownm; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown1; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown2 >> result.unknown3 + >> result.size1 >> result.size2 + >> result.unknown4 >> result.unknown5; + + aZoneFileStream->skipRawData(4); + + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + result.name += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + + *aZoneFileStream >> result.unknown6 >> result.unknown7; + + QByteArray compressionData(8, Qt::Uninitialized); + aZoneFileStream->readRawData(compressionData.data(), 8); + if (compressionData.contains("DXT1")) { + result.compression = COMPRESSION_DXT1; + } else if (compressionData.contains("DXT3")) { + result.compression = COMPRESSION_DXT3; + } else if (compressionData.contains("DXT5")) { + result.compression = COMPRESSION_DXT5; + } else { + result.compression = COMPRESSION_NONE; + } + + *aZoneFileStream >> result.unknown8 >> result.unknown9; + } + + return result; +} + +SoundAsset ZoneFile_COD9_PC::pParseAsset_Sound(QDataStream *aZoneFileStream) { + SoundAsset result; + + qDebug() << aZoneFileStream->device()->pos(); + + QByteArray rootNamePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rootNamePtr.data(), 4); + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.count; + + if (rootNamePtr.toHex() == "ffffffff") { + // Read in sound file name + char soundNameChar; + *aZoneFileStream >> soundNameChar; + while (soundNameChar != 0) { + result.name += soundNameChar; + *aZoneFileStream >> soundNameChar; + } + } + + int tagCount = 0; + int resultCount = 0; + for (quint32 i = 0; i < result.count; i++) { + aZoneFileStream->skipRawData(12); + + QByteArray tagPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(tagPtr.data(), 4); + + if (tagPtr.toHex() == "ffffffff") { + tagCount++; + } + aZoneFileStream->skipRawData(4); + + QByteArray pathPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pathPtr.data(), 4); + + if (pathPtr.toHex() == "ffffffff") { + resultCount++; + } + + aZoneFileStream->skipRawData(160); + } + + for (int i = 0; i < tagCount; i++) { + // Read in tag? + QString tag; + char tagChar; + *aZoneFileStream >> tagChar; + while (tagChar != 0) { + tag += tagChar; + *aZoneFileStream >> tagChar; + } + } + + for (int i = 0; i < resultCount; i++) { + Sound sound; + + if (aZoneFileStream->device()->peek(12).toHex().contains("ffffffff00000000")) { + aZoneFileStream->skipRawData(12); + } + + aZoneFileStream->skipRawData(8); + + QByteArray aliasPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(aliasPtr.data(), 4); + + QByteArray namePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(namePtr.data(), 4); + + *aZoneFileStream >> sound.dataLength; + + if (aliasPtr.toHex() == "ffffffff") { + // Read in sound alias name + char soundAliasChar; + *aZoneFileStream >> soundAliasChar; + while (soundAliasChar != 0) { + sound.alias += soundAliasChar; + *aZoneFileStream >> soundAliasChar; + } + } + + if (aZoneFileStream->device()->peek(4) == "RIFF") { + sound.path = sound.alias; + sound.alias = ""; + } else if (namePtr.toHex() == "ffffffff") { + // Read in sound file path + char soundPathChar; + *aZoneFileStream >> soundPathChar; + while (soundPathChar != 0) { + sound.path += soundPathChar; + *aZoneFileStream >> soundPathChar; + } + sound.path.replace(",", ""); + } + + if (sound.dataLength) { + QByteArray data(sound.dataLength, Qt::Uninitialized); + aZoneFileStream->readRawData(data.data(), sound.dataLength); + sound.data = data; + } + result.sounds.append(sound); + } + + return result; +} + +void ZoneFile_COD9_PC::pParseAsset_ColMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD9_PC::pParseAsset_GameMapSP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD9_PC::pParseAsset_GameMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD9_PC::pParseAsset_LightDef(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD9_PC::pParseAsset_UIMap(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD9_PC::pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD9_PC::pParseAsset_AIType(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD9_PC::pParseAsset_FX(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Animation ZoneFile_COD9_PC::pParseAsset_Animation(QDataStream *aZoneFileStream) { + Animation result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.dataByteCount + >> result.dataShortCount + >> result.dataIntCount + >> result.randomDataByteCount + >> result.randomDataIntCount + >> result.numframes + >> result.isLooped + >> result.isDelta + >> result.noneRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.normalTranslatedBoneCount + >> result.preciseTranslatedBoneCount + >> result.staticTranslatedBoneCount + >> result.noneTranslatedBoneCount + >> result.totalBoneCount + >> result.otherBoneCount1 + >> result.otherBoneCount2 + >> result.notifyCount + >> result.assetType + >> result.pad + >> result.randomDataShortCount + >> result.indexCount + >> result.frameRate + >> result.frequency + >> result.boneIDsPtr + >> result.dataBytePtr + >> result.dataShortPtr + >> result.dataIntPtr + >> result.randomDataShortPtr + >> result.randomDataBytePtr + >> result.randomDataIntPtr + >> result.longIndiciesPtr + >> result.notificationsPtr + >> result.deltaPartsPtr; + + // Read in x_anim file name + QString xAnimName; + char xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + while (xAnimNameChar != 0) { + result.name += xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + } + + // Parse x_anim index header + QVector sectionLengths; + for (int i = 0; i < result.numframes; i++) { + quint8 sectionlength; + *aZoneFileStream >> sectionlength; + sectionLengths.push_back(sectionlength); + // Skip padding + aZoneFileStream->skipRawData(1); + } + // Skip unknown section + aZoneFileStream->skipRawData(2 * 8); + + return result; +} + +MenuFile ZoneFile_COD9_PC::pParseAsset_MenuFile(QDataStream *aZoneFileStream) { + //MENU_FILE + MenuFile result; + + aZoneFileStream->skipRawData(4); // Separator + + // Parse menu def count + *aZoneFileStream >> result.menuCount; + + // Clearly misparsed, never have this much + if (result.menuCount > 1000) { + qDebug() << "Failure reported when parsing menu file."; + return result; + } + for (uint i = 0; i < result.menuCount; i++) { + Menu menu; + + aZoneFileStream->skipRawData(4); // Separator + + // Read in x_anim file name + char menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + while (menuFilepathChar != 0) { + menu.filePath += menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + } + aZoneFileStream->skipRawData(4); // Separator + + *aZoneFileStream >> menu.menuNamePtr; + + float menuRectX, menuRectY, menuRectWidth, menuRectHeight; + *aZoneFileStream >> menuRectX >> menuRectY >> menuRectWidth >> menuRectHeight; + menu.rect = QRectF(menuRectX, menuRectY, menuRectWidth, menuRectHeight); + + quint32 hAlignInt, vAlignInt; + *aZoneFileStream >> hAlignInt >> vAlignInt; + menu.hAlign = (MENU_H_ALIGNMENT)hAlignInt; + menu.vAlign = (MENU_V_ALIGNMENT)vAlignInt; + + float rectClientX, rectClientY, rectClientWidth, rectClientHeight; + *aZoneFileStream >> rectClientX >> rectClientY >> rectClientWidth >> rectClientHeight; + menu.clientRect = QRectF(rectClientX, rectClientY, rectClientWidth, rectClientHeight); + + quint32 hClientAlignInt, vClientAlignInt, styleInt, borderInt; + *aZoneFileStream >> hClientAlignInt >> vClientAlignInt >> menu.groupPtr + >> styleInt >> borderInt >> menu.ownerDraw >> menu.ownerDrawFlags + >> menu.borderSize >> menu.staticFlags >> menu.dynamicFlags >> menu.nextTime; + menu.hClientAlign = (MENU_H_ALIGNMENT)hClientAlignInt; + menu.vClientAlign = (MENU_V_ALIGNMENT)vClientAlignInt; + menu.style = (MENU_WINDOW_STYLE)styleInt; + menu.border = (MENU_WINDOW_BORDER)borderInt; + + float foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA, + backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA, + borderColorR, borderColorG, borderColorB, borderColorA, + outlineColorR, outlineColorG, outlineColorB, outlineColorA; + *aZoneFileStream >> foregroundColorR >> foregroundColorG >> foregroundColorB >> foregroundColorA + >> backgroundColorR >> backgroundColorG >> backgroundColorB >> backgroundColorA + >> borderColorR >> borderColorG >> borderColorB >> borderColorA + >> outlineColorR >> outlineColorG >> outlineColorB >> outlineColorA; + + menu.foregroundColor = QColor(foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA); + menu.backgroundColor = QColor(backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA); + menu.borderColor = QColor(borderColorR, borderColorG, borderColorB, borderColorA); + menu.outlineColor = QColor(outlineColorR, outlineColorG, outlineColorB, outlineColorA); + + *aZoneFileStream >> menu.materialPtr >> menu.fontPtr >> menu.fullScreen >> menu.itemCount + >> menu.fontIndex >> menu.cursorItem >> menu.fadeCycle >> menu.fadeClamp + >> menu.fadeAmount >> menu.fadeInAmount >> menu.blurRadius >> menu.onOpenPtr + >> menu.onFocusPtr >> menu.onClosePtr >> menu.onESCPtr >> menu.onKeyPtr + >> menu.visibleExpCount >> menu.expEntryPtr >> menu.allowedBindingPtr + >> menu.soundNamePtr >> menu.imageTrack; + + float focusColorR, focusColorG, focusColorB, focusColorA, + disabledColorR, disabledColorG, disabledColorB, disabledColorA; + *aZoneFileStream >> focusColorR >> focusColorG >> focusColorB >> focusColorA + >> disabledColorR >> disabledColorG >> disabledColorB >> disabledColorA; + menu.focusColor = QColor(focusColorR, focusColorG, focusColorB, focusColorA); + menu.disabledColor = QColor(disabledColorR, disabledColorG, disabledColorB, disabledColorA); + + *aZoneFileStream >> menu.rectXExpCount >> menu.rectXExpPtr >> menu.rectYExpCount >> menu.rectYExpPtr; + + aZoneFileStream->skipRawData(4); // Separator + + char menuDefNameChar; + int menuDefNameLen = 0; + *aZoneFileStream >> menuDefNameChar; + while (menuDefNameChar != 0 && menuDefNameLen < 30) { + menuDefNameLen++; + menu.name += menuDefNameChar; + *aZoneFileStream >> menuDefNameChar; + } + + char defStringChar; + int defStringLen = 0; + *aZoneFileStream >> defStringChar; + while (defStringChar != 0 && defStringLen < 30) { + defStringLen++; + menu.definition += defStringChar; + *aZoneFileStream >> defStringChar; + } + aZoneFileStream->skipRawData(4 * 10); + + *aZoneFileStream >> menu.itemWindowDefNamePtr; + + float itemRectX, itemRectY, itemRectWidth, itemRectHeight; + *aZoneFileStream >> itemRectX >> itemRectY >> itemRectWidth >> itemRectHeight; + menu.itemRect = QRectF(itemRectX, itemRectY, itemRectWidth, itemRectHeight); + + *aZoneFileStream >> menu.itemHAlignment >> menu.itemVAlignment >> menu.itemGroupPtr + >> menu.itemWindowStyle >> menu.itemWindowBorder >> menu.itemOwnerDraw + >> menu.itemOwnerDrawFlags >> menu.itemBorderSize >> menu.itemStaticFlags + >> menu.itemDynamicFlags >> menu.itemNextTime; + + float itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA, + itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA, + itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA, + itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA; + *aZoneFileStream >> itemForegroundColorR >> itemForegroundColorG >> itemForegroundColorB >> itemForegroundColorA + >> itemBackgroundColorR >> itemBackgroundColorG >> itemBackgroundColorB >> itemBackgroundColorA + >> itemBorderColorR >> itemBorderColorG >> itemBorderColorB >> itemBorderColorA + >> itemOutlineColorR >> itemOutlineColorG >> itemOutlineColorB >> itemOutlineColorA; + + menu.itemForegroundColor = QColor(itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA); + menu.itemBackgroundColor = QColor(itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA); + menu.itemBorderColor = QColor(itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA); + menu.itemOutlineColor = QColor(itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA); + + *aZoneFileStream >> menu.itemMaterialPtr; + + float itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight; + *aZoneFileStream >> itemTextRectX >> itemTextRectY >> itemTextRectWidth >> itemTextRectHeight; + menu.itemTextRect = QRectF(itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight); + + quint32 hItemTextAlignInt, vItemTextAlignInt, itemType, fontTypeInt, textStyleInt; + *aZoneFileStream >> hItemTextAlignInt >> vItemTextAlignInt >> itemType >> menu.dataType + >> menu.alignment >> fontTypeInt >> menu.textAlignMode >> menu.textalignx >> menu.textaligny + >> menu.textscale >> textStyleInt >> menu.gameMsgWindowIndex >> menu.gameMsgWindowMode + >> menu.testPtr >> menu.textSavegameInfo >> menu.parentPtr; + menu.itemText_hAlign = (MENU_H_ALIGNMENT)hItemTextAlignInt; + menu.itemText_vAlign = (MENU_V_ALIGNMENT)vItemTextAlignInt; + menu.itemType = (MENU_ITEM_TYPE)itemType; + menu.fontEnum = (MENU_FONT_TYPE)fontTypeInt; + menu.textStyle = (MENU_ITEM_TEXTSTYLE)textStyleInt; + + *aZoneFileStream >> menu.mouseEnterText >> menu.mouseExitText >> menu.mouseEnter >> menu.mouseExit + >> menu.action >> menu.onAccept >> menu.onFocus >> menu.leaveFocus >> menu.dvar >> menu.dvarTest + >> menu.keyHandlerPtr >> menu.enableDvarPtr >> menu.dvarFlags >> menu.focusSoundPtr + >> menu.special >> menu.cursorPos; + + // itemDefData_t typeData; + + // listBoxDef_s *listBox; + + *aZoneFileStream >> menu.startPos >> menu.endPos >> menu.drawPadding; + + *aZoneFileStream >> menu.elementWidth >> menu.elementHeight; + + *aZoneFileStream >> menu.elementStyle >> menu.numColumns; + + //columnInfo_s columnInfo[16]; + + *aZoneFileStream >> menu.doubleClickPtr; + + + *aZoneFileStream >> menu.notselectable >> menu.noScrollBars >> menu.usePaging; + + float itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA, + itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA, + itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA; + *aZoneFileStream >> itemSelectBorderColorR >> itemSelectBorderColorG >> itemSelectBorderColorB >> itemSelectBorderColorA + >> itemDisableColorR >> itemDisableColorG >> itemDisableColorB >> itemDisableColorA + >> itemFocusColorR >> itemFocusColorG >> itemFocusColorB >> itemFocusColorA; + menu.itemSelectBorderColor = QColor(itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA); + menu.itemDisableColor = QColor(itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA); + menu.itemFocusColor = QColor(itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA); + + *aZoneFileStream >> menu.selectIconPtr >> menu.backgroundItemListboxPtr >> menu.highlightTexturePtr; + + // editFieldDef_s *editField; + + *aZoneFileStream >> menu.minVal >> menu.maxVal >> menu.defVal >> menu.range >> menu.maxChars + >> menu.maxCharsGotoNext >> menu.maxPaintChars >> menu.paintOffset; + + // multiDef_s *multi; + + for (int i = 0; i < 32; i++) { + quint32 dvarList; + *aZoneFileStream >> dvarList; + menu.dvarListPtrs.push_back(dvarList); + } + + for (int i = 0; i < 32; i++) { + quint32 dvarStr; + *aZoneFileStream >> dvarStr; + menu.dvarStrPtrs.push_back(dvarStr); + } + + for (int i = 0; i < 32; i++) { + float dvarValue; + *aZoneFileStream >> dvarValue; + menu.dvarValues.push_back(dvarValue); + } + + *aZoneFileStream >> menu.count >> menu.strDef >> menu.enumDvarNamePtr; + aZoneFileStream->skipRawData(4); + //>> menu.dataPtr + *aZoneFileStream >> menu.itemImageTrack; + + qDebug() << aZoneFileStream->device()->pos(); + + //statement_s visibleExp; + //statement_s textExp; + //statement_s materialExp; + //statement_s rectXExp; + //statement_s rectYExp; + //statement_s rectWExp; + //statement_s rectHExp; + //statement_s foreColorAExp; + result.menuDefs << menu; + } + return result; +} + +void ZoneFile_COD9_PC::pParseAsset_Weapon(QDataStream *aZoneFileStream) { + //WEAPON_FILE + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD9_PC::pParseAsset_D3DBSP(QDataStream *aZoneFileStream) { + //D3DBSP_DUMP + Q_UNUSED(aZoneFileStream); +} + +StringTable ZoneFile_COD9_PC::pParseAsset_StringTable(QDataStream *aZoneFileStream) { + StringTable result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.columnCount + >> result.rowCount; + + // Todo fix this + result.columnCount = 0; + result.rowCount = 0; + + aZoneFileStream->skipRawData(4); + + QString stringTableName; + char stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + while (stringTableNameChar != 0) { + result.name += stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + } + + for (quint32 i = 0; i < result.rowCount; i++) { + QByteArray pointerData(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pointerData.data(), 4); + result.tablePointers.push_back(pointerData.toHex()); + + aZoneFileStream->skipRawData(4); + } + + for (const QString &pointerAddr : result.tablePointers) { + QString leadingContent = ""; + if (pointerAddr == "FFFFFFFF") { + char leadingContentChar; + *aZoneFileStream >> leadingContentChar; + while (leadingContentChar != 0) { + leadingContent += leadingContentChar; + *aZoneFileStream >> leadingContentChar; + } + } else { + leadingContent = pointerAddr; + } + + QString content; + char contentChar; + *aZoneFileStream >> contentChar; + while (contentChar != 0) { + content += contentChar; + *aZoneFileStream >> contentChar; + } + result.content[leadingContent] = content; + } + return result; +} + +AssetType ZoneFile_COD9_PC::AssetStrToEnum(const QString aAssetType) { + const QString cleanedType = aAssetType.toUpper(); + if (cleanedType == "17000000") { // localized string PARTIALLY VERIFIED + return ASSET_LOCAL_STRING; + } else if (cleanedType == "20000000") { // raw_file PARTIALLY VERIFIED + return ASSET_RAW_FILE; + } else if (cleanedType == "1A000000") { // fx PARTIALLY VERIFIED + return ASSET_EFFECT; + } else if (cleanedType == "09000000") { // loaded_sound PARTIALLY VERIFIED + return ASSET_SOUND; + } else if (cleanedType == "04000000") { // x_anim PARTIALLY VERIFIED + return ASSET_ANIMATION; + } else if (cleanedType == "0C000000") { // collision_map PARTIALLY VERIFIED + return ASSET_COLLISION_MAP; + } else if (cleanedType == "21000000") { // string_table PARTIALLY VERIFIED + return ASSET_STRING_TABLE; + } else if (cleanedType == "15000000") { // menu_file PARTIALLY VERIFIED + return ASSET_MENU; + } else if (cleanedType == "07000000") { // tech set PARTIALLY VERIFIED + return ASSET_TECH_SET; + } else if (cleanedType == "18000000") { // weapon PARTIALLY VERIFIED + return ASSET_WEAPON; + } else if (cleanedType == "11000000") { // gfx map PARTIALLY VERIFIED + return ASSET_GFX_MAP; + } else if (cleanedType == "12000000") { // light_def PARTIALLY VERIFIED + return ASSET_LIGHT_DEF; + } else if (cleanedType == "14000000") { // font PARTIALLY VERIFIED + return ASSET_FONT; + } else if (cleanedType == "05000000") { // xmodel PARTIALLY VERIFIED + return ASSET_MODEL; + } else if (cleanedType == "0D000000") { // d3dbsp PARTIALLY VERIFIED + return ASSET_D3DBSP; + } else if (cleanedType == "06000000") { // image PARTIALLY VERIFIED + return ASSET_IMAGE; + } else if (cleanedType == "0E000000") { // game map sp PARTIALLY VERIFIED + return ASSET_GAME_MAP_SP; + } else if (cleanedType == "0B000000") { // col map sp PARTIALLY VERIFIED + return ASSET_COL_MAP_SP; + } + return ASSET_NONE; +} + +QByteArray ZoneFile_COD9_PC::GetBinaryData() { + QByteArray result; + + return result; +} diff --git a/libs/zonefile/PC/zonefile_cod9_pc.h b/libs/zonefile/PC/zonefile_cod9_pc.h new file mode 100644 index 0000000..e71ac54 --- /dev/null +++ b/libs/zonefile/PC/zonefile_cod9_pc.h @@ -0,0 +1,52 @@ +#ifndef ZONEFILE_COD9_PC_H +#define ZONEFILE_COD9_PC_H + +#include "zonefile.h" + +class ZoneFile_COD9_PC : public ZoneFile +{ +public: + ZoneFile_COD9_PC(); + ~ZoneFile_COD9_PC(); + + bool Load(const QByteArray aFileData) override; + AssetType AssetStrToEnum(const QString aAssetType) override; + + QByteArray GetBinaryData() override; + +protected: + void pParseZoneHeader(QDataStream *aZoneFileStream) override; + quint32 pParseZoneSize(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsA(QDataStream *aZoneFileStream) override; + quint32 pParseZoneTagCount(QDataStream *aZoneFileStream) override; + quint32 pParseZoneRecordCount(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsB(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsC(QDataStream *aZoneFileStream) override; + QStringList pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) override; + QStringList pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) override; + AssetMap pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) override; + LocalString pParseAsset_LocalString(QDataStream *aZoneFileStream) override; + RawFile pParseAsset_RawFile(QDataStream *aZoneFileStream) override; + void pParseAsset_PhysPreset(QDataStream *aZoneFileStream) override; + Model pParseAsset_Model(QDataStream *aZoneFileStream) override; + Material pParseAsset_Material(QDataStream *aZoneFileStream) override; + Shader pParseAsset_Shader(QDataStream *aZoneFileStream) override; + TechSet pParseAsset_TechSet(QDataStream *aZoneFileStream) override; + Image pParseAsset_Image(QDataStream *aZoneFileStream) override; + SoundAsset pParseAsset_Sound(QDataStream *aZoneFileStream) override; + void pParseAsset_ColMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapSP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_LightDef(QDataStream *aZoneFileStream) override; + void pParseAsset_UIMap(QDataStream *aZoneFileStream) override; + void pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) override; + void pParseAsset_AIType(QDataStream *aZoneFileStream) override; + void pParseAsset_FX(QDataStream *aZoneFileStream) override; + Animation pParseAsset_Animation(QDataStream *aZoneFileStream) override; + MenuFile pParseAsset_MenuFile(QDataStream *aZoneFileStream) override; + void pParseAsset_Weapon(QDataStream *aZoneFileStream) override; + void pParseAsset_D3DBSP(QDataStream *aZoneFileStream) override; + StringTable pParseAsset_StringTable(QDataStream *aZoneFileStream) override; +}; + +#endif // ZONEFILE_COD9_PC_H diff --git a/libs/zonefile/PS3/zonefile_cod10_ps3.cpp b/libs/zonefile/PS3/zonefile_cod10_ps3.cpp new file mode 100644 index 0000000..243d594 --- /dev/null +++ b/libs/zonefile/PS3/zonefile_cod10_ps3.cpp @@ -0,0 +1,1072 @@ +#include "zonefile_cod10_ps3.h" + +#include +#include +#include + +ZoneFile_COD10_PS3::ZoneFile_COD10_PS3() +{ + +} + +ZoneFile_COD10_PS3::~ZoneFile_COD10_PS3() +{ + +} + +bool ZoneFile_COD10_PS3::Load(const QByteArray aFileData) { + // Open zone file as little endian stream + QDataStream zoneFileStream(aFileData); + zoneFileStream.setByteOrder(QDataStream::BigEndian); + + // Parse data from zone file header + pParseZoneHeader(&zoneFileStream); + SetRecords(pParseZoneIndex(&zoneFileStream, GetRecordCount())); + SetAssetMap(pParseAssets(&zoneFileStream, GetRecords())); + + return true; +} + +void ZoneFile_COD10_PS3::pParseZoneHeader(QDataStream *aZoneFileStream) { + SetSize(pParseZoneSize(aZoneFileStream)); + pParseZoneUnknownsA(aZoneFileStream); + + SetTagCount(pParseZoneTagCount(aZoneFileStream)); + pParseZoneUnknownsB(aZoneFileStream); + + SetRecordCount(pParseZoneRecordCount(aZoneFileStream)); + + quint32 tagCount = GetTagCount(); + if (tagCount) { + pParseZoneUnknownsC(aZoneFileStream); + SetTags(pParseZoneTags(aZoneFileStream, tagCount)); + } else { + aZoneFileStream->skipRawData(4); + } +} + +quint32 ZoneFile_COD10_PS3::pParseZoneSize(QDataStream *aZoneFileStream) { + quint32 zoneFileSize; + *aZoneFileStream >> zoneFileSize; + if (zoneFileSize <= 0) { + qDebug() << "Tried to open empty zone file!"; + exit(-1); + } + zoneFileSize += 36; + return zoneFileSize; +} + +/* + ParseZoneUnknownsA() + + Parses the 1st section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD10_PS3::pParseZoneUnknownsA(QDataStream *aZoneFileStream) { + // Byte 4-7, 8-11, 12-15: unknown + QByteArray unknown1(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown1.data(), 4); + + QByteArray unknown2(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown2.data(), 4); + + QByteArray unknown3(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown3.data(), 4); + + // Byte 16-19, 20-23: empty/unknown + QByteArray unknown4(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown4.data(), 4); + + QByteArray unknown5(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown5.data(), 4); + + // Byte 24-27: somehow related to the filesize, but smaller value + QByteArray unknown6(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown6.data(), 4); + + // Byte 28-31, 32-35: unknown + QByteArray unknown7(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown7.data(), 4); + + QByteArray unknown8(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown8.data(), 4); +} + +/* + ParseZoneTagCount() + + Parses the number of string tags in the zone index +*/ +quint32 ZoneFile_COD10_PS3::pParseZoneTagCount(QDataStream *aZoneFileStream) { + quint32 tagCount; + *aZoneFileStream >> tagCount; + return tagCount; +} + +/* + ParseZoneRecordCount() + + Parses the number of records in the zone index +*/ +quint32 ZoneFile_COD10_PS3::pParseZoneRecordCount(QDataStream *aZoneFileStream) { + quint32 recordCount; + *aZoneFileStream >> recordCount; + return recordCount; +} + +/* + ParseZoneUnknownsB() + + Parses the 2nd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD10_PS3::pParseZoneUnknownsB(QDataStream *aZoneFileStream) { + // Byte 44-47: Unknown/empty? + QByteArray unknown9(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown9.data(), 4); +} + +/* + pParseZoneUnknownsC() + + Parses the 3rd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD10_PS3::pParseZoneUnknownsC(QDataStream *aZoneFileStream) { + // Byte 40-43: Unknown/empty? + QByteArray unknown10(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown10.data(), 4); + + // Byte 44-47: Unknown/empty? + QByteArray unknown11(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown11.data(), 4); +} + +/* + ParseZoneTags() + + Parses the string tags ate the start of zone file +*/ +QStringList ZoneFile_COD10_PS3::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) { + QStringList tags; + + // Byte 48-51: Repeated separators? ÿÿÿÿ x i + aZoneFileStream->skipRawData(4 * (tagCount - 1)); + + // Parse tags/strings before index + QString zoneTag; + char zoneTagChar; + for (quint32 i = 0; i < tagCount; i++) { + *aZoneFileStream >> zoneTagChar; + while (zoneTagChar != 0) { + zoneTag += zoneTagChar; + *aZoneFileStream >> zoneTagChar; + } + tags << zoneTag; + zoneTag.clear(); + } + return tags; +} + +/* + ParseZoneIndex() + + Parse the binary zone index data and populate table +*/ +QStringList ZoneFile_COD10_PS3::pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) { + QStringList result; + + // Don't parse if no records + if (!recordCount) { return result; } + + if (aZoneFileStream->device()->peek(4).toHex().contains("ffff")) { + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 2); + } + + // Parse index & map found asset types + for (quint32 i = 0; i <= recordCount; i++) { + // Skip record start + QByteArray rawAssetType(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rawAssetType.data(), 4); + result << rawAssetType.toHex(); + + // Skip separator + aZoneFileStream->skipRawData(4); + } + return result; +} + +AssetMap ZoneFile_COD10_PS3::pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) { + AssetMap result; + + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 8); + + for (int i = 0; i < assetOrder.size(); i++) { + const QString typeHex = assetOrder[i]; + const AssetType typeStr = AssetStrToEnum(typeHex); + + if (typeStr == ASSET_LOCAL_STRING) { // localized string asset + result.localStrings << pParseAsset_LocalString(aZoneFileStream); + } else if (typeStr == ASSET_RAW_FILE) { // gsc + auto rawFile = pParseAsset_RawFile(aZoneFileStream); + if (rawFile.length) { + result.rawFiles << rawFile; + } + } else if (typeStr == ASSET_PHYS_PRESET) { // physpreset + pParseAsset_PhysPreset(aZoneFileStream); + } else if (typeStr == ASSET_MODEL) { // xmodel + result.models << pParseAsset_Model(aZoneFileStream); + } else if (typeStr == ASSET_MATERIAL) { // material + pParseAsset_Material(aZoneFileStream); + } else if (typeStr == ASSET_SHADER) { // pixelshader + pParseAsset_Shader(aZoneFileStream); + } else if (typeStr == ASSET_TECH_SET) { // techset include + result.techSets << pParseAsset_TechSet(aZoneFileStream); + } else if (typeStr == ASSET_IMAGE) { // image + result.images << pParseAsset_Image(aZoneFileStream); + } else if (typeStr == ASSET_SOUND) { // loaded_sound + result.sounds << pParseAsset_Sound(aZoneFileStream); + } else if (typeStr == ASSET_COLLISION_MAP) { // col_map_mp + pParseAsset_ColMapMP(aZoneFileStream); + } else if (typeStr == ASSET_MP_MAP) { // game_map_sp + pParseAsset_GameMapSP(aZoneFileStream); + } else if (typeStr == ASSET_SP_MAP) { // game_map_mp + pParseAsset_GameMapMP(aZoneFileStream); + } else if (typeStr == ASSET_LIGHT_DEF) { // lightdef + pParseAsset_LightDef(aZoneFileStream); + } else if (typeStr == ASSET_UI_MAP) { // ui_map + pParseAsset_UIMap(aZoneFileStream); + } else if (typeStr == ASSET_SND_DRIVER_GLOBALS) { // snddriverglobals + pParseAsset_SNDDriverGlobals(aZoneFileStream); + } else if (typeStr == ASSET_AI_TYPE) { // aitype + pParseAsset_AIType(aZoneFileStream); + } else if (typeStr == ASSET_EFFECT) { // aitype + pParseAsset_FX(aZoneFileStream); + } else if (typeStr == ASSET_ANIMATION) { // aitype + result.animations << pParseAsset_Animation(aZoneFileStream); + } else if (typeStr == ASSET_STRING_TABLE) { // string_table + result.stringTables << pParseAsset_StringTable(aZoneFileStream); + } else if (typeStr == ASSET_MENU) { // string_table + result.menuFiles << pParseAsset_MenuFile(aZoneFileStream); + } else if (typeStr == ASSET_WEAPON) { // string_table + pParseAsset_Weapon(aZoneFileStream); + } else if (typeStr == ASSET_D3DBSP) { // string_table + pParseAsset_D3DBSP(aZoneFileStream); + } + } + return result; +} + +LocalString ZoneFile_COD10_PS3::pParseAsset_LocalString(QDataStream *aZoneFileStream) { + LocalString result; + + quint32 stringPtr, aliasPtr; + *aZoneFileStream >> stringPtr >> aliasPtr; + if (stringPtr == 4294967295) { + // Parse local string asset contents + QString localStr; + char localStrChar; + *aZoneFileStream >> localStrChar; + while (localStrChar != 0) { + result.string += localStrChar; + *aZoneFileStream >> localStrChar; + } + } else { + result.string = "String Ptr: " + QString::number(stringPtr); + } + + if (aliasPtr == 4294967295) { + // Parse rawfile name + QString aliasName; + char aliasNameChar; + *aZoneFileStream >> aliasNameChar; + while (aliasNameChar != 0) { + result.alias += aliasNameChar; + *aZoneFileStream >> aliasNameChar; + } + } else { + result.string = "Alias Ptr: " + QString::number(aliasPtr); + } + + return result; +} + +RawFile ZoneFile_COD10_PS3::pParseAsset_RawFile(QDataStream *aZoneFileStream) { + RawFile result; + + // Skip start separator FF FF FF FF (pointer?) + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.length; + + // Skip unknown 4 byte data + aZoneFileStream->skipRawData(4); + + // Parse rawfile path + char scriptPathChar; + *aZoneFileStream >> scriptPathChar; + while (scriptPathChar != 0) { + result.path += scriptPathChar; + *aZoneFileStream >> scriptPathChar; + } + result.path.replace(",", ""); + const QStringList pathParts = result.path.split('/'); + if (pathParts.size() == 0) { + qDebug() << "Failed to parse ff path! " << result.path; + exit(-1); + } + + // Parse gsc contents + char rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + while (rawFileContentsChar != 0 && rawFileContentsChar != -1) { + result.contents += rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + } + return result; +} + +void ZoneFile_COD10_PS3::pParseAsset_PhysPreset(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Model ZoneFile_COD10_PS3::pParseAsset_Model(QDataStream *aZoneFileStream) { + Model result; + + *aZoneFileStream >> result.namePtr >> result.tagCount >> result.rootTagCount + >> result.surfCount >> result.unknownCount >> result.boneNamePtr + >> result.parentListPtr >> result.quatsPtr >> result.transPtr + >> result.partClassPtr >> result.baseMatPtr + >> result.surfsPtr >> result.materialHandlesPtr; + + // Parse XModelLodInfo + for (int i = 1; i <= 4; i++) { + quint32 intDist; + *aZoneFileStream >> intDist; + + std::memcpy(&result.lodInfo[i].dist, &intDist, sizeof(result.lodInfo[i].dist)); + *aZoneFileStream >> result.lodInfo[i].numsurfs >> result.lodInfo[i].surfIndex; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.lodInfo[i].partBits[0] + >> result.lodInfo[i].partBits[1] + >> result.lodInfo[i].partBits[2] + >> result.lodInfo[i].partBits[3]; + } + + *aZoneFileStream >> result.collSurfsPtr >> result.numCollSurfs >> result.contents >> result.boneInfoPtr; + + quint32 intRadius, intMins[3], intMaxs[3]; + *aZoneFileStream >> intRadius >> intMins[0] >> intMins[1] + >> intMins[2] >> intMaxs[0] >> intMaxs[1] >> intMaxs[2]; + + std::memcpy(&result.radius, &intRadius, sizeof(result.radius)); + + std::memcpy(&result.mins[0], &intMins[0], sizeof(result.mins[0])); + std::memcpy(&result.mins[1], &intMins[1], sizeof(result.mins[1])); + std::memcpy(&result.mins[2], &intMins[2], sizeof(result.mins[2])); + + std::memcpy(&result.maxs[0], &intMaxs[0], sizeof(result.maxs[0])); + std::memcpy(&result.maxs[1], &intMaxs[1], sizeof(result.maxs[2])); + std::memcpy(&result.maxs[2], &intMaxs[2], sizeof(result.maxs[3])); + + *aZoneFileStream >> result.numLods >> result.collLod >> result.streamInfoPtr + >> result.memUsage >> result.flags >> result.physPresetPtr >> result.physGeomsPtr; + + // Parse model name + char modelNameChar; + *aZoneFileStream >> modelNameChar; + while (modelNameChar == 0) { + *aZoneFileStream >> modelNameChar; + } + while (modelNameChar != 0) { + result.modelName += modelNameChar; + *aZoneFileStream >> modelNameChar; + } + return result; +} + +Material ZoneFile_COD10_PS3::pParseAsset_Material(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); + + return Material(); +} + +Shader ZoneFile_COD10_PS3::pParseAsset_Shader(QDataStream *aZoneFileStream) { + Shader result = Shader(); + + quint8 minorVersion, majorVersion; + *aZoneFileStream >> minorVersion >> majorVersion; + + quint32 magic; + *aZoneFileStream >> magic; + + // Verify .fxc magic + if (magic != 65534 && magic != 65535) { return result; } + + SHADER_TYPE type = SHADER_NONE; + quint16 rawShaderType; + *aZoneFileStream >> rawShaderType; + if (rawShaderType == 65535) { // Pixel shader + type = SHADER_PIXEL; + } else if (rawShaderType == 65534) { // Vertex shader + type = SHADER_VERTEX; + } + Q_UNUSED(type); + + while (true) { + quint32 instructionToken; + *aZoneFileStream >> instructionToken; + + SHADER_OPCODE opCode = (SHADER_OPCODE)(instructionToken & 0xffff); + + int size; + if (opCode == OPCODE_End) { + break; + } else if (opCode == OPCODE_Comment) { + size = (int)((instructionToken >> 16) & 0x7FFF); + } else { + size = (int)((instructionToken >> 24) & 0x0f); + } + Q_UNUSED(size); + } + + + return result; +} + +TechSet ZoneFile_COD10_PS3::pParseAsset_TechSet(QDataStream *aZoneFileStream) { + TechSet result; + + for (int i = 1; i <= 62; i++) { + quint32 ptr; + *aZoneFileStream >> ptr; + + result.pointers << ptr; + } + qDebug() << aZoneFileStream->device()->pos(); + + // Parse techset name + char techSetNameChar; + *aZoneFileStream >> techSetNameChar; + while (techSetNameChar != 0) { + result.name += techSetNameChar; + *aZoneFileStream >> techSetNameChar; + } + result.name.replace(",", ""); + + return result; +} + +Image ZoneFile_COD10_PS3::pParseAsset_Image(QDataStream *aZoneFileStream) { + Image result; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknowna >> result.unknownb + >> result.unknownc >> result.unknownd + >> result.unknowne >> result.unknownf + >> result.unknowng; + + aZoneFileStream->skipRawData(15 * 4); + *aZoneFileStream >> result.unknownh >> result.unknowni; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknownj; + + aZoneFileStream->skipRawData(4); + + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + result.materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + result.materialName.replace(",", ""); + + if (result.unknowna) { + *aZoneFileStream >> result.unknownk; + *aZoneFileStream >> result.unknownl; + *aZoneFileStream >> result.unknownm; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown1; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown2 >> result.unknown3 + >> result.size1 >> result.size2 + >> result.unknown4 >> result.unknown5; + + aZoneFileStream->skipRawData(4); + + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + result.name += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + + *aZoneFileStream >> result.unknown6 >> result.unknown7; + + QByteArray compressionData(8, Qt::Uninitialized); + aZoneFileStream->readRawData(compressionData.data(), 8); + if (compressionData.contains("DXT1")) { + result.compression = COMPRESSION_DXT1; + } else if (compressionData.contains("DXT3")) { + result.compression = COMPRESSION_DXT3; + } else if (compressionData.contains("DXT5")) { + result.compression = COMPRESSION_DXT5; + } else { + result.compression = COMPRESSION_NONE; + } + + *aZoneFileStream >> result.unknown8 >> result.unknown9; + } + + return result; +} + +SoundAsset ZoneFile_COD10_PS3::pParseAsset_Sound(QDataStream *aZoneFileStream) { + SoundAsset result; + + qDebug() << aZoneFileStream->device()->pos(); + + QByteArray rootNamePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rootNamePtr.data(), 4); + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.count; + + if (rootNamePtr.toHex() == "ffffffff") { + // Read in sound file name + char soundNameChar; + *aZoneFileStream >> soundNameChar; + while (soundNameChar != 0) { + result.name += soundNameChar; + *aZoneFileStream >> soundNameChar; + } + } + + int tagCount = 0; + int resultCount = 0; + for (quint32 i = 0; i < result.count; i++) { + aZoneFileStream->skipRawData(12); + + QByteArray tagPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(tagPtr.data(), 4); + + if (tagPtr.toHex() == "ffffffff") { + tagCount++; + } + aZoneFileStream->skipRawData(4); + + QByteArray pathPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pathPtr.data(), 4); + + if (pathPtr.toHex() == "ffffffff") { + resultCount++; + } + + aZoneFileStream->skipRawData(160); + } + + for (int i = 0; i < tagCount; i++) { + // Read in tag? + QString tag; + char tagChar; + *aZoneFileStream >> tagChar; + while (tagChar != 0) { + tag += tagChar; + *aZoneFileStream >> tagChar; + } + } + + for (int i = 0; i < resultCount; i++) { + Sound sound; + + if (aZoneFileStream->device()->peek(12).toHex().contains("ffffffff00000000")) { + aZoneFileStream->skipRawData(12); + } + + aZoneFileStream->skipRawData(8); + + QByteArray aliasPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(aliasPtr.data(), 4); + + QByteArray namePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(namePtr.data(), 4); + + *aZoneFileStream >> sound.dataLength; + + if (aliasPtr.toHex() == "ffffffff") { + // Read in sound alias name + char soundAliasChar; + *aZoneFileStream >> soundAliasChar; + while (soundAliasChar != 0) { + sound.alias += soundAliasChar; + *aZoneFileStream >> soundAliasChar; + } + } + + if (aZoneFileStream->device()->peek(4) == "RIFF") { + sound.path = sound.alias; + sound.alias = ""; + } else if (namePtr.toHex() == "ffffffff") { + // Read in sound file path + char soundPathChar; + *aZoneFileStream >> soundPathChar; + while (soundPathChar != 0) { + sound.path += soundPathChar; + *aZoneFileStream >> soundPathChar; + } + sound.path.replace(",", ""); + } + + if (sound.dataLength) { + QByteArray data(sound.dataLength, Qt::Uninitialized); + aZoneFileStream->readRawData(data.data(), sound.dataLength); + sound.data = data; + } + result.sounds.append(sound); + } + + return result; +} + +void ZoneFile_COD10_PS3::pParseAsset_ColMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD10_PS3::pParseAsset_GameMapSP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD10_PS3::pParseAsset_GameMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD10_PS3::pParseAsset_LightDef(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD10_PS3::pParseAsset_UIMap(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD10_PS3::pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD10_PS3::pParseAsset_AIType(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD10_PS3::pParseAsset_FX(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Animation ZoneFile_COD10_PS3::pParseAsset_Animation(QDataStream *aZoneFileStream) { + Animation result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.dataByteCount + >> result.dataShortCount + >> result.dataIntCount + >> result.randomDataByteCount + >> result.randomDataIntCount + >> result.numframes + >> result.isLooped + >> result.isDelta + >> result.noneRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.normalTranslatedBoneCount + >> result.preciseTranslatedBoneCount + >> result.staticTranslatedBoneCount + >> result.noneTranslatedBoneCount + >> result.totalBoneCount + >> result.otherBoneCount1 + >> result.otherBoneCount2 + >> result.notifyCount + >> result.assetType + >> result.pad + >> result.randomDataShortCount + >> result.indexCount + >> result.frameRate + >> result.frequency + >> result.boneIDsPtr + >> result.dataBytePtr + >> result.dataShortPtr + >> result.dataIntPtr + >> result.randomDataShortPtr + >> result.randomDataBytePtr + >> result.randomDataIntPtr + >> result.longIndiciesPtr + >> result.notificationsPtr + >> result.deltaPartsPtr; + + // Read in x_anim file name + QString xAnimName; + char xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + while (xAnimNameChar != 0) { + result.name += xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + } + + // Parse x_anim index header + QVector sectionLengths; + for (int i = 0; i < result.numframes; i++) { + quint8 sectionlength; + *aZoneFileStream >> sectionlength; + sectionLengths.push_back(sectionlength); + // Skip padding + aZoneFileStream->skipRawData(1); + } + // Skip unknown section + aZoneFileStream->skipRawData(2 * 8); + + return result; +} + +MenuFile ZoneFile_COD10_PS3::pParseAsset_MenuFile(QDataStream *aZoneFileStream) { + //MENU_FILE + MenuFile result; + + aZoneFileStream->skipRawData(4); // Separator + + // Parse menu def count + *aZoneFileStream >> result.menuCount; + + // Clearly misparsed, never have this much + if (result.menuCount > 1000) { + qDebug() << "Failure reported when parsing menu file."; + return result; + } + for (uint i = 0; i < result.menuCount; i++) { + Menu menu; + + aZoneFileStream->skipRawData(4); // Separator + + // Read in x_anim file name + char menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + while (menuFilepathChar != 0) { + menu.filePath += menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + } + aZoneFileStream->skipRawData(4); // Separator + + *aZoneFileStream >> menu.menuNamePtr; + + float menuRectX, menuRectY, menuRectWidth, menuRectHeight; + *aZoneFileStream >> menuRectX >> menuRectY >> menuRectWidth >> menuRectHeight; + menu.rect = QRectF(menuRectX, menuRectY, menuRectWidth, menuRectHeight); + + quint32 hAlignInt, vAlignInt; + *aZoneFileStream >> hAlignInt >> vAlignInt; + menu.hAlign = (MENU_H_ALIGNMENT)hAlignInt; + menu.vAlign = (MENU_V_ALIGNMENT)vAlignInt; + + float rectClientX, rectClientY, rectClientWidth, rectClientHeight; + *aZoneFileStream >> rectClientX >> rectClientY >> rectClientWidth >> rectClientHeight; + menu.clientRect = QRectF(rectClientX, rectClientY, rectClientWidth, rectClientHeight); + + quint32 hClientAlignInt, vClientAlignInt, styleInt, borderInt; + *aZoneFileStream >> hClientAlignInt >> vClientAlignInt >> menu.groupPtr + >> styleInt >> borderInt >> menu.ownerDraw >> menu.ownerDrawFlags + >> menu.borderSize >> menu.staticFlags >> menu.dynamicFlags >> menu.nextTime; + menu.hClientAlign = (MENU_H_ALIGNMENT)hClientAlignInt; + menu.vClientAlign = (MENU_V_ALIGNMENT)vClientAlignInt; + menu.style = (MENU_WINDOW_STYLE)styleInt; + menu.border = (MENU_WINDOW_BORDER)borderInt; + + float foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA, + backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA, + borderColorR, borderColorG, borderColorB, borderColorA, + outlineColorR, outlineColorG, outlineColorB, outlineColorA; + *aZoneFileStream >> foregroundColorR >> foregroundColorG >> foregroundColorB >> foregroundColorA + >> backgroundColorR >> backgroundColorG >> backgroundColorB >> backgroundColorA + >> borderColorR >> borderColorG >> borderColorB >> borderColorA + >> outlineColorR >> outlineColorG >> outlineColorB >> outlineColorA; + + menu.foregroundColor = QColor(foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA); + menu.backgroundColor = QColor(backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA); + menu.borderColor = QColor(borderColorR, borderColorG, borderColorB, borderColorA); + menu.outlineColor = QColor(outlineColorR, outlineColorG, outlineColorB, outlineColorA); + + *aZoneFileStream >> menu.materialPtr >> menu.fontPtr >> menu.fullScreen >> menu.itemCount + >> menu.fontIndex >> menu.cursorItem >> menu.fadeCycle >> menu.fadeClamp + >> menu.fadeAmount >> menu.fadeInAmount >> menu.blurRadius >> menu.onOpenPtr + >> menu.onFocusPtr >> menu.onClosePtr >> menu.onESCPtr >> menu.onKeyPtr + >> menu.visibleExpCount >> menu.expEntryPtr >> menu.allowedBindingPtr + >> menu.soundNamePtr >> menu.imageTrack; + + float focusColorR, focusColorG, focusColorB, focusColorA, + disabledColorR, disabledColorG, disabledColorB, disabledColorA; + *aZoneFileStream >> focusColorR >> focusColorG >> focusColorB >> focusColorA + >> disabledColorR >> disabledColorG >> disabledColorB >> disabledColorA; + menu.focusColor = QColor(focusColorR, focusColorG, focusColorB, focusColorA); + menu.disabledColor = QColor(disabledColorR, disabledColorG, disabledColorB, disabledColorA); + + *aZoneFileStream >> menu.rectXExpCount >> menu.rectXExpPtr >> menu.rectYExpCount >> menu.rectYExpPtr; + + aZoneFileStream->skipRawData(4); // Separator + + char menuDefNameChar; + int menuDefNameLen = 0; + *aZoneFileStream >> menuDefNameChar; + while (menuDefNameChar != 0 && menuDefNameLen < 30) { + menuDefNameLen++; + menu.name += menuDefNameChar; + *aZoneFileStream >> menuDefNameChar; + } + + char defStringChar; + int defStringLen = 0; + *aZoneFileStream >> defStringChar; + while (defStringChar != 0 && defStringLen < 30) { + defStringLen++; + menu.definition += defStringChar; + *aZoneFileStream >> defStringChar; + } + aZoneFileStream->skipRawData(4 * 10); + + *aZoneFileStream >> menu.itemWindowDefNamePtr; + + float itemRectX, itemRectY, itemRectWidth, itemRectHeight; + *aZoneFileStream >> itemRectX >> itemRectY >> itemRectWidth >> itemRectHeight; + menu.itemRect = QRectF(itemRectX, itemRectY, itemRectWidth, itemRectHeight); + + *aZoneFileStream >> menu.itemHAlignment >> menu.itemVAlignment >> menu.itemGroupPtr + >> menu.itemWindowStyle >> menu.itemWindowBorder >> menu.itemOwnerDraw + >> menu.itemOwnerDrawFlags >> menu.itemBorderSize >> menu.itemStaticFlags + >> menu.itemDynamicFlags >> menu.itemNextTime; + + float itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA, + itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA, + itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA, + itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA; + *aZoneFileStream >> itemForegroundColorR >> itemForegroundColorG >> itemForegroundColorB >> itemForegroundColorA + >> itemBackgroundColorR >> itemBackgroundColorG >> itemBackgroundColorB >> itemBackgroundColorA + >> itemBorderColorR >> itemBorderColorG >> itemBorderColorB >> itemBorderColorA + >> itemOutlineColorR >> itemOutlineColorG >> itemOutlineColorB >> itemOutlineColorA; + + menu.itemForegroundColor = QColor(itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA); + menu.itemBackgroundColor = QColor(itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA); + menu.itemBorderColor = QColor(itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA); + menu.itemOutlineColor = QColor(itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA); + + *aZoneFileStream >> menu.itemMaterialPtr; + + float itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight; + *aZoneFileStream >> itemTextRectX >> itemTextRectY >> itemTextRectWidth >> itemTextRectHeight; + menu.itemTextRect = QRectF(itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight); + + quint32 hItemTextAlignInt, vItemTextAlignInt, itemType, fontTypeInt, textStyleInt; + *aZoneFileStream >> hItemTextAlignInt >> vItemTextAlignInt >> itemType >> menu.dataType + >> menu.alignment >> fontTypeInt >> menu.textAlignMode >> menu.textalignx >> menu.textaligny + >> menu.textscale >> textStyleInt >> menu.gameMsgWindowIndex >> menu.gameMsgWindowMode + >> menu.testPtr >> menu.textSavegameInfo >> menu.parentPtr; + menu.itemText_hAlign = (MENU_H_ALIGNMENT)hItemTextAlignInt; + menu.itemText_vAlign = (MENU_V_ALIGNMENT)vItemTextAlignInt; + menu.itemType = (MENU_ITEM_TYPE)itemType; + menu.fontEnum = (MENU_FONT_TYPE)fontTypeInt; + menu.textStyle = (MENU_ITEM_TEXTSTYLE)textStyleInt; + + *aZoneFileStream >> menu.mouseEnterText >> menu.mouseExitText >> menu.mouseEnter >> menu.mouseExit + >> menu.action >> menu.onAccept >> menu.onFocus >> menu.leaveFocus >> menu.dvar >> menu.dvarTest + >> menu.keyHandlerPtr >> menu.enableDvarPtr >> menu.dvarFlags >> menu.focusSoundPtr + >> menu.special >> menu.cursorPos; + + // itemDefData_t typeData; + + // listBoxDef_s *listBox; + + *aZoneFileStream >> menu.startPos >> menu.endPos >> menu.drawPadding; + + *aZoneFileStream >> menu.elementWidth >> menu.elementHeight; + + *aZoneFileStream >> menu.elementStyle >> menu.numColumns; + + //columnInfo_s columnInfo[16]; + + *aZoneFileStream >> menu.doubleClickPtr; + + + *aZoneFileStream >> menu.notselectable >> menu.noScrollBars >> menu.usePaging; + + float itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA, + itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA, + itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA; + *aZoneFileStream >> itemSelectBorderColorR >> itemSelectBorderColorG >> itemSelectBorderColorB >> itemSelectBorderColorA + >> itemDisableColorR >> itemDisableColorG >> itemDisableColorB >> itemDisableColorA + >> itemFocusColorR >> itemFocusColorG >> itemFocusColorB >> itemFocusColorA; + menu.itemSelectBorderColor = QColor(itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA); + menu.itemDisableColor = QColor(itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA); + menu.itemFocusColor = QColor(itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA); + + *aZoneFileStream >> menu.selectIconPtr >> menu.backgroundItemListboxPtr >> menu.highlightTexturePtr; + + // editFieldDef_s *editField; + + *aZoneFileStream >> menu.minVal >> menu.maxVal >> menu.defVal >> menu.range >> menu.maxChars + >> menu.maxCharsGotoNext >> menu.maxPaintChars >> menu.paintOffset; + + // multiDef_s *multi; + + for (int i = 0; i < 32; i++) { + quint32 dvarList; + *aZoneFileStream >> dvarList; + menu.dvarListPtrs.push_back(dvarList); + } + + for (int i = 0; i < 32; i++) { + quint32 dvarStr; + *aZoneFileStream >> dvarStr; + menu.dvarStrPtrs.push_back(dvarStr); + } + + for (int i = 0; i < 32; i++) { + float dvarValue; + *aZoneFileStream >> dvarValue; + menu.dvarValues.push_back(dvarValue); + } + + *aZoneFileStream >> menu.count >> menu.strDef >> menu.enumDvarNamePtr; + aZoneFileStream->skipRawData(4); + //>> menu.dataPtr + *aZoneFileStream >> menu.itemImageTrack; + + qDebug() << aZoneFileStream->device()->pos(); + + //statement_s visibleExp; + //statement_s textExp; + //statement_s materialExp; + //statement_s rectXExp; + //statement_s rectYExp; + //statement_s rectWExp; + //statement_s rectHExp; + //statement_s foreColorAExp; + result.menuDefs << menu; + } + return result; +} + +void ZoneFile_COD10_PS3::pParseAsset_Weapon(QDataStream *aZoneFileStream) { + //WEAPON_FILE + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD10_PS3::pParseAsset_D3DBSP(QDataStream *aZoneFileStream) { + //D3DBSP_DUMP + Q_UNUSED(aZoneFileStream); +} + +StringTable ZoneFile_COD10_PS3::pParseAsset_StringTable(QDataStream *aZoneFileStream) { + StringTable result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.columnCount + >> result.rowCount; + + // Todo fix this + result.columnCount = 0; + result.rowCount = 0; + + aZoneFileStream->skipRawData(4); + + QString stringTableName; + char stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + while (stringTableNameChar != 0) { + result.name += stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + } + + for (quint32 i = 0; i < result.rowCount; i++) { + QByteArray pointerData(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pointerData.data(), 4); + result.tablePointers.push_back(pointerData.toHex()); + + aZoneFileStream->skipRawData(4); + } + + for (const QString &pointerAddr : result.tablePointers) { + QString leadingContent = ""; + if (pointerAddr == "FFFFFFFF") { + char leadingContentChar; + *aZoneFileStream >> leadingContentChar; + while (leadingContentChar != 0) { + leadingContent += leadingContentChar; + *aZoneFileStream >> leadingContentChar; + } + } else { + leadingContent = pointerAddr; + } + + QString content; + char contentChar; + *aZoneFileStream >> contentChar; + while (contentChar != 0) { + content += contentChar; + *aZoneFileStream >> contentChar; + } + result.content[leadingContent] = content; + } + return result; +} + +AssetType ZoneFile_COD10_PS3::AssetStrToEnum(const QString aAssetType) { + const QString cleanedType = aAssetType.toUpper(); + if (cleanedType == "17000000") { // localized string PARTIALLY VERIFIED + return ASSET_LOCAL_STRING; + } else if (cleanedType == "20000000") { // raw_file PARTIALLY VERIFIED + return ASSET_RAW_FILE; + } else if (cleanedType == "1A000000") { // fx PARTIALLY VERIFIED + return ASSET_EFFECT; + } else if (cleanedType == "09000000") { // loaded_sound PARTIALLY VERIFIED + return ASSET_SOUND; + } else if (cleanedType == "04000000") { // x_anim PARTIALLY VERIFIED + return ASSET_ANIMATION; + } else if (cleanedType == "0C000000") { // collision_map PARTIALLY VERIFIED + return ASSET_COLLISION_MAP; + } else if (cleanedType == "21000000") { // string_table PARTIALLY VERIFIED + return ASSET_STRING_TABLE; + } else if (cleanedType == "15000000") { // menu_file PARTIALLY VERIFIED + return ASSET_MENU; + } else if (cleanedType == "07000000") { // tech set PARTIALLY VERIFIED + return ASSET_TECH_SET; + } else if (cleanedType == "18000000") { // weapon PARTIALLY VERIFIED + return ASSET_WEAPON; + } else if (cleanedType == "11000000") { // gfx map PARTIALLY VERIFIED + return ASSET_GFX_MAP; + } else if (cleanedType == "12000000") { // light_def PARTIALLY VERIFIED + return ASSET_LIGHT_DEF; + } else if (cleanedType == "14000000") { // font PARTIALLY VERIFIED + return ASSET_FONT; + } else if (cleanedType == "05000000") { // xmodel PARTIALLY VERIFIED + return ASSET_MODEL; + } else if (cleanedType == "0D000000") { // d3dbsp PARTIALLY VERIFIED + return ASSET_D3DBSP; + } else if (cleanedType == "06000000") { // image PARTIALLY VERIFIED + return ASSET_IMAGE; + } else if (cleanedType == "0E000000") { // game map sp PARTIALLY VERIFIED + return ASSET_GAME_MAP_SP; + } else if (cleanedType == "0B000000") { // col map sp PARTIALLY VERIFIED + return ASSET_COL_MAP_SP; + } + return ASSET_NONE; +} + +QByteArray ZoneFile_COD10_PS3::GetBinaryData() { + QByteArray result; + + return result; +} diff --git a/libs/zonefile/PS3/zonefile_cod10_ps3.h b/libs/zonefile/PS3/zonefile_cod10_ps3.h new file mode 100644 index 0000000..90c07f8 --- /dev/null +++ b/libs/zonefile/PS3/zonefile_cod10_ps3.h @@ -0,0 +1,52 @@ +#ifndef ZONEFILE_COD10_PS3_H +#define ZONEFILE_COD10_PS3_H + +#include "zonefile.h" + +class ZoneFile_COD10_PS3 : public ZoneFile +{ +public: + ZoneFile_COD10_PS3(); + ~ZoneFile_COD10_PS3(); + + bool Load(const QByteArray aFileData) override; + AssetType AssetStrToEnum(const QString aAssetType) override; + + QByteArray GetBinaryData() override; + +protected: + void pParseZoneHeader(QDataStream *aZoneFileStream) override; + quint32 pParseZoneSize(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsA(QDataStream *aZoneFileStream) override; + quint32 pParseZoneTagCount(QDataStream *aZoneFileStream) override; + quint32 pParseZoneRecordCount(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsB(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsC(QDataStream *aZoneFileStream) override; + QStringList pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) override; + QStringList pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) override; + AssetMap pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) override; + LocalString pParseAsset_LocalString(QDataStream *aZoneFileStream) override; + RawFile pParseAsset_RawFile(QDataStream *aZoneFileStream) override; + void pParseAsset_PhysPreset(QDataStream *aZoneFileStream) override; + Model pParseAsset_Model(QDataStream *aZoneFileStream) override; + Material pParseAsset_Material(QDataStream *aZoneFileStream) override; + Shader pParseAsset_Shader(QDataStream *aZoneFileStream) override; + TechSet pParseAsset_TechSet(QDataStream *aZoneFileStream) override; + Image pParseAsset_Image(QDataStream *aZoneFileStream) override; + SoundAsset pParseAsset_Sound(QDataStream *aZoneFileStream) override; + void pParseAsset_ColMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapSP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_LightDef(QDataStream *aZoneFileStream) override; + void pParseAsset_UIMap(QDataStream *aZoneFileStream) override; + void pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) override; + void pParseAsset_AIType(QDataStream *aZoneFileStream) override; + void pParseAsset_FX(QDataStream *aZoneFileStream) override; + Animation pParseAsset_Animation(QDataStream *aZoneFileStream) override; + MenuFile pParseAsset_MenuFile(QDataStream *aZoneFileStream) override; + void pParseAsset_Weapon(QDataStream *aZoneFileStream) override; + void pParseAsset_D3DBSP(QDataStream *aZoneFileStream) override; + StringTable pParseAsset_StringTable(QDataStream *aZoneFileStream) override; +}; + +#endif // ZONEFILE_COD10_PS3_H diff --git a/libs/zonefile/PS3/zonefile_cod11_ps3.cpp b/libs/zonefile/PS3/zonefile_cod11_ps3.cpp new file mode 100644 index 0000000..01fec6b --- /dev/null +++ b/libs/zonefile/PS3/zonefile_cod11_ps3.cpp @@ -0,0 +1,1072 @@ +#include "zonefile_cod11_ps3.h" + +#include +#include +#include + +ZoneFile_COD11_PS3::ZoneFile_COD11_PS3() +{ + +} + +ZoneFile_COD11_PS3::~ZoneFile_COD11_PS3() +{ + +} + +bool ZoneFile_COD11_PS3::Load(const QByteArray aFileData) { + // Open zone file as little endian stream + QDataStream zoneFileStream(aFileData); + zoneFileStream.setByteOrder(QDataStream::BigEndian); + + // Parse data from zone file header + pParseZoneHeader(&zoneFileStream); + SetRecords(pParseZoneIndex(&zoneFileStream, GetRecordCount())); + SetAssetMap(pParseAssets(&zoneFileStream, GetRecords())); + + return true; +} + +void ZoneFile_COD11_PS3::pParseZoneHeader(QDataStream *aZoneFileStream) { + SetSize(pParseZoneSize(aZoneFileStream)); + pParseZoneUnknownsA(aZoneFileStream); + + SetTagCount(pParseZoneTagCount(aZoneFileStream)); + pParseZoneUnknownsB(aZoneFileStream); + + SetRecordCount(pParseZoneRecordCount(aZoneFileStream)); + + quint32 tagCount = GetTagCount(); + if (tagCount) { + pParseZoneUnknownsC(aZoneFileStream); + SetTags(pParseZoneTags(aZoneFileStream, tagCount)); + } else { + aZoneFileStream->skipRawData(4); + } +} + +quint32 ZoneFile_COD11_PS3::pParseZoneSize(QDataStream *aZoneFileStream) { + quint32 zoneFileSize; + *aZoneFileStream >> zoneFileSize; + if (zoneFileSize <= 0) { + qDebug() << "Tried to open empty zone file!"; + exit(-1); + } + zoneFileSize += 36; + return zoneFileSize; +} + +/* + ParseZoneUnknownsA() + + Parses the 1st section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD11_PS3::pParseZoneUnknownsA(QDataStream *aZoneFileStream) { + // Byte 4-7, 8-11, 12-15: unknown + QByteArray unknown1(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown1.data(), 4); + + QByteArray unknown2(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown2.data(), 4); + + QByteArray unknown3(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown3.data(), 4); + + // Byte 16-19, 20-23: empty/unknown + QByteArray unknown4(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown4.data(), 4); + + QByteArray unknown5(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown5.data(), 4); + + // Byte 24-27: somehow related to the filesize, but smaller value + QByteArray unknown6(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown6.data(), 4); + + // Byte 28-31, 32-35: unknown + QByteArray unknown7(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown7.data(), 4); + + QByteArray unknown8(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown8.data(), 4); +} + +/* + ParseZoneTagCount() + + Parses the number of string tags in the zone index +*/ +quint32 ZoneFile_COD11_PS3::pParseZoneTagCount(QDataStream *aZoneFileStream) { + quint32 tagCount; + *aZoneFileStream >> tagCount; + return tagCount; +} + +/* + ParseZoneRecordCount() + + Parses the number of records in the zone index +*/ +quint32 ZoneFile_COD11_PS3::pParseZoneRecordCount(QDataStream *aZoneFileStream) { + quint32 recordCount; + *aZoneFileStream >> recordCount; + return recordCount; +} + +/* + ParseZoneUnknownsB() + + Parses the 2nd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD11_PS3::pParseZoneUnknownsB(QDataStream *aZoneFileStream) { + // Byte 44-47: Unknown/empty? + QByteArray unknown9(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown9.data(), 4); +} + +/* + pParseZoneUnknownsC() + + Parses the 3rd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD11_PS3::pParseZoneUnknownsC(QDataStream *aZoneFileStream) { + // Byte 40-43: Unknown/empty? + QByteArray unknown10(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown10.data(), 4); + + // Byte 44-47: Unknown/empty? + QByteArray unknown11(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown11.data(), 4); +} + +/* + ParseZoneTags() + + Parses the string tags ate the start of zone file +*/ +QStringList ZoneFile_COD11_PS3::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) { + QStringList tags; + + // Byte 48-51: Repeated separators? ÿÿÿÿ x i + aZoneFileStream->skipRawData(4 * (tagCount - 1)); + + // Parse tags/strings before index + QString zoneTag; + char zoneTagChar; + for (quint32 i = 0; i < tagCount; i++) { + *aZoneFileStream >> zoneTagChar; + while (zoneTagChar != 0) { + zoneTag += zoneTagChar; + *aZoneFileStream >> zoneTagChar; + } + tags << zoneTag; + zoneTag.clear(); + } + return tags; +} + +/* + ParseZoneIndex() + + Parse the binary zone index data and populate table +*/ +QStringList ZoneFile_COD11_PS3::pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) { + QStringList result; + + // Don't parse if no records + if (!recordCount) { return result; } + + if (aZoneFileStream->device()->peek(4).toHex().contains("ffff")) { + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 2); + } + + // Parse index & map found asset types + for (quint32 i = 0; i <= recordCount; i++) { + // Skip record start + QByteArray rawAssetType(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rawAssetType.data(), 4); + result << rawAssetType.toHex(); + + // Skip separator + aZoneFileStream->skipRawData(4); + } + return result; +} + +AssetMap ZoneFile_COD11_PS3::pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) { + AssetMap result; + + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 8); + + for (int i = 0; i < assetOrder.size(); i++) { + const QString typeHex = assetOrder[i]; + const AssetType typeStr = AssetStrToEnum(typeHex); + + if (typeStr == ASSET_LOCAL_STRING) { // localized string asset + result.localStrings << pParseAsset_LocalString(aZoneFileStream); + } else if (typeStr == ASSET_RAW_FILE) { // gsc + auto rawFile = pParseAsset_RawFile(aZoneFileStream); + if (rawFile.length) { + result.rawFiles << rawFile; + } + } else if (typeStr == ASSET_PHYS_PRESET) { // physpreset + pParseAsset_PhysPreset(aZoneFileStream); + } else if (typeStr == ASSET_MODEL) { // xmodel + result.models << pParseAsset_Model(aZoneFileStream); + } else if (typeStr == ASSET_MATERIAL) { // material + pParseAsset_Material(aZoneFileStream); + } else if (typeStr == ASSET_SHADER) { // pixelshader + pParseAsset_Shader(aZoneFileStream); + } else if (typeStr == ASSET_TECH_SET) { // techset include + result.techSets << pParseAsset_TechSet(aZoneFileStream); + } else if (typeStr == ASSET_IMAGE) { // image + result.images << pParseAsset_Image(aZoneFileStream); + } else if (typeStr == ASSET_SOUND) { // loaded_sound + result.sounds << pParseAsset_Sound(aZoneFileStream); + } else if (typeStr == ASSET_COLLISION_MAP) { // col_map_mp + pParseAsset_ColMapMP(aZoneFileStream); + } else if (typeStr == ASSET_MP_MAP) { // game_map_sp + pParseAsset_GameMapSP(aZoneFileStream); + } else if (typeStr == ASSET_SP_MAP) { // game_map_mp + pParseAsset_GameMapMP(aZoneFileStream); + } else if (typeStr == ASSET_LIGHT_DEF) { // lightdef + pParseAsset_LightDef(aZoneFileStream); + } else if (typeStr == ASSET_UI_MAP) { // ui_map + pParseAsset_UIMap(aZoneFileStream); + } else if (typeStr == ASSET_SND_DRIVER_GLOBALS) { // snddriverglobals + pParseAsset_SNDDriverGlobals(aZoneFileStream); + } else if (typeStr == ASSET_AI_TYPE) { // aitype + pParseAsset_AIType(aZoneFileStream); + } else if (typeStr == ASSET_EFFECT) { // aitype + pParseAsset_FX(aZoneFileStream); + } else if (typeStr == ASSET_ANIMATION) { // aitype + result.animations << pParseAsset_Animation(aZoneFileStream); + } else if (typeStr == ASSET_STRING_TABLE) { // string_table + result.stringTables << pParseAsset_StringTable(aZoneFileStream); + } else if (typeStr == ASSET_MENU) { // string_table + result.menuFiles << pParseAsset_MenuFile(aZoneFileStream); + } else if (typeStr == ASSET_WEAPON) { // string_table + pParseAsset_Weapon(aZoneFileStream); + } else if (typeStr == ASSET_D3DBSP) { // string_table + pParseAsset_D3DBSP(aZoneFileStream); + } + } + return result; +} + +LocalString ZoneFile_COD11_PS3::pParseAsset_LocalString(QDataStream *aZoneFileStream) { + LocalString result; + + quint32 stringPtr, aliasPtr; + *aZoneFileStream >> stringPtr >> aliasPtr; + if (stringPtr == 4294967295) { + // Parse local string asset contents + QString localStr; + char localStrChar; + *aZoneFileStream >> localStrChar; + while (localStrChar != 0) { + result.string += localStrChar; + *aZoneFileStream >> localStrChar; + } + } else { + result.string = "String Ptr: " + QString::number(stringPtr); + } + + if (aliasPtr == 4294967295) { + // Parse rawfile name + QString aliasName; + char aliasNameChar; + *aZoneFileStream >> aliasNameChar; + while (aliasNameChar != 0) { + result.alias += aliasNameChar; + *aZoneFileStream >> aliasNameChar; + } + } else { + result.string = "Alias Ptr: " + QString::number(aliasPtr); + } + + return result; +} + +RawFile ZoneFile_COD11_PS3::pParseAsset_RawFile(QDataStream *aZoneFileStream) { + RawFile result; + + // Skip start separator FF FF FF FF (pointer?) + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.length; + + // Skip unknown 4 byte data + aZoneFileStream->skipRawData(4); + + // Parse rawfile path + char scriptPathChar; + *aZoneFileStream >> scriptPathChar; + while (scriptPathChar != 0) { + result.path += scriptPathChar; + *aZoneFileStream >> scriptPathChar; + } + result.path.replace(",", ""); + const QStringList pathParts = result.path.split('/'); + if (pathParts.size() == 0) { + qDebug() << "Failed to parse ff path! " << result.path; + exit(-1); + } + + // Parse gsc contents + char rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + while (rawFileContentsChar != 0 && rawFileContentsChar != -1) { + result.contents += rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + } + return result; +} + +void ZoneFile_COD11_PS3::pParseAsset_PhysPreset(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Model ZoneFile_COD11_PS3::pParseAsset_Model(QDataStream *aZoneFileStream) { + Model result; + + *aZoneFileStream >> result.namePtr >> result.tagCount >> result.rootTagCount + >> result.surfCount >> result.unknownCount >> result.boneNamePtr + >> result.parentListPtr >> result.quatsPtr >> result.transPtr + >> result.partClassPtr >> result.baseMatPtr + >> result.surfsPtr >> result.materialHandlesPtr; + + // Parse XModelLodInfo + for (int i = 1; i <= 4; i++) { + quint32 intDist; + *aZoneFileStream >> intDist; + + std::memcpy(&result.lodInfo[i].dist, &intDist, sizeof(result.lodInfo[i].dist)); + *aZoneFileStream >> result.lodInfo[i].numsurfs >> result.lodInfo[i].surfIndex; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.lodInfo[i].partBits[0] + >> result.lodInfo[i].partBits[1] + >> result.lodInfo[i].partBits[2] + >> result.lodInfo[i].partBits[3]; + } + + *aZoneFileStream >> result.collSurfsPtr >> result.numCollSurfs >> result.contents >> result.boneInfoPtr; + + quint32 intRadius, intMins[3], intMaxs[3]; + *aZoneFileStream >> intRadius >> intMins[0] >> intMins[1] + >> intMins[2] >> intMaxs[0] >> intMaxs[1] >> intMaxs[2]; + + std::memcpy(&result.radius, &intRadius, sizeof(result.radius)); + + std::memcpy(&result.mins[0], &intMins[0], sizeof(result.mins[0])); + std::memcpy(&result.mins[1], &intMins[1], sizeof(result.mins[1])); + std::memcpy(&result.mins[2], &intMins[2], sizeof(result.mins[2])); + + std::memcpy(&result.maxs[0], &intMaxs[0], sizeof(result.maxs[0])); + std::memcpy(&result.maxs[1], &intMaxs[1], sizeof(result.maxs[2])); + std::memcpy(&result.maxs[2], &intMaxs[2], sizeof(result.maxs[3])); + + *aZoneFileStream >> result.numLods >> result.collLod >> result.streamInfoPtr + >> result.memUsage >> result.flags >> result.physPresetPtr >> result.physGeomsPtr; + + // Parse model name + char modelNameChar; + *aZoneFileStream >> modelNameChar; + while (modelNameChar == 0) { + *aZoneFileStream >> modelNameChar; + } + while (modelNameChar != 0) { + result.modelName += modelNameChar; + *aZoneFileStream >> modelNameChar; + } + return result; +} + +Material ZoneFile_COD11_PS3::pParseAsset_Material(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); + + return Material(); +} + +Shader ZoneFile_COD11_PS3::pParseAsset_Shader(QDataStream *aZoneFileStream) { + Shader result = Shader(); + + quint8 minorVersion, majorVersion; + *aZoneFileStream >> minorVersion >> majorVersion; + + quint32 magic; + *aZoneFileStream >> magic; + + // Verify .fxc magic + if (magic != 65534 && magic != 65535) { return result; } + + SHADER_TYPE type = SHADER_NONE; + quint16 rawShaderType; + *aZoneFileStream >> rawShaderType; + if (rawShaderType == 65535) { // Pixel shader + type = SHADER_PIXEL; + } else if (rawShaderType == 65534) { // Vertex shader + type = SHADER_VERTEX; + } + Q_UNUSED(type); + + while (true) { + quint32 instructionToken; + *aZoneFileStream >> instructionToken; + + SHADER_OPCODE opCode = (SHADER_OPCODE)(instructionToken & 0xffff); + + int size; + if (opCode == OPCODE_End) { + break; + } else if (opCode == OPCODE_Comment) { + size = (int)((instructionToken >> 16) & 0x7FFF); + } else { + size = (int)((instructionToken >> 24) & 0x0f); + } + Q_UNUSED(size); + } + + + return result; +} + +TechSet ZoneFile_COD11_PS3::pParseAsset_TechSet(QDataStream *aZoneFileStream) { + TechSet result; + + for (int i = 1; i <= 62; i++) { + quint32 ptr; + *aZoneFileStream >> ptr; + + result.pointers << ptr; + } + qDebug() << aZoneFileStream->device()->pos(); + + // Parse techset name + char techSetNameChar; + *aZoneFileStream >> techSetNameChar; + while (techSetNameChar != 0) { + result.name += techSetNameChar; + *aZoneFileStream >> techSetNameChar; + } + result.name.replace(",", ""); + + return result; +} + +Image ZoneFile_COD11_PS3::pParseAsset_Image(QDataStream *aZoneFileStream) { + Image result; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknowna >> result.unknownb + >> result.unknownc >> result.unknownd + >> result.unknowne >> result.unknownf + >> result.unknowng; + + aZoneFileStream->skipRawData(15 * 4); + *aZoneFileStream >> result.unknownh >> result.unknowni; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknownj; + + aZoneFileStream->skipRawData(4); + + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + result.materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + result.materialName.replace(",", ""); + + if (result.unknowna) { + *aZoneFileStream >> result.unknownk; + *aZoneFileStream >> result.unknownl; + *aZoneFileStream >> result.unknownm; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown1; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown2 >> result.unknown3 + >> result.size1 >> result.size2 + >> result.unknown4 >> result.unknown5; + + aZoneFileStream->skipRawData(4); + + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + result.name += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + + *aZoneFileStream >> result.unknown6 >> result.unknown7; + + QByteArray compressionData(8, Qt::Uninitialized); + aZoneFileStream->readRawData(compressionData.data(), 8); + if (compressionData.contains("DXT1")) { + result.compression = COMPRESSION_DXT1; + } else if (compressionData.contains("DXT3")) { + result.compression = COMPRESSION_DXT3; + } else if (compressionData.contains("DXT5")) { + result.compression = COMPRESSION_DXT5; + } else { + result.compression = COMPRESSION_NONE; + } + + *aZoneFileStream >> result.unknown8 >> result.unknown9; + } + + return result; +} + +SoundAsset ZoneFile_COD11_PS3::pParseAsset_Sound(QDataStream *aZoneFileStream) { + SoundAsset result; + + qDebug() << aZoneFileStream->device()->pos(); + + QByteArray rootNamePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rootNamePtr.data(), 4); + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.count; + + if (rootNamePtr.toHex() == "ffffffff") { + // Read in sound file name + char soundNameChar; + *aZoneFileStream >> soundNameChar; + while (soundNameChar != 0) { + result.name += soundNameChar; + *aZoneFileStream >> soundNameChar; + } + } + + int tagCount = 0; + int resultCount = 0; + for (quint32 i = 0; i < result.count; i++) { + aZoneFileStream->skipRawData(12); + + QByteArray tagPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(tagPtr.data(), 4); + + if (tagPtr.toHex() == "ffffffff") { + tagCount++; + } + aZoneFileStream->skipRawData(4); + + QByteArray pathPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pathPtr.data(), 4); + + if (pathPtr.toHex() == "ffffffff") { + resultCount++; + } + + aZoneFileStream->skipRawData(160); + } + + for (int i = 0; i < tagCount; i++) { + // Read in tag? + QString tag; + char tagChar; + *aZoneFileStream >> tagChar; + while (tagChar != 0) { + tag += tagChar; + *aZoneFileStream >> tagChar; + } + } + + for (int i = 0; i < resultCount; i++) { + Sound sound; + + if (aZoneFileStream->device()->peek(12).toHex().contains("ffffffff00000000")) { + aZoneFileStream->skipRawData(12); + } + + aZoneFileStream->skipRawData(8); + + QByteArray aliasPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(aliasPtr.data(), 4); + + QByteArray namePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(namePtr.data(), 4); + + *aZoneFileStream >> sound.dataLength; + + if (aliasPtr.toHex() == "ffffffff") { + // Read in sound alias name + char soundAliasChar; + *aZoneFileStream >> soundAliasChar; + while (soundAliasChar != 0) { + sound.alias += soundAliasChar; + *aZoneFileStream >> soundAliasChar; + } + } + + if (aZoneFileStream->device()->peek(4) == "RIFF") { + sound.path = sound.alias; + sound.alias = ""; + } else if (namePtr.toHex() == "ffffffff") { + // Read in sound file path + char soundPathChar; + *aZoneFileStream >> soundPathChar; + while (soundPathChar != 0) { + sound.path += soundPathChar; + *aZoneFileStream >> soundPathChar; + } + sound.path.replace(",", ""); + } + + if (sound.dataLength) { + QByteArray data(sound.dataLength, Qt::Uninitialized); + aZoneFileStream->readRawData(data.data(), sound.dataLength); + sound.data = data; + } + result.sounds.append(sound); + } + + return result; +} + +void ZoneFile_COD11_PS3::pParseAsset_ColMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD11_PS3::pParseAsset_GameMapSP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD11_PS3::pParseAsset_GameMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD11_PS3::pParseAsset_LightDef(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD11_PS3::pParseAsset_UIMap(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD11_PS3::pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD11_PS3::pParseAsset_AIType(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD11_PS3::pParseAsset_FX(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Animation ZoneFile_COD11_PS3::pParseAsset_Animation(QDataStream *aZoneFileStream) { + Animation result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.dataByteCount + >> result.dataShortCount + >> result.dataIntCount + >> result.randomDataByteCount + >> result.randomDataIntCount + >> result.numframes + >> result.isLooped + >> result.isDelta + >> result.noneRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.normalTranslatedBoneCount + >> result.preciseTranslatedBoneCount + >> result.staticTranslatedBoneCount + >> result.noneTranslatedBoneCount + >> result.totalBoneCount + >> result.otherBoneCount1 + >> result.otherBoneCount2 + >> result.notifyCount + >> result.assetType + >> result.pad + >> result.randomDataShortCount + >> result.indexCount + >> result.frameRate + >> result.frequency + >> result.boneIDsPtr + >> result.dataBytePtr + >> result.dataShortPtr + >> result.dataIntPtr + >> result.randomDataShortPtr + >> result.randomDataBytePtr + >> result.randomDataIntPtr + >> result.longIndiciesPtr + >> result.notificationsPtr + >> result.deltaPartsPtr; + + // Read in x_anim file name + QString xAnimName; + char xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + while (xAnimNameChar != 0) { + result.name += xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + } + + // Parse x_anim index header + QVector sectionLengths; + for (int i = 0; i < result.numframes; i++) { + quint8 sectionlength; + *aZoneFileStream >> sectionlength; + sectionLengths.push_back(sectionlength); + // Skip padding + aZoneFileStream->skipRawData(1); + } + // Skip unknown section + aZoneFileStream->skipRawData(2 * 8); + + return result; +} + +MenuFile ZoneFile_COD11_PS3::pParseAsset_MenuFile(QDataStream *aZoneFileStream) { + //MENU_FILE + MenuFile result; + + aZoneFileStream->skipRawData(4); // Separator + + // Parse menu def count + *aZoneFileStream >> result.menuCount; + + // Clearly misparsed, never have this much + if (result.menuCount > 1000) { + qDebug() << "Failure reported when parsing menu file."; + return result; + } + for (uint i = 0; i < result.menuCount; i++) { + Menu menu; + + aZoneFileStream->skipRawData(4); // Separator + + // Read in x_anim file name + char menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + while (menuFilepathChar != 0) { + menu.filePath += menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + } + aZoneFileStream->skipRawData(4); // Separator + + *aZoneFileStream >> menu.menuNamePtr; + + float menuRectX, menuRectY, menuRectWidth, menuRectHeight; + *aZoneFileStream >> menuRectX >> menuRectY >> menuRectWidth >> menuRectHeight; + menu.rect = QRectF(menuRectX, menuRectY, menuRectWidth, menuRectHeight); + + quint32 hAlignInt, vAlignInt; + *aZoneFileStream >> hAlignInt >> vAlignInt; + menu.hAlign = (MENU_H_ALIGNMENT)hAlignInt; + menu.vAlign = (MENU_V_ALIGNMENT)vAlignInt; + + float rectClientX, rectClientY, rectClientWidth, rectClientHeight; + *aZoneFileStream >> rectClientX >> rectClientY >> rectClientWidth >> rectClientHeight; + menu.clientRect = QRectF(rectClientX, rectClientY, rectClientWidth, rectClientHeight); + + quint32 hClientAlignInt, vClientAlignInt, styleInt, borderInt; + *aZoneFileStream >> hClientAlignInt >> vClientAlignInt >> menu.groupPtr + >> styleInt >> borderInt >> menu.ownerDraw >> menu.ownerDrawFlags + >> menu.borderSize >> menu.staticFlags >> menu.dynamicFlags >> menu.nextTime; + menu.hClientAlign = (MENU_H_ALIGNMENT)hClientAlignInt; + menu.vClientAlign = (MENU_V_ALIGNMENT)vClientAlignInt; + menu.style = (MENU_WINDOW_STYLE)styleInt; + menu.border = (MENU_WINDOW_BORDER)borderInt; + + float foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA, + backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA, + borderColorR, borderColorG, borderColorB, borderColorA, + outlineColorR, outlineColorG, outlineColorB, outlineColorA; + *aZoneFileStream >> foregroundColorR >> foregroundColorG >> foregroundColorB >> foregroundColorA + >> backgroundColorR >> backgroundColorG >> backgroundColorB >> backgroundColorA + >> borderColorR >> borderColorG >> borderColorB >> borderColorA + >> outlineColorR >> outlineColorG >> outlineColorB >> outlineColorA; + + menu.foregroundColor = QColor(foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA); + menu.backgroundColor = QColor(backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA); + menu.borderColor = QColor(borderColorR, borderColorG, borderColorB, borderColorA); + menu.outlineColor = QColor(outlineColorR, outlineColorG, outlineColorB, outlineColorA); + + *aZoneFileStream >> menu.materialPtr >> menu.fontPtr >> menu.fullScreen >> menu.itemCount + >> menu.fontIndex >> menu.cursorItem >> menu.fadeCycle >> menu.fadeClamp + >> menu.fadeAmount >> menu.fadeInAmount >> menu.blurRadius >> menu.onOpenPtr + >> menu.onFocusPtr >> menu.onClosePtr >> menu.onESCPtr >> menu.onKeyPtr + >> menu.visibleExpCount >> menu.expEntryPtr >> menu.allowedBindingPtr + >> menu.soundNamePtr >> menu.imageTrack; + + float focusColorR, focusColorG, focusColorB, focusColorA, + disabledColorR, disabledColorG, disabledColorB, disabledColorA; + *aZoneFileStream >> focusColorR >> focusColorG >> focusColorB >> focusColorA + >> disabledColorR >> disabledColorG >> disabledColorB >> disabledColorA; + menu.focusColor = QColor(focusColorR, focusColorG, focusColorB, focusColorA); + menu.disabledColor = QColor(disabledColorR, disabledColorG, disabledColorB, disabledColorA); + + *aZoneFileStream >> menu.rectXExpCount >> menu.rectXExpPtr >> menu.rectYExpCount >> menu.rectYExpPtr; + + aZoneFileStream->skipRawData(4); // Separator + + char menuDefNameChar; + int menuDefNameLen = 0; + *aZoneFileStream >> menuDefNameChar; + while (menuDefNameChar != 0 && menuDefNameLen < 30) { + menuDefNameLen++; + menu.name += menuDefNameChar; + *aZoneFileStream >> menuDefNameChar; + } + + char defStringChar; + int defStringLen = 0; + *aZoneFileStream >> defStringChar; + while (defStringChar != 0 && defStringLen < 30) { + defStringLen++; + menu.definition += defStringChar; + *aZoneFileStream >> defStringChar; + } + aZoneFileStream->skipRawData(4 * 10); + + *aZoneFileStream >> menu.itemWindowDefNamePtr; + + float itemRectX, itemRectY, itemRectWidth, itemRectHeight; + *aZoneFileStream >> itemRectX >> itemRectY >> itemRectWidth >> itemRectHeight; + menu.itemRect = QRectF(itemRectX, itemRectY, itemRectWidth, itemRectHeight); + + *aZoneFileStream >> menu.itemHAlignment >> menu.itemVAlignment >> menu.itemGroupPtr + >> menu.itemWindowStyle >> menu.itemWindowBorder >> menu.itemOwnerDraw + >> menu.itemOwnerDrawFlags >> menu.itemBorderSize >> menu.itemStaticFlags + >> menu.itemDynamicFlags >> menu.itemNextTime; + + float itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA, + itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA, + itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA, + itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA; + *aZoneFileStream >> itemForegroundColorR >> itemForegroundColorG >> itemForegroundColorB >> itemForegroundColorA + >> itemBackgroundColorR >> itemBackgroundColorG >> itemBackgroundColorB >> itemBackgroundColorA + >> itemBorderColorR >> itemBorderColorG >> itemBorderColorB >> itemBorderColorA + >> itemOutlineColorR >> itemOutlineColorG >> itemOutlineColorB >> itemOutlineColorA; + + menu.itemForegroundColor = QColor(itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA); + menu.itemBackgroundColor = QColor(itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA); + menu.itemBorderColor = QColor(itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA); + menu.itemOutlineColor = QColor(itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA); + + *aZoneFileStream >> menu.itemMaterialPtr; + + float itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight; + *aZoneFileStream >> itemTextRectX >> itemTextRectY >> itemTextRectWidth >> itemTextRectHeight; + menu.itemTextRect = QRectF(itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight); + + quint32 hItemTextAlignInt, vItemTextAlignInt, itemType, fontTypeInt, textStyleInt; + *aZoneFileStream >> hItemTextAlignInt >> vItemTextAlignInt >> itemType >> menu.dataType + >> menu.alignment >> fontTypeInt >> menu.textAlignMode >> menu.textalignx >> menu.textaligny + >> menu.textscale >> textStyleInt >> menu.gameMsgWindowIndex >> menu.gameMsgWindowMode + >> menu.testPtr >> menu.textSavegameInfo >> menu.parentPtr; + menu.itemText_hAlign = (MENU_H_ALIGNMENT)hItemTextAlignInt; + menu.itemText_vAlign = (MENU_V_ALIGNMENT)vItemTextAlignInt; + menu.itemType = (MENU_ITEM_TYPE)itemType; + menu.fontEnum = (MENU_FONT_TYPE)fontTypeInt; + menu.textStyle = (MENU_ITEM_TEXTSTYLE)textStyleInt; + + *aZoneFileStream >> menu.mouseEnterText >> menu.mouseExitText >> menu.mouseEnter >> menu.mouseExit + >> menu.action >> menu.onAccept >> menu.onFocus >> menu.leaveFocus >> menu.dvar >> menu.dvarTest + >> menu.keyHandlerPtr >> menu.enableDvarPtr >> menu.dvarFlags >> menu.focusSoundPtr + >> menu.special >> menu.cursorPos; + + // itemDefData_t typeData; + + // listBoxDef_s *listBox; + + *aZoneFileStream >> menu.startPos >> menu.endPos >> menu.drawPadding; + + *aZoneFileStream >> menu.elementWidth >> menu.elementHeight; + + *aZoneFileStream >> menu.elementStyle >> menu.numColumns; + + //columnInfo_s columnInfo[16]; + + *aZoneFileStream >> menu.doubleClickPtr; + + + *aZoneFileStream >> menu.notselectable >> menu.noScrollBars >> menu.usePaging; + + float itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA, + itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA, + itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA; + *aZoneFileStream >> itemSelectBorderColorR >> itemSelectBorderColorG >> itemSelectBorderColorB >> itemSelectBorderColorA + >> itemDisableColorR >> itemDisableColorG >> itemDisableColorB >> itemDisableColorA + >> itemFocusColorR >> itemFocusColorG >> itemFocusColorB >> itemFocusColorA; + menu.itemSelectBorderColor = QColor(itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA); + menu.itemDisableColor = QColor(itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA); + menu.itemFocusColor = QColor(itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA); + + *aZoneFileStream >> menu.selectIconPtr >> menu.backgroundItemListboxPtr >> menu.highlightTexturePtr; + + // editFieldDef_s *editField; + + *aZoneFileStream >> menu.minVal >> menu.maxVal >> menu.defVal >> menu.range >> menu.maxChars + >> menu.maxCharsGotoNext >> menu.maxPaintChars >> menu.paintOffset; + + // multiDef_s *multi; + + for (int i = 0; i < 32; i++) { + quint32 dvarList; + *aZoneFileStream >> dvarList; + menu.dvarListPtrs.push_back(dvarList); + } + + for (int i = 0; i < 32; i++) { + quint32 dvarStr; + *aZoneFileStream >> dvarStr; + menu.dvarStrPtrs.push_back(dvarStr); + } + + for (int i = 0; i < 32; i++) { + float dvarValue; + *aZoneFileStream >> dvarValue; + menu.dvarValues.push_back(dvarValue); + } + + *aZoneFileStream >> menu.count >> menu.strDef >> menu.enumDvarNamePtr; + aZoneFileStream->skipRawData(4); + //>> menu.dataPtr + *aZoneFileStream >> menu.itemImageTrack; + + qDebug() << aZoneFileStream->device()->pos(); + + //statement_s visibleExp; + //statement_s textExp; + //statement_s materialExp; + //statement_s rectXExp; + //statement_s rectYExp; + //statement_s rectWExp; + //statement_s rectHExp; + //statement_s foreColorAExp; + result.menuDefs << menu; + } + return result; +} + +void ZoneFile_COD11_PS3::pParseAsset_Weapon(QDataStream *aZoneFileStream) { + //WEAPON_FILE + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD11_PS3::pParseAsset_D3DBSP(QDataStream *aZoneFileStream) { + //D3DBSP_DUMP + Q_UNUSED(aZoneFileStream); +} + +StringTable ZoneFile_COD11_PS3::pParseAsset_StringTable(QDataStream *aZoneFileStream) { + StringTable result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.columnCount + >> result.rowCount; + + // Todo fix this + result.columnCount = 0; + result.rowCount = 0; + + aZoneFileStream->skipRawData(4); + + QString stringTableName; + char stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + while (stringTableNameChar != 0) { + result.name += stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + } + + for (quint32 i = 0; i < result.rowCount; i++) { + QByteArray pointerData(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pointerData.data(), 4); + result.tablePointers.push_back(pointerData.toHex()); + + aZoneFileStream->skipRawData(4); + } + + for (const QString &pointerAddr : result.tablePointers) { + QString leadingContent = ""; + if (pointerAddr == "FFFFFFFF") { + char leadingContentChar; + *aZoneFileStream >> leadingContentChar; + while (leadingContentChar != 0) { + leadingContent += leadingContentChar; + *aZoneFileStream >> leadingContentChar; + } + } else { + leadingContent = pointerAddr; + } + + QString content; + char contentChar; + *aZoneFileStream >> contentChar; + while (contentChar != 0) { + content += contentChar; + *aZoneFileStream >> contentChar; + } + result.content[leadingContent] = content; + } + return result; +} + +AssetType ZoneFile_COD11_PS3::AssetStrToEnum(const QString aAssetType) { + const QString cleanedType = aAssetType.toUpper(); + if (cleanedType == "17000000") { // localized string PARTIALLY VERIFIED + return ASSET_LOCAL_STRING; + } else if (cleanedType == "20000000") { // raw_file PARTIALLY VERIFIED + return ASSET_RAW_FILE; + } else if (cleanedType == "1A000000") { // fx PARTIALLY VERIFIED + return ASSET_EFFECT; + } else if (cleanedType == "09000000") { // loaded_sound PARTIALLY VERIFIED + return ASSET_SOUND; + } else if (cleanedType == "04000000") { // x_anim PARTIALLY VERIFIED + return ASSET_ANIMATION; + } else if (cleanedType == "0C000000") { // collision_map PARTIALLY VERIFIED + return ASSET_COLLISION_MAP; + } else if (cleanedType == "21000000") { // string_table PARTIALLY VERIFIED + return ASSET_STRING_TABLE; + } else if (cleanedType == "15000000") { // menu_file PARTIALLY VERIFIED + return ASSET_MENU; + } else if (cleanedType == "07000000") { // tech set PARTIALLY VERIFIED + return ASSET_TECH_SET; + } else if (cleanedType == "18000000") { // weapon PARTIALLY VERIFIED + return ASSET_WEAPON; + } else if (cleanedType == "11000000") { // gfx map PARTIALLY VERIFIED + return ASSET_GFX_MAP; + } else if (cleanedType == "12000000") { // light_def PARTIALLY VERIFIED + return ASSET_LIGHT_DEF; + } else if (cleanedType == "14000000") { // font PARTIALLY VERIFIED + return ASSET_FONT; + } else if (cleanedType == "05000000") { // xmodel PARTIALLY VERIFIED + return ASSET_MODEL; + } else if (cleanedType == "0D000000") { // d3dbsp PARTIALLY VERIFIED + return ASSET_D3DBSP; + } else if (cleanedType == "06000000") { // image PARTIALLY VERIFIED + return ASSET_IMAGE; + } else if (cleanedType == "0E000000") { // game map sp PARTIALLY VERIFIED + return ASSET_GAME_MAP_SP; + } else if (cleanedType == "0B000000") { // col map sp PARTIALLY VERIFIED + return ASSET_COL_MAP_SP; + } + return ASSET_NONE; +} + +QByteArray ZoneFile_COD11_PS3::GetBinaryData() { + QByteArray result; + + return result; +} diff --git a/libs/zonefile/PS3/zonefile_cod11_ps3.h b/libs/zonefile/PS3/zonefile_cod11_ps3.h new file mode 100644 index 0000000..a8c16f3 --- /dev/null +++ b/libs/zonefile/PS3/zonefile_cod11_ps3.h @@ -0,0 +1,52 @@ +#ifndef ZONEFILE_COD11_PS3_H +#define ZONEFILE_COD11_PS3_H + +#include "zonefile.h" + +class ZoneFile_COD11_PS3 : public ZoneFile +{ +public: + ZoneFile_COD11_PS3(); + ~ZoneFile_COD11_PS3(); + + bool Load(const QByteArray aFileData) override; + AssetType AssetStrToEnum(const QString aAssetType) override; + + QByteArray GetBinaryData() override; + +protected: + void pParseZoneHeader(QDataStream *aZoneFileStream) override; + quint32 pParseZoneSize(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsA(QDataStream *aZoneFileStream) override; + quint32 pParseZoneTagCount(QDataStream *aZoneFileStream) override; + quint32 pParseZoneRecordCount(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsB(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsC(QDataStream *aZoneFileStream) override; + QStringList pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) override; + QStringList pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) override; + AssetMap pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) override; + LocalString pParseAsset_LocalString(QDataStream *aZoneFileStream) override; + RawFile pParseAsset_RawFile(QDataStream *aZoneFileStream) override; + void pParseAsset_PhysPreset(QDataStream *aZoneFileStream) override; + Model pParseAsset_Model(QDataStream *aZoneFileStream) override; + Material pParseAsset_Material(QDataStream *aZoneFileStream) override; + Shader pParseAsset_Shader(QDataStream *aZoneFileStream) override; + TechSet pParseAsset_TechSet(QDataStream *aZoneFileStream) override; + Image pParseAsset_Image(QDataStream *aZoneFileStream) override; + SoundAsset pParseAsset_Sound(QDataStream *aZoneFileStream) override; + void pParseAsset_ColMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapSP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_LightDef(QDataStream *aZoneFileStream) override; + void pParseAsset_UIMap(QDataStream *aZoneFileStream) override; + void pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) override; + void pParseAsset_AIType(QDataStream *aZoneFileStream) override; + void pParseAsset_FX(QDataStream *aZoneFileStream) override; + Animation pParseAsset_Animation(QDataStream *aZoneFileStream) override; + MenuFile pParseAsset_MenuFile(QDataStream *aZoneFileStream) override; + void pParseAsset_Weapon(QDataStream *aZoneFileStream) override; + void pParseAsset_D3DBSP(QDataStream *aZoneFileStream) override; + StringTable pParseAsset_StringTable(QDataStream *aZoneFileStream) override; +}; + +#endif // ZONEFILE_COD11_PS3_H diff --git a/libs/zonefile/PS3/zonefile_cod12_ps3.cpp b/libs/zonefile/PS3/zonefile_cod12_ps3.cpp new file mode 100644 index 0000000..9d6f3f1 --- /dev/null +++ b/libs/zonefile/PS3/zonefile_cod12_ps3.cpp @@ -0,0 +1,1072 @@ +#include "zonefile_cod12_ps3.h" + +#include +#include +#include + +ZoneFile_COD12_PS3::ZoneFile_COD12_PS3() +{ + +} + +ZoneFile_COD12_PS3::~ZoneFile_COD12_PS3() +{ + +} + +bool ZoneFile_COD12_PS3::Load(const QByteArray aFileData) { + // Open zone file as little endian stream + QDataStream zoneFileStream(aFileData); + zoneFileStream.setByteOrder(QDataStream::BigEndian); + + // Parse data from zone file header + pParseZoneHeader(&zoneFileStream); + SetRecords(pParseZoneIndex(&zoneFileStream, GetRecordCount())); + SetAssetMap(pParseAssets(&zoneFileStream, GetRecords())); + + return true; +} + +void ZoneFile_COD12_PS3::pParseZoneHeader(QDataStream *aZoneFileStream) { + SetSize(pParseZoneSize(aZoneFileStream)); + pParseZoneUnknownsA(aZoneFileStream); + + SetTagCount(pParseZoneTagCount(aZoneFileStream)); + pParseZoneUnknownsB(aZoneFileStream); + + SetRecordCount(pParseZoneRecordCount(aZoneFileStream)); + + quint32 tagCount = GetTagCount(); + if (tagCount) { + pParseZoneUnknownsC(aZoneFileStream); + SetTags(pParseZoneTags(aZoneFileStream, tagCount)); + } else { + aZoneFileStream->skipRawData(4); + } +} + +quint32 ZoneFile_COD12_PS3::pParseZoneSize(QDataStream *aZoneFileStream) { + quint32 zoneFileSize; + *aZoneFileStream >> zoneFileSize; + if (zoneFileSize <= 0) { + qDebug() << "Tried to open empty zone file!"; + exit(-1); + } + zoneFileSize += 36; + return zoneFileSize; +} + +/* + ParseZoneUnknownsA() + + Parses the 1st section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD12_PS3::pParseZoneUnknownsA(QDataStream *aZoneFileStream) { + // Byte 4-7, 8-11, 12-15: unknown + QByteArray unknown1(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown1.data(), 4); + + QByteArray unknown2(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown2.data(), 4); + + QByteArray unknown3(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown3.data(), 4); + + // Byte 16-19, 20-23: empty/unknown + QByteArray unknown4(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown4.data(), 4); + + QByteArray unknown5(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown5.data(), 4); + + // Byte 24-27: somehow related to the filesize, but smaller value + QByteArray unknown6(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown6.data(), 4); + + // Byte 28-31, 32-35: unknown + QByteArray unknown7(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown7.data(), 4); + + QByteArray unknown8(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown8.data(), 4); +} + +/* + ParseZoneTagCount() + + Parses the number of string tags in the zone index +*/ +quint32 ZoneFile_COD12_PS3::pParseZoneTagCount(QDataStream *aZoneFileStream) { + quint32 tagCount; + *aZoneFileStream >> tagCount; + return tagCount; +} + +/* + ParseZoneRecordCount() + + Parses the number of records in the zone index +*/ +quint32 ZoneFile_COD12_PS3::pParseZoneRecordCount(QDataStream *aZoneFileStream) { + quint32 recordCount; + *aZoneFileStream >> recordCount; + return recordCount; +} + +/* + ParseZoneUnknownsB() + + Parses the 2nd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD12_PS3::pParseZoneUnknownsB(QDataStream *aZoneFileStream) { + // Byte 44-47: Unknown/empty? + QByteArray unknown9(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown9.data(), 4); +} + +/* + pParseZoneUnknownsC() + + Parses the 3rd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD12_PS3::pParseZoneUnknownsC(QDataStream *aZoneFileStream) { + // Byte 40-43: Unknown/empty? + QByteArray unknown10(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown10.data(), 4); + + // Byte 44-47: Unknown/empty? + QByteArray unknown11(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown11.data(), 4); +} + +/* + ParseZoneTags() + + Parses the string tags ate the start of zone file +*/ +QStringList ZoneFile_COD12_PS3::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) { + QStringList tags; + + // Byte 48-51: Repeated separators? ÿÿÿÿ x i + aZoneFileStream->skipRawData(4 * (tagCount - 1)); + + // Parse tags/strings before index + QString zoneTag; + char zoneTagChar; + for (quint32 i = 0; i < tagCount; i++) { + *aZoneFileStream >> zoneTagChar; + while (zoneTagChar != 0) { + zoneTag += zoneTagChar; + *aZoneFileStream >> zoneTagChar; + } + tags << zoneTag; + zoneTag.clear(); + } + return tags; +} + +/* + ParseZoneIndex() + + Parse the binary zone index data and populate table +*/ +QStringList ZoneFile_COD12_PS3::pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) { + QStringList result; + + // Don't parse if no records + if (!recordCount) { return result; } + + if (aZoneFileStream->device()->peek(4).toHex().contains("ffff")) { + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 2); + } + + // Parse index & map found asset types + for (quint32 i = 0; i <= recordCount; i++) { + // Skip record start + QByteArray rawAssetType(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rawAssetType.data(), 4); + result << rawAssetType.toHex(); + + // Skip separator + aZoneFileStream->skipRawData(4); + } + return result; +} + +AssetMap ZoneFile_COD12_PS3::pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) { + AssetMap result; + + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 8); + + for (int i = 0; i < assetOrder.size(); i++) { + const QString typeHex = assetOrder[i]; + const AssetType typeStr = AssetStrToEnum(typeHex); + + if (typeStr == ASSET_LOCAL_STRING) { // localized string asset + result.localStrings << pParseAsset_LocalString(aZoneFileStream); + } else if (typeStr == ASSET_RAW_FILE) { // gsc + auto rawFile = pParseAsset_RawFile(aZoneFileStream); + if (rawFile.length) { + result.rawFiles << rawFile; + } + } else if (typeStr == ASSET_PHYS_PRESET) { // physpreset + pParseAsset_PhysPreset(aZoneFileStream); + } else if (typeStr == ASSET_MODEL) { // xmodel + result.models << pParseAsset_Model(aZoneFileStream); + } else if (typeStr == ASSET_MATERIAL) { // material + pParseAsset_Material(aZoneFileStream); + } else if (typeStr == ASSET_SHADER) { // pixelshader + pParseAsset_Shader(aZoneFileStream); + } else if (typeStr == ASSET_TECH_SET) { // techset include + result.techSets << pParseAsset_TechSet(aZoneFileStream); + } else if (typeStr == ASSET_IMAGE) { // image + result.images << pParseAsset_Image(aZoneFileStream); + } else if (typeStr == ASSET_SOUND) { // loaded_sound + result.sounds << pParseAsset_Sound(aZoneFileStream); + } else if (typeStr == ASSET_COLLISION_MAP) { // col_map_mp + pParseAsset_ColMapMP(aZoneFileStream); + } else if (typeStr == ASSET_MP_MAP) { // game_map_sp + pParseAsset_GameMapSP(aZoneFileStream); + } else if (typeStr == ASSET_SP_MAP) { // game_map_mp + pParseAsset_GameMapMP(aZoneFileStream); + } else if (typeStr == ASSET_LIGHT_DEF) { // lightdef + pParseAsset_LightDef(aZoneFileStream); + } else if (typeStr == ASSET_UI_MAP) { // ui_map + pParseAsset_UIMap(aZoneFileStream); + } else if (typeStr == ASSET_SND_DRIVER_GLOBALS) { // snddriverglobals + pParseAsset_SNDDriverGlobals(aZoneFileStream); + } else if (typeStr == ASSET_AI_TYPE) { // aitype + pParseAsset_AIType(aZoneFileStream); + } else if (typeStr == ASSET_EFFECT) { // aitype + pParseAsset_FX(aZoneFileStream); + } else if (typeStr == ASSET_ANIMATION) { // aitype + result.animations << pParseAsset_Animation(aZoneFileStream); + } else if (typeStr == ASSET_STRING_TABLE) { // string_table + result.stringTables << pParseAsset_StringTable(aZoneFileStream); + } else if (typeStr == ASSET_MENU) { // string_table + result.menuFiles << pParseAsset_MenuFile(aZoneFileStream); + } else if (typeStr == ASSET_WEAPON) { // string_table + pParseAsset_Weapon(aZoneFileStream); + } else if (typeStr == ASSET_D3DBSP) { // string_table + pParseAsset_D3DBSP(aZoneFileStream); + } + } + return result; +} + +LocalString ZoneFile_COD12_PS3::pParseAsset_LocalString(QDataStream *aZoneFileStream) { + LocalString result; + + quint32 stringPtr, aliasPtr; + *aZoneFileStream >> stringPtr >> aliasPtr; + if (stringPtr == 4294967295) { + // Parse local string asset contents + QString localStr; + char localStrChar; + *aZoneFileStream >> localStrChar; + while (localStrChar != 0) { + result.string += localStrChar; + *aZoneFileStream >> localStrChar; + } + } else { + result.string = "String Ptr: " + QString::number(stringPtr); + } + + if (aliasPtr == 4294967295) { + // Parse rawfile name + QString aliasName; + char aliasNameChar; + *aZoneFileStream >> aliasNameChar; + while (aliasNameChar != 0) { + result.alias += aliasNameChar; + *aZoneFileStream >> aliasNameChar; + } + } else { + result.string = "Alias Ptr: " + QString::number(aliasPtr); + } + + return result; +} + +RawFile ZoneFile_COD12_PS3::pParseAsset_RawFile(QDataStream *aZoneFileStream) { + RawFile result; + + // Skip start separator FF FF FF FF (pointer?) + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.length; + + // Skip unknown 4 byte data + aZoneFileStream->skipRawData(4); + + // Parse rawfile path + char scriptPathChar; + *aZoneFileStream >> scriptPathChar; + while (scriptPathChar != 0) { + result.path += scriptPathChar; + *aZoneFileStream >> scriptPathChar; + } + result.path.replace(",", ""); + const QStringList pathParts = result.path.split('/'); + if (pathParts.size() == 0) { + qDebug() << "Failed to parse ff path! " << result.path; + exit(-1); + } + + // Parse gsc contents + char rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + while (rawFileContentsChar != 0 && rawFileContentsChar != -1) { + result.contents += rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + } + return result; +} + +void ZoneFile_COD12_PS3::pParseAsset_PhysPreset(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Model ZoneFile_COD12_PS3::pParseAsset_Model(QDataStream *aZoneFileStream) { + Model result; + + *aZoneFileStream >> result.namePtr >> result.tagCount >> result.rootTagCount + >> result.surfCount >> result.unknownCount >> result.boneNamePtr + >> result.parentListPtr >> result.quatsPtr >> result.transPtr + >> result.partClassPtr >> result.baseMatPtr + >> result.surfsPtr >> result.materialHandlesPtr; + + // Parse XModelLodInfo + for (int i = 1; i <= 4; i++) { + quint32 intDist; + *aZoneFileStream >> intDist; + + std::memcpy(&result.lodInfo[i].dist, &intDist, sizeof(result.lodInfo[i].dist)); + *aZoneFileStream >> result.lodInfo[i].numsurfs >> result.lodInfo[i].surfIndex; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.lodInfo[i].partBits[0] + >> result.lodInfo[i].partBits[1] + >> result.lodInfo[i].partBits[2] + >> result.lodInfo[i].partBits[3]; + } + + *aZoneFileStream >> result.collSurfsPtr >> result.numCollSurfs >> result.contents >> result.boneInfoPtr; + + quint32 intRadius, intMins[3], intMaxs[3]; + *aZoneFileStream >> intRadius >> intMins[0] >> intMins[1] + >> intMins[2] >> intMaxs[0] >> intMaxs[1] >> intMaxs[2]; + + std::memcpy(&result.radius, &intRadius, sizeof(result.radius)); + + std::memcpy(&result.mins[0], &intMins[0], sizeof(result.mins[0])); + std::memcpy(&result.mins[1], &intMins[1], sizeof(result.mins[1])); + std::memcpy(&result.mins[2], &intMins[2], sizeof(result.mins[2])); + + std::memcpy(&result.maxs[0], &intMaxs[0], sizeof(result.maxs[0])); + std::memcpy(&result.maxs[1], &intMaxs[1], sizeof(result.maxs[2])); + std::memcpy(&result.maxs[2], &intMaxs[2], sizeof(result.maxs[3])); + + *aZoneFileStream >> result.numLods >> result.collLod >> result.streamInfoPtr + >> result.memUsage >> result.flags >> result.physPresetPtr >> result.physGeomsPtr; + + // Parse model name + char modelNameChar; + *aZoneFileStream >> modelNameChar; + while (modelNameChar == 0) { + *aZoneFileStream >> modelNameChar; + } + while (modelNameChar != 0) { + result.modelName += modelNameChar; + *aZoneFileStream >> modelNameChar; + } + return result; +} + +Material ZoneFile_COD12_PS3::pParseAsset_Material(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); + + return Material(); +} + +Shader ZoneFile_COD12_PS3::pParseAsset_Shader(QDataStream *aZoneFileStream) { + Shader result = Shader(); + + quint8 minorVersion, majorVersion; + *aZoneFileStream >> minorVersion >> majorVersion; + + quint32 magic; + *aZoneFileStream >> magic; + + // Verify .fxc magic + if (magic != 65534 && magic != 65535) { return result; } + + SHADER_TYPE type = SHADER_NONE; + quint16 rawShaderType; + *aZoneFileStream >> rawShaderType; + if (rawShaderType == 65535) { // Pixel shader + type = SHADER_PIXEL; + } else if (rawShaderType == 65534) { // Vertex shader + type = SHADER_VERTEX; + } + Q_UNUSED(type); + + while (true) { + quint32 instructionToken; + *aZoneFileStream >> instructionToken; + + SHADER_OPCODE opCode = (SHADER_OPCODE)(instructionToken & 0xffff); + + int size; + if (opCode == OPCODE_End) { + break; + } else if (opCode == OPCODE_Comment) { + size = (int)((instructionToken >> 16) & 0x7FFF); + } else { + size = (int)((instructionToken >> 24) & 0x0f); + } + Q_UNUSED(size); + } + + + return result; +} + +TechSet ZoneFile_COD12_PS3::pParseAsset_TechSet(QDataStream *aZoneFileStream) { + TechSet result; + + for (int i = 1; i <= 62; i++) { + quint32 ptr; + *aZoneFileStream >> ptr; + + result.pointers << ptr; + } + qDebug() << aZoneFileStream->device()->pos(); + + // Parse techset name + char techSetNameChar; + *aZoneFileStream >> techSetNameChar; + while (techSetNameChar != 0) { + result.name += techSetNameChar; + *aZoneFileStream >> techSetNameChar; + } + result.name.replace(",", ""); + + return result; +} + +Image ZoneFile_COD12_PS3::pParseAsset_Image(QDataStream *aZoneFileStream) { + Image result; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknowna >> result.unknownb + >> result.unknownc >> result.unknownd + >> result.unknowne >> result.unknownf + >> result.unknowng; + + aZoneFileStream->skipRawData(15 * 4); + *aZoneFileStream >> result.unknownh >> result.unknowni; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknownj; + + aZoneFileStream->skipRawData(4); + + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + result.materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + result.materialName.replace(",", ""); + + if (result.unknowna) { + *aZoneFileStream >> result.unknownk; + *aZoneFileStream >> result.unknownl; + *aZoneFileStream >> result.unknownm; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown1; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown2 >> result.unknown3 + >> result.size1 >> result.size2 + >> result.unknown4 >> result.unknown5; + + aZoneFileStream->skipRawData(4); + + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + result.name += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + + *aZoneFileStream >> result.unknown6 >> result.unknown7; + + QByteArray compressionData(8, Qt::Uninitialized); + aZoneFileStream->readRawData(compressionData.data(), 8); + if (compressionData.contains("DXT1")) { + result.compression = COMPRESSION_DXT1; + } else if (compressionData.contains("DXT3")) { + result.compression = COMPRESSION_DXT3; + } else if (compressionData.contains("DXT5")) { + result.compression = COMPRESSION_DXT5; + } else { + result.compression = COMPRESSION_NONE; + } + + *aZoneFileStream >> result.unknown8 >> result.unknown9; + } + + return result; +} + +SoundAsset ZoneFile_COD12_PS3::pParseAsset_Sound(QDataStream *aZoneFileStream) { + SoundAsset result; + + qDebug() << aZoneFileStream->device()->pos(); + + QByteArray rootNamePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rootNamePtr.data(), 4); + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.count; + + if (rootNamePtr.toHex() == "ffffffff") { + // Read in sound file name + char soundNameChar; + *aZoneFileStream >> soundNameChar; + while (soundNameChar != 0) { + result.name += soundNameChar; + *aZoneFileStream >> soundNameChar; + } + } + + int tagCount = 0; + int resultCount = 0; + for (quint32 i = 0; i < result.count; i++) { + aZoneFileStream->skipRawData(12); + + QByteArray tagPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(tagPtr.data(), 4); + + if (tagPtr.toHex() == "ffffffff") { + tagCount++; + } + aZoneFileStream->skipRawData(4); + + QByteArray pathPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pathPtr.data(), 4); + + if (pathPtr.toHex() == "ffffffff") { + resultCount++; + } + + aZoneFileStream->skipRawData(160); + } + + for (int i = 0; i < tagCount; i++) { + // Read in tag? + QString tag; + char tagChar; + *aZoneFileStream >> tagChar; + while (tagChar != 0) { + tag += tagChar; + *aZoneFileStream >> tagChar; + } + } + + for (int i = 0; i < resultCount; i++) { + Sound sound; + + if (aZoneFileStream->device()->peek(12).toHex().contains("ffffffff00000000")) { + aZoneFileStream->skipRawData(12); + } + + aZoneFileStream->skipRawData(8); + + QByteArray aliasPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(aliasPtr.data(), 4); + + QByteArray namePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(namePtr.data(), 4); + + *aZoneFileStream >> sound.dataLength; + + if (aliasPtr.toHex() == "ffffffff") { + // Read in sound alias name + char soundAliasChar; + *aZoneFileStream >> soundAliasChar; + while (soundAliasChar != 0) { + sound.alias += soundAliasChar; + *aZoneFileStream >> soundAliasChar; + } + } + + if (aZoneFileStream->device()->peek(4) == "RIFF") { + sound.path = sound.alias; + sound.alias = ""; + } else if (namePtr.toHex() == "ffffffff") { + // Read in sound file path + char soundPathChar; + *aZoneFileStream >> soundPathChar; + while (soundPathChar != 0) { + sound.path += soundPathChar; + *aZoneFileStream >> soundPathChar; + } + sound.path.replace(",", ""); + } + + if (sound.dataLength) { + QByteArray data(sound.dataLength, Qt::Uninitialized); + aZoneFileStream->readRawData(data.data(), sound.dataLength); + sound.data = data; + } + result.sounds.append(sound); + } + + return result; +} + +void ZoneFile_COD12_PS3::pParseAsset_ColMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD12_PS3::pParseAsset_GameMapSP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD12_PS3::pParseAsset_GameMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD12_PS3::pParseAsset_LightDef(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD12_PS3::pParseAsset_UIMap(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD12_PS3::pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD12_PS3::pParseAsset_AIType(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD12_PS3::pParseAsset_FX(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Animation ZoneFile_COD12_PS3::pParseAsset_Animation(QDataStream *aZoneFileStream) { + Animation result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.dataByteCount + >> result.dataShortCount + >> result.dataIntCount + >> result.randomDataByteCount + >> result.randomDataIntCount + >> result.numframes + >> result.isLooped + >> result.isDelta + >> result.noneRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.normalTranslatedBoneCount + >> result.preciseTranslatedBoneCount + >> result.staticTranslatedBoneCount + >> result.noneTranslatedBoneCount + >> result.totalBoneCount + >> result.otherBoneCount1 + >> result.otherBoneCount2 + >> result.notifyCount + >> result.assetType + >> result.pad + >> result.randomDataShortCount + >> result.indexCount + >> result.frameRate + >> result.frequency + >> result.boneIDsPtr + >> result.dataBytePtr + >> result.dataShortPtr + >> result.dataIntPtr + >> result.randomDataShortPtr + >> result.randomDataBytePtr + >> result.randomDataIntPtr + >> result.longIndiciesPtr + >> result.notificationsPtr + >> result.deltaPartsPtr; + + // Read in x_anim file name + QString xAnimName; + char xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + while (xAnimNameChar != 0) { + result.name += xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + } + + // Parse x_anim index header + QVector sectionLengths; + for (int i = 0; i < result.numframes; i++) { + quint8 sectionlength; + *aZoneFileStream >> sectionlength; + sectionLengths.push_back(sectionlength); + // Skip padding + aZoneFileStream->skipRawData(1); + } + // Skip unknown section + aZoneFileStream->skipRawData(2 * 8); + + return result; +} + +MenuFile ZoneFile_COD12_PS3::pParseAsset_MenuFile(QDataStream *aZoneFileStream) { + //MENU_FILE + MenuFile result; + + aZoneFileStream->skipRawData(4); // Separator + + // Parse menu def count + *aZoneFileStream >> result.menuCount; + + // Clearly misparsed, never have this much + if (result.menuCount > 1000) { + qDebug() << "Failure reported when parsing menu file."; + return result; + } + for (uint i = 0; i < result.menuCount; i++) { + Menu menu; + + aZoneFileStream->skipRawData(4); // Separator + + // Read in x_anim file name + char menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + while (menuFilepathChar != 0) { + menu.filePath += menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + } + aZoneFileStream->skipRawData(4); // Separator + + *aZoneFileStream >> menu.menuNamePtr; + + float menuRectX, menuRectY, menuRectWidth, menuRectHeight; + *aZoneFileStream >> menuRectX >> menuRectY >> menuRectWidth >> menuRectHeight; + menu.rect = QRectF(menuRectX, menuRectY, menuRectWidth, menuRectHeight); + + quint32 hAlignInt, vAlignInt; + *aZoneFileStream >> hAlignInt >> vAlignInt; + menu.hAlign = (MENU_H_ALIGNMENT)hAlignInt; + menu.vAlign = (MENU_V_ALIGNMENT)vAlignInt; + + float rectClientX, rectClientY, rectClientWidth, rectClientHeight; + *aZoneFileStream >> rectClientX >> rectClientY >> rectClientWidth >> rectClientHeight; + menu.clientRect = QRectF(rectClientX, rectClientY, rectClientWidth, rectClientHeight); + + quint32 hClientAlignInt, vClientAlignInt, styleInt, borderInt; + *aZoneFileStream >> hClientAlignInt >> vClientAlignInt >> menu.groupPtr + >> styleInt >> borderInt >> menu.ownerDraw >> menu.ownerDrawFlags + >> menu.borderSize >> menu.staticFlags >> menu.dynamicFlags >> menu.nextTime; + menu.hClientAlign = (MENU_H_ALIGNMENT)hClientAlignInt; + menu.vClientAlign = (MENU_V_ALIGNMENT)vClientAlignInt; + menu.style = (MENU_WINDOW_STYLE)styleInt; + menu.border = (MENU_WINDOW_BORDER)borderInt; + + float foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA, + backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA, + borderColorR, borderColorG, borderColorB, borderColorA, + outlineColorR, outlineColorG, outlineColorB, outlineColorA; + *aZoneFileStream >> foregroundColorR >> foregroundColorG >> foregroundColorB >> foregroundColorA + >> backgroundColorR >> backgroundColorG >> backgroundColorB >> backgroundColorA + >> borderColorR >> borderColorG >> borderColorB >> borderColorA + >> outlineColorR >> outlineColorG >> outlineColorB >> outlineColorA; + + menu.foregroundColor = QColor(foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA); + menu.backgroundColor = QColor(backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA); + menu.borderColor = QColor(borderColorR, borderColorG, borderColorB, borderColorA); + menu.outlineColor = QColor(outlineColorR, outlineColorG, outlineColorB, outlineColorA); + + *aZoneFileStream >> menu.materialPtr >> menu.fontPtr >> menu.fullScreen >> menu.itemCount + >> menu.fontIndex >> menu.cursorItem >> menu.fadeCycle >> menu.fadeClamp + >> menu.fadeAmount >> menu.fadeInAmount >> menu.blurRadius >> menu.onOpenPtr + >> menu.onFocusPtr >> menu.onClosePtr >> menu.onESCPtr >> menu.onKeyPtr + >> menu.visibleExpCount >> menu.expEntryPtr >> menu.allowedBindingPtr + >> menu.soundNamePtr >> menu.imageTrack; + + float focusColorR, focusColorG, focusColorB, focusColorA, + disabledColorR, disabledColorG, disabledColorB, disabledColorA; + *aZoneFileStream >> focusColorR >> focusColorG >> focusColorB >> focusColorA + >> disabledColorR >> disabledColorG >> disabledColorB >> disabledColorA; + menu.focusColor = QColor(focusColorR, focusColorG, focusColorB, focusColorA); + menu.disabledColor = QColor(disabledColorR, disabledColorG, disabledColorB, disabledColorA); + + *aZoneFileStream >> menu.rectXExpCount >> menu.rectXExpPtr >> menu.rectYExpCount >> menu.rectYExpPtr; + + aZoneFileStream->skipRawData(4); // Separator + + char menuDefNameChar; + int menuDefNameLen = 0; + *aZoneFileStream >> menuDefNameChar; + while (menuDefNameChar != 0 && menuDefNameLen < 30) { + menuDefNameLen++; + menu.name += menuDefNameChar; + *aZoneFileStream >> menuDefNameChar; + } + + char defStringChar; + int defStringLen = 0; + *aZoneFileStream >> defStringChar; + while (defStringChar != 0 && defStringLen < 30) { + defStringLen++; + menu.definition += defStringChar; + *aZoneFileStream >> defStringChar; + } + aZoneFileStream->skipRawData(4 * 10); + + *aZoneFileStream >> menu.itemWindowDefNamePtr; + + float itemRectX, itemRectY, itemRectWidth, itemRectHeight; + *aZoneFileStream >> itemRectX >> itemRectY >> itemRectWidth >> itemRectHeight; + menu.itemRect = QRectF(itemRectX, itemRectY, itemRectWidth, itemRectHeight); + + *aZoneFileStream >> menu.itemHAlignment >> menu.itemVAlignment >> menu.itemGroupPtr + >> menu.itemWindowStyle >> menu.itemWindowBorder >> menu.itemOwnerDraw + >> menu.itemOwnerDrawFlags >> menu.itemBorderSize >> menu.itemStaticFlags + >> menu.itemDynamicFlags >> menu.itemNextTime; + + float itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA, + itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA, + itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA, + itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA; + *aZoneFileStream >> itemForegroundColorR >> itemForegroundColorG >> itemForegroundColorB >> itemForegroundColorA + >> itemBackgroundColorR >> itemBackgroundColorG >> itemBackgroundColorB >> itemBackgroundColorA + >> itemBorderColorR >> itemBorderColorG >> itemBorderColorB >> itemBorderColorA + >> itemOutlineColorR >> itemOutlineColorG >> itemOutlineColorB >> itemOutlineColorA; + + menu.itemForegroundColor = QColor(itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA); + menu.itemBackgroundColor = QColor(itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA); + menu.itemBorderColor = QColor(itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA); + menu.itemOutlineColor = QColor(itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA); + + *aZoneFileStream >> menu.itemMaterialPtr; + + float itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight; + *aZoneFileStream >> itemTextRectX >> itemTextRectY >> itemTextRectWidth >> itemTextRectHeight; + menu.itemTextRect = QRectF(itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight); + + quint32 hItemTextAlignInt, vItemTextAlignInt, itemType, fontTypeInt, textStyleInt; + *aZoneFileStream >> hItemTextAlignInt >> vItemTextAlignInt >> itemType >> menu.dataType + >> menu.alignment >> fontTypeInt >> menu.textAlignMode >> menu.textalignx >> menu.textaligny + >> menu.textscale >> textStyleInt >> menu.gameMsgWindowIndex >> menu.gameMsgWindowMode + >> menu.testPtr >> menu.textSavegameInfo >> menu.parentPtr; + menu.itemText_hAlign = (MENU_H_ALIGNMENT)hItemTextAlignInt; + menu.itemText_vAlign = (MENU_V_ALIGNMENT)vItemTextAlignInt; + menu.itemType = (MENU_ITEM_TYPE)itemType; + menu.fontEnum = (MENU_FONT_TYPE)fontTypeInt; + menu.textStyle = (MENU_ITEM_TEXTSTYLE)textStyleInt; + + *aZoneFileStream >> menu.mouseEnterText >> menu.mouseExitText >> menu.mouseEnter >> menu.mouseExit + >> menu.action >> menu.onAccept >> menu.onFocus >> menu.leaveFocus >> menu.dvar >> menu.dvarTest + >> menu.keyHandlerPtr >> menu.enableDvarPtr >> menu.dvarFlags >> menu.focusSoundPtr + >> menu.special >> menu.cursorPos; + + // itemDefData_t typeData; + + // listBoxDef_s *listBox; + + *aZoneFileStream >> menu.startPos >> menu.endPos >> menu.drawPadding; + + *aZoneFileStream >> menu.elementWidth >> menu.elementHeight; + + *aZoneFileStream >> menu.elementStyle >> menu.numColumns; + + //columnInfo_s columnInfo[16]; + + *aZoneFileStream >> menu.doubleClickPtr; + + + *aZoneFileStream >> menu.notselectable >> menu.noScrollBars >> menu.usePaging; + + float itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA, + itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA, + itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA; + *aZoneFileStream >> itemSelectBorderColorR >> itemSelectBorderColorG >> itemSelectBorderColorB >> itemSelectBorderColorA + >> itemDisableColorR >> itemDisableColorG >> itemDisableColorB >> itemDisableColorA + >> itemFocusColorR >> itemFocusColorG >> itemFocusColorB >> itemFocusColorA; + menu.itemSelectBorderColor = QColor(itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA); + menu.itemDisableColor = QColor(itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA); + menu.itemFocusColor = QColor(itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA); + + *aZoneFileStream >> menu.selectIconPtr >> menu.backgroundItemListboxPtr >> menu.highlightTexturePtr; + + // editFieldDef_s *editField; + + *aZoneFileStream >> menu.minVal >> menu.maxVal >> menu.defVal >> menu.range >> menu.maxChars + >> menu.maxCharsGotoNext >> menu.maxPaintChars >> menu.paintOffset; + + // multiDef_s *multi; + + for (int i = 0; i < 32; i++) { + quint32 dvarList; + *aZoneFileStream >> dvarList; + menu.dvarListPtrs.push_back(dvarList); + } + + for (int i = 0; i < 32; i++) { + quint32 dvarStr; + *aZoneFileStream >> dvarStr; + menu.dvarStrPtrs.push_back(dvarStr); + } + + for (int i = 0; i < 32; i++) { + float dvarValue; + *aZoneFileStream >> dvarValue; + menu.dvarValues.push_back(dvarValue); + } + + *aZoneFileStream >> menu.count >> menu.strDef >> menu.enumDvarNamePtr; + aZoneFileStream->skipRawData(4); + //>> menu.dataPtr + *aZoneFileStream >> menu.itemImageTrack; + + qDebug() << aZoneFileStream->device()->pos(); + + //statement_s visibleExp; + //statement_s textExp; + //statement_s materialExp; + //statement_s rectXExp; + //statement_s rectYExp; + //statement_s rectWExp; + //statement_s rectHExp; + //statement_s foreColorAExp; + result.menuDefs << menu; + } + return result; +} + +void ZoneFile_COD12_PS3::pParseAsset_Weapon(QDataStream *aZoneFileStream) { + //WEAPON_FILE + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD12_PS3::pParseAsset_D3DBSP(QDataStream *aZoneFileStream) { + //D3DBSP_DUMP + Q_UNUSED(aZoneFileStream); +} + +StringTable ZoneFile_COD12_PS3::pParseAsset_StringTable(QDataStream *aZoneFileStream) { + StringTable result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.columnCount + >> result.rowCount; + + // Todo fix this + result.columnCount = 0; + result.rowCount = 0; + + aZoneFileStream->skipRawData(4); + + QString stringTableName; + char stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + while (stringTableNameChar != 0) { + result.name += stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + } + + for (quint32 i = 0; i < result.rowCount; i++) { + QByteArray pointerData(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pointerData.data(), 4); + result.tablePointers.push_back(pointerData.toHex()); + + aZoneFileStream->skipRawData(4); + } + + for (const QString &pointerAddr : result.tablePointers) { + QString leadingContent = ""; + if (pointerAddr == "FFFFFFFF") { + char leadingContentChar; + *aZoneFileStream >> leadingContentChar; + while (leadingContentChar != 0) { + leadingContent += leadingContentChar; + *aZoneFileStream >> leadingContentChar; + } + } else { + leadingContent = pointerAddr; + } + + QString content; + char contentChar; + *aZoneFileStream >> contentChar; + while (contentChar != 0) { + content += contentChar; + *aZoneFileStream >> contentChar; + } + result.content[leadingContent] = content; + } + return result; +} + +AssetType ZoneFile_COD12_PS3::AssetStrToEnum(const QString aAssetType) { + const QString cleanedType = aAssetType.toUpper(); + if (cleanedType == "17000000") { // localized string PARTIALLY VERIFIED + return ASSET_LOCAL_STRING; + } else if (cleanedType == "20000000") { // raw_file PARTIALLY VERIFIED + return ASSET_RAW_FILE; + } else if (cleanedType == "1A000000") { // fx PARTIALLY VERIFIED + return ASSET_EFFECT; + } else if (cleanedType == "09000000") { // loaded_sound PARTIALLY VERIFIED + return ASSET_SOUND; + } else if (cleanedType == "04000000") { // x_anim PARTIALLY VERIFIED + return ASSET_ANIMATION; + } else if (cleanedType == "0C000000") { // collision_map PARTIALLY VERIFIED + return ASSET_COLLISION_MAP; + } else if (cleanedType == "21000000") { // string_table PARTIALLY VERIFIED + return ASSET_STRING_TABLE; + } else if (cleanedType == "15000000") { // menu_file PARTIALLY VERIFIED + return ASSET_MENU; + } else if (cleanedType == "07000000") { // tech set PARTIALLY VERIFIED + return ASSET_TECH_SET; + } else if (cleanedType == "18000000") { // weapon PARTIALLY VERIFIED + return ASSET_WEAPON; + } else if (cleanedType == "11000000") { // gfx map PARTIALLY VERIFIED + return ASSET_GFX_MAP; + } else if (cleanedType == "12000000") { // light_def PARTIALLY VERIFIED + return ASSET_LIGHT_DEF; + } else if (cleanedType == "14000000") { // font PARTIALLY VERIFIED + return ASSET_FONT; + } else if (cleanedType == "05000000") { // xmodel PARTIALLY VERIFIED + return ASSET_MODEL; + } else if (cleanedType == "0D000000") { // d3dbsp PARTIALLY VERIFIED + return ASSET_D3DBSP; + } else if (cleanedType == "06000000") { // image PARTIALLY VERIFIED + return ASSET_IMAGE; + } else if (cleanedType == "0E000000") { // game map sp PARTIALLY VERIFIED + return ASSET_GAME_MAP_SP; + } else if (cleanedType == "0B000000") { // col map sp PARTIALLY VERIFIED + return ASSET_COL_MAP_SP; + } + return ASSET_NONE; +} + +QByteArray ZoneFile_COD12_PS3::GetBinaryData() { + QByteArray result; + + return result; +} diff --git a/libs/zonefile/PS3/zonefile_cod12_ps3.h b/libs/zonefile/PS3/zonefile_cod12_ps3.h new file mode 100644 index 0000000..98c1b09 --- /dev/null +++ b/libs/zonefile/PS3/zonefile_cod12_ps3.h @@ -0,0 +1,52 @@ +#ifndef ZONEFILE_COD12_PS3_H +#define ZONEFILE_COD12_PS3_H + +#include "zonefile.h" + +class ZoneFile_COD12_PS3 : public ZoneFile +{ +public: + ZoneFile_COD12_PS3(); + ~ZoneFile_COD12_PS3(); + + bool Load(const QByteArray aFileData) override; + AssetType AssetStrToEnum(const QString aAssetType) override; + + QByteArray GetBinaryData() override; + +protected: + void pParseZoneHeader(QDataStream *aZoneFileStream) override; + quint32 pParseZoneSize(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsA(QDataStream *aZoneFileStream) override; + quint32 pParseZoneTagCount(QDataStream *aZoneFileStream) override; + quint32 pParseZoneRecordCount(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsB(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsC(QDataStream *aZoneFileStream) override; + QStringList pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) override; + QStringList pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) override; + AssetMap pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) override; + LocalString pParseAsset_LocalString(QDataStream *aZoneFileStream) override; + RawFile pParseAsset_RawFile(QDataStream *aZoneFileStream) override; + void pParseAsset_PhysPreset(QDataStream *aZoneFileStream) override; + Model pParseAsset_Model(QDataStream *aZoneFileStream) override; + Material pParseAsset_Material(QDataStream *aZoneFileStream) override; + Shader pParseAsset_Shader(QDataStream *aZoneFileStream) override; + TechSet pParseAsset_TechSet(QDataStream *aZoneFileStream) override; + Image pParseAsset_Image(QDataStream *aZoneFileStream) override; + SoundAsset pParseAsset_Sound(QDataStream *aZoneFileStream) override; + void pParseAsset_ColMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapSP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_LightDef(QDataStream *aZoneFileStream) override; + void pParseAsset_UIMap(QDataStream *aZoneFileStream) override; + void pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) override; + void pParseAsset_AIType(QDataStream *aZoneFileStream) override; + void pParseAsset_FX(QDataStream *aZoneFileStream) override; + Animation pParseAsset_Animation(QDataStream *aZoneFileStream) override; + MenuFile pParseAsset_MenuFile(QDataStream *aZoneFileStream) override; + void pParseAsset_Weapon(QDataStream *aZoneFileStream) override; + void pParseAsset_D3DBSP(QDataStream *aZoneFileStream) override; + StringTable pParseAsset_StringTable(QDataStream *aZoneFileStream) override; +}; + +#endif // ZONEFILE_COD12_PS3_H diff --git a/libs/zonefile/PS3/zonefile_cod4_ps3.cpp b/libs/zonefile/PS3/zonefile_cod4_ps3.cpp new file mode 100644 index 0000000..4e6243a --- /dev/null +++ b/libs/zonefile/PS3/zonefile_cod4_ps3.cpp @@ -0,0 +1,1139 @@ +#include "zonefile_cod4_ps3.h" + +#include +#include +#include + +ZoneFile_COD4_PS3::ZoneFile_COD4_PS3() + : ZoneFile() { + +} + +ZoneFile_COD4_PS3::~ZoneFile_COD4_PS3() { + +} + +bool ZoneFile_COD4_PS3::Load(const QByteArray aFileData) { + // Open zone file as little endian stream + QDataStream zoneFileStream(aFileData); + zoneFileStream.setByteOrder(QDataStream::BigEndian); + + // Parse data from zone file header + pParseZoneHeader(&zoneFileStream); + SetRecords(pParseZoneIndex(&zoneFileStream, GetRecordCount())); + SetAssetMap(pParseAssets(&zoneFileStream, GetRecords())); + + return true; +} + +void ZoneFile_COD4_PS3::pParseZoneHeader(QDataStream *aZoneFileStream) { + SetSize(pParseZoneSize(aZoneFileStream)); + pParseZoneUnknownsA(aZoneFileStream); + + SetTagCount(pParseZoneTagCount(aZoneFileStream)); + pParseZoneUnknownsB(aZoneFileStream); + + SetRecordCount(pParseZoneRecordCount(aZoneFileStream)); + + quint32 tagCount = GetTagCount(); + if (tagCount) { + pParseZoneUnknownsC(aZoneFileStream); + SetTags(pParseZoneTags(aZoneFileStream, tagCount)); + } else { + aZoneFileStream->skipRawData(4); + } +} + +quint32 ZoneFile_COD4_PS3::pParseZoneSize(QDataStream *aZoneFileStream) { + quint32 zoneFileSize; + *aZoneFileStream >> zoneFileSize; + if (zoneFileSize <= 0) { + qDebug() << "Tried to open empty zone file!"; + exit(-1); + } + zoneFileSize += 36; + return zoneFileSize; +} + +/* + ParseZoneUnknownsA() + + Parses the 1st section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD4_PS3::pParseZoneUnknownsA(QDataStream *aZoneFileStream) { + // Byte 4-7, 8-11, 12-15: unknown + QByteArray unknown1(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown1.data(), 4); + + QByteArray unknown2(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown2.data(), 4); + + QByteArray unknown3(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown3.data(), 4); + + // Byte 16-19, 20-23: empty/unknown + QByteArray unknown4(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown4.data(), 4); + + QByteArray unknown5(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown5.data(), 4); + + // Byte 24-27: somehow related to the filesize, but smaller value + QByteArray unknown6(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown6.data(), 4); + + // Byte 28-31, 32-35: unknown + QByteArray unknown7(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown7.data(), 4); + + QByteArray unknown8(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown8.data(), 4); +} + +/* + ParseZoneTagCount() + + Parses the number of string tags in the zone index +*/ +quint32 ZoneFile_COD4_PS3::pParseZoneTagCount(QDataStream *aZoneFileStream) { + quint32 tagCount; + *aZoneFileStream >> tagCount; + return tagCount; +} + +/* + ParseZoneRecordCount() + + Parses the number of records in the zone index +*/ +quint32 ZoneFile_COD4_PS3::pParseZoneRecordCount(QDataStream *aZoneFileStream) { + quint32 recordCount; + *aZoneFileStream >> recordCount; + return recordCount; +} + +/* + ParseZoneUnknownsB() + + Parses the 2nd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD4_PS3::pParseZoneUnknownsB(QDataStream *aZoneFileStream) { + // Byte 44-47: Unknown/empty? + QByteArray unknown9(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown9.data(), 4); +} + +/* + pParseZoneUnknownsC() + + Parses the 3rd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD4_PS3::pParseZoneUnknownsC(QDataStream *aZoneFileStream) { + // Byte 40-43: Unknown/empty? + QByteArray unknown10(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown10.data(), 4); + + // Byte 44-47: Unknown/empty? + QByteArray unknown11(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown11.data(), 4); +} + +/* + ParseZoneTags() + + Parses the string tags ate the start of zone file +*/ +QStringList ZoneFile_COD4_PS3::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) { + QStringList tags; + + // Byte 48-51: Repeated separators? ÿÿÿÿ x i + aZoneFileStream->skipRawData(4 * (tagCount - 1)); + + // Parse tags/strings before index + QString zoneTag; + char zoneTagChar; + for (quint32 i = 0; i < tagCount; i++) { + *aZoneFileStream >> zoneTagChar; + while (zoneTagChar != 0) { + zoneTag += zoneTagChar; + *aZoneFileStream >> zoneTagChar; + } + tags << zoneTag; + zoneTag.clear(); + } + return tags; +} + +/* + ParseZoneIndex() + + Parse the binary zone index data and populate table +*/ +QStringList ZoneFile_COD4_PS3::pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) { + QStringList result; + + // Don't parse if no records + if (!recordCount) { return result; } + + if (aZoneFileStream->device()->peek(4).toHex().contains("ffff")) { + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 2); + } + + // Parse index & map found asset types + for (quint32 i = 0; i <= recordCount; i++) { + // Skip record start + QByteArray rawAssetType(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rawAssetType.data(), 4); + result << rawAssetType.toHex(); + + // Skip separator + aZoneFileStream->skipRawData(4); + } + return result; +} + +AssetMap ZoneFile_COD4_PS3::pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) { + AssetMap result; + + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 8); + + for (int i = 0; i < assetOrder.size(); i++) { + const QString typeHex = assetOrder[i]; + const AssetType typeStr = AssetStrToEnum(typeHex); + + if (typeStr == ASSET_LOCAL_STRING) { // localized string asset + result.localStrings << pParseAsset_LocalString(aZoneFileStream); + } else if (typeStr == ASSET_RAW_FILE) { // gsc + auto rawFile = pParseAsset_RawFile(aZoneFileStream); + if (rawFile.length) { + result.rawFiles << rawFile; + } + } else if (typeStr == ASSET_PHYS_PRESET) { // physpreset + pParseAsset_PhysPreset(aZoneFileStream); + } else if (typeStr == ASSET_MODEL) { // xmodel + result.models << pParseAsset_Model(aZoneFileStream); + } else if (typeStr == ASSET_MATERIAL) { // material + pParseAsset_Material(aZoneFileStream); + } else if (typeStr == ASSET_SHADER) { // pixelshader + pParseAsset_Shader(aZoneFileStream); + } else if (typeStr == ASSET_TECH_SET) { // techset include + result.techSets << pParseAsset_TechSet(aZoneFileStream); + } else if (typeStr == ASSET_IMAGE) { // image + result.images << pParseAsset_Image(aZoneFileStream); + } else if (typeStr == ASSET_SOUND) { // loaded_sound + result.sounds << pParseAsset_Sound(aZoneFileStream); + } else if (typeStr == ASSET_COLLISION_MAP) { // col_map_mp + pParseAsset_ColMapMP(aZoneFileStream); + } else if (typeStr == ASSET_MP_MAP) { // game_map_sp + pParseAsset_GameMapSP(aZoneFileStream); + } else if (typeStr == ASSET_SP_MAP) { // game_map_mp + pParseAsset_GameMapMP(aZoneFileStream); + } else if (typeStr == ASSET_LIGHT_DEF) { // lightdef + pParseAsset_LightDef(aZoneFileStream); + } else if (typeStr == ASSET_UI_MAP) { // ui_map + pParseAsset_UIMap(aZoneFileStream); + } else if (typeStr == ASSET_SND_DRIVER_GLOBALS) { // snddriverglobals + pParseAsset_SNDDriverGlobals(aZoneFileStream); + } else if (typeStr == ASSET_AI_TYPE) { // aitype + pParseAsset_AIType(aZoneFileStream); + } else if (typeStr == ASSET_EFFECT) { // aitype + pParseAsset_FX(aZoneFileStream); + } else if (typeStr == ASSET_ANIMATION) { // aitype + result.animations << pParseAsset_Animation(aZoneFileStream); + } else if (typeStr == ASSET_STRING_TABLE) { // string_table + result.stringTables << pParseAsset_StringTable(aZoneFileStream); + } else if (typeStr == ASSET_MENU) { // string_table + result.menuFiles << pParseAsset_MenuFile(aZoneFileStream); + } else if (typeStr == ASSET_WEAPON) { // string_table + pParseAsset_Weapon(aZoneFileStream); + } else if (typeStr == ASSET_D3DBSP) { // string_table + pParseAsset_D3DBSP(aZoneFileStream); + } + } + return result; +} + +LocalString ZoneFile_COD4_PS3::pParseAsset_LocalString(QDataStream *aZoneFileStream) { + LocalString result; + + quint32 stringPtr, aliasPtr; + *aZoneFileStream >> stringPtr >> aliasPtr; + if (stringPtr == 4294967295) { + // Parse local string asset contents + QString localStr; + char localStrChar; + *aZoneFileStream >> localStrChar; + while (localStrChar != 0) { + result.string += localStrChar; + *aZoneFileStream >> localStrChar; + } + } else { + result.string = "String Ptr: " + QString::number(stringPtr); + } + + if (aliasPtr == 4294967295) { + // Parse rawfile name + QString aliasName; + char aliasNameChar; + *aZoneFileStream >> aliasNameChar; + while (aliasNameChar != 0) { + result.alias += aliasNameChar; + *aZoneFileStream >> aliasNameChar; + } + } else { + result.string = "Alias Ptr: " + QString::number(aliasPtr); + } + + return result; +} + +RawFile ZoneFile_COD4_PS3::pParseAsset_RawFile(QDataStream *aZoneFileStream) { + RawFile result; + + // Skip start separator FF FF FF FF (pointer?) + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.length; + + // Skip unknown 4 byte data + aZoneFileStream->skipRawData(4); + + // Parse rawfile path + char scriptPathChar; + *aZoneFileStream >> scriptPathChar; + while (scriptPathChar != 0) { + result.path += scriptPathChar; + *aZoneFileStream >> scriptPathChar; + } + result.path.replace(",", ""); + + const QStringList pathParts = result.path.split('/'); + if (pathParts.size() == 0) { + qDebug() << "Failed to parse ff path! " << result.path; + exit(-1); + } + if (result.path.contains(".bik")) { + qDebug() << "rawFileLength: " << result.length; + QByteArray bikData(result.length, Qt::Uninitialized); + aZoneFileStream->readRawData(bikData.data(), result.length); + + //QFile bikFile(QDir::currentPath() + "/" + rawFilePath.split('/').last()); + //qDebug() << bikFile.fileName(); + //if (!bikFile.open(QIODevice::WriteOnly)) { + // qWarning() << "Failed to open .bik file for writing!"; + // return; + //} + //qDebug() << QString("%1: %2").arg(rawFilePath).arg(bikFile.fileName()); + //bikFile.write(bikData); + } else { + // Parse gsc contents + char rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + while (rawFileContentsChar != 0 && rawFileContentsChar != -1) { + result.contents += rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + } + } + return result; +} + +void ZoneFile_COD4_PS3::pParseAsset_PhysPreset(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Model ZoneFile_COD4_PS3::pParseAsset_Model(QDataStream *aZoneFileStream) { + Model result; + + *aZoneFileStream >> result.namePtr >> result.tagCount >> result.rootTagCount + >> result.surfCount >> result.unknownCount >> result.boneNamePtr + >> result.parentListPtr >> result.quatsPtr >> result.transPtr + >> result.partClassPtr >> result.baseMatPtr + >> result.surfsPtr >> result.materialHandlesPtr; + + // Parse XModelLodInfo + for (int i = 1; i <= 4; i++) { + quint32 intDist; + *aZoneFileStream >> intDist; + + std::memcpy(&result.lodInfo[i].dist, &intDist, sizeof(result.lodInfo[i].dist)); + *aZoneFileStream >> result.lodInfo[i].numsurfs >> result.lodInfo[i].surfIndex; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.lodInfo[i].partBits[0] + >> result.lodInfo[i].partBits[1] + >> result.lodInfo[i].partBits[2] + >> result.lodInfo[i].partBits[3]; + } + + *aZoneFileStream >> result.collSurfsPtr >> result.numCollSurfs >> result.contents >> result.boneInfoPtr; + + quint32 intRadius, intMins[3], intMaxs[3]; + *aZoneFileStream >> intRadius >> intMins[0] >> intMins[1] + >> intMins[2] >> intMaxs[0] >> intMaxs[1] >> intMaxs[2]; + + std::memcpy(&result.radius, &intRadius, sizeof(result.radius)); + + std::memcpy(&result.mins[0], &intMins[0], sizeof(result.mins[0])); + std::memcpy(&result.mins[1], &intMins[1], sizeof(result.mins[1])); + std::memcpy(&result.mins[2], &intMins[2], sizeof(result.mins[2])); + + std::memcpy(&result.maxs[0], &intMaxs[0], sizeof(result.maxs[0])); + std::memcpy(&result.maxs[1], &intMaxs[1], sizeof(result.maxs[2])); + std::memcpy(&result.maxs[2], &intMaxs[2], sizeof(result.maxs[3])); + + *aZoneFileStream >> result.numLods >> result.collLod >> result.streamInfoPtr + >> result.memUsage >> result.flags >> result.physPresetPtr >> result.physGeomsPtr; + + // Parse model name + char modelNameChar; + *aZoneFileStream >> modelNameChar; + while (modelNameChar == 0) { + *aZoneFileStream >> modelNameChar; + } + while (modelNameChar != 0) { + result.modelName += modelNameChar; + *aZoneFileStream >> modelNameChar; + } + return result; +} + +Material ZoneFile_COD4_PS3::pParseAsset_Material(QDataStream *aZoneFileStream) { + aZoneFileStream->skipRawData(27 * 4); + + qint32 materialNamePtr; + *aZoneFileStream >> materialNamePtr; + if (materialNamePtr == -1) { + QString materialName; + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + } + + aZoneFileStream->skipRawData(3 * 4); + + qint32 compressionPtr, compression, unknownSectionPtr; + *aZoneFileStream >> compressionPtr; + if (compressionPtr == -1) { + *aZoneFileStream >> compression; + + *aZoneFileStream >> unknownSectionPtr; + if (unknownSectionPtr == -2) { + aZoneFileStream->skipRawData(6 * 4); + } + } + + qint32 imageNamePtr; + *aZoneFileStream >> imageNamePtr; + if (imageNamePtr == -1) { + QString imageName; + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + imageName += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + } + + QByteArray compressionData(4, Qt::Uninitialized); + QString compressionStr; + if (compressionPtr == -1) { + aZoneFileStream->skipRawData(2 * 4); + aZoneFileStream->readRawData(compressionData.data(), 4); + aZoneFileStream->skipRawData(4); + compressionStr = QString::fromUtf8(compressionData); + aZoneFileStream->skipRawData(4); + } + aZoneFileStream->skipRawData(4); + + // TODO: Fill out this material + return Material(); +} + +Shader ZoneFile_COD4_PS3::pParseAsset_Shader(QDataStream *aZoneFileStream) { + Shader result = Shader(); + + quint8 minorVersion, majorVersion; + *aZoneFileStream >> minorVersion >> majorVersion; + + quint32 magic; + *aZoneFileStream >> magic; + + // Verify .fxc magic + if (magic != 65534 && magic != 65535) { return result; } + + SHADER_TYPE type = SHADER_NONE; + quint16 rawShaderType; + *aZoneFileStream >> rawShaderType; + if (rawShaderType == 65535) { // Pixel shader + type = SHADER_PIXEL; + } else if (rawShaderType == 65534) { // Vertex shader + type = SHADER_VERTEX; + } + Q_UNUSED(type); + + while (true) { + quint32 instructionToken; + *aZoneFileStream >> instructionToken; + + SHADER_OPCODE opCode = (SHADER_OPCODE)(instructionToken & 0xffff); + + int size; + if (opCode == OPCODE_End) { + break; + } else if (opCode == OPCODE_Comment) { + size = (int)((instructionToken >> 16) & 0x7FFF); + } else { + size = (int)((instructionToken >> 24) & 0x0f); + } + Q_UNUSED(size); + } + + + return result; +} + +TechSet ZoneFile_COD4_PS3::pParseAsset_TechSet(QDataStream *aZoneFileStream) { + TechSet result; + + for (int i = 1; i <= 62; i++) { + quint32 ptr; + *aZoneFileStream >> ptr; + + result.pointers << ptr; + } + qDebug() << aZoneFileStream->device()->pos(); + + // Parse techset name + char techSetNameChar; + *aZoneFileStream >> techSetNameChar; + while (techSetNameChar != 0) { + result.name += techSetNameChar; + *aZoneFileStream >> techSetNameChar; + } + result.name.replace(",", ""); + + return result; +} + +Image ZoneFile_COD4_PS3::pParseAsset_Image(QDataStream *aZoneFileStream) { + Image result; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknowna >> result.unknownb + >> result.unknownc >> result.unknownd + >> result.unknowne >> result.unknownf + >> result.unknowng; + + aZoneFileStream->skipRawData(15 * 4); + *aZoneFileStream >> result.unknownh >> result.unknowni; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknownj; + + aZoneFileStream->skipRawData(4); + + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + result.materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + result.materialName.replace(",", ""); + + if (result.unknowna) { + *aZoneFileStream >> result.unknownk; + *aZoneFileStream >> result.unknownl; + *aZoneFileStream >> result.unknownm; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown1; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown2 >> result.unknown3 + >> result.size1 >> result.size2 + >> result.unknown4 >> result.unknown5; + + aZoneFileStream->skipRawData(4); + + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + result.name += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + + *aZoneFileStream >> result.unknown6 >> result.unknown7; + + QByteArray compressionData(8, Qt::Uninitialized); + aZoneFileStream->readRawData(compressionData.data(), 8); + if (compressionData.contains("DXT1")) { + result.compression = COMPRESSION_DXT1; + } else if (compressionData.contains("DXT3")) { + result.compression = COMPRESSION_DXT3; + } else if (compressionData.contains("DXT5")) { + result.compression = COMPRESSION_DXT5; + } else { + result.compression = COMPRESSION_NONE; + } + + *aZoneFileStream >> result.unknown8 >> result.unknown9; + } + + return result; +} + +SoundAsset ZoneFile_COD4_PS3::pParseAsset_Sound(QDataStream *aZoneFileStream) { + SoundAsset result; + + qDebug() << aZoneFileStream->device()->pos(); + + QByteArray rootNamePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rootNamePtr.data(), 4); + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.count; + + if (rootNamePtr.toHex() == "ffffffff") { + // Read in sound file name + char soundNameChar; + *aZoneFileStream >> soundNameChar; + while (soundNameChar != 0) { + result.name += soundNameChar; + *aZoneFileStream >> soundNameChar; + } + } + + int tagCount = 0; + int resultCount = 0; + for (quint32 i = 0; i < result.count; i++) { + aZoneFileStream->skipRawData(12); + + QByteArray tagPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(tagPtr.data(), 4); + + if (tagPtr.toHex() == "ffffffff") { + tagCount++; + } + aZoneFileStream->skipRawData(4); + + QByteArray pathPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pathPtr.data(), 4); + + if (pathPtr.toHex() == "ffffffff") { + resultCount++; + } + + aZoneFileStream->skipRawData(160); + } + + for (int i = 0; i < tagCount; i++) { + // Read in tag? + QString tag; + char tagChar; + *aZoneFileStream >> tagChar; + while (tagChar != 0) { + tag += tagChar; + *aZoneFileStream >> tagChar; + } + } + + for (int i = 0; i < resultCount; i++) { + Sound sound; + + if (aZoneFileStream->device()->peek(12).toHex().contains("ffffffff00000000")) { + aZoneFileStream->skipRawData(12); + } + + aZoneFileStream->skipRawData(8); + + QByteArray aliasPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(aliasPtr.data(), 4); + + QByteArray namePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(namePtr.data(), 4); + + *aZoneFileStream >> sound.dataLength; + + if (aliasPtr.toHex() == "ffffffff") { + // Read in sound alias name + char soundAliasChar; + *aZoneFileStream >> soundAliasChar; + while (soundAliasChar != 0) { + sound.alias += soundAliasChar; + *aZoneFileStream >> soundAliasChar; + } + } + + if (aZoneFileStream->device()->peek(4) == "RIFF") { + sound.path = sound.alias; + sound.alias = ""; + } else if (namePtr.toHex() == "ffffffff") { + // Read in sound file path + char soundPathChar; + *aZoneFileStream >> soundPathChar; + while (soundPathChar != 0) { + sound.path += soundPathChar; + *aZoneFileStream >> soundPathChar; + } + sound.path.replace(",", ""); + } + + if (sound.dataLength) { + QByteArray data(sound.dataLength, Qt::Uninitialized); + aZoneFileStream->readRawData(data.data(), sound.dataLength); + sound.data = data; + } + result.sounds.append(sound); + } + + return result; +} + +void ZoneFile_COD4_PS3::pParseAsset_ColMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD4_PS3::pParseAsset_GameMapSP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD4_PS3::pParseAsset_GameMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD4_PS3::pParseAsset_LightDef(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD4_PS3::pParseAsset_UIMap(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD4_PS3::pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD4_PS3::pParseAsset_AIType(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD4_PS3::pParseAsset_FX(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Animation ZoneFile_COD4_PS3::pParseAsset_Animation(QDataStream *aZoneFileStream) { + Animation result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.dataByteCount + >> result.dataShortCount + >> result.dataIntCount + >> result.randomDataByteCount + >> result.randomDataIntCount + >> result.numframes + >> result.isLooped + >> result.isDelta + >> result.noneRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.normalTranslatedBoneCount + >> result.preciseTranslatedBoneCount + >> result.staticTranslatedBoneCount + >> result.noneTranslatedBoneCount + >> result.totalBoneCount + >> result.otherBoneCount1 + >> result.otherBoneCount2 + >> result.notifyCount + >> result.assetType + >> result.pad + >> result.randomDataShortCount + >> result.indexCount + >> result.frameRate + >> result.frequency + >> result.boneIDsPtr + >> result.dataBytePtr + >> result.dataShortPtr + >> result.dataIntPtr + >> result.randomDataShortPtr + >> result.randomDataBytePtr + >> result.randomDataIntPtr + >> result.longIndiciesPtr + >> result.notificationsPtr + >> result.deltaPartsPtr; + + // Read in x_anim file name + QString xAnimName; + char xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + while (xAnimNameChar != 0) { + result.name += xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + } + + // Parse x_anim index header + QVector sectionLengths; + for (int i = 0; i < result.numframes; i++) { + quint8 sectionlength; + *aZoneFileStream >> sectionlength; + sectionLengths.push_back(sectionlength); + // Skip padding + aZoneFileStream->skipRawData(1); + } + // Skip unknown section + aZoneFileStream->skipRawData(2 * 8); + + return result; +} + +MenuFile ZoneFile_COD4_PS3::pParseAsset_MenuFile(QDataStream *aZoneFileStream) { + //MENU_FILE + MenuFile result; + + aZoneFileStream->skipRawData(4); // Separator + + // Parse menu def count + *aZoneFileStream >> result.menuCount; + + // Clearly misparsed, never have this much + if (result.menuCount > 1000) { + qDebug() << "Failure reported when parsing menu file."; + return result; + } + for (uint i = 0; i < result.menuCount; i++) { + Menu menu; + + aZoneFileStream->skipRawData(4); // Separator + + // Read in x_anim file name + char menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + while (menuFilepathChar != 0) { + menu.filePath += menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + } + aZoneFileStream->skipRawData(4); // Separator + + *aZoneFileStream >> menu.menuNamePtr; + + float menuRectX, menuRectY, menuRectWidth, menuRectHeight; + *aZoneFileStream >> menuRectX >> menuRectY >> menuRectWidth >> menuRectHeight; + menu.rect = QRectF(menuRectX, menuRectY, menuRectWidth, menuRectHeight); + + quint32 hAlignInt, vAlignInt; + *aZoneFileStream >> hAlignInt >> vAlignInt; + menu.hAlign = (MENU_H_ALIGNMENT)hAlignInt; + menu.vAlign = (MENU_V_ALIGNMENT)vAlignInt; + + float rectClientX, rectClientY, rectClientWidth, rectClientHeight; + *aZoneFileStream >> rectClientX >> rectClientY >> rectClientWidth >> rectClientHeight; + menu.clientRect = QRectF(rectClientX, rectClientY, rectClientWidth, rectClientHeight); + + quint32 hClientAlignInt, vClientAlignInt, styleInt, borderInt; + *aZoneFileStream >> hClientAlignInt >> vClientAlignInt >> menu.groupPtr + >> styleInt >> borderInt >> menu.ownerDraw >> menu.ownerDrawFlags + >> menu.borderSize >> menu.staticFlags >> menu.dynamicFlags >> menu.nextTime; + menu.hClientAlign = (MENU_H_ALIGNMENT)hClientAlignInt; + menu.vClientAlign = (MENU_V_ALIGNMENT)vClientAlignInt; + menu.style = (MENU_WINDOW_STYLE)styleInt; + menu.border = (MENU_WINDOW_BORDER)borderInt; + + float foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA, + backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA, + borderColorR, borderColorG, borderColorB, borderColorA, + outlineColorR, outlineColorG, outlineColorB, outlineColorA; + *aZoneFileStream >> foregroundColorR >> foregroundColorG >> foregroundColorB >> foregroundColorA + >> backgroundColorR >> backgroundColorG >> backgroundColorB >> backgroundColorA + >> borderColorR >> borderColorG >> borderColorB >> borderColorA + >> outlineColorR >> outlineColorG >> outlineColorB >> outlineColorA; + + menu.foregroundColor = QColor(foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA); + menu.backgroundColor = QColor(backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA); + menu.borderColor = QColor(borderColorR, borderColorG, borderColorB, borderColorA); + menu.outlineColor = QColor(outlineColorR, outlineColorG, outlineColorB, outlineColorA); + + *aZoneFileStream >> menu.materialPtr >> menu.fontPtr >> menu.fullScreen >> menu.itemCount + >> menu.fontIndex >> menu.cursorItem >> menu.fadeCycle >> menu.fadeClamp + >> menu.fadeAmount >> menu.fadeInAmount >> menu.blurRadius >> menu.onOpenPtr + >> menu.onFocusPtr >> menu.onClosePtr >> menu.onESCPtr >> menu.onKeyPtr + >> menu.visibleExpCount >> menu.expEntryPtr >> menu.allowedBindingPtr + >> menu.soundNamePtr >> menu.imageTrack; + + float focusColorR, focusColorG, focusColorB, focusColorA, + disabledColorR, disabledColorG, disabledColorB, disabledColorA; + *aZoneFileStream >> focusColorR >> focusColorG >> focusColorB >> focusColorA + >> disabledColorR >> disabledColorG >> disabledColorB >> disabledColorA; + menu.focusColor = QColor(focusColorR, focusColorG, focusColorB, focusColorA); + menu.disabledColor = QColor(disabledColorR, disabledColorG, disabledColorB, disabledColorA); + + *aZoneFileStream >> menu.rectXExpCount >> menu.rectXExpPtr >> menu.rectYExpCount >> menu.rectYExpPtr; + + aZoneFileStream->skipRawData(4); // Separator + + char menuDefNameChar; + int menuDefNameLen = 0; + *aZoneFileStream >> menuDefNameChar; + while (menuDefNameChar != 0 && menuDefNameLen < 30) { + menuDefNameLen++; + menu.name += menuDefNameChar; + *aZoneFileStream >> menuDefNameChar; + } + + char defStringChar; + int defStringLen = 0; + *aZoneFileStream >> defStringChar; + while (defStringChar != 0 && defStringLen < 30) { + defStringLen++; + menu.definition += defStringChar; + *aZoneFileStream >> defStringChar; + } + aZoneFileStream->skipRawData(4 * 10); + + *aZoneFileStream >> menu.itemWindowDefNamePtr; + + float itemRectX, itemRectY, itemRectWidth, itemRectHeight; + *aZoneFileStream >> itemRectX >> itemRectY >> itemRectWidth >> itemRectHeight; + menu.itemRect = QRectF(itemRectX, itemRectY, itemRectWidth, itemRectHeight); + + *aZoneFileStream >> menu.itemHAlignment >> menu.itemVAlignment >> menu.itemGroupPtr + >> menu.itemWindowStyle >> menu.itemWindowBorder >> menu.itemOwnerDraw + >> menu.itemOwnerDrawFlags >> menu.itemBorderSize >> menu.itemStaticFlags + >> menu.itemDynamicFlags >> menu.itemNextTime; + + float itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA, + itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA, + itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA, + itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA; + *aZoneFileStream >> itemForegroundColorR >> itemForegroundColorG >> itemForegroundColorB >> itemForegroundColorA + >> itemBackgroundColorR >> itemBackgroundColorG >> itemBackgroundColorB >> itemBackgroundColorA + >> itemBorderColorR >> itemBorderColorG >> itemBorderColorB >> itemBorderColorA + >> itemOutlineColorR >> itemOutlineColorG >> itemOutlineColorB >> itemOutlineColorA; + + menu.itemForegroundColor = QColor(itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA); + menu.itemBackgroundColor = QColor(itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA); + menu.itemBorderColor = QColor(itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA); + menu.itemOutlineColor = QColor(itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA); + + *aZoneFileStream >> menu.itemMaterialPtr; + + float itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight; + *aZoneFileStream >> itemTextRectX >> itemTextRectY >> itemTextRectWidth >> itemTextRectHeight; + menu.itemTextRect = QRectF(itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight); + + quint32 hItemTextAlignInt, vItemTextAlignInt, itemType, fontTypeInt, textStyleInt; + *aZoneFileStream >> hItemTextAlignInt >> vItemTextAlignInt >> itemType >> menu.dataType + >> menu.alignment >> fontTypeInt >> menu.textAlignMode >> menu.textalignx >> menu.textaligny + >> menu.textscale >> textStyleInt >> menu.gameMsgWindowIndex >> menu.gameMsgWindowMode + >> menu.testPtr >> menu.textSavegameInfo >> menu.parentPtr; + menu.itemText_hAlign = (MENU_H_ALIGNMENT)hItemTextAlignInt; + menu.itemText_vAlign = (MENU_V_ALIGNMENT)vItemTextAlignInt; + menu.itemType = (MENU_ITEM_TYPE)itemType; + menu.fontEnum = (MENU_FONT_TYPE)fontTypeInt; + menu.textStyle = (MENU_ITEM_TEXTSTYLE)textStyleInt; + + *aZoneFileStream >> menu.mouseEnterText >> menu.mouseExitText >> menu.mouseEnter >> menu.mouseExit + >> menu.action >> menu.onAccept >> menu.onFocus >> menu.leaveFocus >> menu.dvar >> menu.dvarTest + >> menu.keyHandlerPtr >> menu.enableDvarPtr >> menu.dvarFlags >> menu.focusSoundPtr + >> menu.special >> menu.cursorPos; + + // itemDefData_t typeData; + + // listBoxDef_s *listBox; + + *aZoneFileStream >> menu.startPos >> menu.endPos >> menu.drawPadding; + + *aZoneFileStream >> menu.elementWidth >> menu.elementHeight; + + *aZoneFileStream >> menu.elementStyle >> menu.numColumns; + + //columnInfo_s columnInfo[16]; + + *aZoneFileStream >> menu.doubleClickPtr; + + + *aZoneFileStream >> menu.notselectable >> menu.noScrollBars >> menu.usePaging; + + float itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA, + itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA, + itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA; + *aZoneFileStream >> itemSelectBorderColorR >> itemSelectBorderColorG >> itemSelectBorderColorB >> itemSelectBorderColorA + >> itemDisableColorR >> itemDisableColorG >> itemDisableColorB >> itemDisableColorA + >> itemFocusColorR >> itemFocusColorG >> itemFocusColorB >> itemFocusColorA; + menu.itemSelectBorderColor = QColor(itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA); + menu.itemDisableColor = QColor(itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA); + menu.itemFocusColor = QColor(itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA); + + *aZoneFileStream >> menu.selectIconPtr >> menu.backgroundItemListboxPtr >> menu.highlightTexturePtr; + + // editFieldDef_s *editField; + + *aZoneFileStream >> menu.minVal >> menu.maxVal >> menu.defVal >> menu.range >> menu.maxChars + >> menu.maxCharsGotoNext >> menu.maxPaintChars >> menu.paintOffset; + + // multiDef_s *multi; + + for (int i = 0; i < 32; i++) { + quint32 dvarList; + *aZoneFileStream >> dvarList; + menu.dvarListPtrs.push_back(dvarList); + } + + for (int i = 0; i < 32; i++) { + quint32 dvarStr; + *aZoneFileStream >> dvarStr; + menu.dvarStrPtrs.push_back(dvarStr); + } + + for (int i = 0; i < 32; i++) { + float dvarValue; + *aZoneFileStream >> dvarValue; + menu.dvarValues.push_back(dvarValue); + } + + *aZoneFileStream >> menu.count >> menu.strDef >> menu.enumDvarNamePtr; + aZoneFileStream->skipRawData(4); + //>> menu.dataPtr + *aZoneFileStream >> menu.itemImageTrack; + + qDebug() << aZoneFileStream->device()->pos(); + + //statement_s visibleExp; + //statement_s textExp; + //statement_s materialExp; + //statement_s rectXExp; + //statement_s rectYExp; + //statement_s rectWExp; + //statement_s rectHExp; + //statement_s foreColorAExp; + result.menuDefs << menu; + } + return result; +} + +void ZoneFile_COD4_PS3::pParseAsset_Weapon(QDataStream *aZoneFileStream) { + //WEAPON_FILE + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD4_PS3::pParseAsset_D3DBSP(QDataStream *aZoneFileStream) { + //D3DBSP_DUMP + Q_UNUSED(aZoneFileStream); +} + +StringTable ZoneFile_COD4_PS3::pParseAsset_StringTable(QDataStream *aZoneFileStream) { + StringTable result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.columnCount + >> result.rowCount; + + // Todo fix this + result.columnCount = 0; + result.rowCount = 0; + + aZoneFileStream->skipRawData(4); + + QString stringTableName; + char stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + while (stringTableNameChar != 0) { + result.name += stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + } + + for (quint32 i = 0; i < result.rowCount; i++) { + QByteArray pointerData(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pointerData.data(), 4); + result.tablePointers.push_back(pointerData.toHex()); + + aZoneFileStream->skipRawData(4); + } + + for (const QString &pointerAddr : result.tablePointers) { + QString leadingContent = ""; + if (pointerAddr == "FFFFFFFF") { + char leadingContentChar; + *aZoneFileStream >> leadingContentChar; + while (leadingContentChar != 0) { + leadingContent += leadingContentChar; + *aZoneFileStream >> leadingContentChar; + } + } else { + leadingContent = pointerAddr; + } + + QString content; + char contentChar; + *aZoneFileStream >> contentChar; + while (contentChar != 0) { + content += contentChar; + *aZoneFileStream >> contentChar; + } + result.content[leadingContent] = content; + } + return result; +} + +AssetType ZoneFile_COD4_PS3::AssetStrToEnum(const QString aAssetType) { + const QString cleanedType = aAssetType.toUpper(); + if (cleanedType == "17000000") { // localized string PARTIALLY VERIFIED + return ASSET_RAW_FILE; + } else if (cleanedType == "20000000") { // raw_file PARTIALLY VERIFIED + return ASSET_SCRIPT_PARSE_TREE; + } else if (cleanedType == "1A000000") { // fx PARTIALLY VERIFIED + return ASSET_EFFECT; + } else if (cleanedType == "09000000") { // loaded_sound PARTIALLY VERIFIED + return ASSET_SOUND; + } else if (cleanedType == "04000000") { // x_anim PARTIALLY VERIFIED + return ASSET_ANIMATION; + } else if (cleanedType == "0C000000") { // collision_map PARTIALLY VERIFIED + return ASSET_COLLISION_MAP; + } else if (cleanedType == "21000000") { // string_table PARTIALLY VERIFIED + return ASSET_STRING_TABLE; + } else if (cleanedType == "15000000") { // menu_file PARTIALLY VERIFIED + return ASSET_MENU; + } else if (cleanedType == "07000000") { // tech set PARTIALLY VERIFIED + return ASSET_TECH_SET; + } else if (cleanedType == "18000000") { // weapon PARTIALLY VERIFIED + return ASSET_WEAPON; + } else if (cleanedType == "11000000") { // gfx map PARTIALLY VERIFIED + return ASSET_GFX_MAP; + } else if (cleanedType == "12000000") { // light_def PARTIALLY VERIFIED + return ASSET_LIGHT_DEF; + } else if (cleanedType == "14000000") { // font PARTIALLY VERIFIED + return ASSET_FONT; + } else if (cleanedType == "05000000") { // xmodel PARTIALLY VERIFIED + return ASSET_MODEL; + } else if (cleanedType == "0D000000") { // d3dbsp PARTIALLY VERIFIED + return ASSET_D3DBSP; + } else if (cleanedType == "06000000") { // image PARTIALLY VERIFIED + return ASSET_IMAGE; + } else if (cleanedType == "0E000000") { // game map sp PARTIALLY VERIFIED + return ASSET_GAME_MAP_SP; + } else if (cleanedType == "0B000000") { // col map sp PARTIALLY VERIFIED + return ASSET_COL_MAP_SP; + } else if (cleanedType == "01000000") { // physics preset PARTIALLY VERIFIED + return ASSET_PHYS_PRESET; + } else if (cleanedType == "03000000") { // destructible def PARTIALLY VERIFIED + return ASSET_DESTRUCTIBLE; + } + return ASSET_NONE; +} + +QByteArray ZoneFile_COD4_PS3::GetBinaryData() { + QByteArray result; + + return result; +} diff --git a/libs/zonefile/PS3/zonefile_cod4_ps3.h b/libs/zonefile/PS3/zonefile_cod4_ps3.h new file mode 100644 index 0000000..90033c2 --- /dev/null +++ b/libs/zonefile/PS3/zonefile_cod4_ps3.h @@ -0,0 +1,54 @@ +#ifndef ZONEFILE_COD4_PS3_H +#define ZONEFILE_COD4_PS3_H + +#include + +#include "zonefile.h" + +class ZoneFile_COD4_PS3 : public ZoneFile +{ +public: + ZoneFile_COD4_PS3(); + ~ZoneFile_COD4_PS3(); + + bool Load(const QByteArray aFileData) override; + AssetType AssetStrToEnum(const QString aAssetType) override; + + QByteArray GetBinaryData() override; + +private: + void pParseZoneHeader(QDataStream *aZoneFileStream) override; + quint32 pParseZoneSize(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsA(QDataStream *aZoneFileStream) override; + quint32 pParseZoneTagCount(QDataStream *aZoneFileStream) override; + quint32 pParseZoneRecordCount(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsB(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsC(QDataStream *aZoneFileStream) override; + QStringList pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) override; + QStringList pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) override; + AssetMap pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) override; + LocalString pParseAsset_LocalString(QDataStream *aZoneFileStream) override; + RawFile pParseAsset_RawFile(QDataStream *aZoneFileStream) override; + void pParseAsset_PhysPreset(QDataStream *aZoneFileStream) override; + Model pParseAsset_Model(QDataStream *aZoneFileStream) override; + Material pParseAsset_Material(QDataStream *aZoneFileStream) override; + Shader pParseAsset_Shader(QDataStream *aZoneFileStream) override; + TechSet pParseAsset_TechSet(QDataStream *aZoneFileStream) override; + Image pParseAsset_Image(QDataStream *aZoneFileStream) override; + SoundAsset pParseAsset_Sound(QDataStream *aZoneFileStream) override; + void pParseAsset_ColMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapSP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_LightDef(QDataStream *aZoneFileStream) override; + void pParseAsset_UIMap(QDataStream *aZoneFileStream) override; + void pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) override; + void pParseAsset_AIType(QDataStream *aZoneFileStream) override; + void pParseAsset_FX(QDataStream *aZoneFileStream) override; + Animation pParseAsset_Animation(QDataStream *aZoneFileStream) override; + MenuFile pParseAsset_MenuFile(QDataStream *aZoneFileStream) override; + void pParseAsset_Weapon(QDataStream *aZoneFileStream) override; + void pParseAsset_D3DBSP(QDataStream *aZoneFileStream) override; + StringTable pParseAsset_StringTable(QDataStream *aZoneFileStream) override; +}; + +#endif // ZONEFILE_COD4_PS3_H diff --git a/libs/zonefile/PS3/zonefile_cod5_ps3.cpp b/libs/zonefile/PS3/zonefile_cod5_ps3.cpp new file mode 100644 index 0000000..3eb2015 --- /dev/null +++ b/libs/zonefile/PS3/zonefile_cod5_ps3.cpp @@ -0,0 +1,1139 @@ +#include "zonefile_cod5_ps3.h" + +#include +#include +#include + +ZoneFile_COD5_PS3::ZoneFile_COD5_PS3() + : ZoneFile() { + +} + +ZoneFile_COD5_PS3::~ZoneFile_COD5_PS3() { + +} + +bool ZoneFile_COD5_PS3::Load(const QByteArray aFileData) { + // Open zone file as little endian stream + QDataStream zoneFileStream(aFileData); + zoneFileStream.setByteOrder(QDataStream::BigEndian); + + // Parse data from zone file header + pParseZoneHeader(&zoneFileStream); + SetRecords(pParseZoneIndex(&zoneFileStream, GetRecordCount())); + SetAssetMap(pParseAssets(&zoneFileStream, GetRecords())); + + return true; +} + +void ZoneFile_COD5_PS3::pParseZoneHeader(QDataStream *aZoneFileStream) { + SetSize(pParseZoneSize(aZoneFileStream)); + pParseZoneUnknownsA(aZoneFileStream); + + SetTagCount(pParseZoneTagCount(aZoneFileStream)); + pParseZoneUnknownsB(aZoneFileStream); + + SetRecordCount(pParseZoneRecordCount(aZoneFileStream)); + + quint32 tagCount = GetTagCount(); + if (tagCount) { + pParseZoneUnknownsC(aZoneFileStream); + SetTags(pParseZoneTags(aZoneFileStream, tagCount)); + } else { + aZoneFileStream->skipRawData(4); + } +} + +quint32 ZoneFile_COD5_PS3::pParseZoneSize(QDataStream *aZoneFileStream) { + quint32 zoneFileSize; + *aZoneFileStream >> zoneFileSize; + if (zoneFileSize <= 0) { + qDebug() << "Tried to open empty zone file!"; + exit(-1); + } + zoneFileSize += 36; + return zoneFileSize; +} + +/* + ParseZoneUnknownsA() + + Parses the 1st section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD5_PS3::pParseZoneUnknownsA(QDataStream *aZoneFileStream) { + // Byte 4-7, 8-11, 12-15: unknown + QByteArray unknown1(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown1.data(), 4); + + QByteArray unknown2(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown2.data(), 4); + + QByteArray unknown3(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown3.data(), 4); + + // Byte 16-19, 20-23: empty/unknown + QByteArray unknown4(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown4.data(), 4); + + QByteArray unknown5(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown5.data(), 4); + + // Byte 24-27: somehow related to the filesize, but smaller value + QByteArray unknown6(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown6.data(), 4); + + // Byte 28-31, 32-35: unknown + QByteArray unknown7(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown7.data(), 4); + + QByteArray unknown8(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown8.data(), 4); +} + +/* + ParseZoneTagCount() + + Parses the number of string tags in the zone index +*/ +quint32 ZoneFile_COD5_PS3::pParseZoneTagCount(QDataStream *aZoneFileStream) { + quint32 tagCount; + *aZoneFileStream >> tagCount; + return tagCount; +} + +/* + ParseZoneRecordCount() + + Parses the number of records in the zone index +*/ +quint32 ZoneFile_COD5_PS3::pParseZoneRecordCount(QDataStream *aZoneFileStream) { + quint32 recordCount; + *aZoneFileStream >> recordCount; + return recordCount; +} + +/* + ParseZoneUnknownsB() + + Parses the 2nd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD5_PS3::pParseZoneUnknownsB(QDataStream *aZoneFileStream) { + // Byte 44-47: Unknown/empty? + QByteArray unknown9(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown9.data(), 4); +} + +/* + pParseZoneUnknownsC() + + Parses the 3rd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD5_PS3::pParseZoneUnknownsC(QDataStream *aZoneFileStream) { + // Byte 40-43: Unknown/empty? + QByteArray unknown10(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown10.data(), 4); + + // Byte 44-47: Unknown/empty? + QByteArray unknown11(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown11.data(), 4); +} + +/* + ParseZoneTags() + + Parses the string tags ate the start of zone file +*/ +QStringList ZoneFile_COD5_PS3::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) { + QStringList tags; + + // Byte 48-51: Repeated separators? ÿÿÿÿ x i + aZoneFileStream->skipRawData(4 * (tagCount - 1)); + + // Parse tags/strings before index + QString zoneTag; + char zoneTagChar; + for (quint32 i = 0; i < tagCount; i++) { + *aZoneFileStream >> zoneTagChar; + while (zoneTagChar != 0) { + zoneTag += zoneTagChar; + *aZoneFileStream >> zoneTagChar; + } + tags << zoneTag; + zoneTag.clear(); + } + return tags; +} + +/* + ParseZoneIndex() + + Parse the binary zone index data and populate table +*/ +QStringList ZoneFile_COD5_PS3::pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) { + QStringList result; + + // Don't parse if no records + if (!recordCount) { return result; } + + if (aZoneFileStream->device()->peek(4).toHex().contains("ffff")) { + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 2); + } + + // Parse index & map found asset types + for (quint32 i = 0; i <= recordCount; i++) { + // Skip record start + QByteArray rawAssetType(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rawAssetType.data(), 4); + result << rawAssetType.toHex(); + + // Skip separator + aZoneFileStream->skipRawData(4); + } + return result; +} + +AssetMap ZoneFile_COD5_PS3::pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) { + AssetMap result; + + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 8); + + for (int i = 0; i < assetOrder.size(); i++) { + const QString typeHex = assetOrder[i]; + const AssetType typeStr = AssetStrToEnum(typeHex); + + if (typeStr == ASSET_LOCAL_STRING) { // localized string asset + result.localStrings << pParseAsset_LocalString(aZoneFileStream); + } else if (typeStr == ASSET_RAW_FILE) { // gsc + auto rawFile = pParseAsset_RawFile(aZoneFileStream); + if (rawFile.length) { + result.rawFiles << rawFile; + } + } else if (typeStr == ASSET_PHYS_PRESET) { // physpreset + pParseAsset_PhysPreset(aZoneFileStream); + } else if (typeStr == ASSET_MODEL) { // xmodel + result.models << pParseAsset_Model(aZoneFileStream); + } else if (typeStr == ASSET_MATERIAL) { // material + pParseAsset_Material(aZoneFileStream); + } else if (typeStr == ASSET_SHADER) { // pixelshader + pParseAsset_Shader(aZoneFileStream); + } else if (typeStr == ASSET_TECH_SET) { // techset include + result.techSets << pParseAsset_TechSet(aZoneFileStream); + } else if (typeStr == ASSET_IMAGE) { // image + result.images << pParseAsset_Image(aZoneFileStream); + } else if (typeStr == ASSET_SOUND) { // loaded_sound + result.sounds << pParseAsset_Sound(aZoneFileStream); + } else if (typeStr == ASSET_COLLISION_MAP) { // col_map_mp + pParseAsset_ColMapMP(aZoneFileStream); + } else if (typeStr == ASSET_MP_MAP) { // game_map_sp + pParseAsset_GameMapSP(aZoneFileStream); + } else if (typeStr == ASSET_SP_MAP) { // game_map_mp + pParseAsset_GameMapMP(aZoneFileStream); + } else if (typeStr == ASSET_LIGHT_DEF) { // lightdef + pParseAsset_LightDef(aZoneFileStream); + } else if (typeStr == ASSET_UI_MAP) { // ui_map + pParseAsset_UIMap(aZoneFileStream); + } else if (typeStr == ASSET_SND_DRIVER_GLOBALS) { // snddriverglobals + pParseAsset_SNDDriverGlobals(aZoneFileStream); + } else if (typeStr == ASSET_AI_TYPE) { // aitype + pParseAsset_AIType(aZoneFileStream); + } else if (typeStr == ASSET_EFFECT) { // aitype + pParseAsset_FX(aZoneFileStream); + } else if (typeStr == ASSET_ANIMATION) { // aitype + result.animations << pParseAsset_Animation(aZoneFileStream); + } else if (typeStr == ASSET_STRING_TABLE) { // string_table + result.stringTables << pParseAsset_StringTable(aZoneFileStream); + } else if (typeStr == ASSET_MENU) { // string_table + result.menuFiles << pParseAsset_MenuFile(aZoneFileStream); + } else if (typeStr == ASSET_WEAPON) { // string_table + pParseAsset_Weapon(aZoneFileStream); + } else if (typeStr == ASSET_D3DBSP) { // string_table + pParseAsset_D3DBSP(aZoneFileStream); + } + } + return result; +} + +LocalString ZoneFile_COD5_PS3::pParseAsset_LocalString(QDataStream *aZoneFileStream) { + LocalString result; + + quint32 stringPtr, aliasPtr; + *aZoneFileStream >> stringPtr >> aliasPtr; + if (stringPtr == 4294967295) { + // Parse local string asset contents + QString localStr; + char localStrChar; + *aZoneFileStream >> localStrChar; + while (localStrChar != 0) { + result.string += localStrChar; + *aZoneFileStream >> localStrChar; + } + } else { + result.string = "String Ptr: " + QString::number(stringPtr); + } + + if (aliasPtr == 4294967295) { + // Parse rawfile name + QString aliasName; + char aliasNameChar; + *aZoneFileStream >> aliasNameChar; + while (aliasNameChar != 0) { + result.alias += aliasNameChar; + *aZoneFileStream >> aliasNameChar; + } + } else { + result.string = "Alias Ptr: " + QString::number(aliasPtr); + } + + return result; +} + +RawFile ZoneFile_COD5_PS3::pParseAsset_RawFile(QDataStream *aZoneFileStream) { + RawFile result; + + // Skip start separator FF FF FF FF (pointer?) + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.length; + + // Skip unknown 4 byte data + aZoneFileStream->skipRawData(4); + + // Parse rawfile path + char scriptPathChar; + *aZoneFileStream >> scriptPathChar; + while (scriptPathChar != 0) { + result.path += scriptPathChar; + *aZoneFileStream >> scriptPathChar; + } + result.path.replace(",", ""); + + const QStringList pathParts = result.path.split('/'); + if (pathParts.size() == 0) { + qDebug() << "Failed to parse ff path! " << result.path; + exit(-1); + } + if (result.path.contains(".bik")) { + qDebug() << "rawFileLength: " << result.length; + QByteArray bikData(result.length, Qt::Uninitialized); + aZoneFileStream->readRawData(bikData.data(), result.length); + + //QFile bikFile(QDir::currentPath() + "/" + rawFilePath.split('/').last()); + //qDebug() << bikFile.fileName(); + //if (!bikFile.open(QIODevice::WriteOnly)) { + // qWarning() << "Failed to open .bik file for writing!"; + // return; + //} + //qDebug() << QString("%1: %2").arg(rawFilePath).arg(bikFile.fileName()); + //bikFile.write(bikData); + } else { + // Parse gsc contents + char rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + while (rawFileContentsChar != 0 && rawFileContentsChar != -1) { + result.contents += rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + } + } + return result; +} + +void ZoneFile_COD5_PS3::pParseAsset_PhysPreset(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Model ZoneFile_COD5_PS3::pParseAsset_Model(QDataStream *aZoneFileStream) { + Model result; + + *aZoneFileStream >> result.namePtr >> result.tagCount >> result.rootTagCount + >> result.surfCount >> result.unknownCount >> result.boneNamePtr + >> result.parentListPtr >> result.quatsPtr >> result.transPtr + >> result.partClassPtr >> result.baseMatPtr + >> result.surfsPtr >> result.materialHandlesPtr; + + // Parse XModelLodInfo + for (int i = 1; i <= 4; i++) { + quint32 intDist; + *aZoneFileStream >> intDist; + + std::memcpy(&result.lodInfo[i].dist, &intDist, sizeof(result.lodInfo[i].dist)); + *aZoneFileStream >> result.lodInfo[i].numsurfs >> result.lodInfo[i].surfIndex; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.lodInfo[i].partBits[0] + >> result.lodInfo[i].partBits[1] + >> result.lodInfo[i].partBits[2] + >> result.lodInfo[i].partBits[3]; + } + + *aZoneFileStream >> result.collSurfsPtr >> result.numCollSurfs >> result.contents >> result.boneInfoPtr; + + quint32 intRadius, intMins[3], intMaxs[3]; + *aZoneFileStream >> intRadius >> intMins[0] >> intMins[1] + >> intMins[2] >> intMaxs[0] >> intMaxs[1] >> intMaxs[2]; + + std::memcpy(&result.radius, &intRadius, sizeof(result.radius)); + + std::memcpy(&result.mins[0], &intMins[0], sizeof(result.mins[0])); + std::memcpy(&result.mins[1], &intMins[1], sizeof(result.mins[1])); + std::memcpy(&result.mins[2], &intMins[2], sizeof(result.mins[2])); + + std::memcpy(&result.maxs[0], &intMaxs[0], sizeof(result.maxs[0])); + std::memcpy(&result.maxs[1], &intMaxs[1], sizeof(result.maxs[2])); + std::memcpy(&result.maxs[2], &intMaxs[2], sizeof(result.maxs[3])); + + *aZoneFileStream >> result.numLods >> result.collLod >> result.streamInfoPtr + >> result.memUsage >> result.flags >> result.physPresetPtr >> result.physGeomsPtr; + + // Parse model name + char modelNameChar; + *aZoneFileStream >> modelNameChar; + while (modelNameChar == 0) { + *aZoneFileStream >> modelNameChar; + } + while (modelNameChar != 0) { + result.modelName += modelNameChar; + *aZoneFileStream >> modelNameChar; + } + return result; +} + +Material ZoneFile_COD5_PS3::pParseAsset_Material(QDataStream *aZoneFileStream) { + aZoneFileStream->skipRawData(27 * 4); + + qint32 materialNamePtr; + *aZoneFileStream >> materialNamePtr; + if (materialNamePtr == -1) { + QString materialName; + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + } + + aZoneFileStream->skipRawData(3 * 4); + + qint32 compressionPtr, compression, unknownSectionPtr; + *aZoneFileStream >> compressionPtr; + if (compressionPtr == -1) { + *aZoneFileStream >> compression; + + *aZoneFileStream >> unknownSectionPtr; + if (unknownSectionPtr == -2) { + aZoneFileStream->skipRawData(6 * 4); + } + } + + qint32 imageNamePtr; + *aZoneFileStream >> imageNamePtr; + if (imageNamePtr == -1) { + QString imageName; + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + imageName += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + } + + QByteArray compressionData(4, Qt::Uninitialized); + QString compressionStr; + if (compressionPtr == -1) { + aZoneFileStream->skipRawData(2 * 4); + aZoneFileStream->readRawData(compressionData.data(), 4); + aZoneFileStream->skipRawData(4); + compressionStr = QString::fromUtf8(compressionData); + aZoneFileStream->skipRawData(4); + } + aZoneFileStream->skipRawData(4); + + // TODO: Fill out this material + return Material(); +} + +Shader ZoneFile_COD5_PS3::pParseAsset_Shader(QDataStream *aZoneFileStream) { + Shader result = Shader(); + + quint8 minorVersion, majorVersion; + *aZoneFileStream >> minorVersion >> majorVersion; + + quint32 magic; + *aZoneFileStream >> magic; + + // Verify .fxc magic + if (magic != 65534 && magic != 65535) { return result; } + + SHADER_TYPE type = SHADER_NONE; + quint16 rawShaderType; + *aZoneFileStream >> rawShaderType; + if (rawShaderType == 65535) { // Pixel shader + type = SHADER_PIXEL; + } else if (rawShaderType == 65534) { // Vertex shader + type = SHADER_VERTEX; + } + Q_UNUSED(type); + + while (true) { + quint32 instructionToken; + *aZoneFileStream >> instructionToken; + + SHADER_OPCODE opCode = (SHADER_OPCODE)(instructionToken & 0xffff); + + int size; + if (opCode == OPCODE_End) { + break; + } else if (opCode == OPCODE_Comment) { + size = (int)((instructionToken >> 16) & 0x7FFF); + } else { + size = (int)((instructionToken >> 24) & 0x0f); + } + Q_UNUSED(size); + } + + + return result; +} + +TechSet ZoneFile_COD5_PS3::pParseAsset_TechSet(QDataStream *aZoneFileStream) { + TechSet result; + + for (int i = 1; i <= 62; i++) { + quint32 ptr; + *aZoneFileStream >> ptr; + + result.pointers << ptr; + } + qDebug() << aZoneFileStream->device()->pos(); + + // Parse techset name + char techSetNameChar; + *aZoneFileStream >> techSetNameChar; + while (techSetNameChar != 0) { + result.name += techSetNameChar; + *aZoneFileStream >> techSetNameChar; + } + result.name.replace(",", ""); + + return result; +} + +Image ZoneFile_COD5_PS3::pParseAsset_Image(QDataStream *aZoneFileStream) { + Image result; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknowna >> result.unknownb + >> result.unknownc >> result.unknownd + >> result.unknowne >> result.unknownf + >> result.unknowng; + + aZoneFileStream->skipRawData(15 * 4); + *aZoneFileStream >> result.unknownh >> result.unknowni; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknownj; + + aZoneFileStream->skipRawData(4); + + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + result.materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + result.materialName.replace(",", ""); + + if (result.unknowna) { + *aZoneFileStream >> result.unknownk; + *aZoneFileStream >> result.unknownl; + *aZoneFileStream >> result.unknownm; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown1; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown2 >> result.unknown3 + >> result.size1 >> result.size2 + >> result.unknown4 >> result.unknown5; + + aZoneFileStream->skipRawData(4); + + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + result.name += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + + *aZoneFileStream >> result.unknown6 >> result.unknown7; + + QByteArray compressionData(8, Qt::Uninitialized); + aZoneFileStream->readRawData(compressionData.data(), 8); + if (compressionData.contains("DXT1")) { + result.compression = COMPRESSION_DXT1; + } else if (compressionData.contains("DXT3")) { + result.compression = COMPRESSION_DXT3; + } else if (compressionData.contains("DXT5")) { + result.compression = COMPRESSION_DXT5; + } else { + result.compression = COMPRESSION_NONE; + } + + *aZoneFileStream >> result.unknown8 >> result.unknown9; + } + + return result; +} + +SoundAsset ZoneFile_COD5_PS3::pParseAsset_Sound(QDataStream *aZoneFileStream) { + SoundAsset result; + + qDebug() << aZoneFileStream->device()->pos(); + + QByteArray rootNamePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rootNamePtr.data(), 4); + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.count; + + if (rootNamePtr.toHex() == "ffffffff") { + // Read in sound file name + char soundNameChar; + *aZoneFileStream >> soundNameChar; + while (soundNameChar != 0) { + result.name += soundNameChar; + *aZoneFileStream >> soundNameChar; + } + } + + int tagCount = 0; + int resultCount = 0; + for (quint32 i = 0; i < result.count; i++) { + aZoneFileStream->skipRawData(12); + + QByteArray tagPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(tagPtr.data(), 4); + + if (tagPtr.toHex() == "ffffffff") { + tagCount++; + } + aZoneFileStream->skipRawData(4); + + QByteArray pathPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pathPtr.data(), 4); + + if (pathPtr.toHex() == "ffffffff") { + resultCount++; + } + + aZoneFileStream->skipRawData(160); + } + + for (int i = 0; i < tagCount; i++) { + // Read in tag? + QString tag; + char tagChar; + *aZoneFileStream >> tagChar; + while (tagChar != 0) { + tag += tagChar; + *aZoneFileStream >> tagChar; + } + } + + for (int i = 0; i < resultCount; i++) { + Sound sound; + + if (aZoneFileStream->device()->peek(12).toHex().contains("ffffffff00000000")) { + aZoneFileStream->skipRawData(12); + } + + aZoneFileStream->skipRawData(8); + + QByteArray aliasPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(aliasPtr.data(), 4); + + QByteArray namePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(namePtr.data(), 4); + + *aZoneFileStream >> sound.dataLength; + + if (aliasPtr.toHex() == "ffffffff") { + // Read in sound alias name + char soundAliasChar; + *aZoneFileStream >> soundAliasChar; + while (soundAliasChar != 0) { + sound.alias += soundAliasChar; + *aZoneFileStream >> soundAliasChar; + } + } + + if (aZoneFileStream->device()->peek(4) == "RIFF") { + sound.path = sound.alias; + sound.alias = ""; + } else if (namePtr.toHex() == "ffffffff") { + // Read in sound file path + char soundPathChar; + *aZoneFileStream >> soundPathChar; + while (soundPathChar != 0) { + sound.path += soundPathChar; + *aZoneFileStream >> soundPathChar; + } + sound.path.replace(",", ""); + } + + if (sound.dataLength) { + QByteArray data(sound.dataLength, Qt::Uninitialized); + aZoneFileStream->readRawData(data.data(), sound.dataLength); + sound.data = data; + } + result.sounds.append(sound); + } + + return result; +} + +void ZoneFile_COD5_PS3::pParseAsset_ColMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD5_PS3::pParseAsset_GameMapSP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD5_PS3::pParseAsset_GameMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD5_PS3::pParseAsset_LightDef(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD5_PS3::pParseAsset_UIMap(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD5_PS3::pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD5_PS3::pParseAsset_AIType(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD5_PS3::pParseAsset_FX(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Animation ZoneFile_COD5_PS3::pParseAsset_Animation(QDataStream *aZoneFileStream) { + Animation result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.dataByteCount + >> result.dataShortCount + >> result.dataIntCount + >> result.randomDataByteCount + >> result.randomDataIntCount + >> result.numframes + >> result.isLooped + >> result.isDelta + >> result.noneRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.normalTranslatedBoneCount + >> result.preciseTranslatedBoneCount + >> result.staticTranslatedBoneCount + >> result.noneTranslatedBoneCount + >> result.totalBoneCount + >> result.otherBoneCount1 + >> result.otherBoneCount2 + >> result.notifyCount + >> result.assetType + >> result.pad + >> result.randomDataShortCount + >> result.indexCount + >> result.frameRate + >> result.frequency + >> result.boneIDsPtr + >> result.dataBytePtr + >> result.dataShortPtr + >> result.dataIntPtr + >> result.randomDataShortPtr + >> result.randomDataBytePtr + >> result.randomDataIntPtr + >> result.longIndiciesPtr + >> result.notificationsPtr + >> result.deltaPartsPtr; + + // Read in x_anim file name + QString xAnimName; + char xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + while (xAnimNameChar != 0) { + result.name += xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + } + + // Parse x_anim index header + QVector sectionLengths; + for (int i = 0; i < result.numframes; i++) { + quint8 sectionlength; + *aZoneFileStream >> sectionlength; + sectionLengths.push_back(sectionlength); + // Skip padding + aZoneFileStream->skipRawData(1); + } + // Skip unknown section + aZoneFileStream->skipRawData(2 * 8); + + return result; +} + +MenuFile ZoneFile_COD5_PS3::pParseAsset_MenuFile(QDataStream *aZoneFileStream) { + //MENU_FILE + MenuFile result; + + aZoneFileStream->skipRawData(4); // Separator + + // Parse menu def count + *aZoneFileStream >> result.menuCount; + + // Clearly misparsed, never have this much + if (result.menuCount > 1000) { + qDebug() << "Failure reported when parsing menu file."; + return result; + } + for (uint i = 0; i < result.menuCount; i++) { + Menu menu; + + aZoneFileStream->skipRawData(4); // Separator + + // Read in x_anim file name + char menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + while (menuFilepathChar != 0) { + menu.filePath += menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + } + aZoneFileStream->skipRawData(4); // Separator + + *aZoneFileStream >> menu.menuNamePtr; + + float menuRectX, menuRectY, menuRectWidth, menuRectHeight; + *aZoneFileStream >> menuRectX >> menuRectY >> menuRectWidth >> menuRectHeight; + menu.rect = QRectF(menuRectX, menuRectY, menuRectWidth, menuRectHeight); + + quint32 hAlignInt, vAlignInt; + *aZoneFileStream >> hAlignInt >> vAlignInt; + menu.hAlign = (MENU_H_ALIGNMENT)hAlignInt; + menu.vAlign = (MENU_V_ALIGNMENT)vAlignInt; + + float rectClientX, rectClientY, rectClientWidth, rectClientHeight; + *aZoneFileStream >> rectClientX >> rectClientY >> rectClientWidth >> rectClientHeight; + menu.clientRect = QRectF(rectClientX, rectClientY, rectClientWidth, rectClientHeight); + + quint32 hClientAlignInt, vClientAlignInt, styleInt, borderInt; + *aZoneFileStream >> hClientAlignInt >> vClientAlignInt >> menu.groupPtr + >> styleInt >> borderInt >> menu.ownerDraw >> menu.ownerDrawFlags + >> menu.borderSize >> menu.staticFlags >> menu.dynamicFlags >> menu.nextTime; + menu.hClientAlign = (MENU_H_ALIGNMENT)hClientAlignInt; + menu.vClientAlign = (MENU_V_ALIGNMENT)vClientAlignInt; + menu.style = (MENU_WINDOW_STYLE)styleInt; + menu.border = (MENU_WINDOW_BORDER)borderInt; + + float foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA, + backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA, + borderColorR, borderColorG, borderColorB, borderColorA, + outlineColorR, outlineColorG, outlineColorB, outlineColorA; + *aZoneFileStream >> foregroundColorR >> foregroundColorG >> foregroundColorB >> foregroundColorA + >> backgroundColorR >> backgroundColorG >> backgroundColorB >> backgroundColorA + >> borderColorR >> borderColorG >> borderColorB >> borderColorA + >> outlineColorR >> outlineColorG >> outlineColorB >> outlineColorA; + + menu.foregroundColor = QColor(foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA); + menu.backgroundColor = QColor(backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA); + menu.borderColor = QColor(borderColorR, borderColorG, borderColorB, borderColorA); + menu.outlineColor = QColor(outlineColorR, outlineColorG, outlineColorB, outlineColorA); + + *aZoneFileStream >> menu.materialPtr >> menu.fontPtr >> menu.fullScreen >> menu.itemCount + >> menu.fontIndex >> menu.cursorItem >> menu.fadeCycle >> menu.fadeClamp + >> menu.fadeAmount >> menu.fadeInAmount >> menu.blurRadius >> menu.onOpenPtr + >> menu.onFocusPtr >> menu.onClosePtr >> menu.onESCPtr >> menu.onKeyPtr + >> menu.visibleExpCount >> menu.expEntryPtr >> menu.allowedBindingPtr + >> menu.soundNamePtr >> menu.imageTrack; + + float focusColorR, focusColorG, focusColorB, focusColorA, + disabledColorR, disabledColorG, disabledColorB, disabledColorA; + *aZoneFileStream >> focusColorR >> focusColorG >> focusColorB >> focusColorA + >> disabledColorR >> disabledColorG >> disabledColorB >> disabledColorA; + menu.focusColor = QColor(focusColorR, focusColorG, focusColorB, focusColorA); + menu.disabledColor = QColor(disabledColorR, disabledColorG, disabledColorB, disabledColorA); + + *aZoneFileStream >> menu.rectXExpCount >> menu.rectXExpPtr >> menu.rectYExpCount >> menu.rectYExpPtr; + + aZoneFileStream->skipRawData(4); // Separator + + char menuDefNameChar; + int menuDefNameLen = 0; + *aZoneFileStream >> menuDefNameChar; + while (menuDefNameChar != 0 && menuDefNameLen < 30) { + menuDefNameLen++; + menu.name += menuDefNameChar; + *aZoneFileStream >> menuDefNameChar; + } + + char defStringChar; + int defStringLen = 0; + *aZoneFileStream >> defStringChar; + while (defStringChar != 0 && defStringLen < 30) { + defStringLen++; + menu.definition += defStringChar; + *aZoneFileStream >> defStringChar; + } + aZoneFileStream->skipRawData(4 * 10); + + *aZoneFileStream >> menu.itemWindowDefNamePtr; + + float itemRectX, itemRectY, itemRectWidth, itemRectHeight; + *aZoneFileStream >> itemRectX >> itemRectY >> itemRectWidth >> itemRectHeight; + menu.itemRect = QRectF(itemRectX, itemRectY, itemRectWidth, itemRectHeight); + + *aZoneFileStream >> menu.itemHAlignment >> menu.itemVAlignment >> menu.itemGroupPtr + >> menu.itemWindowStyle >> menu.itemWindowBorder >> menu.itemOwnerDraw + >> menu.itemOwnerDrawFlags >> menu.itemBorderSize >> menu.itemStaticFlags + >> menu.itemDynamicFlags >> menu.itemNextTime; + + float itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA, + itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA, + itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA, + itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA; + *aZoneFileStream >> itemForegroundColorR >> itemForegroundColorG >> itemForegroundColorB >> itemForegroundColorA + >> itemBackgroundColorR >> itemBackgroundColorG >> itemBackgroundColorB >> itemBackgroundColorA + >> itemBorderColorR >> itemBorderColorG >> itemBorderColorB >> itemBorderColorA + >> itemOutlineColorR >> itemOutlineColorG >> itemOutlineColorB >> itemOutlineColorA; + + menu.itemForegroundColor = QColor(itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA); + menu.itemBackgroundColor = QColor(itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA); + menu.itemBorderColor = QColor(itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA); + menu.itemOutlineColor = QColor(itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA); + + *aZoneFileStream >> menu.itemMaterialPtr; + + float itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight; + *aZoneFileStream >> itemTextRectX >> itemTextRectY >> itemTextRectWidth >> itemTextRectHeight; + menu.itemTextRect = QRectF(itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight); + + quint32 hItemTextAlignInt, vItemTextAlignInt, itemType, fontTypeInt, textStyleInt; + *aZoneFileStream >> hItemTextAlignInt >> vItemTextAlignInt >> itemType >> menu.dataType + >> menu.alignment >> fontTypeInt >> menu.textAlignMode >> menu.textalignx >> menu.textaligny + >> menu.textscale >> textStyleInt >> menu.gameMsgWindowIndex >> menu.gameMsgWindowMode + >> menu.testPtr >> menu.textSavegameInfo >> menu.parentPtr; + menu.itemText_hAlign = (MENU_H_ALIGNMENT)hItemTextAlignInt; + menu.itemText_vAlign = (MENU_V_ALIGNMENT)vItemTextAlignInt; + menu.itemType = (MENU_ITEM_TYPE)itemType; + menu.fontEnum = (MENU_FONT_TYPE)fontTypeInt; + menu.textStyle = (MENU_ITEM_TEXTSTYLE)textStyleInt; + + *aZoneFileStream >> menu.mouseEnterText >> menu.mouseExitText >> menu.mouseEnter >> menu.mouseExit + >> menu.action >> menu.onAccept >> menu.onFocus >> menu.leaveFocus >> menu.dvar >> menu.dvarTest + >> menu.keyHandlerPtr >> menu.enableDvarPtr >> menu.dvarFlags >> menu.focusSoundPtr + >> menu.special >> menu.cursorPos; + + // itemDefData_t typeData; + + // listBoxDef_s *listBox; + + *aZoneFileStream >> menu.startPos >> menu.endPos >> menu.drawPadding; + + *aZoneFileStream >> menu.elementWidth >> menu.elementHeight; + + *aZoneFileStream >> menu.elementStyle >> menu.numColumns; + + //columnInfo_s columnInfo[16]; + + *aZoneFileStream >> menu.doubleClickPtr; + + + *aZoneFileStream >> menu.notselectable >> menu.noScrollBars >> menu.usePaging; + + float itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA, + itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA, + itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA; + *aZoneFileStream >> itemSelectBorderColorR >> itemSelectBorderColorG >> itemSelectBorderColorB >> itemSelectBorderColorA + >> itemDisableColorR >> itemDisableColorG >> itemDisableColorB >> itemDisableColorA + >> itemFocusColorR >> itemFocusColorG >> itemFocusColorB >> itemFocusColorA; + menu.itemSelectBorderColor = QColor(itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA); + menu.itemDisableColor = QColor(itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA); + menu.itemFocusColor = QColor(itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA); + + *aZoneFileStream >> menu.selectIconPtr >> menu.backgroundItemListboxPtr >> menu.highlightTexturePtr; + + // editFieldDef_s *editField; + + *aZoneFileStream >> menu.minVal >> menu.maxVal >> menu.defVal >> menu.range >> menu.maxChars + >> menu.maxCharsGotoNext >> menu.maxPaintChars >> menu.paintOffset; + + // multiDef_s *multi; + + for (int i = 0; i < 32; i++) { + quint32 dvarList; + *aZoneFileStream >> dvarList; + menu.dvarListPtrs.push_back(dvarList); + } + + for (int i = 0; i < 32; i++) { + quint32 dvarStr; + *aZoneFileStream >> dvarStr; + menu.dvarStrPtrs.push_back(dvarStr); + } + + for (int i = 0; i < 32; i++) { + float dvarValue; + *aZoneFileStream >> dvarValue; + menu.dvarValues.push_back(dvarValue); + } + + *aZoneFileStream >> menu.count >> menu.strDef >> menu.enumDvarNamePtr; + aZoneFileStream->skipRawData(4); + //>> menu.dataPtr + *aZoneFileStream >> menu.itemImageTrack; + + qDebug() << aZoneFileStream->device()->pos(); + + //statement_s visibleExp; + //statement_s textExp; + //statement_s materialExp; + //statement_s rectXExp; + //statement_s rectYExp; + //statement_s rectWExp; + //statement_s rectHExp; + //statement_s foreColorAExp; + result.menuDefs << menu; + } + return result; +} + +void ZoneFile_COD5_PS3::pParseAsset_Weapon(QDataStream *aZoneFileStream) { + //WEAPON_FILE + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD5_PS3::pParseAsset_D3DBSP(QDataStream *aZoneFileStream) { + //D3DBSP_DUMP + Q_UNUSED(aZoneFileStream); +} + +StringTable ZoneFile_COD5_PS3::pParseAsset_StringTable(QDataStream *aZoneFileStream) { + StringTable result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.columnCount + >> result.rowCount; + + // Todo fix this + result.columnCount = 0; + result.rowCount = 0; + + aZoneFileStream->skipRawData(4); + + QString stringTableName; + char stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + while (stringTableNameChar != 0) { + result.name += stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + } + + for (quint32 i = 0; i < result.rowCount; i++) { + QByteArray pointerData(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pointerData.data(), 4); + result.tablePointers.push_back(pointerData.toHex()); + + aZoneFileStream->skipRawData(4); + } + + for (const QString &pointerAddr : result.tablePointers) { + QString leadingContent = ""; + if (pointerAddr == "FFFFFFFF") { + char leadingContentChar; + *aZoneFileStream >> leadingContentChar; + while (leadingContentChar != 0) { + leadingContent += leadingContentChar; + *aZoneFileStream >> leadingContentChar; + } + } else { + leadingContent = pointerAddr; + } + + QString content; + char contentChar; + *aZoneFileStream >> contentChar; + while (contentChar != 0) { + content += contentChar; + *aZoneFileStream >> contentChar; + } + result.content[leadingContent] = content; + } + return result; +} + +AssetType ZoneFile_COD5_PS3::AssetStrToEnum(const QString aAssetType) { + const QString cleanedType = aAssetType.toUpper(); + if (cleanedType == "17000000") { // localized string PARTIALLY VERIFIED + return ASSET_RAW_FILE; + } else if (cleanedType == "20000000") { // raw_file PARTIALLY VERIFIED + return ASSET_SCRIPT_PARSE_TREE; + } else if (cleanedType == "1A000000") { // fx PARTIALLY VERIFIED + return ASSET_EFFECT; + } else if (cleanedType == "09000000") { // loaded_sound PARTIALLY VERIFIED + return ASSET_SOUND; + } else if (cleanedType == "04000000") { // x_anim PARTIALLY VERIFIED + return ASSET_ANIMATION; + } else if (cleanedType == "0C000000") { // collision_map PARTIALLY VERIFIED + return ASSET_COLLISION_MAP; + } else if (cleanedType == "21000000") { // string_table PARTIALLY VERIFIED + return ASSET_STRING_TABLE; + } else if (cleanedType == "15000000") { // menu_file PARTIALLY VERIFIED + return ASSET_MENU; + } else if (cleanedType == "07000000") { // tech set PARTIALLY VERIFIED + return ASSET_TECH_SET; + } else if (cleanedType == "18000000") { // weapon PARTIALLY VERIFIED + return ASSET_WEAPON; + } else if (cleanedType == "11000000") { // gfx map PARTIALLY VERIFIED + return ASSET_GFX_MAP; + } else if (cleanedType == "12000000") { // light_def PARTIALLY VERIFIED + return ASSET_LIGHT_DEF; + } else if (cleanedType == "14000000") { // font PARTIALLY VERIFIED + return ASSET_FONT; + } else if (cleanedType == "05000000") { // xmodel PARTIALLY VERIFIED + return ASSET_MODEL; + } else if (cleanedType == "0D000000") { // d3dbsp PARTIALLY VERIFIED + return ASSET_D3DBSP; + } else if (cleanedType == "06000000") { // image PARTIALLY VERIFIED + return ASSET_IMAGE; + } else if (cleanedType == "0E000000") { // game map sp PARTIALLY VERIFIED + return ASSET_GAME_MAP_SP; + } else if (cleanedType == "0B000000") { // col map sp PARTIALLY VERIFIED + return ASSET_COL_MAP_SP; + } else if (cleanedType == "01000000") { // physics preset PARTIALLY VERIFIED + return ASSET_PHYS_PRESET; + } else if (cleanedType == "03000000") { // destructible def PARTIALLY VERIFIED + return ASSET_DESTRUCTIBLE; + } + return ASSET_NONE; +} + +QByteArray ZoneFile_COD5_PS3::GetBinaryData() { + QByteArray result; + + return result; +} diff --git a/libs/zonefile/PS3/zonefile_cod5_ps3.h b/libs/zonefile/PS3/zonefile_cod5_ps3.h new file mode 100644 index 0000000..62260e0 --- /dev/null +++ b/libs/zonefile/PS3/zonefile_cod5_ps3.h @@ -0,0 +1,54 @@ +#ifndef ZONEFILE_COD5_PS3_H +#define ZONEFILE_COD5_PS3_H + +#include + +#include "zonefile.h" + +class ZoneFile_COD5_PS3 : public ZoneFile +{ +public: + ZoneFile_COD5_PS3(); + ~ZoneFile_COD5_PS3(); + + bool Load(const QByteArray aFileData) override; + AssetType AssetStrToEnum(const QString aAssetType) override; + + QByteArray GetBinaryData() override; + +private: + void pParseZoneHeader(QDataStream *aZoneFileStream) override; + quint32 pParseZoneSize(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsA(QDataStream *aZoneFileStream) override; + quint32 pParseZoneTagCount(QDataStream *aZoneFileStream) override; + quint32 pParseZoneRecordCount(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsB(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsC(QDataStream *aZoneFileStream) override; + QStringList pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) override; + QStringList pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) override; + AssetMap pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) override; + LocalString pParseAsset_LocalString(QDataStream *aZoneFileStream) override; + RawFile pParseAsset_RawFile(QDataStream *aZoneFileStream) override; + void pParseAsset_PhysPreset(QDataStream *aZoneFileStream) override; + Model pParseAsset_Model(QDataStream *aZoneFileStream) override; + Material pParseAsset_Material(QDataStream *aZoneFileStream) override; + Shader pParseAsset_Shader(QDataStream *aZoneFileStream) override; + TechSet pParseAsset_TechSet(QDataStream *aZoneFileStream) override; + Image pParseAsset_Image(QDataStream *aZoneFileStream) override; + SoundAsset pParseAsset_Sound(QDataStream *aZoneFileStream) override; + void pParseAsset_ColMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapSP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_LightDef(QDataStream *aZoneFileStream) override; + void pParseAsset_UIMap(QDataStream *aZoneFileStream) override; + void pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) override; + void pParseAsset_AIType(QDataStream *aZoneFileStream) override; + void pParseAsset_FX(QDataStream *aZoneFileStream) override; + Animation pParseAsset_Animation(QDataStream *aZoneFileStream) override; + MenuFile pParseAsset_MenuFile(QDataStream *aZoneFileStream) override; + void pParseAsset_Weapon(QDataStream *aZoneFileStream) override; + void pParseAsset_D3DBSP(QDataStream *aZoneFileStream) override; + StringTable pParseAsset_StringTable(QDataStream *aZoneFileStream) override; +}; + +#endif // ZONEFILE_COD5_PS3_H diff --git a/libs/zonefile/PS3/zonefile_cod6_ps3.cpp b/libs/zonefile/PS3/zonefile_cod6_ps3.cpp new file mode 100644 index 0000000..9fb8d78 --- /dev/null +++ b/libs/zonefile/PS3/zonefile_cod6_ps3.cpp @@ -0,0 +1,1139 @@ +#include "zonefile_cod6_ps3.h" + +#include +#include +#include + +ZoneFile_COD6_PS3::ZoneFile_COD6_PS3() + : ZoneFile() { + +} + +ZoneFile_COD6_PS3::~ZoneFile_COD6_PS3() { + +} + +bool ZoneFile_COD6_PS3::Load(const QByteArray aFileData) { + // Open zone file as little endian stream + QDataStream zoneFileStream(aFileData); + zoneFileStream.setByteOrder(QDataStream::BigEndian); + + // Parse data from zone file header + pParseZoneHeader(&zoneFileStream); + SetRecords(pParseZoneIndex(&zoneFileStream, GetRecordCount())); + SetAssetMap(pParseAssets(&zoneFileStream, GetRecords())); + + return true; +} + +void ZoneFile_COD6_PS3::pParseZoneHeader(QDataStream *aZoneFileStream) { + SetSize(pParseZoneSize(aZoneFileStream)); + pParseZoneUnknownsA(aZoneFileStream); + + SetTagCount(pParseZoneTagCount(aZoneFileStream)); + pParseZoneUnknownsB(aZoneFileStream); + + SetRecordCount(pParseZoneRecordCount(aZoneFileStream)); + + quint32 tagCount = GetTagCount(); + if (tagCount) { + pParseZoneUnknownsC(aZoneFileStream); + SetTags(pParseZoneTags(aZoneFileStream, tagCount)); + } else { + aZoneFileStream->skipRawData(4); + } +} + +quint32 ZoneFile_COD6_PS3::pParseZoneSize(QDataStream *aZoneFileStream) { + quint32 zoneFileSize; + *aZoneFileStream >> zoneFileSize; + if (zoneFileSize <= 0) { + qDebug() << "Tried to open empty zone file!"; + exit(-1); + } + zoneFileSize += 36; + return zoneFileSize; +} + +/* + ParseZoneUnknownsA() + + Parses the 1st section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD6_PS3::pParseZoneUnknownsA(QDataStream *aZoneFileStream) { + // Byte 4-7, 8-11, 12-15: unknown + QByteArray unknown1(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown1.data(), 4); + + QByteArray unknown2(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown2.data(), 4); + + QByteArray unknown3(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown3.data(), 4); + + // Byte 16-19, 20-23: empty/unknown + QByteArray unknown4(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown4.data(), 4); + + QByteArray unknown5(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown5.data(), 4); + + // Byte 24-27: somehow related to the filesize, but smaller value + QByteArray unknown6(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown6.data(), 4); + + // Byte 28-31, 32-35: unknown + QByteArray unknown7(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown7.data(), 4); + + QByteArray unknown8(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown8.data(), 4); +} + +/* + ParseZoneTagCount() + + Parses the number of string tags in the zone index +*/ +quint32 ZoneFile_COD6_PS3::pParseZoneTagCount(QDataStream *aZoneFileStream) { + quint32 tagCount; + *aZoneFileStream >> tagCount; + return tagCount; +} + +/* + ParseZoneRecordCount() + + Parses the number of records in the zone index +*/ +quint32 ZoneFile_COD6_PS3::pParseZoneRecordCount(QDataStream *aZoneFileStream) { + quint32 recordCount; + *aZoneFileStream >> recordCount; + return recordCount; +} + +/* + ParseZoneUnknownsB() + + Parses the 2nd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD6_PS3::pParseZoneUnknownsB(QDataStream *aZoneFileStream) { + // Byte 44-47: Unknown/empty? + QByteArray unknown9(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown9.data(), 4); +} + +/* + pParseZoneUnknownsC() + + Parses the 3rd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD6_PS3::pParseZoneUnknownsC(QDataStream *aZoneFileStream) { + // Byte 40-43: Unknown/empty? + QByteArray unknown10(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown10.data(), 4); + + // Byte 44-47: Unknown/empty? + QByteArray unknown11(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown11.data(), 4); +} + +/* + ParseZoneTags() + + Parses the string tags ate the start of zone file +*/ +QStringList ZoneFile_COD6_PS3::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) { + QStringList tags; + + // Byte 48-51: Repeated separators? ÿÿÿÿ x i + aZoneFileStream->skipRawData(4 * (tagCount - 1)); + + // Parse tags/strings before index + QString zoneTag; + char zoneTagChar; + for (quint32 i = 0; i < tagCount; i++) { + *aZoneFileStream >> zoneTagChar; + while (zoneTagChar != 0) { + zoneTag += zoneTagChar; + *aZoneFileStream >> zoneTagChar; + } + tags << zoneTag; + zoneTag.clear(); + } + return tags; +} + +/* + ParseZoneIndex() + + Parse the binary zone index data and populate table +*/ +QStringList ZoneFile_COD6_PS3::pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) { + QStringList result; + + // Don't parse if no records + if (!recordCount) { return result; } + + if (aZoneFileStream->device()->peek(4).toHex().contains("ffff")) { + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 2); + } + + // Parse index & map found asset types + for (quint32 i = 0; i <= recordCount; i++) { + // Skip record start + QByteArray rawAssetType(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rawAssetType.data(), 4); + result << rawAssetType.toHex(); + + // Skip separator + aZoneFileStream->skipRawData(4); + } + return result; +} + +AssetMap ZoneFile_COD6_PS3::pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) { + AssetMap result; + + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 8); + + for (int i = 0; i < assetOrder.size(); i++) { + const QString typeHex = assetOrder[i]; + const AssetType typeStr = AssetStrToEnum(typeHex); + + if (typeStr == ASSET_LOCAL_STRING) { // localized string asset + result.localStrings << pParseAsset_LocalString(aZoneFileStream); + } else if (typeStr == ASSET_RAW_FILE) { // gsc + auto rawFile = pParseAsset_RawFile(aZoneFileStream); + if (rawFile.length) { + result.rawFiles << rawFile; + } + } else if (typeStr == ASSET_PHYS_PRESET) { // physpreset + pParseAsset_PhysPreset(aZoneFileStream); + } else if (typeStr == ASSET_MODEL) { // xmodel + result.models << pParseAsset_Model(aZoneFileStream); + } else if (typeStr == ASSET_MATERIAL) { // material + pParseAsset_Material(aZoneFileStream); + } else if (typeStr == ASSET_SHADER) { // pixelshader + pParseAsset_Shader(aZoneFileStream); + } else if (typeStr == ASSET_TECH_SET) { // techset include + result.techSets << pParseAsset_TechSet(aZoneFileStream); + } else if (typeStr == ASSET_IMAGE) { // image + result.images << pParseAsset_Image(aZoneFileStream); + } else if (typeStr == ASSET_SOUND) { // loaded_sound + result.sounds << pParseAsset_Sound(aZoneFileStream); + } else if (typeStr == ASSET_COLLISION_MAP) { // col_map_mp + pParseAsset_ColMapMP(aZoneFileStream); + } else if (typeStr == ASSET_MP_MAP) { // game_map_sp + pParseAsset_GameMapSP(aZoneFileStream); + } else if (typeStr == ASSET_SP_MAP) { // game_map_mp + pParseAsset_GameMapMP(aZoneFileStream); + } else if (typeStr == ASSET_LIGHT_DEF) { // lightdef + pParseAsset_LightDef(aZoneFileStream); + } else if (typeStr == ASSET_UI_MAP) { // ui_map + pParseAsset_UIMap(aZoneFileStream); + } else if (typeStr == ASSET_SND_DRIVER_GLOBALS) { // snddriverglobals + pParseAsset_SNDDriverGlobals(aZoneFileStream); + } else if (typeStr == ASSET_AI_TYPE) { // aitype + pParseAsset_AIType(aZoneFileStream); + } else if (typeStr == ASSET_EFFECT) { // aitype + pParseAsset_FX(aZoneFileStream); + } else if (typeStr == ASSET_ANIMATION) { // aitype + result.animations << pParseAsset_Animation(aZoneFileStream); + } else if (typeStr == ASSET_STRING_TABLE) { // string_table + result.stringTables << pParseAsset_StringTable(aZoneFileStream); + } else if (typeStr == ASSET_MENU) { // string_table + result.menuFiles << pParseAsset_MenuFile(aZoneFileStream); + } else if (typeStr == ASSET_WEAPON) { // string_table + pParseAsset_Weapon(aZoneFileStream); + } else if (typeStr == ASSET_D3DBSP) { // string_table + pParseAsset_D3DBSP(aZoneFileStream); + } + } + return result; +} + +LocalString ZoneFile_COD6_PS3::pParseAsset_LocalString(QDataStream *aZoneFileStream) { + LocalString result; + + quint32 stringPtr, aliasPtr; + *aZoneFileStream >> stringPtr >> aliasPtr; + if (stringPtr == 4294967295) { + // Parse local string asset contents + QString localStr; + char localStrChar; + *aZoneFileStream >> localStrChar; + while (localStrChar != 0) { + result.string += localStrChar; + *aZoneFileStream >> localStrChar; + } + } else { + result.string = "String Ptr: " + QString::number(stringPtr); + } + + if (aliasPtr == 4294967295) { + // Parse rawfile name + QString aliasName; + char aliasNameChar; + *aZoneFileStream >> aliasNameChar; + while (aliasNameChar != 0) { + result.alias += aliasNameChar; + *aZoneFileStream >> aliasNameChar; + } + } else { + result.string = "Alias Ptr: " + QString::number(aliasPtr); + } + + return result; +} + +RawFile ZoneFile_COD6_PS3::pParseAsset_RawFile(QDataStream *aZoneFileStream) { + RawFile result; + + // Skip start separator FF FF FF FF (pointer?) + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.length; + + // Skip unknown 4 byte data + aZoneFileStream->skipRawData(4); + + // Parse rawfile path + char scriptPathChar; + *aZoneFileStream >> scriptPathChar; + while (scriptPathChar != 0) { + result.path += scriptPathChar; + *aZoneFileStream >> scriptPathChar; + } + result.path.replace(",", ""); + + const QStringList pathParts = result.path.split('/'); + if (pathParts.size() == 0) { + qDebug() << "Failed to parse ff path! " << result.path; + exit(-1); + } + if (result.path.contains(".bik")) { + qDebug() << "rawFileLength: " << result.length; + QByteArray bikData(result.length, Qt::Uninitialized); + aZoneFileStream->readRawData(bikData.data(), result.length); + + //QFile bikFile(QDir::currentPath() + "/" + rawFilePath.split('/').last()); + //qDebug() << bikFile.fileName(); + //if (!bikFile.open(QIODevice::WriteOnly)) { + // qWarning() << "Failed to open .bik file for writing!"; + // return; + //} + //qDebug() << QString("%1: %2").arg(rawFilePath).arg(bikFile.fileName()); + //bikFile.write(bikData); + } else { + // Parse gsc contents + char rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + while (rawFileContentsChar != 0 && rawFileContentsChar != -1) { + result.contents += rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + } + } + return result; +} + +void ZoneFile_COD6_PS3::pParseAsset_PhysPreset(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Model ZoneFile_COD6_PS3::pParseAsset_Model(QDataStream *aZoneFileStream) { + Model result; + + *aZoneFileStream >> result.namePtr >> result.tagCount >> result.rootTagCount + >> result.surfCount >> result.unknownCount >> result.boneNamePtr + >> result.parentListPtr >> result.quatsPtr >> result.transPtr + >> result.partClassPtr >> result.baseMatPtr + >> result.surfsPtr >> result.materialHandlesPtr; + + // Parse XModelLodInfo + for (int i = 1; i <= 4; i++) { + quint32 intDist; + *aZoneFileStream >> intDist; + + std::memcpy(&result.lodInfo[i].dist, &intDist, sizeof(result.lodInfo[i].dist)); + *aZoneFileStream >> result.lodInfo[i].numsurfs >> result.lodInfo[i].surfIndex; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.lodInfo[i].partBits[0] + >> result.lodInfo[i].partBits[1] + >> result.lodInfo[i].partBits[2] + >> result.lodInfo[i].partBits[3]; + } + + *aZoneFileStream >> result.collSurfsPtr >> result.numCollSurfs >> result.contents >> result.boneInfoPtr; + + quint32 intRadius, intMins[3], intMaxs[3]; + *aZoneFileStream >> intRadius >> intMins[0] >> intMins[1] + >> intMins[2] >> intMaxs[0] >> intMaxs[1] >> intMaxs[2]; + + std::memcpy(&result.radius, &intRadius, sizeof(result.radius)); + + std::memcpy(&result.mins[0], &intMins[0], sizeof(result.mins[0])); + std::memcpy(&result.mins[1], &intMins[1], sizeof(result.mins[1])); + std::memcpy(&result.mins[2], &intMins[2], sizeof(result.mins[2])); + + std::memcpy(&result.maxs[0], &intMaxs[0], sizeof(result.maxs[0])); + std::memcpy(&result.maxs[1], &intMaxs[1], sizeof(result.maxs[2])); + std::memcpy(&result.maxs[2], &intMaxs[2], sizeof(result.maxs[3])); + + *aZoneFileStream >> result.numLods >> result.collLod >> result.streamInfoPtr + >> result.memUsage >> result.flags >> result.physPresetPtr >> result.physGeomsPtr; + + // Parse model name + char modelNameChar; + *aZoneFileStream >> modelNameChar; + while (modelNameChar == 0) { + *aZoneFileStream >> modelNameChar; + } + while (modelNameChar != 0) { + result.modelName += modelNameChar; + *aZoneFileStream >> modelNameChar; + } + return result; +} + +Material ZoneFile_COD6_PS3::pParseAsset_Material(QDataStream *aZoneFileStream) { + aZoneFileStream->skipRawData(27 * 4); + + qint32 materialNamePtr; + *aZoneFileStream >> materialNamePtr; + if (materialNamePtr == -1) { + QString materialName; + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + } + + aZoneFileStream->skipRawData(3 * 4); + + qint32 compressionPtr, compression, unknownSectionPtr; + *aZoneFileStream >> compressionPtr; + if (compressionPtr == -1) { + *aZoneFileStream >> compression; + + *aZoneFileStream >> unknownSectionPtr; + if (unknownSectionPtr == -2) { + aZoneFileStream->skipRawData(6 * 4); + } + } + + qint32 imageNamePtr; + *aZoneFileStream >> imageNamePtr; + if (imageNamePtr == -1) { + QString imageName; + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + imageName += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + } + + QByteArray compressionData(4, Qt::Uninitialized); + QString compressionStr; + if (compressionPtr == -1) { + aZoneFileStream->skipRawData(2 * 4); + aZoneFileStream->readRawData(compressionData.data(), 4); + aZoneFileStream->skipRawData(4); + compressionStr = QString::fromUtf8(compressionData); + aZoneFileStream->skipRawData(4); + } + aZoneFileStream->skipRawData(4); + + // TODO: Fill out this material + return Material(); +} + +Shader ZoneFile_COD6_PS3::pParseAsset_Shader(QDataStream *aZoneFileStream) { + Shader result = Shader(); + + quint8 minorVersion, majorVersion; + *aZoneFileStream >> minorVersion >> majorVersion; + + quint32 magic; + *aZoneFileStream >> magic; + + // Verify .fxc magic + if (magic != 65534 && magic != 65535) { return result; } + + SHADER_TYPE type = SHADER_NONE; + quint16 rawShaderType; + *aZoneFileStream >> rawShaderType; + if (rawShaderType == 65535) { // Pixel shader + type = SHADER_PIXEL; + } else if (rawShaderType == 65534) { // Vertex shader + type = SHADER_VERTEX; + } + Q_UNUSED(type); + + while (true) { + quint32 instructionToken; + *aZoneFileStream >> instructionToken; + + SHADER_OPCODE opCode = (SHADER_OPCODE)(instructionToken & 0xffff); + + int size; + if (opCode == OPCODE_End) { + break; + } else if (opCode == OPCODE_Comment) { + size = (int)((instructionToken >> 16) & 0x7FFF); + } else { + size = (int)((instructionToken >> 24) & 0x0f); + } + Q_UNUSED(size); + } + + + return result; +} + +TechSet ZoneFile_COD6_PS3::pParseAsset_TechSet(QDataStream *aZoneFileStream) { + TechSet result; + + for (int i = 1; i <= 62; i++) { + quint32 ptr; + *aZoneFileStream >> ptr; + + result.pointers << ptr; + } + qDebug() << aZoneFileStream->device()->pos(); + + // Parse techset name + char techSetNameChar; + *aZoneFileStream >> techSetNameChar; + while (techSetNameChar != 0) { + result.name += techSetNameChar; + *aZoneFileStream >> techSetNameChar; + } + result.name.replace(",", ""); + + return result; +} + +Image ZoneFile_COD6_PS3::pParseAsset_Image(QDataStream *aZoneFileStream) { + Image result; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknowna >> result.unknownb + >> result.unknownc >> result.unknownd + >> result.unknowne >> result.unknownf + >> result.unknowng; + + aZoneFileStream->skipRawData(15 * 4); + *aZoneFileStream >> result.unknownh >> result.unknowni; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknownj; + + aZoneFileStream->skipRawData(4); + + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + result.materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + result.materialName.replace(",", ""); + + if (result.unknowna) { + *aZoneFileStream >> result.unknownk; + *aZoneFileStream >> result.unknownl; + *aZoneFileStream >> result.unknownm; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown1; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown2 >> result.unknown3 + >> result.size1 >> result.size2 + >> result.unknown4 >> result.unknown5; + + aZoneFileStream->skipRawData(4); + + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + result.name += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + + *aZoneFileStream >> result.unknown6 >> result.unknown7; + + QByteArray compressionData(8, Qt::Uninitialized); + aZoneFileStream->readRawData(compressionData.data(), 8); + if (compressionData.contains("DXT1")) { + result.compression = COMPRESSION_DXT1; + } else if (compressionData.contains("DXT3")) { + result.compression = COMPRESSION_DXT3; + } else if (compressionData.contains("DXT5")) { + result.compression = COMPRESSION_DXT5; + } else { + result.compression = COMPRESSION_NONE; + } + + *aZoneFileStream >> result.unknown8 >> result.unknown9; + } + + return result; +} + +SoundAsset ZoneFile_COD6_PS3::pParseAsset_Sound(QDataStream *aZoneFileStream) { + SoundAsset result; + + qDebug() << aZoneFileStream->device()->pos(); + + QByteArray rootNamePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rootNamePtr.data(), 4); + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.count; + + if (rootNamePtr.toHex() == "ffffffff") { + // Read in sound file name + char soundNameChar; + *aZoneFileStream >> soundNameChar; + while (soundNameChar != 0) { + result.name += soundNameChar; + *aZoneFileStream >> soundNameChar; + } + } + + int tagCount = 0; + int resultCount = 0; + for (quint32 i = 0; i < result.count; i++) { + aZoneFileStream->skipRawData(12); + + QByteArray tagPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(tagPtr.data(), 4); + + if (tagPtr.toHex() == "ffffffff") { + tagCount++; + } + aZoneFileStream->skipRawData(4); + + QByteArray pathPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pathPtr.data(), 4); + + if (pathPtr.toHex() == "ffffffff") { + resultCount++; + } + + aZoneFileStream->skipRawData(160); + } + + for (int i = 0; i < tagCount; i++) { + // Read in tag? + QString tag; + char tagChar; + *aZoneFileStream >> tagChar; + while (tagChar != 0) { + tag += tagChar; + *aZoneFileStream >> tagChar; + } + } + + for (int i = 0; i < resultCount; i++) { + Sound sound; + + if (aZoneFileStream->device()->peek(12).toHex().contains("ffffffff00000000")) { + aZoneFileStream->skipRawData(12); + } + + aZoneFileStream->skipRawData(8); + + QByteArray aliasPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(aliasPtr.data(), 4); + + QByteArray namePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(namePtr.data(), 4); + + *aZoneFileStream >> sound.dataLength; + + if (aliasPtr.toHex() == "ffffffff") { + // Read in sound alias name + char soundAliasChar; + *aZoneFileStream >> soundAliasChar; + while (soundAliasChar != 0) { + sound.alias += soundAliasChar; + *aZoneFileStream >> soundAliasChar; + } + } + + if (aZoneFileStream->device()->peek(4) == "RIFF") { + sound.path = sound.alias; + sound.alias = ""; + } else if (namePtr.toHex() == "ffffffff") { + // Read in sound file path + char soundPathChar; + *aZoneFileStream >> soundPathChar; + while (soundPathChar != 0) { + sound.path += soundPathChar; + *aZoneFileStream >> soundPathChar; + } + sound.path.replace(",", ""); + } + + if (sound.dataLength) { + QByteArray data(sound.dataLength, Qt::Uninitialized); + aZoneFileStream->readRawData(data.data(), sound.dataLength); + sound.data = data; + } + result.sounds.append(sound); + } + + return result; +} + +void ZoneFile_COD6_PS3::pParseAsset_ColMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD6_PS3::pParseAsset_GameMapSP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD6_PS3::pParseAsset_GameMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD6_PS3::pParseAsset_LightDef(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD6_PS3::pParseAsset_UIMap(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD6_PS3::pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD6_PS3::pParseAsset_AIType(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD6_PS3::pParseAsset_FX(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Animation ZoneFile_COD6_PS3::pParseAsset_Animation(QDataStream *aZoneFileStream) { + Animation result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.dataByteCount + >> result.dataShortCount + >> result.dataIntCount + >> result.randomDataByteCount + >> result.randomDataIntCount + >> result.numframes + >> result.isLooped + >> result.isDelta + >> result.noneRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.normalTranslatedBoneCount + >> result.preciseTranslatedBoneCount + >> result.staticTranslatedBoneCount + >> result.noneTranslatedBoneCount + >> result.totalBoneCount + >> result.otherBoneCount1 + >> result.otherBoneCount2 + >> result.notifyCount + >> result.assetType + >> result.pad + >> result.randomDataShortCount + >> result.indexCount + >> result.frameRate + >> result.frequency + >> result.boneIDsPtr + >> result.dataBytePtr + >> result.dataShortPtr + >> result.dataIntPtr + >> result.randomDataShortPtr + >> result.randomDataBytePtr + >> result.randomDataIntPtr + >> result.longIndiciesPtr + >> result.notificationsPtr + >> result.deltaPartsPtr; + + // Read in x_anim file name + QString xAnimName; + char xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + while (xAnimNameChar != 0) { + result.name += xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + } + + // Parse x_anim index header + QVector sectionLengths; + for (int i = 0; i < result.numframes; i++) { + quint8 sectionlength; + *aZoneFileStream >> sectionlength; + sectionLengths.push_back(sectionlength); + // Skip padding + aZoneFileStream->skipRawData(1); + } + // Skip unknown section + aZoneFileStream->skipRawData(2 * 8); + + return result; +} + +MenuFile ZoneFile_COD6_PS3::pParseAsset_MenuFile(QDataStream *aZoneFileStream) { + //MENU_FILE + MenuFile result; + + aZoneFileStream->skipRawData(4); // Separator + + // Parse menu def count + *aZoneFileStream >> result.menuCount; + + // Clearly misparsed, never have this much + if (result.menuCount > 1000) { + qDebug() << "Failure reported when parsing menu file."; + return result; + } + for (uint i = 0; i < result.menuCount; i++) { + Menu menu; + + aZoneFileStream->skipRawData(4); // Separator + + // Read in x_anim file name + char menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + while (menuFilepathChar != 0) { + menu.filePath += menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + } + aZoneFileStream->skipRawData(4); // Separator + + *aZoneFileStream >> menu.menuNamePtr; + + float menuRectX, menuRectY, menuRectWidth, menuRectHeight; + *aZoneFileStream >> menuRectX >> menuRectY >> menuRectWidth >> menuRectHeight; + menu.rect = QRectF(menuRectX, menuRectY, menuRectWidth, menuRectHeight); + + quint32 hAlignInt, vAlignInt; + *aZoneFileStream >> hAlignInt >> vAlignInt; + menu.hAlign = (MENU_H_ALIGNMENT)hAlignInt; + menu.vAlign = (MENU_V_ALIGNMENT)vAlignInt; + + float rectClientX, rectClientY, rectClientWidth, rectClientHeight; + *aZoneFileStream >> rectClientX >> rectClientY >> rectClientWidth >> rectClientHeight; + menu.clientRect = QRectF(rectClientX, rectClientY, rectClientWidth, rectClientHeight); + + quint32 hClientAlignInt, vClientAlignInt, styleInt, borderInt; + *aZoneFileStream >> hClientAlignInt >> vClientAlignInt >> menu.groupPtr + >> styleInt >> borderInt >> menu.ownerDraw >> menu.ownerDrawFlags + >> menu.borderSize >> menu.staticFlags >> menu.dynamicFlags >> menu.nextTime; + menu.hClientAlign = (MENU_H_ALIGNMENT)hClientAlignInt; + menu.vClientAlign = (MENU_V_ALIGNMENT)vClientAlignInt; + menu.style = (MENU_WINDOW_STYLE)styleInt; + menu.border = (MENU_WINDOW_BORDER)borderInt; + + float foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA, + backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA, + borderColorR, borderColorG, borderColorB, borderColorA, + outlineColorR, outlineColorG, outlineColorB, outlineColorA; + *aZoneFileStream >> foregroundColorR >> foregroundColorG >> foregroundColorB >> foregroundColorA + >> backgroundColorR >> backgroundColorG >> backgroundColorB >> backgroundColorA + >> borderColorR >> borderColorG >> borderColorB >> borderColorA + >> outlineColorR >> outlineColorG >> outlineColorB >> outlineColorA; + + menu.foregroundColor = QColor(foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA); + menu.backgroundColor = QColor(backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA); + menu.borderColor = QColor(borderColorR, borderColorG, borderColorB, borderColorA); + menu.outlineColor = QColor(outlineColorR, outlineColorG, outlineColorB, outlineColorA); + + *aZoneFileStream >> menu.materialPtr >> menu.fontPtr >> menu.fullScreen >> menu.itemCount + >> menu.fontIndex >> menu.cursorItem >> menu.fadeCycle >> menu.fadeClamp + >> menu.fadeAmount >> menu.fadeInAmount >> menu.blurRadius >> menu.onOpenPtr + >> menu.onFocusPtr >> menu.onClosePtr >> menu.onESCPtr >> menu.onKeyPtr + >> menu.visibleExpCount >> menu.expEntryPtr >> menu.allowedBindingPtr + >> menu.soundNamePtr >> menu.imageTrack; + + float focusColorR, focusColorG, focusColorB, focusColorA, + disabledColorR, disabledColorG, disabledColorB, disabledColorA; + *aZoneFileStream >> focusColorR >> focusColorG >> focusColorB >> focusColorA + >> disabledColorR >> disabledColorG >> disabledColorB >> disabledColorA; + menu.focusColor = QColor(focusColorR, focusColorG, focusColorB, focusColorA); + menu.disabledColor = QColor(disabledColorR, disabledColorG, disabledColorB, disabledColorA); + + *aZoneFileStream >> menu.rectXExpCount >> menu.rectXExpPtr >> menu.rectYExpCount >> menu.rectYExpPtr; + + aZoneFileStream->skipRawData(4); // Separator + + char menuDefNameChar; + int menuDefNameLen = 0; + *aZoneFileStream >> menuDefNameChar; + while (menuDefNameChar != 0 && menuDefNameLen < 30) { + menuDefNameLen++; + menu.name += menuDefNameChar; + *aZoneFileStream >> menuDefNameChar; + } + + char defStringChar; + int defStringLen = 0; + *aZoneFileStream >> defStringChar; + while (defStringChar != 0 && defStringLen < 30) { + defStringLen++; + menu.definition += defStringChar; + *aZoneFileStream >> defStringChar; + } + aZoneFileStream->skipRawData(4 * 10); + + *aZoneFileStream >> menu.itemWindowDefNamePtr; + + float itemRectX, itemRectY, itemRectWidth, itemRectHeight; + *aZoneFileStream >> itemRectX >> itemRectY >> itemRectWidth >> itemRectHeight; + menu.itemRect = QRectF(itemRectX, itemRectY, itemRectWidth, itemRectHeight); + + *aZoneFileStream >> menu.itemHAlignment >> menu.itemVAlignment >> menu.itemGroupPtr + >> menu.itemWindowStyle >> menu.itemWindowBorder >> menu.itemOwnerDraw + >> menu.itemOwnerDrawFlags >> menu.itemBorderSize >> menu.itemStaticFlags + >> menu.itemDynamicFlags >> menu.itemNextTime; + + float itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA, + itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA, + itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA, + itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA; + *aZoneFileStream >> itemForegroundColorR >> itemForegroundColorG >> itemForegroundColorB >> itemForegroundColorA + >> itemBackgroundColorR >> itemBackgroundColorG >> itemBackgroundColorB >> itemBackgroundColorA + >> itemBorderColorR >> itemBorderColorG >> itemBorderColorB >> itemBorderColorA + >> itemOutlineColorR >> itemOutlineColorG >> itemOutlineColorB >> itemOutlineColorA; + + menu.itemForegroundColor = QColor(itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA); + menu.itemBackgroundColor = QColor(itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA); + menu.itemBorderColor = QColor(itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA); + menu.itemOutlineColor = QColor(itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA); + + *aZoneFileStream >> menu.itemMaterialPtr; + + float itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight; + *aZoneFileStream >> itemTextRectX >> itemTextRectY >> itemTextRectWidth >> itemTextRectHeight; + menu.itemTextRect = QRectF(itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight); + + quint32 hItemTextAlignInt, vItemTextAlignInt, itemType, fontTypeInt, textStyleInt; + *aZoneFileStream >> hItemTextAlignInt >> vItemTextAlignInt >> itemType >> menu.dataType + >> menu.alignment >> fontTypeInt >> menu.textAlignMode >> menu.textalignx >> menu.textaligny + >> menu.textscale >> textStyleInt >> menu.gameMsgWindowIndex >> menu.gameMsgWindowMode + >> menu.testPtr >> menu.textSavegameInfo >> menu.parentPtr; + menu.itemText_hAlign = (MENU_H_ALIGNMENT)hItemTextAlignInt; + menu.itemText_vAlign = (MENU_V_ALIGNMENT)vItemTextAlignInt; + menu.itemType = (MENU_ITEM_TYPE)itemType; + menu.fontEnum = (MENU_FONT_TYPE)fontTypeInt; + menu.textStyle = (MENU_ITEM_TEXTSTYLE)textStyleInt; + + *aZoneFileStream >> menu.mouseEnterText >> menu.mouseExitText >> menu.mouseEnter >> menu.mouseExit + >> menu.action >> menu.onAccept >> menu.onFocus >> menu.leaveFocus >> menu.dvar >> menu.dvarTest + >> menu.keyHandlerPtr >> menu.enableDvarPtr >> menu.dvarFlags >> menu.focusSoundPtr + >> menu.special >> menu.cursorPos; + + // itemDefData_t typeData; + + // listBoxDef_s *listBox; + + *aZoneFileStream >> menu.startPos >> menu.endPos >> menu.drawPadding; + + *aZoneFileStream >> menu.elementWidth >> menu.elementHeight; + + *aZoneFileStream >> menu.elementStyle >> menu.numColumns; + + //columnInfo_s columnInfo[16]; + + *aZoneFileStream >> menu.doubleClickPtr; + + + *aZoneFileStream >> menu.notselectable >> menu.noScrollBars >> menu.usePaging; + + float itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA, + itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA, + itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA; + *aZoneFileStream >> itemSelectBorderColorR >> itemSelectBorderColorG >> itemSelectBorderColorB >> itemSelectBorderColorA + >> itemDisableColorR >> itemDisableColorG >> itemDisableColorB >> itemDisableColorA + >> itemFocusColorR >> itemFocusColorG >> itemFocusColorB >> itemFocusColorA; + menu.itemSelectBorderColor = QColor(itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA); + menu.itemDisableColor = QColor(itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA); + menu.itemFocusColor = QColor(itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA); + + *aZoneFileStream >> menu.selectIconPtr >> menu.backgroundItemListboxPtr >> menu.highlightTexturePtr; + + // editFieldDef_s *editField; + + *aZoneFileStream >> menu.minVal >> menu.maxVal >> menu.defVal >> menu.range >> menu.maxChars + >> menu.maxCharsGotoNext >> menu.maxPaintChars >> menu.paintOffset; + + // multiDef_s *multi; + + for (int i = 0; i < 32; i++) { + quint32 dvarList; + *aZoneFileStream >> dvarList; + menu.dvarListPtrs.push_back(dvarList); + } + + for (int i = 0; i < 32; i++) { + quint32 dvarStr; + *aZoneFileStream >> dvarStr; + menu.dvarStrPtrs.push_back(dvarStr); + } + + for (int i = 0; i < 32; i++) { + float dvarValue; + *aZoneFileStream >> dvarValue; + menu.dvarValues.push_back(dvarValue); + } + + *aZoneFileStream >> menu.count >> menu.strDef >> menu.enumDvarNamePtr; + aZoneFileStream->skipRawData(4); + //>> menu.dataPtr + *aZoneFileStream >> menu.itemImageTrack; + + qDebug() << aZoneFileStream->device()->pos(); + + //statement_s visibleExp; + //statement_s textExp; + //statement_s materialExp; + //statement_s rectXExp; + //statement_s rectYExp; + //statement_s rectWExp; + //statement_s rectHExp; + //statement_s foreColorAExp; + result.menuDefs << menu; + } + return result; +} + +void ZoneFile_COD6_PS3::pParseAsset_Weapon(QDataStream *aZoneFileStream) { + //WEAPON_FILE + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD6_PS3::pParseAsset_D3DBSP(QDataStream *aZoneFileStream) { + //D3DBSP_DUMP + Q_UNUSED(aZoneFileStream); +} + +StringTable ZoneFile_COD6_PS3::pParseAsset_StringTable(QDataStream *aZoneFileStream) { + StringTable result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.columnCount + >> result.rowCount; + + // Todo fix this + result.columnCount = 0; + result.rowCount = 0; + + aZoneFileStream->skipRawData(4); + + QString stringTableName; + char stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + while (stringTableNameChar != 0) { + result.name += stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + } + + for (quint32 i = 0; i < result.rowCount; i++) { + QByteArray pointerData(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pointerData.data(), 4); + result.tablePointers.push_back(pointerData.toHex()); + + aZoneFileStream->skipRawData(4); + } + + for (const QString &pointerAddr : result.tablePointers) { + QString leadingContent = ""; + if (pointerAddr == "FFFFFFFF") { + char leadingContentChar; + *aZoneFileStream >> leadingContentChar; + while (leadingContentChar != 0) { + leadingContent += leadingContentChar; + *aZoneFileStream >> leadingContentChar; + } + } else { + leadingContent = pointerAddr; + } + + QString content; + char contentChar; + *aZoneFileStream >> contentChar; + while (contentChar != 0) { + content += contentChar; + *aZoneFileStream >> contentChar; + } + result.content[leadingContent] = content; + } + return result; +} + +AssetType ZoneFile_COD6_PS3::AssetStrToEnum(const QString aAssetType) { + const QString cleanedType = aAssetType.toUpper(); + if (cleanedType == "17000000") { // localized string PARTIALLY VERIFIED + return ASSET_RAW_FILE; + } else if (cleanedType == "20000000") { // raw_file PARTIALLY VERIFIED + return ASSET_SCRIPT_PARSE_TREE; + } else if (cleanedType == "1A000000") { // fx PARTIALLY VERIFIED + return ASSET_EFFECT; + } else if (cleanedType == "09000000") { // loaded_sound PARTIALLY VERIFIED + return ASSET_SOUND; + } else if (cleanedType == "04000000") { // x_anim PARTIALLY VERIFIED + return ASSET_ANIMATION; + } else if (cleanedType == "0C000000") { // collision_map PARTIALLY VERIFIED + return ASSET_COLLISION_MAP; + } else if (cleanedType == "21000000") { // string_table PARTIALLY VERIFIED + return ASSET_STRING_TABLE; + } else if (cleanedType == "15000000") { // menu_file PARTIALLY VERIFIED + return ASSET_MENU; + } else if (cleanedType == "07000000") { // tech set PARTIALLY VERIFIED + return ASSET_TECH_SET; + } else if (cleanedType == "18000000") { // weapon PARTIALLY VERIFIED + return ASSET_WEAPON; + } else if (cleanedType == "11000000") { // gfx map PARTIALLY VERIFIED + return ASSET_GFX_MAP; + } else if (cleanedType == "12000000") { // light_def PARTIALLY VERIFIED + return ASSET_LIGHT_DEF; + } else if (cleanedType == "14000000") { // font PARTIALLY VERIFIED + return ASSET_FONT; + } else if (cleanedType == "05000000") { // xmodel PARTIALLY VERIFIED + return ASSET_MODEL; + } else if (cleanedType == "0D000000") { // d3dbsp PARTIALLY VERIFIED + return ASSET_D3DBSP; + } else if (cleanedType == "06000000") { // image PARTIALLY VERIFIED + return ASSET_IMAGE; + } else if (cleanedType == "0E000000") { // game map sp PARTIALLY VERIFIED + return ASSET_GAME_MAP_SP; + } else if (cleanedType == "0B000000") { // col map sp PARTIALLY VERIFIED + return ASSET_COL_MAP_SP; + } else if (cleanedType == "01000000") { // physics preset PARTIALLY VERIFIED + return ASSET_PHYS_PRESET; + } else if (cleanedType == "03000000") { // destructible def PARTIALLY VERIFIED + return ASSET_DESTRUCTIBLE; + } + return ASSET_NONE; +} + +QByteArray ZoneFile_COD6_PS3::GetBinaryData() { + QByteArray result; + + return result; +} diff --git a/libs/zonefile/PS3/zonefile_cod6_ps3.h b/libs/zonefile/PS3/zonefile_cod6_ps3.h new file mode 100644 index 0000000..4be12ec --- /dev/null +++ b/libs/zonefile/PS3/zonefile_cod6_ps3.h @@ -0,0 +1,54 @@ +#ifndef ZONEFILE_COD6_PS3_H +#define ZONEFILE_COD6_PS3_H + +#include + +#include "zonefile.h" + +class ZoneFile_COD6_PS3 : public ZoneFile +{ +public: + ZoneFile_COD6_PS3(); + ~ZoneFile_COD6_PS3(); + + bool Load(const QByteArray aFileData) override; + AssetType AssetStrToEnum(const QString aAssetType) override; + + QByteArray GetBinaryData() override; + +private: + void pParseZoneHeader(QDataStream *aZoneFileStream) override; + quint32 pParseZoneSize(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsA(QDataStream *aZoneFileStream) override; + quint32 pParseZoneTagCount(QDataStream *aZoneFileStream) override; + quint32 pParseZoneRecordCount(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsB(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsC(QDataStream *aZoneFileStream) override; + QStringList pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) override; + QStringList pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) override; + AssetMap pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) override; + LocalString pParseAsset_LocalString(QDataStream *aZoneFileStream) override; + RawFile pParseAsset_RawFile(QDataStream *aZoneFileStream) override; + void pParseAsset_PhysPreset(QDataStream *aZoneFileStream) override; + Model pParseAsset_Model(QDataStream *aZoneFileStream) override; + Material pParseAsset_Material(QDataStream *aZoneFileStream) override; + Shader pParseAsset_Shader(QDataStream *aZoneFileStream) override; + TechSet pParseAsset_TechSet(QDataStream *aZoneFileStream) override; + Image pParseAsset_Image(QDataStream *aZoneFileStream) override; + SoundAsset pParseAsset_Sound(QDataStream *aZoneFileStream) override; + void pParseAsset_ColMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapSP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_LightDef(QDataStream *aZoneFileStream) override; + void pParseAsset_UIMap(QDataStream *aZoneFileStream) override; + void pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) override; + void pParseAsset_AIType(QDataStream *aZoneFileStream) override; + void pParseAsset_FX(QDataStream *aZoneFileStream) override; + Animation pParseAsset_Animation(QDataStream *aZoneFileStream) override; + MenuFile pParseAsset_MenuFile(QDataStream *aZoneFileStream) override; + void pParseAsset_Weapon(QDataStream *aZoneFileStream) override; + void pParseAsset_D3DBSP(QDataStream *aZoneFileStream) override; + StringTable pParseAsset_StringTable(QDataStream *aZoneFileStream) override; +}; + +#endif // ZONEFILE_COD6_PS3_H diff --git a/libs/zonefile/PS3/zonefile_cod7_ps3.cpp b/libs/zonefile/PS3/zonefile_cod7_ps3.cpp new file mode 100644 index 0000000..0386fc6 --- /dev/null +++ b/libs/zonefile/PS3/zonefile_cod7_ps3.cpp @@ -0,0 +1,1077 @@ +#include "zonefile_cod7_ps3.h" + +#include +#include +#include + +ZoneFile_COD7_PS3::ZoneFile_COD7_PS3() +{ + +} + +ZoneFile_COD7_PS3::~ZoneFile_COD7_PS3() +{ + +} + +bool ZoneFile_COD7_PS3::Load(const QByteArray aFileData) { + // Open zone file as little endian stream + QDataStream zoneFileStream(aFileData); + zoneFileStream.setByteOrder(QDataStream::BigEndian); + + // Parse data from zone file header + pParseZoneHeader(&zoneFileStream); + zoneFileStream.device()->seek(zoneFileStream.device()->pos() - 1); + SetRecords(pParseZoneIndex(&zoneFileStream, GetRecordCount())); + SetAssetMap(pParseAssets(&zoneFileStream, GetRecords())); + + return true; +} + +void ZoneFile_COD7_PS3::pParseZoneHeader(QDataStream *aZoneFileStream) { + quint32 size = pParseZoneSize(aZoneFileStream); + SetSize(size); + + pParseZoneUnknownsA(aZoneFileStream); + + quint32 tagCount = pParseZoneTagCount(aZoneFileStream); + SetTagCount(tagCount); + + pParseZoneUnknownsB(aZoneFileStream); + + quint32 recordCount = pParseZoneRecordCount(aZoneFileStream); + SetRecordCount(recordCount); + + if (tagCount) { + pParseZoneUnknownsC(aZoneFileStream); + SetTags(pParseZoneTags(aZoneFileStream, tagCount)); + } else { + aZoneFileStream->skipRawData(4); + } +} + +quint32 ZoneFile_COD7_PS3::pParseZoneSize(QDataStream *aZoneFileStream) { + quint32 zoneFileSize; + *aZoneFileStream >> zoneFileSize; + if (zoneFileSize <= 0) { + qDebug() << "Tried to open empty zone file!"; + exit(-1); + } + zoneFileSize += 36; + return zoneFileSize; +} + +/* + ParseZoneUnknownsA() + + Parses the 1st section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD7_PS3::pParseZoneUnknownsA(QDataStream *aZoneFileStream) { + // Byte 4-7, 8-11, 12-15: unknown + QByteArray unknown1(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown1.data(), 4); + + QByteArray unknown2(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown2.data(), 4); + + QByteArray unknown3(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown3.data(), 4); + + // Byte 16-19, 20-23: empty/unknown + QByteArray unknown4(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown4.data(), 4); + + QByteArray unknown5(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown5.data(), 4); + + // Byte 24-27: somehow related to the filesize, but smaller value + QByteArray unknown6(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown6.data(), 4); + + // Byte 28-31, 32-35: unknown + QByteArray unknown7(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown7.data(), 4); + + QByteArray unknown8(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown8.data(), 4); +} + +/* + ParseZoneTagCount() + + Parses the number of string tags in the zone index +*/ +quint32 ZoneFile_COD7_PS3::pParseZoneTagCount(QDataStream *aZoneFileStream) { + quint32 tagCount; + *aZoneFileStream >> tagCount; + return tagCount; +} + +/* + ParseZoneRecordCount() + + Parses the number of records in the zone index +*/ +quint32 ZoneFile_COD7_PS3::pParseZoneRecordCount(QDataStream *aZoneFileStream) { + quint32 recordCount; + *aZoneFileStream >> recordCount; + return recordCount; +} + +/* + ParseZoneUnknownsB() + + Parses the 2nd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD7_PS3::pParseZoneUnknownsB(QDataStream *aZoneFileStream) { + // Byte 44-47: Unknown/empty? + QByteArray unknown9(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown9.data(), 4); +} + +/* + pParseZoneUnknownsC() + + Parses the 3rd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD7_PS3::pParseZoneUnknownsC(QDataStream *aZoneFileStream) { + // Byte 40-43: Unknown/empty? + QByteArray unknown10(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown10.data(), 4); + + // Byte 44-47: Unknown/empty? + QByteArray unknown11(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown11.data(), 4); +} + +/* + ParseZoneTags() + + Parses the string tags ate the start of zone file +*/ +QStringList ZoneFile_COD7_PS3::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) { + QStringList tags; + + // Byte 48-51: Repeated separators? ÿÿÿÿ x i + aZoneFileStream->skipRawData(4 * (tagCount - 1)); + + // Parse tags/strings before index + QString zoneTag; + char zoneTagChar; + for (quint32 i = 0; i < tagCount; i++) { + *aZoneFileStream >> zoneTagChar; + while (zoneTagChar != 0) { + zoneTag += zoneTagChar; + *aZoneFileStream >> zoneTagChar; + } + tags << zoneTag; + zoneTag.clear(); + } + return tags; +} + +/* + ParseZoneIndex() + + Parse the binary zone index data and populate table +*/ +QStringList ZoneFile_COD7_PS3::pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) { + QStringList result; + + // Don't parse if no records + if (!recordCount) { return result; } + + if (aZoneFileStream->device()->peek(4).toHex().contains("ffff")) { + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 2); + } + + // Parse index & map found asset types + for (quint32 i = 0; i <= recordCount; i++) { + // Skip record start + QByteArray rawAssetType(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rawAssetType.data(), 4); + result << rawAssetType.toHex(); + + // Skip separator + aZoneFileStream->skipRawData(4); + } + return result; +} + +AssetMap ZoneFile_COD7_PS3::pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) { + AssetMap result; + + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 8); + + for (int i = 0; i < assetOrder.size(); i++) { + const QString typeHex = assetOrder[i]; + const AssetType typeStr = AssetStrToEnum(typeHex); + + if (typeStr == ASSET_LOCAL_STRING) { // localized string asset + result.localStrings << pParseAsset_LocalString(aZoneFileStream); + } else if (typeStr == ASSET_RAW_FILE) { // gsc + auto rawFile = pParseAsset_RawFile(aZoneFileStream); + if (rawFile.length) { + result.rawFiles << rawFile; + } + } else if (typeStr == ASSET_PHYS_PRESET) { // physpreset + pParseAsset_PhysPreset(aZoneFileStream); + } else if (typeStr == ASSET_MODEL) { // xmodel + result.models << pParseAsset_Model(aZoneFileStream); + } else if (typeStr == ASSET_MATERIAL) { // material + pParseAsset_Material(aZoneFileStream); + } else if (typeStr == ASSET_SHADER) { // pixelshader + pParseAsset_Shader(aZoneFileStream); + } else if (typeStr == ASSET_TECH_SET) { // techset include + result.techSets << pParseAsset_TechSet(aZoneFileStream); + } else if (typeStr == ASSET_IMAGE) { // image + result.images << pParseAsset_Image(aZoneFileStream); + } else if (typeStr == ASSET_SOUND) { // loaded_sound + result.sounds << pParseAsset_Sound(aZoneFileStream); + } else if (typeStr == ASSET_COLLISION_MAP) { // col_map_mp + pParseAsset_ColMapMP(aZoneFileStream); + } else if (typeStr == ASSET_MP_MAP) { // game_map_sp + pParseAsset_GameMapSP(aZoneFileStream); + } else if (typeStr == ASSET_SP_MAP) { // game_map_mp + pParseAsset_GameMapMP(aZoneFileStream); + } else if (typeStr == ASSET_LIGHT_DEF) { // lightdef + pParseAsset_LightDef(aZoneFileStream); + } else if (typeStr == ASSET_UI_MAP) { // ui_map + pParseAsset_UIMap(aZoneFileStream); + } else if (typeStr == ASSET_SND_DRIVER_GLOBALS) { // snddriverglobals + pParseAsset_SNDDriverGlobals(aZoneFileStream); + } else if (typeStr == ASSET_AI_TYPE) { // aitype + pParseAsset_AIType(aZoneFileStream); + } else if (typeStr == ASSET_EFFECT) { // aitype + pParseAsset_FX(aZoneFileStream); + } else if (typeStr == ASSET_ANIMATION) { // aitype + result.animations << pParseAsset_Animation(aZoneFileStream); + } else if (typeStr == ASSET_STRING_TABLE) { // string_table + result.stringTables << pParseAsset_StringTable(aZoneFileStream); + } else if (typeStr == ASSET_MENU) { // string_table + result.menuFiles << pParseAsset_MenuFile(aZoneFileStream); + } else if (typeStr == ASSET_WEAPON) { // string_table + pParseAsset_Weapon(aZoneFileStream); + } else if (typeStr == ASSET_D3DBSP) { // string_table + pParseAsset_D3DBSP(aZoneFileStream); + } + } + return result; +} + +LocalString ZoneFile_COD7_PS3::pParseAsset_LocalString(QDataStream *aZoneFileStream) { + LocalString result; + + quint32 stringPtr, aliasPtr; + *aZoneFileStream >> stringPtr >> aliasPtr; + if (stringPtr == 4294967295) { + // Parse local string asset contents + QString localStr; + char localStrChar; + *aZoneFileStream >> localStrChar; + while (localStrChar != 0) { + result.string += localStrChar; + *aZoneFileStream >> localStrChar; + } + } else { + result.string = "String Ptr: " + QString::number(stringPtr); + } + + if (aliasPtr == 4294967295) { + // Parse rawfile name + QString aliasName; + char aliasNameChar; + *aZoneFileStream >> aliasNameChar; + while (aliasNameChar != 0) { + result.alias += aliasNameChar; + *aZoneFileStream >> aliasNameChar; + } + } else { + result.string = "Alias Ptr: " + QString::number(aliasPtr); + } + + return result; +} + +RawFile ZoneFile_COD7_PS3::pParseAsset_RawFile(QDataStream *aZoneFileStream) { + RawFile result; + + // Skip start separator FF FF FF FF (pointer?) + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.length; + + // Skip unknown 4 byte data + aZoneFileStream->skipRawData(4); + + // Parse rawfile path + char scriptPathChar; + *aZoneFileStream >> scriptPathChar; + while (scriptPathChar != 0) { + result.path += scriptPathChar; + *aZoneFileStream >> scriptPathChar; + } + result.path.replace(",", ""); + const QStringList pathParts = result.path.split('/'); + if (pathParts.size() == 0) { + qDebug() << "Failed to parse ff path! " << result.path; + exit(-1); + } + + // Parse gsc contents + char rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + while (rawFileContentsChar != 0 && rawFileContentsChar != -1) { + result.contents += rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + } + return result; +} + +void ZoneFile_COD7_PS3::pParseAsset_PhysPreset(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Model ZoneFile_COD7_PS3::pParseAsset_Model(QDataStream *aZoneFileStream) { + Model result; + + *aZoneFileStream >> result.namePtr >> result.tagCount >> result.rootTagCount + >> result.surfCount >> result.unknownCount >> result.boneNamePtr + >> result.parentListPtr >> result.quatsPtr >> result.transPtr + >> result.partClassPtr >> result.baseMatPtr + >> result.surfsPtr >> result.materialHandlesPtr; + + // Parse XModelLodInfo + for (int i = 1; i <= 4; i++) { + quint32 intDist; + *aZoneFileStream >> intDist; + + std::memcpy(&result.lodInfo[i].dist, &intDist, sizeof(result.lodInfo[i].dist)); + *aZoneFileStream >> result.lodInfo[i].numsurfs >> result.lodInfo[i].surfIndex; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.lodInfo[i].partBits[0] + >> result.lodInfo[i].partBits[1] + >> result.lodInfo[i].partBits[2] + >> result.lodInfo[i].partBits[3]; + } + + *aZoneFileStream >> result.collSurfsPtr >> result.numCollSurfs >> result.contents >> result.boneInfoPtr; + + quint32 intRadius, intMins[3], intMaxs[3]; + *aZoneFileStream >> intRadius >> intMins[0] >> intMins[1] + >> intMins[2] >> intMaxs[0] >> intMaxs[1] >> intMaxs[2]; + + std::memcpy(&result.radius, &intRadius, sizeof(result.radius)); + + std::memcpy(&result.mins[0], &intMins[0], sizeof(result.mins[0])); + std::memcpy(&result.mins[1], &intMins[1], sizeof(result.mins[1])); + std::memcpy(&result.mins[2], &intMins[2], sizeof(result.mins[2])); + + std::memcpy(&result.maxs[0], &intMaxs[0], sizeof(result.maxs[0])); + std::memcpy(&result.maxs[1], &intMaxs[1], sizeof(result.maxs[2])); + std::memcpy(&result.maxs[2], &intMaxs[2], sizeof(result.maxs[3])); + + *aZoneFileStream >> result.numLods >> result.collLod >> result.streamInfoPtr + >> result.memUsage >> result.flags >> result.physPresetPtr >> result.physGeomsPtr; + + // Parse model name + char modelNameChar; + *aZoneFileStream >> modelNameChar; + while (modelNameChar == 0) { + *aZoneFileStream >> modelNameChar; + } + while (modelNameChar != 0) { + result.modelName += modelNameChar; + *aZoneFileStream >> modelNameChar; + } + return result; +} + +Material ZoneFile_COD7_PS3::pParseAsset_Material(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); + + return Material(); +} + +Shader ZoneFile_COD7_PS3::pParseAsset_Shader(QDataStream *aZoneFileStream) { + Shader result = Shader(); + + quint8 minorVersion, majorVersion; + *aZoneFileStream >> minorVersion >> majorVersion; + + quint32 magic; + *aZoneFileStream >> magic; + + // Verify .fxc magic + if (magic != 65534 && magic != 65535) { return result; } + + SHADER_TYPE type = SHADER_NONE; + quint16 rawShaderType; + *aZoneFileStream >> rawShaderType; + if (rawShaderType == 65535) { // Pixel shader + type = SHADER_PIXEL; + } else if (rawShaderType == 65534) { // Vertex shader + type = SHADER_VERTEX; + } + Q_UNUSED(type); + + while (true) { + quint32 instructionToken; + *aZoneFileStream >> instructionToken; + + SHADER_OPCODE opCode = (SHADER_OPCODE)(instructionToken & 0xffff); + + int size; + if (opCode == OPCODE_End) { + break; + } else if (opCode == OPCODE_Comment) { + size = (int)((instructionToken >> 16) & 0x7FFF); + } else { + size = (int)((instructionToken >> 24) & 0x0f); + } + Q_UNUSED(size); + } + + + return result; +} + +TechSet ZoneFile_COD7_PS3::pParseAsset_TechSet(QDataStream *aZoneFileStream) { + TechSet result; + + for (int i = 1; i <= 62; i++) { + quint32 ptr; + *aZoneFileStream >> ptr; + + result.pointers << ptr; + } + qDebug() << aZoneFileStream->device()->pos(); + + // Parse techset name + char techSetNameChar; + *aZoneFileStream >> techSetNameChar; + while (techSetNameChar != 0) { + result.name += techSetNameChar; + *aZoneFileStream >> techSetNameChar; + } + result.name.replace(",", ""); + + return result; +} + +Image ZoneFile_COD7_PS3::pParseAsset_Image(QDataStream *aZoneFileStream) { + Image result; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknowna >> result.unknownb + >> result.unknownc >> result.unknownd + >> result.unknowne >> result.unknownf + >> result.unknowng; + + aZoneFileStream->skipRawData(15 * 4); + *aZoneFileStream >> result.unknownh >> result.unknowni; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknownj; + + aZoneFileStream->skipRawData(4); + + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + result.materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + result.materialName.replace(",", ""); + + if (result.unknowna) { + *aZoneFileStream >> result.unknownk; + *aZoneFileStream >> result.unknownl; + *aZoneFileStream >> result.unknownm; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown1; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown2 >> result.unknown3 + >> result.size1 >> result.size2 + >> result.unknown4 >> result.unknown5; + + aZoneFileStream->skipRawData(4); + + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + result.name += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + + *aZoneFileStream >> result.unknown6 >> result.unknown7; + + QByteArray compressionData(8, Qt::Uninitialized); + aZoneFileStream->readRawData(compressionData.data(), 8); + if (compressionData.contains("DXT1")) { + result.compression = COMPRESSION_DXT1; + } else if (compressionData.contains("DXT3")) { + result.compression = COMPRESSION_DXT3; + } else if (compressionData.contains("DXT5")) { + result.compression = COMPRESSION_DXT5; + } else { + result.compression = COMPRESSION_NONE; + } + + *aZoneFileStream >> result.unknown8 >> result.unknown9; + } + + return result; +} + +SoundAsset ZoneFile_COD7_PS3::pParseAsset_Sound(QDataStream *aZoneFileStream) { + SoundAsset result; + + qDebug() << aZoneFileStream->device()->pos(); + + QByteArray rootNamePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rootNamePtr.data(), 4); + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.count; + + if (rootNamePtr.toHex() == "ffffffff") { + // Read in sound file name + char soundNameChar; + *aZoneFileStream >> soundNameChar; + while (soundNameChar != 0) { + result.name += soundNameChar; + *aZoneFileStream >> soundNameChar; + } + } + + int tagCount = 0; + int resultCount = 0; + for (quint32 i = 0; i < result.count; i++) { + aZoneFileStream->skipRawData(12); + + QByteArray tagPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(tagPtr.data(), 4); + + if (tagPtr.toHex() == "ffffffff") { + tagCount++; + } + aZoneFileStream->skipRawData(4); + + QByteArray pathPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pathPtr.data(), 4); + + if (pathPtr.toHex() == "ffffffff") { + resultCount++; + } + + aZoneFileStream->skipRawData(160); + } + + for (int i = 0; i < tagCount; i++) { + // Read in tag? + QString tag; + char tagChar; + *aZoneFileStream >> tagChar; + while (tagChar != 0) { + tag += tagChar; + *aZoneFileStream >> tagChar; + } + } + + for (int i = 0; i < resultCount; i++) { + Sound sound; + + if (aZoneFileStream->device()->peek(12).toHex().contains("ffffffff00000000")) { + aZoneFileStream->skipRawData(12); + } + + aZoneFileStream->skipRawData(8); + + QByteArray aliasPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(aliasPtr.data(), 4); + + QByteArray namePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(namePtr.data(), 4); + + *aZoneFileStream >> sound.dataLength; + + if (aliasPtr.toHex() == "ffffffff") { + // Read in sound alias name + char soundAliasChar; + *aZoneFileStream >> soundAliasChar; + while (soundAliasChar != 0) { + sound.alias += soundAliasChar; + *aZoneFileStream >> soundAliasChar; + } + } + + if (aZoneFileStream->device()->peek(4) == "RIFF") { + sound.path = sound.alias; + sound.alias = ""; + } else if (namePtr.toHex() == "ffffffff") { + // Read in sound file path + char soundPathChar; + *aZoneFileStream >> soundPathChar; + while (soundPathChar != 0) { + sound.path += soundPathChar; + *aZoneFileStream >> soundPathChar; + } + sound.path.replace(",", ""); + } + + if (sound.dataLength) { + QByteArray data(sound.dataLength, Qt::Uninitialized); + aZoneFileStream->readRawData(data.data(), sound.dataLength); + sound.data = data; + } + result.sounds.append(sound); + } + + return result; +} + +void ZoneFile_COD7_PS3::pParseAsset_ColMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD7_PS3::pParseAsset_GameMapSP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD7_PS3::pParseAsset_GameMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD7_PS3::pParseAsset_LightDef(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD7_PS3::pParseAsset_UIMap(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD7_PS3::pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD7_PS3::pParseAsset_AIType(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD7_PS3::pParseAsset_FX(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Animation ZoneFile_COD7_PS3::pParseAsset_Animation(QDataStream *aZoneFileStream) { + Animation result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.dataByteCount + >> result.dataShortCount + >> result.dataIntCount + >> result.randomDataByteCount + >> result.randomDataIntCount + >> result.numframes + >> result.isLooped + >> result.isDelta + >> result.noneRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.normalTranslatedBoneCount + >> result.preciseTranslatedBoneCount + >> result.staticTranslatedBoneCount + >> result.noneTranslatedBoneCount + >> result.totalBoneCount + >> result.otherBoneCount1 + >> result.otherBoneCount2 + >> result.notifyCount + >> result.assetType + >> result.pad + >> result.randomDataShortCount + >> result.indexCount + >> result.frameRate + >> result.frequency + >> result.boneIDsPtr + >> result.dataBytePtr + >> result.dataShortPtr + >> result.dataIntPtr + >> result.randomDataShortPtr + >> result.randomDataBytePtr + >> result.randomDataIntPtr + >> result.longIndiciesPtr + >> result.notificationsPtr + >> result.deltaPartsPtr; + + // Read in x_anim file name + QString xAnimName; + char xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + while (xAnimNameChar != 0) { + result.name += xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + } + + // Parse x_anim index header + QVector sectionLengths; + for (int i = 0; i < result.numframes; i++) { + quint8 sectionlength; + *aZoneFileStream >> sectionlength; + sectionLengths.push_back(sectionlength); + // Skip padding + aZoneFileStream->skipRawData(1); + } + // Skip unknown section + aZoneFileStream->skipRawData(2 * 8); + + return result; +} + +MenuFile ZoneFile_COD7_PS3::pParseAsset_MenuFile(QDataStream *aZoneFileStream) { + //MENU_FILE + MenuFile result; + + aZoneFileStream->skipRawData(4); // Separator + + // Parse menu def count + *aZoneFileStream >> result.menuCount; + + // Clearly misparsed, never have this much + if (result.menuCount > 1000) { + qDebug() << "Failure reported when parsing menu file."; + return result; + } + for (uint i = 0; i < result.menuCount; i++) { + Menu menu; + + aZoneFileStream->skipRawData(4); // Separator + + // Read in x_anim file name + char menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + while (menuFilepathChar != 0) { + menu.filePath += menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + } + aZoneFileStream->skipRawData(4); // Separator + + *aZoneFileStream >> menu.menuNamePtr; + + float menuRectX, menuRectY, menuRectWidth, menuRectHeight; + *aZoneFileStream >> menuRectX >> menuRectY >> menuRectWidth >> menuRectHeight; + menu.rect = QRectF(menuRectX, menuRectY, menuRectWidth, menuRectHeight); + + quint32 hAlignInt, vAlignInt; + *aZoneFileStream >> hAlignInt >> vAlignInt; + menu.hAlign = (MENU_H_ALIGNMENT)hAlignInt; + menu.vAlign = (MENU_V_ALIGNMENT)vAlignInt; + + float rectClientX, rectClientY, rectClientWidth, rectClientHeight; + *aZoneFileStream >> rectClientX >> rectClientY >> rectClientWidth >> rectClientHeight; + menu.clientRect = QRectF(rectClientX, rectClientY, rectClientWidth, rectClientHeight); + + quint32 hClientAlignInt, vClientAlignInt, styleInt, borderInt; + *aZoneFileStream >> hClientAlignInt >> vClientAlignInt >> menu.groupPtr + >> styleInt >> borderInt >> menu.ownerDraw >> menu.ownerDrawFlags + >> menu.borderSize >> menu.staticFlags >> menu.dynamicFlags >> menu.nextTime; + menu.hClientAlign = (MENU_H_ALIGNMENT)hClientAlignInt; + menu.vClientAlign = (MENU_V_ALIGNMENT)vClientAlignInt; + menu.style = (MENU_WINDOW_STYLE)styleInt; + menu.border = (MENU_WINDOW_BORDER)borderInt; + + float foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA, + backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA, + borderColorR, borderColorG, borderColorB, borderColorA, + outlineColorR, outlineColorG, outlineColorB, outlineColorA; + *aZoneFileStream >> foregroundColorR >> foregroundColorG >> foregroundColorB >> foregroundColorA + >> backgroundColorR >> backgroundColorG >> backgroundColorB >> backgroundColorA + >> borderColorR >> borderColorG >> borderColorB >> borderColorA + >> outlineColorR >> outlineColorG >> outlineColorB >> outlineColorA; + + menu.foregroundColor = QColor(foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA); + menu.backgroundColor = QColor(backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA); + menu.borderColor = QColor(borderColorR, borderColorG, borderColorB, borderColorA); + menu.outlineColor = QColor(outlineColorR, outlineColorG, outlineColorB, outlineColorA); + + *aZoneFileStream >> menu.materialPtr >> menu.fontPtr >> menu.fullScreen >> menu.itemCount + >> menu.fontIndex >> menu.cursorItem >> menu.fadeCycle >> menu.fadeClamp + >> menu.fadeAmount >> menu.fadeInAmount >> menu.blurRadius >> menu.onOpenPtr + >> menu.onFocusPtr >> menu.onClosePtr >> menu.onESCPtr >> menu.onKeyPtr + >> menu.visibleExpCount >> menu.expEntryPtr >> menu.allowedBindingPtr + >> menu.soundNamePtr >> menu.imageTrack; + + float focusColorR, focusColorG, focusColorB, focusColorA, + disabledColorR, disabledColorG, disabledColorB, disabledColorA; + *aZoneFileStream >> focusColorR >> focusColorG >> focusColorB >> focusColorA + >> disabledColorR >> disabledColorG >> disabledColorB >> disabledColorA; + menu.focusColor = QColor(focusColorR, focusColorG, focusColorB, focusColorA); + menu.disabledColor = QColor(disabledColorR, disabledColorG, disabledColorB, disabledColorA); + + *aZoneFileStream >> menu.rectXExpCount >> menu.rectXExpPtr >> menu.rectYExpCount >> menu.rectYExpPtr; + + aZoneFileStream->skipRawData(4); // Separator + + char menuDefNameChar; + int menuDefNameLen = 0; + *aZoneFileStream >> menuDefNameChar; + while (menuDefNameChar != 0 && menuDefNameLen < 30) { + menuDefNameLen++; + menu.name += menuDefNameChar; + *aZoneFileStream >> menuDefNameChar; + } + + char defStringChar; + int defStringLen = 0; + *aZoneFileStream >> defStringChar; + while (defStringChar != 0 && defStringLen < 30) { + defStringLen++; + menu.definition += defStringChar; + *aZoneFileStream >> defStringChar; + } + aZoneFileStream->skipRawData(4 * 10); + + *aZoneFileStream >> menu.itemWindowDefNamePtr; + + float itemRectX, itemRectY, itemRectWidth, itemRectHeight; + *aZoneFileStream >> itemRectX >> itemRectY >> itemRectWidth >> itemRectHeight; + menu.itemRect = QRectF(itemRectX, itemRectY, itemRectWidth, itemRectHeight); + + *aZoneFileStream >> menu.itemHAlignment >> menu.itemVAlignment >> menu.itemGroupPtr + >> menu.itemWindowStyle >> menu.itemWindowBorder >> menu.itemOwnerDraw + >> menu.itemOwnerDrawFlags >> menu.itemBorderSize >> menu.itemStaticFlags + >> menu.itemDynamicFlags >> menu.itemNextTime; + + float itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA, + itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA, + itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA, + itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA; + *aZoneFileStream >> itemForegroundColorR >> itemForegroundColorG >> itemForegroundColorB >> itemForegroundColorA + >> itemBackgroundColorR >> itemBackgroundColorG >> itemBackgroundColorB >> itemBackgroundColorA + >> itemBorderColorR >> itemBorderColorG >> itemBorderColorB >> itemBorderColorA + >> itemOutlineColorR >> itemOutlineColorG >> itemOutlineColorB >> itemOutlineColorA; + + menu.itemForegroundColor = QColor(itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA); + menu.itemBackgroundColor = QColor(itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA); + menu.itemBorderColor = QColor(itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA); + menu.itemOutlineColor = QColor(itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA); + + *aZoneFileStream >> menu.itemMaterialPtr; + + float itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight; + *aZoneFileStream >> itemTextRectX >> itemTextRectY >> itemTextRectWidth >> itemTextRectHeight; + menu.itemTextRect = QRectF(itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight); + + quint32 hItemTextAlignInt, vItemTextAlignInt, itemType, fontTypeInt, textStyleInt; + *aZoneFileStream >> hItemTextAlignInt >> vItemTextAlignInt >> itemType >> menu.dataType + >> menu.alignment >> fontTypeInt >> menu.textAlignMode >> menu.textalignx >> menu.textaligny + >> menu.textscale >> textStyleInt >> menu.gameMsgWindowIndex >> menu.gameMsgWindowMode + >> menu.testPtr >> menu.textSavegameInfo >> menu.parentPtr; + menu.itemText_hAlign = (MENU_H_ALIGNMENT)hItemTextAlignInt; + menu.itemText_vAlign = (MENU_V_ALIGNMENT)vItemTextAlignInt; + menu.itemType = (MENU_ITEM_TYPE)itemType; + menu.fontEnum = (MENU_FONT_TYPE)fontTypeInt; + menu.textStyle = (MENU_ITEM_TEXTSTYLE)textStyleInt; + + *aZoneFileStream >> menu.mouseEnterText >> menu.mouseExitText >> menu.mouseEnter >> menu.mouseExit + >> menu.action >> menu.onAccept >> menu.onFocus >> menu.leaveFocus >> menu.dvar >> menu.dvarTest + >> menu.keyHandlerPtr >> menu.enableDvarPtr >> menu.dvarFlags >> menu.focusSoundPtr + >> menu.special >> menu.cursorPos; + + // itemDefData_t typeData; + + // listBoxDef_s *listBox; + + *aZoneFileStream >> menu.startPos >> menu.endPos >> menu.drawPadding; + + *aZoneFileStream >> menu.elementWidth >> menu.elementHeight; + + *aZoneFileStream >> menu.elementStyle >> menu.numColumns; + + //columnInfo_s columnInfo[16]; + + *aZoneFileStream >> menu.doubleClickPtr; + + + *aZoneFileStream >> menu.notselectable >> menu.noScrollBars >> menu.usePaging; + + float itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA, + itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA, + itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA; + *aZoneFileStream >> itemSelectBorderColorR >> itemSelectBorderColorG >> itemSelectBorderColorB >> itemSelectBorderColorA + >> itemDisableColorR >> itemDisableColorG >> itemDisableColorB >> itemDisableColorA + >> itemFocusColorR >> itemFocusColorG >> itemFocusColorB >> itemFocusColorA; + menu.itemSelectBorderColor = QColor(itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA); + menu.itemDisableColor = QColor(itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA); + menu.itemFocusColor = QColor(itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA); + + *aZoneFileStream >> menu.selectIconPtr >> menu.backgroundItemListboxPtr >> menu.highlightTexturePtr; + + // editFieldDef_s *editField; + + *aZoneFileStream >> menu.minVal >> menu.maxVal >> menu.defVal >> menu.range >> menu.maxChars + >> menu.maxCharsGotoNext >> menu.maxPaintChars >> menu.paintOffset; + + // multiDef_s *multi; + + for (int i = 0; i < 32; i++) { + quint32 dvarList; + *aZoneFileStream >> dvarList; + menu.dvarListPtrs.push_back(dvarList); + } + + for (int i = 0; i < 32; i++) { + quint32 dvarStr; + *aZoneFileStream >> dvarStr; + menu.dvarStrPtrs.push_back(dvarStr); + } + + for (int i = 0; i < 32; i++) { + float dvarValue; + *aZoneFileStream >> dvarValue; + menu.dvarValues.push_back(dvarValue); + } + + *aZoneFileStream >> menu.count >> menu.strDef >> menu.enumDvarNamePtr; + aZoneFileStream->skipRawData(4); + //>> menu.dataPtr + *aZoneFileStream >> menu.itemImageTrack; + + qDebug() << aZoneFileStream->device()->pos(); + + //statement_s visibleExp; + //statement_s textExp; + //statement_s materialExp; + //statement_s rectXExp; + //statement_s rectYExp; + //statement_s rectWExp; + //statement_s rectHExp; + //statement_s foreColorAExp; + result.menuDefs << menu; + } + return result; +} + +void ZoneFile_COD7_PS3::pParseAsset_Weapon(QDataStream *aZoneFileStream) { + //WEAPON_FILE + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD7_PS3::pParseAsset_D3DBSP(QDataStream *aZoneFileStream) { + //D3DBSP_DUMP + Q_UNUSED(aZoneFileStream); +} + +StringTable ZoneFile_COD7_PS3::pParseAsset_StringTable(QDataStream *aZoneFileStream) { + StringTable result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.columnCount + >> result.rowCount; + + // Todo fix this + result.columnCount = 0; + result.rowCount = 0; + + aZoneFileStream->skipRawData(4); + + QString stringTableName; + char stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + while (stringTableNameChar != 0) { + result.name += stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + } + + for (quint32 i = 0; i < result.rowCount; i++) { + QByteArray pointerData(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pointerData.data(), 4); + result.tablePointers.push_back(pointerData.toHex()); + + aZoneFileStream->skipRawData(4); + } + + for (const QString &pointerAddr : result.tablePointers) { + QString leadingContent = ""; + if (pointerAddr == "FFFFFFFF") { + char leadingContentChar; + *aZoneFileStream >> leadingContentChar; + while (leadingContentChar != 0) { + leadingContent += leadingContentChar; + *aZoneFileStream >> leadingContentChar; + } + } else { + leadingContent = pointerAddr; + } + + QString content; + char contentChar; + *aZoneFileStream >> contentChar; + while (contentChar != 0) { + content += contentChar; + *aZoneFileStream >> contentChar; + } + result.content[leadingContent] = content; + } + return result; +} + +AssetType ZoneFile_COD7_PS3::AssetStrToEnum(const QString aAssetType) { + const QString cleanedType = aAssetType.toUpper(); + if (cleanedType == "17000000") { // localized string PARTIALLY VERIFIED + return ASSET_LOCAL_STRING; + } else if (cleanedType == "20000000") { // raw_file PARTIALLY VERIFIED + return ASSET_RAW_FILE; + } else if (cleanedType == "1A000000") { // fx PARTIALLY VERIFIED + return ASSET_EFFECT; + } else if (cleanedType == "09000000") { // loaded_sound PARTIALLY VERIFIED + return ASSET_SOUND; + } else if (cleanedType == "04000000") { // x_anim PARTIALLY VERIFIED + return ASSET_ANIMATION; + } else if (cleanedType == "0C000000") { // collision_map PARTIALLY VERIFIED + return ASSET_COLLISION_MAP; + } else if (cleanedType == "21000000") { // string_table PARTIALLY VERIFIED + return ASSET_STRING_TABLE; + } else if (cleanedType == "15000000") { // menu_file PARTIALLY VERIFIED + return ASSET_MENU; + } else if (cleanedType == "07000000") { // tech set PARTIALLY VERIFIED + return ASSET_TECH_SET; + } else if (cleanedType == "18000000") { // weapon PARTIALLY VERIFIED + return ASSET_WEAPON; + } else if (cleanedType == "11000000") { // gfx map PARTIALLY VERIFIED + return ASSET_GFX_MAP; + } else if (cleanedType == "12000000") { // light_def PARTIALLY VERIFIED + return ASSET_LIGHT_DEF; + } else if (cleanedType == "14000000") { // font PARTIALLY VERIFIED + return ASSET_FONT; + } else if (cleanedType == "05000000") { // xmodel PARTIALLY VERIFIED + return ASSET_MODEL; + } else if (cleanedType == "0D000000") { // d3dbsp PARTIALLY VERIFIED + return ASSET_D3DBSP; + } else if (cleanedType == "06000000") { // image PARTIALLY VERIFIED + return ASSET_IMAGE; + } else if (cleanedType == "0E000000") { // game map sp PARTIALLY VERIFIED + return ASSET_GAME_MAP_SP; + } else if (cleanedType == "0B000000") { // col map sp PARTIALLY VERIFIED + return ASSET_COL_MAP_SP; + } + return ASSET_NONE; +} + +QByteArray ZoneFile_COD7_PS3::GetBinaryData() { + QByteArray result; + + return result; +} diff --git a/libs/zonefile/PS3/zonefile_cod7_ps3.h b/libs/zonefile/PS3/zonefile_cod7_ps3.h new file mode 100644 index 0000000..73ddd3e --- /dev/null +++ b/libs/zonefile/PS3/zonefile_cod7_ps3.h @@ -0,0 +1,52 @@ +#ifndef ZONEFILE_COD7_PS3_H +#define ZONEFILE_COD7_PS3_H + +#include "zonefile.h" + +class ZoneFile_COD7_PS3 : public ZoneFile +{ +public: + ZoneFile_COD7_PS3(); + ~ZoneFile_COD7_PS3(); + + bool Load(const QByteArray aFileData) override; + AssetType AssetStrToEnum(const QString aAssetType) override; + + QByteArray GetBinaryData() override; + +protected: + void pParseZoneHeader(QDataStream *aZoneFileStream) override; + quint32 pParseZoneSize(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsA(QDataStream *aZoneFileStream) override; + quint32 pParseZoneTagCount(QDataStream *aZoneFileStream) override; + quint32 pParseZoneRecordCount(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsB(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsC(QDataStream *aZoneFileStream) override; + QStringList pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) override; + QStringList pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) override; + AssetMap pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) override; + LocalString pParseAsset_LocalString(QDataStream *aZoneFileStream) override; + RawFile pParseAsset_RawFile(QDataStream *aZoneFileStream) override; + void pParseAsset_PhysPreset(QDataStream *aZoneFileStream) override; + Model pParseAsset_Model(QDataStream *aZoneFileStream) override; + Material pParseAsset_Material(QDataStream *aZoneFileStream) override; + Shader pParseAsset_Shader(QDataStream *aZoneFileStream) override; + TechSet pParseAsset_TechSet(QDataStream *aZoneFileStream) override; + Image pParseAsset_Image(QDataStream *aZoneFileStream) override; + SoundAsset pParseAsset_Sound(QDataStream *aZoneFileStream) override; + void pParseAsset_ColMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapSP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_LightDef(QDataStream *aZoneFileStream) override; + void pParseAsset_UIMap(QDataStream *aZoneFileStream) override; + void pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) override; + void pParseAsset_AIType(QDataStream *aZoneFileStream) override; + void pParseAsset_FX(QDataStream *aZoneFileStream) override; + Animation pParseAsset_Animation(QDataStream *aZoneFileStream) override; + MenuFile pParseAsset_MenuFile(QDataStream *aZoneFileStream) override; + void pParseAsset_Weapon(QDataStream *aZoneFileStream) override; + void pParseAsset_D3DBSP(QDataStream *aZoneFileStream) override; + StringTable pParseAsset_StringTable(QDataStream *aZoneFileStream) override; +}; + +#endif // ZONEFILE_COD7_PS3_H diff --git a/libs/zonefile/PS3/zonefile_cod8_ps3.cpp b/libs/zonefile/PS3/zonefile_cod8_ps3.cpp new file mode 100644 index 0000000..00eaf6d --- /dev/null +++ b/libs/zonefile/PS3/zonefile_cod8_ps3.cpp @@ -0,0 +1,1077 @@ +#include "zonefile_cod8_ps3.h" + +#include +#include +#include + +ZoneFile_COD8_PS3::ZoneFile_COD8_PS3() +{ + +} + +ZoneFile_COD8_PS3::~ZoneFile_COD8_PS3() +{ + +} + +bool ZoneFile_COD8_PS3::Load(const QByteArray aFileData) { + // Open zone file as little endian stream + QDataStream zoneFileStream(aFileData); + zoneFileStream.setByteOrder(QDataStream::BigEndian); + + // Parse data from zone file header + pParseZoneHeader(&zoneFileStream); + zoneFileStream.device()->seek(zoneFileStream.device()->pos() - 1); + SetRecords(pParseZoneIndex(&zoneFileStream, GetRecordCount())); + SetAssetMap(pParseAssets(&zoneFileStream, GetRecords())); + + return true; +} + +void ZoneFile_COD8_PS3::pParseZoneHeader(QDataStream *aZoneFileStream) { + quint32 size = pParseZoneSize(aZoneFileStream); + SetSize(size); + + pParseZoneUnknownsA(aZoneFileStream); + + quint32 tagCount = pParseZoneTagCount(aZoneFileStream); + SetTagCount(tagCount); + + pParseZoneUnknownsB(aZoneFileStream); + + quint32 recordCount = pParseZoneRecordCount(aZoneFileStream); + SetRecordCount(recordCount); + + if (tagCount) { + pParseZoneUnknownsC(aZoneFileStream); + SetTags(pParseZoneTags(aZoneFileStream, tagCount)); + } else { + aZoneFileStream->skipRawData(4); + } +} + +quint32 ZoneFile_COD8_PS3::pParseZoneSize(QDataStream *aZoneFileStream) { + quint32 zoneFileSize; + *aZoneFileStream >> zoneFileSize; + if (zoneFileSize <= 0) { + qDebug() << "Tried to open empty zone file!"; + exit(-1); + } + zoneFileSize += 36; + return zoneFileSize; +} + +/* + ParseZoneUnknownsA() + + Parses the 1st section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD8_PS3::pParseZoneUnknownsA(QDataStream *aZoneFileStream) { + // Byte 4-7, 8-11, 12-15: unknown + QByteArray unknown1(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown1.data(), 4); + + QByteArray unknown2(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown2.data(), 4); + + QByteArray unknown3(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown3.data(), 4); + + // Byte 16-19, 20-23: empty/unknown + QByteArray unknown4(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown4.data(), 4); + + QByteArray unknown5(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown5.data(), 4); + + // Byte 24-27: somehow related to the filesize, but smaller value + QByteArray unknown6(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown6.data(), 4); + + // Byte 28-31, 32-35: unknown + QByteArray unknown7(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown7.data(), 4); + + QByteArray unknown8(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown8.data(), 4); +} + +/* + ParseZoneTagCount() + + Parses the number of string tags in the zone index +*/ +quint32 ZoneFile_COD8_PS3::pParseZoneTagCount(QDataStream *aZoneFileStream) { + quint32 tagCount; + *aZoneFileStream >> tagCount; + return tagCount; +} + +/* + ParseZoneRecordCount() + + Parses the number of records in the zone index +*/ +quint32 ZoneFile_COD8_PS3::pParseZoneRecordCount(QDataStream *aZoneFileStream) { + quint32 recordCount; + *aZoneFileStream >> recordCount; + return recordCount; +} + +/* + ParseZoneUnknownsB() + + Parses the 2nd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD8_PS3::pParseZoneUnknownsB(QDataStream *aZoneFileStream) { + // Byte 44-47: Unknown/empty? + QByteArray unknown9(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown9.data(), 4); +} + +/* + pParseZoneUnknownsC() + + Parses the 3rd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD8_PS3::pParseZoneUnknownsC(QDataStream *aZoneFileStream) { + // Byte 40-43: Unknown/empty? + QByteArray unknown10(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown10.data(), 4); + + // Byte 44-47: Unknown/empty? + QByteArray unknown11(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown11.data(), 4); +} + +/* + ParseZoneTags() + + Parses the string tags ate the start of zone file +*/ +QStringList ZoneFile_COD8_PS3::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) { + QStringList tags; + + // Byte 48-51: Repeated separators? ÿÿÿÿ x i + aZoneFileStream->skipRawData(4 * (tagCount - 1)); + + // Parse tags/strings before index + QString zoneTag; + char zoneTagChar; + for (quint32 i = 0; i < tagCount; i++) { + *aZoneFileStream >> zoneTagChar; + while (zoneTagChar != 0) { + zoneTag += zoneTagChar; + *aZoneFileStream >> zoneTagChar; + } + tags << zoneTag; + zoneTag.clear(); + } + return tags; +} + +/* + ParseZoneIndex() + + Parse the binary zone index data and populate table +*/ +QStringList ZoneFile_COD8_PS3::pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) { + QStringList result; + + // Don't parse if no records + if (!recordCount) { return result; } + + if (aZoneFileStream->device()->peek(4).toHex().contains("ffff")) { + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 2); + } + + // Parse index & map found asset types + for (quint32 i = 0; i <= recordCount; i++) { + // Skip record start + QByteArray rawAssetType(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rawAssetType.data(), 4); + result << rawAssetType.toHex(); + + // Skip separator + aZoneFileStream->skipRawData(4); + } + return result; +} + +AssetMap ZoneFile_COD8_PS3::pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) { + AssetMap result; + + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 8); + + for (int i = 0; i < assetOrder.size(); i++) { + const QString typeHex = assetOrder[i]; + const AssetType typeStr = AssetStrToEnum(typeHex); + + if (typeStr == ASSET_LOCAL_STRING) { // localized string asset + result.localStrings << pParseAsset_LocalString(aZoneFileStream); + } else if (typeStr == ASSET_RAW_FILE) { // gsc + auto rawFile = pParseAsset_RawFile(aZoneFileStream); + if (rawFile.length) { + result.rawFiles << rawFile; + } + } else if (typeStr == ASSET_PHYS_PRESET) { // physpreset + pParseAsset_PhysPreset(aZoneFileStream); + } else if (typeStr == ASSET_MODEL) { // xmodel + result.models << pParseAsset_Model(aZoneFileStream); + } else if (typeStr == ASSET_MATERIAL) { // material + pParseAsset_Material(aZoneFileStream); + } else if (typeStr == ASSET_SHADER) { // pixelshader + pParseAsset_Shader(aZoneFileStream); + } else if (typeStr == ASSET_TECH_SET) { // techset include + result.techSets << pParseAsset_TechSet(aZoneFileStream); + } else if (typeStr == ASSET_IMAGE) { // image + result.images << pParseAsset_Image(aZoneFileStream); + } else if (typeStr == ASSET_SOUND) { // loaded_sound + result.sounds << pParseAsset_Sound(aZoneFileStream); + } else if (typeStr == ASSET_COLLISION_MAP) { // col_map_mp + pParseAsset_ColMapMP(aZoneFileStream); + } else if (typeStr == ASSET_MP_MAP) { // game_map_sp + pParseAsset_GameMapSP(aZoneFileStream); + } else if (typeStr == ASSET_SP_MAP) { // game_map_mp + pParseAsset_GameMapMP(aZoneFileStream); + } else if (typeStr == ASSET_LIGHT_DEF) { // lightdef + pParseAsset_LightDef(aZoneFileStream); + } else if (typeStr == ASSET_UI_MAP) { // ui_map + pParseAsset_UIMap(aZoneFileStream); + } else if (typeStr == ASSET_SND_DRIVER_GLOBALS) { // snddriverglobals + pParseAsset_SNDDriverGlobals(aZoneFileStream); + } else if (typeStr == ASSET_AI_TYPE) { // aitype + pParseAsset_AIType(aZoneFileStream); + } else if (typeStr == ASSET_EFFECT) { // aitype + pParseAsset_FX(aZoneFileStream); + } else if (typeStr == ASSET_ANIMATION) { // aitype + result.animations << pParseAsset_Animation(aZoneFileStream); + } else if (typeStr == ASSET_STRING_TABLE) { // string_table + result.stringTables << pParseAsset_StringTable(aZoneFileStream); + } else if (typeStr == ASSET_MENU) { // string_table + result.menuFiles << pParseAsset_MenuFile(aZoneFileStream); + } else if (typeStr == ASSET_WEAPON) { // string_table + pParseAsset_Weapon(aZoneFileStream); + } else if (typeStr == ASSET_D3DBSP) { // string_table + pParseAsset_D3DBSP(aZoneFileStream); + } + } + return result; +} + +LocalString ZoneFile_COD8_PS3::pParseAsset_LocalString(QDataStream *aZoneFileStream) { + LocalString result; + + quint32 stringPtr, aliasPtr; + *aZoneFileStream >> stringPtr >> aliasPtr; + if (stringPtr == 4294967295) { + // Parse local string asset contents + QString localStr; + char localStrChar; + *aZoneFileStream >> localStrChar; + while (localStrChar != 0) { + result.string += localStrChar; + *aZoneFileStream >> localStrChar; + } + } else { + result.string = "String Ptr: " + QString::number(stringPtr); + } + + if (aliasPtr == 4294967295) { + // Parse rawfile name + QString aliasName; + char aliasNameChar; + *aZoneFileStream >> aliasNameChar; + while (aliasNameChar != 0) { + result.alias += aliasNameChar; + *aZoneFileStream >> aliasNameChar; + } + } else { + result.string = "Alias Ptr: " + QString::number(aliasPtr); + } + + return result; +} + +RawFile ZoneFile_COD8_PS3::pParseAsset_RawFile(QDataStream *aZoneFileStream) { + RawFile result; + + // Skip start separator FF FF FF FF (pointer?) + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.length; + + // Skip unknown 4 byte data + aZoneFileStream->skipRawData(4); + + // Parse rawfile path + char scriptPathChar; + *aZoneFileStream >> scriptPathChar; + while (scriptPathChar != 0) { + result.path += scriptPathChar; + *aZoneFileStream >> scriptPathChar; + } + result.path.replace(",", ""); + const QStringList pathParts = result.path.split('/'); + if (pathParts.size() == 0) { + qDebug() << "Failed to parse ff path! " << result.path; + exit(-1); + } + + // Parse gsc contents + char rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + while (rawFileContentsChar != 0 && rawFileContentsChar != -1) { + result.contents += rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + } + return result; +} + +void ZoneFile_COD8_PS3::pParseAsset_PhysPreset(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Model ZoneFile_COD8_PS3::pParseAsset_Model(QDataStream *aZoneFileStream) { + Model result; + + *aZoneFileStream >> result.namePtr >> result.tagCount >> result.rootTagCount + >> result.surfCount >> result.unknownCount >> result.boneNamePtr + >> result.parentListPtr >> result.quatsPtr >> result.transPtr + >> result.partClassPtr >> result.baseMatPtr + >> result.surfsPtr >> result.materialHandlesPtr; + + // Parse XModelLodInfo + for (int i = 1; i <= 4; i++) { + quint32 intDist; + *aZoneFileStream >> intDist; + + std::memcpy(&result.lodInfo[i].dist, &intDist, sizeof(result.lodInfo[i].dist)); + *aZoneFileStream >> result.lodInfo[i].numsurfs >> result.lodInfo[i].surfIndex; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.lodInfo[i].partBits[0] + >> result.lodInfo[i].partBits[1] + >> result.lodInfo[i].partBits[2] + >> result.lodInfo[i].partBits[3]; + } + + *aZoneFileStream >> result.collSurfsPtr >> result.numCollSurfs >> result.contents >> result.boneInfoPtr; + + quint32 intRadius, intMins[3], intMaxs[3]; + *aZoneFileStream >> intRadius >> intMins[0] >> intMins[1] + >> intMins[2] >> intMaxs[0] >> intMaxs[1] >> intMaxs[2]; + + std::memcpy(&result.radius, &intRadius, sizeof(result.radius)); + + std::memcpy(&result.mins[0], &intMins[0], sizeof(result.mins[0])); + std::memcpy(&result.mins[1], &intMins[1], sizeof(result.mins[1])); + std::memcpy(&result.mins[2], &intMins[2], sizeof(result.mins[2])); + + std::memcpy(&result.maxs[0], &intMaxs[0], sizeof(result.maxs[0])); + std::memcpy(&result.maxs[1], &intMaxs[1], sizeof(result.maxs[2])); + std::memcpy(&result.maxs[2], &intMaxs[2], sizeof(result.maxs[3])); + + *aZoneFileStream >> result.numLods >> result.collLod >> result.streamInfoPtr + >> result.memUsage >> result.flags >> result.physPresetPtr >> result.physGeomsPtr; + + // Parse model name + char modelNameChar; + *aZoneFileStream >> modelNameChar; + while (modelNameChar == 0) { + *aZoneFileStream >> modelNameChar; + } + while (modelNameChar != 0) { + result.modelName += modelNameChar; + *aZoneFileStream >> modelNameChar; + } + return result; +} + +Material ZoneFile_COD8_PS3::pParseAsset_Material(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); + + return Material(); +} + +Shader ZoneFile_COD8_PS3::pParseAsset_Shader(QDataStream *aZoneFileStream) { + Shader result = Shader(); + + quint8 minorVersion, majorVersion; + *aZoneFileStream >> minorVersion >> majorVersion; + + quint32 magic; + *aZoneFileStream >> magic; + + // Verify .fxc magic + if (magic != 65534 && magic != 65535) { return result; } + + SHADER_TYPE type = SHADER_NONE; + quint16 rawShaderType; + *aZoneFileStream >> rawShaderType; + if (rawShaderType == 65535) { // Pixel shader + type = SHADER_PIXEL; + } else if (rawShaderType == 65534) { // Vertex shader + type = SHADER_VERTEX; + } + Q_UNUSED(type); + + while (true) { + quint32 instructionToken; + *aZoneFileStream >> instructionToken; + + SHADER_OPCODE opCode = (SHADER_OPCODE)(instructionToken & 0xffff); + + int size; + if (opCode == OPCODE_End) { + break; + } else if (opCode == OPCODE_Comment) { + size = (int)((instructionToken >> 16) & 0x7FFF); + } else { + size = (int)((instructionToken >> 24) & 0x0f); + } + Q_UNUSED(size); + } + + + return result; +} + +TechSet ZoneFile_COD8_PS3::pParseAsset_TechSet(QDataStream *aZoneFileStream) { + TechSet result; + + for (int i = 1; i <= 62; i++) { + quint32 ptr; + *aZoneFileStream >> ptr; + + result.pointers << ptr; + } + qDebug() << aZoneFileStream->device()->pos(); + + // Parse techset name + char techSetNameChar; + *aZoneFileStream >> techSetNameChar; + while (techSetNameChar != 0) { + result.name += techSetNameChar; + *aZoneFileStream >> techSetNameChar; + } + result.name.replace(",", ""); + + return result; +} + +Image ZoneFile_COD8_PS3::pParseAsset_Image(QDataStream *aZoneFileStream) { + Image result; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknowna >> result.unknownb + >> result.unknownc >> result.unknownd + >> result.unknowne >> result.unknownf + >> result.unknowng; + + aZoneFileStream->skipRawData(15 * 4); + *aZoneFileStream >> result.unknownh >> result.unknowni; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknownj; + + aZoneFileStream->skipRawData(4); + + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + result.materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + result.materialName.replace(",", ""); + + if (result.unknowna) { + *aZoneFileStream >> result.unknownk; + *aZoneFileStream >> result.unknownl; + *aZoneFileStream >> result.unknownm; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown1; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown2 >> result.unknown3 + >> result.size1 >> result.size2 + >> result.unknown4 >> result.unknown5; + + aZoneFileStream->skipRawData(4); + + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + result.name += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + + *aZoneFileStream >> result.unknown6 >> result.unknown7; + + QByteArray compressionData(8, Qt::Uninitialized); + aZoneFileStream->readRawData(compressionData.data(), 8); + if (compressionData.contains("DXT1")) { + result.compression = COMPRESSION_DXT1; + } else if (compressionData.contains("DXT3")) { + result.compression = COMPRESSION_DXT3; + } else if (compressionData.contains("DXT5")) { + result.compression = COMPRESSION_DXT5; + } else { + result.compression = COMPRESSION_NONE; + } + + *aZoneFileStream >> result.unknown8 >> result.unknown9; + } + + return result; +} + +SoundAsset ZoneFile_COD8_PS3::pParseAsset_Sound(QDataStream *aZoneFileStream) { + SoundAsset result; + + qDebug() << aZoneFileStream->device()->pos(); + + QByteArray rootNamePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rootNamePtr.data(), 4); + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.count; + + if (rootNamePtr.toHex() == "ffffffff") { + // Read in sound file name + char soundNameChar; + *aZoneFileStream >> soundNameChar; + while (soundNameChar != 0) { + result.name += soundNameChar; + *aZoneFileStream >> soundNameChar; + } + } + + int tagCount = 0; + int resultCount = 0; + for (quint32 i = 0; i < result.count; i++) { + aZoneFileStream->skipRawData(12); + + QByteArray tagPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(tagPtr.data(), 4); + + if (tagPtr.toHex() == "ffffffff") { + tagCount++; + } + aZoneFileStream->skipRawData(4); + + QByteArray pathPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pathPtr.data(), 4); + + if (pathPtr.toHex() == "ffffffff") { + resultCount++; + } + + aZoneFileStream->skipRawData(160); + } + + for (int i = 0; i < tagCount; i++) { + // Read in tag? + QString tag; + char tagChar; + *aZoneFileStream >> tagChar; + while (tagChar != 0) { + tag += tagChar; + *aZoneFileStream >> tagChar; + } + } + + for (int i = 0; i < resultCount; i++) { + Sound sound; + + if (aZoneFileStream->device()->peek(12).toHex().contains("ffffffff00000000")) { + aZoneFileStream->skipRawData(12); + } + + aZoneFileStream->skipRawData(8); + + QByteArray aliasPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(aliasPtr.data(), 4); + + QByteArray namePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(namePtr.data(), 4); + + *aZoneFileStream >> sound.dataLength; + + if (aliasPtr.toHex() == "ffffffff") { + // Read in sound alias name + char soundAliasChar; + *aZoneFileStream >> soundAliasChar; + while (soundAliasChar != 0) { + sound.alias += soundAliasChar; + *aZoneFileStream >> soundAliasChar; + } + } + + if (aZoneFileStream->device()->peek(4) == "RIFF") { + sound.path = sound.alias; + sound.alias = ""; + } else if (namePtr.toHex() == "ffffffff") { + // Read in sound file path + char soundPathChar; + *aZoneFileStream >> soundPathChar; + while (soundPathChar != 0) { + sound.path += soundPathChar; + *aZoneFileStream >> soundPathChar; + } + sound.path.replace(",", ""); + } + + if (sound.dataLength) { + QByteArray data(sound.dataLength, Qt::Uninitialized); + aZoneFileStream->readRawData(data.data(), sound.dataLength); + sound.data = data; + } + result.sounds.append(sound); + } + + return result; +} + +void ZoneFile_COD8_PS3::pParseAsset_ColMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD8_PS3::pParseAsset_GameMapSP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD8_PS3::pParseAsset_GameMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD8_PS3::pParseAsset_LightDef(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD8_PS3::pParseAsset_UIMap(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD8_PS3::pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD8_PS3::pParseAsset_AIType(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD8_PS3::pParseAsset_FX(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Animation ZoneFile_COD8_PS3::pParseAsset_Animation(QDataStream *aZoneFileStream) { + Animation result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.dataByteCount + >> result.dataShortCount + >> result.dataIntCount + >> result.randomDataByteCount + >> result.randomDataIntCount + >> result.numframes + >> result.isLooped + >> result.isDelta + >> result.noneRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.normalTranslatedBoneCount + >> result.preciseTranslatedBoneCount + >> result.staticTranslatedBoneCount + >> result.noneTranslatedBoneCount + >> result.totalBoneCount + >> result.otherBoneCount1 + >> result.otherBoneCount2 + >> result.notifyCount + >> result.assetType + >> result.pad + >> result.randomDataShortCount + >> result.indexCount + >> result.frameRate + >> result.frequency + >> result.boneIDsPtr + >> result.dataBytePtr + >> result.dataShortPtr + >> result.dataIntPtr + >> result.randomDataShortPtr + >> result.randomDataBytePtr + >> result.randomDataIntPtr + >> result.longIndiciesPtr + >> result.notificationsPtr + >> result.deltaPartsPtr; + + // Read in x_anim file name + QString xAnimName; + char xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + while (xAnimNameChar != 0) { + result.name += xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + } + + // Parse x_anim index header + QVector sectionLengths; + for (int i = 0; i < result.numframes; i++) { + quint8 sectionlength; + *aZoneFileStream >> sectionlength; + sectionLengths.push_back(sectionlength); + // Skip padding + aZoneFileStream->skipRawData(1); + } + // Skip unknown section + aZoneFileStream->skipRawData(2 * 8); + + return result; +} + +MenuFile ZoneFile_COD8_PS3::pParseAsset_MenuFile(QDataStream *aZoneFileStream) { + //MENU_FILE + MenuFile result; + + aZoneFileStream->skipRawData(4); // Separator + + // Parse menu def count + *aZoneFileStream >> result.menuCount; + + // Clearly misparsed, never have this much + if (result.menuCount > 1000) { + qDebug() << "Failure reported when parsing menu file."; + return result; + } + for (uint i = 0; i < result.menuCount; i++) { + Menu menu; + + aZoneFileStream->skipRawData(4); // Separator + + // Read in x_anim file name + char menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + while (menuFilepathChar != 0) { + menu.filePath += menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + } + aZoneFileStream->skipRawData(4); // Separator + + *aZoneFileStream >> menu.menuNamePtr; + + float menuRectX, menuRectY, menuRectWidth, menuRectHeight; + *aZoneFileStream >> menuRectX >> menuRectY >> menuRectWidth >> menuRectHeight; + menu.rect = QRectF(menuRectX, menuRectY, menuRectWidth, menuRectHeight); + + quint32 hAlignInt, vAlignInt; + *aZoneFileStream >> hAlignInt >> vAlignInt; + menu.hAlign = (MENU_H_ALIGNMENT)hAlignInt; + menu.vAlign = (MENU_V_ALIGNMENT)vAlignInt; + + float rectClientX, rectClientY, rectClientWidth, rectClientHeight; + *aZoneFileStream >> rectClientX >> rectClientY >> rectClientWidth >> rectClientHeight; + menu.clientRect = QRectF(rectClientX, rectClientY, rectClientWidth, rectClientHeight); + + quint32 hClientAlignInt, vClientAlignInt, styleInt, borderInt; + *aZoneFileStream >> hClientAlignInt >> vClientAlignInt >> menu.groupPtr + >> styleInt >> borderInt >> menu.ownerDraw >> menu.ownerDrawFlags + >> menu.borderSize >> menu.staticFlags >> menu.dynamicFlags >> menu.nextTime; + menu.hClientAlign = (MENU_H_ALIGNMENT)hClientAlignInt; + menu.vClientAlign = (MENU_V_ALIGNMENT)vClientAlignInt; + menu.style = (MENU_WINDOW_STYLE)styleInt; + menu.border = (MENU_WINDOW_BORDER)borderInt; + + float foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA, + backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA, + borderColorR, borderColorG, borderColorB, borderColorA, + outlineColorR, outlineColorG, outlineColorB, outlineColorA; + *aZoneFileStream >> foregroundColorR >> foregroundColorG >> foregroundColorB >> foregroundColorA + >> backgroundColorR >> backgroundColorG >> backgroundColorB >> backgroundColorA + >> borderColorR >> borderColorG >> borderColorB >> borderColorA + >> outlineColorR >> outlineColorG >> outlineColorB >> outlineColorA; + + menu.foregroundColor = QColor(foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA); + menu.backgroundColor = QColor(backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA); + menu.borderColor = QColor(borderColorR, borderColorG, borderColorB, borderColorA); + menu.outlineColor = QColor(outlineColorR, outlineColorG, outlineColorB, outlineColorA); + + *aZoneFileStream >> menu.materialPtr >> menu.fontPtr >> menu.fullScreen >> menu.itemCount + >> menu.fontIndex >> menu.cursorItem >> menu.fadeCycle >> menu.fadeClamp + >> menu.fadeAmount >> menu.fadeInAmount >> menu.blurRadius >> menu.onOpenPtr + >> menu.onFocusPtr >> menu.onClosePtr >> menu.onESCPtr >> menu.onKeyPtr + >> menu.visibleExpCount >> menu.expEntryPtr >> menu.allowedBindingPtr + >> menu.soundNamePtr >> menu.imageTrack; + + float focusColorR, focusColorG, focusColorB, focusColorA, + disabledColorR, disabledColorG, disabledColorB, disabledColorA; + *aZoneFileStream >> focusColorR >> focusColorG >> focusColorB >> focusColorA + >> disabledColorR >> disabledColorG >> disabledColorB >> disabledColorA; + menu.focusColor = QColor(focusColorR, focusColorG, focusColorB, focusColorA); + menu.disabledColor = QColor(disabledColorR, disabledColorG, disabledColorB, disabledColorA); + + *aZoneFileStream >> menu.rectXExpCount >> menu.rectXExpPtr >> menu.rectYExpCount >> menu.rectYExpPtr; + + aZoneFileStream->skipRawData(4); // Separator + + char menuDefNameChar; + int menuDefNameLen = 0; + *aZoneFileStream >> menuDefNameChar; + while (menuDefNameChar != 0 && menuDefNameLen < 30) { + menuDefNameLen++; + menu.name += menuDefNameChar; + *aZoneFileStream >> menuDefNameChar; + } + + char defStringChar; + int defStringLen = 0; + *aZoneFileStream >> defStringChar; + while (defStringChar != 0 && defStringLen < 30) { + defStringLen++; + menu.definition += defStringChar; + *aZoneFileStream >> defStringChar; + } + aZoneFileStream->skipRawData(4 * 10); + + *aZoneFileStream >> menu.itemWindowDefNamePtr; + + float itemRectX, itemRectY, itemRectWidth, itemRectHeight; + *aZoneFileStream >> itemRectX >> itemRectY >> itemRectWidth >> itemRectHeight; + menu.itemRect = QRectF(itemRectX, itemRectY, itemRectWidth, itemRectHeight); + + *aZoneFileStream >> menu.itemHAlignment >> menu.itemVAlignment >> menu.itemGroupPtr + >> menu.itemWindowStyle >> menu.itemWindowBorder >> menu.itemOwnerDraw + >> menu.itemOwnerDrawFlags >> menu.itemBorderSize >> menu.itemStaticFlags + >> menu.itemDynamicFlags >> menu.itemNextTime; + + float itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA, + itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA, + itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA, + itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA; + *aZoneFileStream >> itemForegroundColorR >> itemForegroundColorG >> itemForegroundColorB >> itemForegroundColorA + >> itemBackgroundColorR >> itemBackgroundColorG >> itemBackgroundColorB >> itemBackgroundColorA + >> itemBorderColorR >> itemBorderColorG >> itemBorderColorB >> itemBorderColorA + >> itemOutlineColorR >> itemOutlineColorG >> itemOutlineColorB >> itemOutlineColorA; + + menu.itemForegroundColor = QColor(itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA); + menu.itemBackgroundColor = QColor(itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA); + menu.itemBorderColor = QColor(itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA); + menu.itemOutlineColor = QColor(itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA); + + *aZoneFileStream >> menu.itemMaterialPtr; + + float itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight; + *aZoneFileStream >> itemTextRectX >> itemTextRectY >> itemTextRectWidth >> itemTextRectHeight; + menu.itemTextRect = QRectF(itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight); + + quint32 hItemTextAlignInt, vItemTextAlignInt, itemType, fontTypeInt, textStyleInt; + *aZoneFileStream >> hItemTextAlignInt >> vItemTextAlignInt >> itemType >> menu.dataType + >> menu.alignment >> fontTypeInt >> menu.textAlignMode >> menu.textalignx >> menu.textaligny + >> menu.textscale >> textStyleInt >> menu.gameMsgWindowIndex >> menu.gameMsgWindowMode + >> menu.testPtr >> menu.textSavegameInfo >> menu.parentPtr; + menu.itemText_hAlign = (MENU_H_ALIGNMENT)hItemTextAlignInt; + menu.itemText_vAlign = (MENU_V_ALIGNMENT)vItemTextAlignInt; + menu.itemType = (MENU_ITEM_TYPE)itemType; + menu.fontEnum = (MENU_FONT_TYPE)fontTypeInt; + menu.textStyle = (MENU_ITEM_TEXTSTYLE)textStyleInt; + + *aZoneFileStream >> menu.mouseEnterText >> menu.mouseExitText >> menu.mouseEnter >> menu.mouseExit + >> menu.action >> menu.onAccept >> menu.onFocus >> menu.leaveFocus >> menu.dvar >> menu.dvarTest + >> menu.keyHandlerPtr >> menu.enableDvarPtr >> menu.dvarFlags >> menu.focusSoundPtr + >> menu.special >> menu.cursorPos; + + // itemDefData_t typeData; + + // listBoxDef_s *listBox; + + *aZoneFileStream >> menu.startPos >> menu.endPos >> menu.drawPadding; + + *aZoneFileStream >> menu.elementWidth >> menu.elementHeight; + + *aZoneFileStream >> menu.elementStyle >> menu.numColumns; + + //columnInfo_s columnInfo[16]; + + *aZoneFileStream >> menu.doubleClickPtr; + + + *aZoneFileStream >> menu.notselectable >> menu.noScrollBars >> menu.usePaging; + + float itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA, + itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA, + itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA; + *aZoneFileStream >> itemSelectBorderColorR >> itemSelectBorderColorG >> itemSelectBorderColorB >> itemSelectBorderColorA + >> itemDisableColorR >> itemDisableColorG >> itemDisableColorB >> itemDisableColorA + >> itemFocusColorR >> itemFocusColorG >> itemFocusColorB >> itemFocusColorA; + menu.itemSelectBorderColor = QColor(itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA); + menu.itemDisableColor = QColor(itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA); + menu.itemFocusColor = QColor(itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA); + + *aZoneFileStream >> menu.selectIconPtr >> menu.backgroundItemListboxPtr >> menu.highlightTexturePtr; + + // editFieldDef_s *editField; + + *aZoneFileStream >> menu.minVal >> menu.maxVal >> menu.defVal >> menu.range >> menu.maxChars + >> menu.maxCharsGotoNext >> menu.maxPaintChars >> menu.paintOffset; + + // multiDef_s *multi; + + for (int i = 0; i < 32; i++) { + quint32 dvarList; + *aZoneFileStream >> dvarList; + menu.dvarListPtrs.push_back(dvarList); + } + + for (int i = 0; i < 32; i++) { + quint32 dvarStr; + *aZoneFileStream >> dvarStr; + menu.dvarStrPtrs.push_back(dvarStr); + } + + for (int i = 0; i < 32; i++) { + float dvarValue; + *aZoneFileStream >> dvarValue; + menu.dvarValues.push_back(dvarValue); + } + + *aZoneFileStream >> menu.count >> menu.strDef >> menu.enumDvarNamePtr; + aZoneFileStream->skipRawData(4); + //>> menu.dataPtr + *aZoneFileStream >> menu.itemImageTrack; + + qDebug() << aZoneFileStream->device()->pos(); + + //statement_s visibleExp; + //statement_s textExp; + //statement_s materialExp; + //statement_s rectXExp; + //statement_s rectYExp; + //statement_s rectWExp; + //statement_s rectHExp; + //statement_s foreColorAExp; + result.menuDefs << menu; + } + return result; +} + +void ZoneFile_COD8_PS3::pParseAsset_Weapon(QDataStream *aZoneFileStream) { + //WEAPON_FILE + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD8_PS3::pParseAsset_D3DBSP(QDataStream *aZoneFileStream) { + //D3DBSP_DUMP + Q_UNUSED(aZoneFileStream); +} + +StringTable ZoneFile_COD8_PS3::pParseAsset_StringTable(QDataStream *aZoneFileStream) { + StringTable result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.columnCount + >> result.rowCount; + + // Todo fix this + result.columnCount = 0; + result.rowCount = 0; + + aZoneFileStream->skipRawData(4); + + QString stringTableName; + char stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + while (stringTableNameChar != 0) { + result.name += stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + } + + for (quint32 i = 0; i < result.rowCount; i++) { + QByteArray pointerData(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pointerData.data(), 4); + result.tablePointers.push_back(pointerData.toHex()); + + aZoneFileStream->skipRawData(4); + } + + for (const QString &pointerAddr : result.tablePointers) { + QString leadingContent = ""; + if (pointerAddr == "FFFFFFFF") { + char leadingContentChar; + *aZoneFileStream >> leadingContentChar; + while (leadingContentChar != 0) { + leadingContent += leadingContentChar; + *aZoneFileStream >> leadingContentChar; + } + } else { + leadingContent = pointerAddr; + } + + QString content; + char contentChar; + *aZoneFileStream >> contentChar; + while (contentChar != 0) { + content += contentChar; + *aZoneFileStream >> contentChar; + } + result.content[leadingContent] = content; + } + return result; +} + +AssetType ZoneFile_COD8_PS3::AssetStrToEnum(const QString aAssetType) { + const QString cleanedType = aAssetType.toUpper(); + if (cleanedType == "17000000") { // localized string PARTIALLY VERIFIED + return ASSET_LOCAL_STRING; + } else if (cleanedType == "20000000") { // raw_file PARTIALLY VERIFIED + return ASSET_RAW_FILE; + } else if (cleanedType == "1A000000") { // fx PARTIALLY VERIFIED + return ASSET_EFFECT; + } else if (cleanedType == "09000000") { // loaded_sound PARTIALLY VERIFIED + return ASSET_SOUND; + } else if (cleanedType == "04000000") { // x_anim PARTIALLY VERIFIED + return ASSET_ANIMATION; + } else if (cleanedType == "0C000000") { // collision_map PARTIALLY VERIFIED + return ASSET_COLLISION_MAP; + } else if (cleanedType == "21000000") { // string_table PARTIALLY VERIFIED + return ASSET_STRING_TABLE; + } else if (cleanedType == "15000000") { // menu_file PARTIALLY VERIFIED + return ASSET_MENU; + } else if (cleanedType == "07000000") { // tech set PARTIALLY VERIFIED + return ASSET_TECH_SET; + } else if (cleanedType == "18000000") { // weapon PARTIALLY VERIFIED + return ASSET_WEAPON; + } else if (cleanedType == "11000000") { // gfx map PARTIALLY VERIFIED + return ASSET_GFX_MAP; + } else if (cleanedType == "12000000") { // light_def PARTIALLY VERIFIED + return ASSET_LIGHT_DEF; + } else if (cleanedType == "14000000") { // font PARTIALLY VERIFIED + return ASSET_FONT; + } else if (cleanedType == "05000000") { // xmodel PARTIALLY VERIFIED + return ASSET_MODEL; + } else if (cleanedType == "0D000000") { // d3dbsp PARTIALLY VERIFIED + return ASSET_D3DBSP; + } else if (cleanedType == "06000000") { // image PARTIALLY VERIFIED + return ASSET_IMAGE; + } else if (cleanedType == "0E000000") { // game map sp PARTIALLY VERIFIED + return ASSET_GAME_MAP_SP; + } else if (cleanedType == "0B000000") { // col map sp PARTIALLY VERIFIED + return ASSET_COL_MAP_SP; + } + return ASSET_NONE; +} + +QByteArray ZoneFile_COD8_PS3::GetBinaryData() { + QByteArray result; + + return result; +} diff --git a/libs/zonefile/PS3/zonefile_cod8_ps3.h b/libs/zonefile/PS3/zonefile_cod8_ps3.h new file mode 100644 index 0000000..5787d58 --- /dev/null +++ b/libs/zonefile/PS3/zonefile_cod8_ps3.h @@ -0,0 +1,52 @@ +#ifndef ZONEFILE_COD8_PS3_H +#define ZONEFILE_COD8_PS3_H + +#include "zonefile.h" + +class ZoneFile_COD8_PS3 : public ZoneFile +{ +public: + ZoneFile_COD8_PS3(); + ~ZoneFile_COD8_PS3(); + + bool Load(const QByteArray aFileData) override; + AssetType AssetStrToEnum(const QString aAssetType) override; + + QByteArray GetBinaryData() override; + +protected: + void pParseZoneHeader(QDataStream *aZoneFileStream) override; + quint32 pParseZoneSize(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsA(QDataStream *aZoneFileStream) override; + quint32 pParseZoneTagCount(QDataStream *aZoneFileStream) override; + quint32 pParseZoneRecordCount(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsB(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsC(QDataStream *aZoneFileStream) override; + QStringList pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) override; + QStringList pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) override; + AssetMap pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) override; + LocalString pParseAsset_LocalString(QDataStream *aZoneFileStream) override; + RawFile pParseAsset_RawFile(QDataStream *aZoneFileStream) override; + void pParseAsset_PhysPreset(QDataStream *aZoneFileStream) override; + Model pParseAsset_Model(QDataStream *aZoneFileStream) override; + Material pParseAsset_Material(QDataStream *aZoneFileStream) override; + Shader pParseAsset_Shader(QDataStream *aZoneFileStream) override; + TechSet pParseAsset_TechSet(QDataStream *aZoneFileStream) override; + Image pParseAsset_Image(QDataStream *aZoneFileStream) override; + SoundAsset pParseAsset_Sound(QDataStream *aZoneFileStream) override; + void pParseAsset_ColMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapSP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_LightDef(QDataStream *aZoneFileStream) override; + void pParseAsset_UIMap(QDataStream *aZoneFileStream) override; + void pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) override; + void pParseAsset_AIType(QDataStream *aZoneFileStream) override; + void pParseAsset_FX(QDataStream *aZoneFileStream) override; + Animation pParseAsset_Animation(QDataStream *aZoneFileStream) override; + MenuFile pParseAsset_MenuFile(QDataStream *aZoneFileStream) override; + void pParseAsset_Weapon(QDataStream *aZoneFileStream) override; + void pParseAsset_D3DBSP(QDataStream *aZoneFileStream) override; + StringTable pParseAsset_StringTable(QDataStream *aZoneFileStream) override; +}; + +#endif // ZONEFILE_COD8_PS3_H diff --git a/libs/zonefile/PS3/zonefile_cod9_ps3.cpp b/libs/zonefile/PS3/zonefile_cod9_ps3.cpp new file mode 100644 index 0000000..12ae674 --- /dev/null +++ b/libs/zonefile/PS3/zonefile_cod9_ps3.cpp @@ -0,0 +1,1072 @@ +#include "zonefile_cod9_ps3.h" + +#include +#include +#include + +ZoneFile_COD9_PS3::ZoneFile_COD9_PS3() +{ + +} + +ZoneFile_COD9_PS3::~ZoneFile_COD9_PS3() +{ + +} + +bool ZoneFile_COD9_PS3::Load(const QByteArray aFileData) { + // Open zone file as little endian stream + QDataStream zoneFileStream(aFileData); + zoneFileStream.setByteOrder(QDataStream::BigEndian); + + // Parse data from zone file header + pParseZoneHeader(&zoneFileStream); + SetRecords(pParseZoneIndex(&zoneFileStream, GetRecordCount())); + SetAssetMap(pParseAssets(&zoneFileStream, GetRecords())); + + return true; +} + +void ZoneFile_COD9_PS3::pParseZoneHeader(QDataStream *aZoneFileStream) { + SetSize(pParseZoneSize(aZoneFileStream)); + pParseZoneUnknownsA(aZoneFileStream); + + SetTagCount(pParseZoneTagCount(aZoneFileStream)); + pParseZoneUnknownsB(aZoneFileStream); + + SetRecordCount(pParseZoneRecordCount(aZoneFileStream)); + + quint32 tagCount = GetTagCount(); + if (tagCount) { + pParseZoneUnknownsC(aZoneFileStream); + SetTags(pParseZoneTags(aZoneFileStream, tagCount)); + } else { + aZoneFileStream->skipRawData(4); + } +} + +quint32 ZoneFile_COD9_PS3::pParseZoneSize(QDataStream *aZoneFileStream) { + quint32 zoneFileSize; + *aZoneFileStream >> zoneFileSize; + if (zoneFileSize <= 0) { + qDebug() << "Tried to open empty zone file!"; + exit(-1); + } + zoneFileSize += 36; + return zoneFileSize; +} + +/* + ParseZoneUnknownsA() + + Parses the 1st section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD9_PS3::pParseZoneUnknownsA(QDataStream *aZoneFileStream) { + // Byte 4-7, 8-11, 12-15: unknown + QByteArray unknown1(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown1.data(), 4); + + QByteArray unknown2(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown2.data(), 4); + + QByteArray unknown3(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown3.data(), 4); + + // Byte 16-19, 20-23: empty/unknown + QByteArray unknown4(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown4.data(), 4); + + QByteArray unknown5(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown5.data(), 4); + + // Byte 24-27: somehow related to the filesize, but smaller value + QByteArray unknown6(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown6.data(), 4); + + // Byte 28-31, 32-35: unknown + QByteArray unknown7(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown7.data(), 4); + + QByteArray unknown8(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown8.data(), 4); +} + +/* + ParseZoneTagCount() + + Parses the number of string tags in the zone index +*/ +quint32 ZoneFile_COD9_PS3::pParseZoneTagCount(QDataStream *aZoneFileStream) { + quint32 tagCount; + *aZoneFileStream >> tagCount; + return tagCount; +} + +/* + ParseZoneRecordCount() + + Parses the number of records in the zone index +*/ +quint32 ZoneFile_COD9_PS3::pParseZoneRecordCount(QDataStream *aZoneFileStream) { + quint32 recordCount; + *aZoneFileStream >> recordCount; + return recordCount; +} + +/* + ParseZoneUnknownsB() + + Parses the 2nd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD9_PS3::pParseZoneUnknownsB(QDataStream *aZoneFileStream) { + // Byte 44-47: Unknown/empty? + QByteArray unknown9(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown9.data(), 4); +} + +/* + pParseZoneUnknownsC() + + Parses the 3rd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD9_PS3::pParseZoneUnknownsC(QDataStream *aZoneFileStream) { + // Byte 40-43: Unknown/empty? + QByteArray unknown10(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown10.data(), 4); + + // Byte 44-47: Unknown/empty? + QByteArray unknown11(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown11.data(), 4); +} + +/* + ParseZoneTags() + + Parses the string tags ate the start of zone file +*/ +QStringList ZoneFile_COD9_PS3::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) { + QStringList tags; + + // Byte 48-51: Repeated separators? ÿÿÿÿ x i + aZoneFileStream->skipRawData(4 * (tagCount - 1)); + + // Parse tags/strings before index + QString zoneTag; + char zoneTagChar; + for (quint32 i = 0; i < tagCount; i++) { + *aZoneFileStream >> zoneTagChar; + while (zoneTagChar != 0) { + zoneTag += zoneTagChar; + *aZoneFileStream >> zoneTagChar; + } + tags << zoneTag; + zoneTag.clear(); + } + return tags; +} + +/* + ParseZoneIndex() + + Parse the binary zone index data and populate table +*/ +QStringList ZoneFile_COD9_PS3::pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) { + QStringList result; + + // Don't parse if no records + if (!recordCount) { return result; } + + if (aZoneFileStream->device()->peek(4).toHex().contains("ffff")) { + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 2); + } + + // Parse index & map found asset types + for (quint32 i = 0; i <= recordCount; i++) { + // Skip record start + QByteArray rawAssetType(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rawAssetType.data(), 4); + result << rawAssetType.toHex(); + + // Skip separator + aZoneFileStream->skipRawData(4); + } + return result; +} + +AssetMap ZoneFile_COD9_PS3::pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) { + AssetMap result; + + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 8); + + for (int i = 0; i < assetOrder.size(); i++) { + const QString typeHex = assetOrder[i]; + const AssetType typeStr = AssetStrToEnum(typeHex); + + if (typeStr == ASSET_LOCAL_STRING) { // localized string asset + result.localStrings << pParseAsset_LocalString(aZoneFileStream); + } else if (typeStr == ASSET_RAW_FILE) { // gsc + auto rawFile = pParseAsset_RawFile(aZoneFileStream); + if (rawFile.length) { + result.rawFiles << rawFile; + } + } else if (typeStr == ASSET_PHYS_PRESET) { // physpreset + pParseAsset_PhysPreset(aZoneFileStream); + } else if (typeStr == ASSET_MODEL) { // xmodel + result.models << pParseAsset_Model(aZoneFileStream); + } else if (typeStr == ASSET_MATERIAL) { // material + pParseAsset_Material(aZoneFileStream); + } else if (typeStr == ASSET_SHADER) { // pixelshader + pParseAsset_Shader(aZoneFileStream); + } else if (typeStr == ASSET_TECH_SET) { // techset include + result.techSets << pParseAsset_TechSet(aZoneFileStream); + } else if (typeStr == ASSET_IMAGE) { // image + result.images << pParseAsset_Image(aZoneFileStream); + } else if (typeStr == ASSET_SOUND) { // loaded_sound + result.sounds << pParseAsset_Sound(aZoneFileStream); + } else if (typeStr == ASSET_COLLISION_MAP) { // col_map_mp + pParseAsset_ColMapMP(aZoneFileStream); + } else if (typeStr == ASSET_MP_MAP) { // game_map_sp + pParseAsset_GameMapSP(aZoneFileStream); + } else if (typeStr == ASSET_SP_MAP) { // game_map_mp + pParseAsset_GameMapMP(aZoneFileStream); + } else if (typeStr == ASSET_LIGHT_DEF) { // lightdef + pParseAsset_LightDef(aZoneFileStream); + } else if (typeStr == ASSET_UI_MAP) { // ui_map + pParseAsset_UIMap(aZoneFileStream); + } else if (typeStr == ASSET_SND_DRIVER_GLOBALS) { // snddriverglobals + pParseAsset_SNDDriverGlobals(aZoneFileStream); + } else if (typeStr == ASSET_AI_TYPE) { // aitype + pParseAsset_AIType(aZoneFileStream); + } else if (typeStr == ASSET_EFFECT) { // aitype + pParseAsset_FX(aZoneFileStream); + } else if (typeStr == ASSET_ANIMATION) { // aitype + result.animations << pParseAsset_Animation(aZoneFileStream); + } else if (typeStr == ASSET_STRING_TABLE) { // string_table + result.stringTables << pParseAsset_StringTable(aZoneFileStream); + } else if (typeStr == ASSET_MENU) { // string_table + result.menuFiles << pParseAsset_MenuFile(aZoneFileStream); + } else if (typeStr == ASSET_WEAPON) { // string_table + pParseAsset_Weapon(aZoneFileStream); + } else if (typeStr == ASSET_D3DBSP) { // string_table + pParseAsset_D3DBSP(aZoneFileStream); + } + } + return result; +} + +LocalString ZoneFile_COD9_PS3::pParseAsset_LocalString(QDataStream *aZoneFileStream) { + LocalString result; + + quint32 stringPtr, aliasPtr; + *aZoneFileStream >> stringPtr >> aliasPtr; + if (stringPtr == 4294967295) { + // Parse local string asset contents + QString localStr; + char localStrChar; + *aZoneFileStream >> localStrChar; + while (localStrChar != 0) { + result.string += localStrChar; + *aZoneFileStream >> localStrChar; + } + } else { + result.string = "String Ptr: " + QString::number(stringPtr); + } + + if (aliasPtr == 4294967295) { + // Parse rawfile name + QString aliasName; + char aliasNameChar; + *aZoneFileStream >> aliasNameChar; + while (aliasNameChar != 0) { + result.alias += aliasNameChar; + *aZoneFileStream >> aliasNameChar; + } + } else { + result.string = "Alias Ptr: " + QString::number(aliasPtr); + } + + return result; +} + +RawFile ZoneFile_COD9_PS3::pParseAsset_RawFile(QDataStream *aZoneFileStream) { + RawFile result; + + // Skip start separator FF FF FF FF (pointer?) + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.length; + + // Skip unknown 4 byte data + aZoneFileStream->skipRawData(4); + + // Parse rawfile path + char scriptPathChar; + *aZoneFileStream >> scriptPathChar; + while (scriptPathChar != 0) { + result.path += scriptPathChar; + *aZoneFileStream >> scriptPathChar; + } + result.path.replace(",", ""); + const QStringList pathParts = result.path.split('/'); + if (pathParts.size() == 0) { + qDebug() << "Failed to parse ff path! " << result.path; + exit(-1); + } + + // Parse gsc contents + char rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + while (rawFileContentsChar != 0 && rawFileContentsChar != -1) { + result.contents += rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + } + return result; +} + +void ZoneFile_COD9_PS3::pParseAsset_PhysPreset(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Model ZoneFile_COD9_PS3::pParseAsset_Model(QDataStream *aZoneFileStream) { + Model result; + + *aZoneFileStream >> result.namePtr >> result.tagCount >> result.rootTagCount + >> result.surfCount >> result.unknownCount >> result.boneNamePtr + >> result.parentListPtr >> result.quatsPtr >> result.transPtr + >> result.partClassPtr >> result.baseMatPtr + >> result.surfsPtr >> result.materialHandlesPtr; + + // Parse XModelLodInfo + for (int i = 1; i <= 4; i++) { + quint32 intDist; + *aZoneFileStream >> intDist; + + std::memcpy(&result.lodInfo[i].dist, &intDist, sizeof(result.lodInfo[i].dist)); + *aZoneFileStream >> result.lodInfo[i].numsurfs >> result.lodInfo[i].surfIndex; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.lodInfo[i].partBits[0] + >> result.lodInfo[i].partBits[1] + >> result.lodInfo[i].partBits[2] + >> result.lodInfo[i].partBits[3]; + } + + *aZoneFileStream >> result.collSurfsPtr >> result.numCollSurfs >> result.contents >> result.boneInfoPtr; + + quint32 intRadius, intMins[3], intMaxs[3]; + *aZoneFileStream >> intRadius >> intMins[0] >> intMins[1] + >> intMins[2] >> intMaxs[0] >> intMaxs[1] >> intMaxs[2]; + + std::memcpy(&result.radius, &intRadius, sizeof(result.radius)); + + std::memcpy(&result.mins[0], &intMins[0], sizeof(result.mins[0])); + std::memcpy(&result.mins[1], &intMins[1], sizeof(result.mins[1])); + std::memcpy(&result.mins[2], &intMins[2], sizeof(result.mins[2])); + + std::memcpy(&result.maxs[0], &intMaxs[0], sizeof(result.maxs[0])); + std::memcpy(&result.maxs[1], &intMaxs[1], sizeof(result.maxs[2])); + std::memcpy(&result.maxs[2], &intMaxs[2], sizeof(result.maxs[3])); + + *aZoneFileStream >> result.numLods >> result.collLod >> result.streamInfoPtr + >> result.memUsage >> result.flags >> result.physPresetPtr >> result.physGeomsPtr; + + // Parse model name + char modelNameChar; + *aZoneFileStream >> modelNameChar; + while (modelNameChar == 0) { + *aZoneFileStream >> modelNameChar; + } + while (modelNameChar != 0) { + result.modelName += modelNameChar; + *aZoneFileStream >> modelNameChar; + } + return result; +} + +Material ZoneFile_COD9_PS3::pParseAsset_Material(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); + + return Material(); +} + +Shader ZoneFile_COD9_PS3::pParseAsset_Shader(QDataStream *aZoneFileStream) { + Shader result = Shader(); + + quint8 minorVersion, majorVersion; + *aZoneFileStream >> minorVersion >> majorVersion; + + quint32 magic; + *aZoneFileStream >> magic; + + // Verify .fxc magic + if (magic != 65534 && magic != 65535) { return result; } + + SHADER_TYPE type = SHADER_NONE; + quint16 rawShaderType; + *aZoneFileStream >> rawShaderType; + if (rawShaderType == 65535) { // Pixel shader + type = SHADER_PIXEL; + } else if (rawShaderType == 65534) { // Vertex shader + type = SHADER_VERTEX; + } + Q_UNUSED(type); + + while (true) { + quint32 instructionToken; + *aZoneFileStream >> instructionToken; + + SHADER_OPCODE opCode = (SHADER_OPCODE)(instructionToken & 0xffff); + + int size; + if (opCode == OPCODE_End) { + break; + } else if (opCode == OPCODE_Comment) { + size = (int)((instructionToken >> 16) & 0x7FFF); + } else { + size = (int)((instructionToken >> 24) & 0x0f); + } + Q_UNUSED(size); + } + + + return result; +} + +TechSet ZoneFile_COD9_PS3::pParseAsset_TechSet(QDataStream *aZoneFileStream) { + TechSet result; + + for (int i = 1; i <= 62; i++) { + quint32 ptr; + *aZoneFileStream >> ptr; + + result.pointers << ptr; + } + qDebug() << aZoneFileStream->device()->pos(); + + // Parse techset name + char techSetNameChar; + *aZoneFileStream >> techSetNameChar; + while (techSetNameChar != 0) { + result.name += techSetNameChar; + *aZoneFileStream >> techSetNameChar; + } + result.name.replace(",", ""); + + return result; +} + +Image ZoneFile_COD9_PS3::pParseAsset_Image(QDataStream *aZoneFileStream) { + Image result; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknowna >> result.unknownb + >> result.unknownc >> result.unknownd + >> result.unknowne >> result.unknownf + >> result.unknowng; + + aZoneFileStream->skipRawData(15 * 4); + *aZoneFileStream >> result.unknownh >> result.unknowni; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknownj; + + aZoneFileStream->skipRawData(4); + + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + result.materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + result.materialName.replace(",", ""); + + if (result.unknowna) { + *aZoneFileStream >> result.unknownk; + *aZoneFileStream >> result.unknownl; + *aZoneFileStream >> result.unknownm; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown1; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown2 >> result.unknown3 + >> result.size1 >> result.size2 + >> result.unknown4 >> result.unknown5; + + aZoneFileStream->skipRawData(4); + + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + result.name += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + + *aZoneFileStream >> result.unknown6 >> result.unknown7; + + QByteArray compressionData(8, Qt::Uninitialized); + aZoneFileStream->readRawData(compressionData.data(), 8); + if (compressionData.contains("DXT1")) { + result.compression = COMPRESSION_DXT1; + } else if (compressionData.contains("DXT3")) { + result.compression = COMPRESSION_DXT3; + } else if (compressionData.contains("DXT5")) { + result.compression = COMPRESSION_DXT5; + } else { + result.compression = COMPRESSION_NONE; + } + + *aZoneFileStream >> result.unknown8 >> result.unknown9; + } + + return result; +} + +SoundAsset ZoneFile_COD9_PS3::pParseAsset_Sound(QDataStream *aZoneFileStream) { + SoundAsset result; + + qDebug() << aZoneFileStream->device()->pos(); + + QByteArray rootNamePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rootNamePtr.data(), 4); + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.count; + + if (rootNamePtr.toHex() == "ffffffff") { + // Read in sound file name + char soundNameChar; + *aZoneFileStream >> soundNameChar; + while (soundNameChar != 0) { + result.name += soundNameChar; + *aZoneFileStream >> soundNameChar; + } + } + + int tagCount = 0; + int resultCount = 0; + for (quint32 i = 0; i < result.count; i++) { + aZoneFileStream->skipRawData(12); + + QByteArray tagPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(tagPtr.data(), 4); + + if (tagPtr.toHex() == "ffffffff") { + tagCount++; + } + aZoneFileStream->skipRawData(4); + + QByteArray pathPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pathPtr.data(), 4); + + if (pathPtr.toHex() == "ffffffff") { + resultCount++; + } + + aZoneFileStream->skipRawData(160); + } + + for (int i = 0; i < tagCount; i++) { + // Read in tag? + QString tag; + char tagChar; + *aZoneFileStream >> tagChar; + while (tagChar != 0) { + tag += tagChar; + *aZoneFileStream >> tagChar; + } + } + + for (int i = 0; i < resultCount; i++) { + Sound sound; + + if (aZoneFileStream->device()->peek(12).toHex().contains("ffffffff00000000")) { + aZoneFileStream->skipRawData(12); + } + + aZoneFileStream->skipRawData(8); + + QByteArray aliasPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(aliasPtr.data(), 4); + + QByteArray namePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(namePtr.data(), 4); + + *aZoneFileStream >> sound.dataLength; + + if (aliasPtr.toHex() == "ffffffff") { + // Read in sound alias name + char soundAliasChar; + *aZoneFileStream >> soundAliasChar; + while (soundAliasChar != 0) { + sound.alias += soundAliasChar; + *aZoneFileStream >> soundAliasChar; + } + } + + if (aZoneFileStream->device()->peek(4) == "RIFF") { + sound.path = sound.alias; + sound.alias = ""; + } else if (namePtr.toHex() == "ffffffff") { + // Read in sound file path + char soundPathChar; + *aZoneFileStream >> soundPathChar; + while (soundPathChar != 0) { + sound.path += soundPathChar; + *aZoneFileStream >> soundPathChar; + } + sound.path.replace(",", ""); + } + + if (sound.dataLength) { + QByteArray data(sound.dataLength, Qt::Uninitialized); + aZoneFileStream->readRawData(data.data(), sound.dataLength); + sound.data = data; + } + result.sounds.append(sound); + } + + return result; +} + +void ZoneFile_COD9_PS3::pParseAsset_ColMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD9_PS3::pParseAsset_GameMapSP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD9_PS3::pParseAsset_GameMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD9_PS3::pParseAsset_LightDef(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD9_PS3::pParseAsset_UIMap(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD9_PS3::pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD9_PS3::pParseAsset_AIType(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD9_PS3::pParseAsset_FX(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Animation ZoneFile_COD9_PS3::pParseAsset_Animation(QDataStream *aZoneFileStream) { + Animation result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.dataByteCount + >> result.dataShortCount + >> result.dataIntCount + >> result.randomDataByteCount + >> result.randomDataIntCount + >> result.numframes + >> result.isLooped + >> result.isDelta + >> result.noneRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.normalTranslatedBoneCount + >> result.preciseTranslatedBoneCount + >> result.staticTranslatedBoneCount + >> result.noneTranslatedBoneCount + >> result.totalBoneCount + >> result.otherBoneCount1 + >> result.otherBoneCount2 + >> result.notifyCount + >> result.assetType + >> result.pad + >> result.randomDataShortCount + >> result.indexCount + >> result.frameRate + >> result.frequency + >> result.boneIDsPtr + >> result.dataBytePtr + >> result.dataShortPtr + >> result.dataIntPtr + >> result.randomDataShortPtr + >> result.randomDataBytePtr + >> result.randomDataIntPtr + >> result.longIndiciesPtr + >> result.notificationsPtr + >> result.deltaPartsPtr; + + // Read in x_anim file name + QString xAnimName; + char xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + while (xAnimNameChar != 0) { + result.name += xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + } + + // Parse x_anim index header + QVector sectionLengths; + for (int i = 0; i < result.numframes; i++) { + quint8 sectionlength; + *aZoneFileStream >> sectionlength; + sectionLengths.push_back(sectionlength); + // Skip padding + aZoneFileStream->skipRawData(1); + } + // Skip unknown section + aZoneFileStream->skipRawData(2 * 8); + + return result; +} + +MenuFile ZoneFile_COD9_PS3::pParseAsset_MenuFile(QDataStream *aZoneFileStream) { + //MENU_FILE + MenuFile result; + + aZoneFileStream->skipRawData(4); // Separator + + // Parse menu def count + *aZoneFileStream >> result.menuCount; + + // Clearly misparsed, never have this much + if (result.menuCount > 1000) { + qDebug() << "Failure reported when parsing menu file."; + return result; + } + for (uint i = 0; i < result.menuCount; i++) { + Menu menu; + + aZoneFileStream->skipRawData(4); // Separator + + // Read in x_anim file name + char menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + while (menuFilepathChar != 0) { + menu.filePath += menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + } + aZoneFileStream->skipRawData(4); // Separator + + *aZoneFileStream >> menu.menuNamePtr; + + float menuRectX, menuRectY, menuRectWidth, menuRectHeight; + *aZoneFileStream >> menuRectX >> menuRectY >> menuRectWidth >> menuRectHeight; + menu.rect = QRectF(menuRectX, menuRectY, menuRectWidth, menuRectHeight); + + quint32 hAlignInt, vAlignInt; + *aZoneFileStream >> hAlignInt >> vAlignInt; + menu.hAlign = (MENU_H_ALIGNMENT)hAlignInt; + menu.vAlign = (MENU_V_ALIGNMENT)vAlignInt; + + float rectClientX, rectClientY, rectClientWidth, rectClientHeight; + *aZoneFileStream >> rectClientX >> rectClientY >> rectClientWidth >> rectClientHeight; + menu.clientRect = QRectF(rectClientX, rectClientY, rectClientWidth, rectClientHeight); + + quint32 hClientAlignInt, vClientAlignInt, styleInt, borderInt; + *aZoneFileStream >> hClientAlignInt >> vClientAlignInt >> menu.groupPtr + >> styleInt >> borderInt >> menu.ownerDraw >> menu.ownerDrawFlags + >> menu.borderSize >> menu.staticFlags >> menu.dynamicFlags >> menu.nextTime; + menu.hClientAlign = (MENU_H_ALIGNMENT)hClientAlignInt; + menu.vClientAlign = (MENU_V_ALIGNMENT)vClientAlignInt; + menu.style = (MENU_WINDOW_STYLE)styleInt; + menu.border = (MENU_WINDOW_BORDER)borderInt; + + float foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA, + backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA, + borderColorR, borderColorG, borderColorB, borderColorA, + outlineColorR, outlineColorG, outlineColorB, outlineColorA; + *aZoneFileStream >> foregroundColorR >> foregroundColorG >> foregroundColorB >> foregroundColorA + >> backgroundColorR >> backgroundColorG >> backgroundColorB >> backgroundColorA + >> borderColorR >> borderColorG >> borderColorB >> borderColorA + >> outlineColorR >> outlineColorG >> outlineColorB >> outlineColorA; + + menu.foregroundColor = QColor(foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA); + menu.backgroundColor = QColor(backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA); + menu.borderColor = QColor(borderColorR, borderColorG, borderColorB, borderColorA); + menu.outlineColor = QColor(outlineColorR, outlineColorG, outlineColorB, outlineColorA); + + *aZoneFileStream >> menu.materialPtr >> menu.fontPtr >> menu.fullScreen >> menu.itemCount + >> menu.fontIndex >> menu.cursorItem >> menu.fadeCycle >> menu.fadeClamp + >> menu.fadeAmount >> menu.fadeInAmount >> menu.blurRadius >> menu.onOpenPtr + >> menu.onFocusPtr >> menu.onClosePtr >> menu.onESCPtr >> menu.onKeyPtr + >> menu.visibleExpCount >> menu.expEntryPtr >> menu.allowedBindingPtr + >> menu.soundNamePtr >> menu.imageTrack; + + float focusColorR, focusColorG, focusColorB, focusColorA, + disabledColorR, disabledColorG, disabledColorB, disabledColorA; + *aZoneFileStream >> focusColorR >> focusColorG >> focusColorB >> focusColorA + >> disabledColorR >> disabledColorG >> disabledColorB >> disabledColorA; + menu.focusColor = QColor(focusColorR, focusColorG, focusColorB, focusColorA); + menu.disabledColor = QColor(disabledColorR, disabledColorG, disabledColorB, disabledColorA); + + *aZoneFileStream >> menu.rectXExpCount >> menu.rectXExpPtr >> menu.rectYExpCount >> menu.rectYExpPtr; + + aZoneFileStream->skipRawData(4); // Separator + + char menuDefNameChar; + int menuDefNameLen = 0; + *aZoneFileStream >> menuDefNameChar; + while (menuDefNameChar != 0 && menuDefNameLen < 30) { + menuDefNameLen++; + menu.name += menuDefNameChar; + *aZoneFileStream >> menuDefNameChar; + } + + char defStringChar; + int defStringLen = 0; + *aZoneFileStream >> defStringChar; + while (defStringChar != 0 && defStringLen < 30) { + defStringLen++; + menu.definition += defStringChar; + *aZoneFileStream >> defStringChar; + } + aZoneFileStream->skipRawData(4 * 10); + + *aZoneFileStream >> menu.itemWindowDefNamePtr; + + float itemRectX, itemRectY, itemRectWidth, itemRectHeight; + *aZoneFileStream >> itemRectX >> itemRectY >> itemRectWidth >> itemRectHeight; + menu.itemRect = QRectF(itemRectX, itemRectY, itemRectWidth, itemRectHeight); + + *aZoneFileStream >> menu.itemHAlignment >> menu.itemVAlignment >> menu.itemGroupPtr + >> menu.itemWindowStyle >> menu.itemWindowBorder >> menu.itemOwnerDraw + >> menu.itemOwnerDrawFlags >> menu.itemBorderSize >> menu.itemStaticFlags + >> menu.itemDynamicFlags >> menu.itemNextTime; + + float itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA, + itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA, + itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA, + itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA; + *aZoneFileStream >> itemForegroundColorR >> itemForegroundColorG >> itemForegroundColorB >> itemForegroundColorA + >> itemBackgroundColorR >> itemBackgroundColorG >> itemBackgroundColorB >> itemBackgroundColorA + >> itemBorderColorR >> itemBorderColorG >> itemBorderColorB >> itemBorderColorA + >> itemOutlineColorR >> itemOutlineColorG >> itemOutlineColorB >> itemOutlineColorA; + + menu.itemForegroundColor = QColor(itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA); + menu.itemBackgroundColor = QColor(itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA); + menu.itemBorderColor = QColor(itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA); + menu.itemOutlineColor = QColor(itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA); + + *aZoneFileStream >> menu.itemMaterialPtr; + + float itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight; + *aZoneFileStream >> itemTextRectX >> itemTextRectY >> itemTextRectWidth >> itemTextRectHeight; + menu.itemTextRect = QRectF(itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight); + + quint32 hItemTextAlignInt, vItemTextAlignInt, itemType, fontTypeInt, textStyleInt; + *aZoneFileStream >> hItemTextAlignInt >> vItemTextAlignInt >> itemType >> menu.dataType + >> menu.alignment >> fontTypeInt >> menu.textAlignMode >> menu.textalignx >> menu.textaligny + >> menu.textscale >> textStyleInt >> menu.gameMsgWindowIndex >> menu.gameMsgWindowMode + >> menu.testPtr >> menu.textSavegameInfo >> menu.parentPtr; + menu.itemText_hAlign = (MENU_H_ALIGNMENT)hItemTextAlignInt; + menu.itemText_vAlign = (MENU_V_ALIGNMENT)vItemTextAlignInt; + menu.itemType = (MENU_ITEM_TYPE)itemType; + menu.fontEnum = (MENU_FONT_TYPE)fontTypeInt; + menu.textStyle = (MENU_ITEM_TEXTSTYLE)textStyleInt; + + *aZoneFileStream >> menu.mouseEnterText >> menu.mouseExitText >> menu.mouseEnter >> menu.mouseExit + >> menu.action >> menu.onAccept >> menu.onFocus >> menu.leaveFocus >> menu.dvar >> menu.dvarTest + >> menu.keyHandlerPtr >> menu.enableDvarPtr >> menu.dvarFlags >> menu.focusSoundPtr + >> menu.special >> menu.cursorPos; + + // itemDefData_t typeData; + + // listBoxDef_s *listBox; + + *aZoneFileStream >> menu.startPos >> menu.endPos >> menu.drawPadding; + + *aZoneFileStream >> menu.elementWidth >> menu.elementHeight; + + *aZoneFileStream >> menu.elementStyle >> menu.numColumns; + + //columnInfo_s columnInfo[16]; + + *aZoneFileStream >> menu.doubleClickPtr; + + + *aZoneFileStream >> menu.notselectable >> menu.noScrollBars >> menu.usePaging; + + float itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA, + itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA, + itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA; + *aZoneFileStream >> itemSelectBorderColorR >> itemSelectBorderColorG >> itemSelectBorderColorB >> itemSelectBorderColorA + >> itemDisableColorR >> itemDisableColorG >> itemDisableColorB >> itemDisableColorA + >> itemFocusColorR >> itemFocusColorG >> itemFocusColorB >> itemFocusColorA; + menu.itemSelectBorderColor = QColor(itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA); + menu.itemDisableColor = QColor(itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA); + menu.itemFocusColor = QColor(itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA); + + *aZoneFileStream >> menu.selectIconPtr >> menu.backgroundItemListboxPtr >> menu.highlightTexturePtr; + + // editFieldDef_s *editField; + + *aZoneFileStream >> menu.minVal >> menu.maxVal >> menu.defVal >> menu.range >> menu.maxChars + >> menu.maxCharsGotoNext >> menu.maxPaintChars >> menu.paintOffset; + + // multiDef_s *multi; + + for (int i = 0; i < 32; i++) { + quint32 dvarList; + *aZoneFileStream >> dvarList; + menu.dvarListPtrs.push_back(dvarList); + } + + for (int i = 0; i < 32; i++) { + quint32 dvarStr; + *aZoneFileStream >> dvarStr; + menu.dvarStrPtrs.push_back(dvarStr); + } + + for (int i = 0; i < 32; i++) { + float dvarValue; + *aZoneFileStream >> dvarValue; + menu.dvarValues.push_back(dvarValue); + } + + *aZoneFileStream >> menu.count >> menu.strDef >> menu.enumDvarNamePtr; + aZoneFileStream->skipRawData(4); + //>> menu.dataPtr + *aZoneFileStream >> menu.itemImageTrack; + + qDebug() << aZoneFileStream->device()->pos(); + + //statement_s visibleExp; + //statement_s textExp; + //statement_s materialExp; + //statement_s rectXExp; + //statement_s rectYExp; + //statement_s rectWExp; + //statement_s rectHExp; + //statement_s foreColorAExp; + result.menuDefs << menu; + } + return result; +} + +void ZoneFile_COD9_PS3::pParseAsset_Weapon(QDataStream *aZoneFileStream) { + //WEAPON_FILE + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD9_PS3::pParseAsset_D3DBSP(QDataStream *aZoneFileStream) { + //D3DBSP_DUMP + Q_UNUSED(aZoneFileStream); +} + +StringTable ZoneFile_COD9_PS3::pParseAsset_StringTable(QDataStream *aZoneFileStream) { + StringTable result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.columnCount + >> result.rowCount; + + // Todo fix this + result.columnCount = 0; + result.rowCount = 0; + + aZoneFileStream->skipRawData(4); + + QString stringTableName; + char stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + while (stringTableNameChar != 0) { + result.name += stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + } + + for (quint32 i = 0; i < result.rowCount; i++) { + QByteArray pointerData(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pointerData.data(), 4); + result.tablePointers.push_back(pointerData.toHex()); + + aZoneFileStream->skipRawData(4); + } + + for (const QString &pointerAddr : result.tablePointers) { + QString leadingContent = ""; + if (pointerAddr == "FFFFFFFF") { + char leadingContentChar; + *aZoneFileStream >> leadingContentChar; + while (leadingContentChar != 0) { + leadingContent += leadingContentChar; + *aZoneFileStream >> leadingContentChar; + } + } else { + leadingContent = pointerAddr; + } + + QString content; + char contentChar; + *aZoneFileStream >> contentChar; + while (contentChar != 0) { + content += contentChar; + *aZoneFileStream >> contentChar; + } + result.content[leadingContent] = content; + } + return result; +} + +AssetType ZoneFile_COD9_PS3::AssetStrToEnum(const QString aAssetType) { + const QString cleanedType = aAssetType.toUpper(); + if (cleanedType == "17000000") { // localized string PARTIALLY VERIFIED + return ASSET_LOCAL_STRING; + } else if (cleanedType == "20000000") { // raw_file PARTIALLY VERIFIED + return ASSET_RAW_FILE; + } else if (cleanedType == "1A000000") { // fx PARTIALLY VERIFIED + return ASSET_EFFECT; + } else if (cleanedType == "09000000") { // loaded_sound PARTIALLY VERIFIED + return ASSET_SOUND; + } else if (cleanedType == "04000000") { // x_anim PARTIALLY VERIFIED + return ASSET_ANIMATION; + } else if (cleanedType == "0C000000") { // collision_map PARTIALLY VERIFIED + return ASSET_COLLISION_MAP; + } else if (cleanedType == "21000000") { // string_table PARTIALLY VERIFIED + return ASSET_STRING_TABLE; + } else if (cleanedType == "15000000") { // menu_file PARTIALLY VERIFIED + return ASSET_MENU; + } else if (cleanedType == "07000000") { // tech set PARTIALLY VERIFIED + return ASSET_TECH_SET; + } else if (cleanedType == "18000000") { // weapon PARTIALLY VERIFIED + return ASSET_WEAPON; + } else if (cleanedType == "11000000") { // gfx map PARTIALLY VERIFIED + return ASSET_GFX_MAP; + } else if (cleanedType == "12000000") { // light_def PARTIALLY VERIFIED + return ASSET_LIGHT_DEF; + } else if (cleanedType == "14000000") { // font PARTIALLY VERIFIED + return ASSET_FONT; + } else if (cleanedType == "05000000") { // xmodel PARTIALLY VERIFIED + return ASSET_MODEL; + } else if (cleanedType == "0D000000") { // d3dbsp PARTIALLY VERIFIED + return ASSET_D3DBSP; + } else if (cleanedType == "06000000") { // image PARTIALLY VERIFIED + return ASSET_IMAGE; + } else if (cleanedType == "0E000000") { // game map sp PARTIALLY VERIFIED + return ASSET_GAME_MAP_SP; + } else if (cleanedType == "0B000000") { // col map sp PARTIALLY VERIFIED + return ASSET_COL_MAP_SP; + } + return ASSET_NONE; +} + +QByteArray ZoneFile_COD9_PS3::GetBinaryData() { + QByteArray result; + + return result; +} diff --git a/libs/zonefile/PS3/zonefile_cod9_ps3.h b/libs/zonefile/PS3/zonefile_cod9_ps3.h new file mode 100644 index 0000000..cba7420 --- /dev/null +++ b/libs/zonefile/PS3/zonefile_cod9_ps3.h @@ -0,0 +1,52 @@ +#ifndef ZONEFILE_COD9_PS3_H +#define ZONEFILE_COD9_PS3_H + +#include "zonefile.h" + +class ZoneFile_COD9_PS3 : public ZoneFile +{ +public: + ZoneFile_COD9_PS3(); + ~ZoneFile_COD9_PS3(); + + bool Load(const QByteArray aFileData) override; + AssetType AssetStrToEnum(const QString aAssetType) override; + + QByteArray GetBinaryData() override; + +protected: + void pParseZoneHeader(QDataStream *aZoneFileStream) override; + quint32 pParseZoneSize(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsA(QDataStream *aZoneFileStream) override; + quint32 pParseZoneTagCount(QDataStream *aZoneFileStream) override; + quint32 pParseZoneRecordCount(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsB(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsC(QDataStream *aZoneFileStream) override; + QStringList pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) override; + QStringList pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) override; + AssetMap pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) override; + LocalString pParseAsset_LocalString(QDataStream *aZoneFileStream) override; + RawFile pParseAsset_RawFile(QDataStream *aZoneFileStream) override; + void pParseAsset_PhysPreset(QDataStream *aZoneFileStream) override; + Model pParseAsset_Model(QDataStream *aZoneFileStream) override; + Material pParseAsset_Material(QDataStream *aZoneFileStream) override; + Shader pParseAsset_Shader(QDataStream *aZoneFileStream) override; + TechSet pParseAsset_TechSet(QDataStream *aZoneFileStream) override; + Image pParseAsset_Image(QDataStream *aZoneFileStream) override; + SoundAsset pParseAsset_Sound(QDataStream *aZoneFileStream) override; + void pParseAsset_ColMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapSP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_LightDef(QDataStream *aZoneFileStream) override; + void pParseAsset_UIMap(QDataStream *aZoneFileStream) override; + void pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) override; + void pParseAsset_AIType(QDataStream *aZoneFileStream) override; + void pParseAsset_FX(QDataStream *aZoneFileStream) override; + Animation pParseAsset_Animation(QDataStream *aZoneFileStream) override; + MenuFile pParseAsset_MenuFile(QDataStream *aZoneFileStream) override; + void pParseAsset_Weapon(QDataStream *aZoneFileStream) override; + void pParseAsset_D3DBSP(QDataStream *aZoneFileStream) override; + StringTable pParseAsset_StringTable(QDataStream *aZoneFileStream) override; +}; + +#endif // ZONEFILE_COD9_PS3_H diff --git a/libs/zonefile/Wii/zonefile_cod4_wii.cpp b/libs/zonefile/Wii/zonefile_cod4_wii.cpp new file mode 100644 index 0000000..6894d5a --- /dev/null +++ b/libs/zonefile/Wii/zonefile_cod4_wii.cpp @@ -0,0 +1,1077 @@ +#include "zonefile_cod4_wii.h" + +#include +#include +#include + +ZoneFile_COD4_Wii::ZoneFile_COD4_Wii() +{ + +} + +ZoneFile_COD4_Wii::~ZoneFile_COD4_Wii() +{ + +} + +bool ZoneFile_COD4_Wii::Load(const QByteArray aFileData) { + // Open zone file as little endian stream + QDataStream zoneFileStream(aFileData); + zoneFileStream.setByteOrder(QDataStream::BigEndian); + + // Parse data from zone file header + pParseZoneHeader(&zoneFileStream); + zoneFileStream.device()->seek(zoneFileStream.device()->pos() - 1); + SetRecords(pParseZoneIndex(&zoneFileStream, GetRecordCount())); + SetAssetMap(pParseAssets(&zoneFileStream, GetRecords())); + + return true; +} + +void ZoneFile_COD4_Wii::pParseZoneHeader(QDataStream *aZoneFileStream) { + quint32 size = pParseZoneSize(aZoneFileStream); + SetSize(size); + + aZoneFileStream->skipRawData(36); + + quint32 tagCount = pParseZoneTagCount(aZoneFileStream); + SetTagCount(tagCount - 1); + + pParseZoneUnknownsB(aZoneFileStream); + + quint32 recordCount = pParseZoneRecordCount(aZoneFileStream); + SetRecordCount(recordCount); + + if (tagCount) { + pParseZoneUnknownsC(aZoneFileStream); + SetTags(pParseZoneTags(aZoneFileStream, tagCount)); + } else { + aZoneFileStream->skipRawData(4); + } +} + +quint32 ZoneFile_COD4_Wii::pParseZoneSize(QDataStream *aZoneFileStream) { + quint32 zoneFileSize; + *aZoneFileStream >> zoneFileSize; + if (zoneFileSize <= 0) { + qDebug() << "Tried to open empty zone file!"; + exit(-1); + } + zoneFileSize += 36; + return zoneFileSize; +} + +/* + ParseZoneUnknownsA() + + Parses the 1st section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD4_Wii::pParseZoneUnknownsA(QDataStream *aZoneFileStream) { + // Byte 4-7, 8-11, 12-15: unknown + QByteArray unknown1(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown1.data(), 4); + + QByteArray unknown2(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown2.data(), 4); + + QByteArray unknown3(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown3.data(), 4); + + // Byte 16-19, 20-23: empty/unknown + QByteArray unknown4(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown4.data(), 4); + + QByteArray unknown5(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown5.data(), 4); + + // Byte 24-27: somehow related to the filesize, but smaller value + QByteArray unknown6(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown6.data(), 4); + + // Byte 28-31, 32-35: unknown + QByteArray unknown7(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown7.data(), 4); + + QByteArray unknown8(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown8.data(), 4); +} + +/* + ParseZoneTagCount() + + Parses the number of string tags in the zone index +*/ +quint32 ZoneFile_COD4_Wii::pParseZoneTagCount(QDataStream *aZoneFileStream) { + quint32 tagCount; + *aZoneFileStream >> tagCount; + return tagCount; +} + +/* + ParseZoneRecordCount() + + Parses the number of records in the zone index +*/ +quint32 ZoneFile_COD4_Wii::pParseZoneRecordCount(QDataStream *aZoneFileStream) { + quint32 recordCount; + *aZoneFileStream >> recordCount; + return recordCount; +} + +/* + ParseZoneUnknownsB() + + Parses the 2nd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD4_Wii::pParseZoneUnknownsB(QDataStream *aZoneFileStream) { + // Byte 44-47: Unknown/empty? + QByteArray unknown9(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown9.data(), 4); +} + +/* + pParseZoneUnknownsC() + + Parses the 3rd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD4_Wii::pParseZoneUnknownsC(QDataStream *aZoneFileStream) { + // Byte 40-43: Unknown/empty? + QByteArray unknown10(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown10.data(), 4); + + // Byte 44-47: Unknown/empty? + QByteArray unknown11(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown11.data(), 4); +} + +/* + ParseZoneTags() + + Parses the string tags ate the start of zone file +*/ +QStringList ZoneFile_COD4_Wii::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) { + QStringList tags; + + // Byte 48-51: Repeated separators? ÿÿÿÿ x i + aZoneFileStream->skipRawData(4 * (tagCount - 1)); + + // Parse tags/strings before index + QString zoneTag; + char zoneTagChar; + for (quint32 i = 0; i < tagCount; i++) { + *aZoneFileStream >> zoneTagChar; + while (zoneTagChar != 0) { + zoneTag += zoneTagChar; + *aZoneFileStream >> zoneTagChar; + } + tags << zoneTag; + zoneTag.clear(); + } + return tags; +} + +/* + ParseZoneIndex() + + Parse the binary zone index data and populate table +*/ +QStringList ZoneFile_COD4_Wii::pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) { + QStringList result; + + // Don't parse if no records + if (!recordCount) { return result; } + + if (aZoneFileStream->device()->peek(4).toHex().contains("ffff")) { + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 2); + } + + // Parse index & map found asset types + for (quint32 i = 0; i <= recordCount; i++) { + // Skip record start + QByteArray rawAssetType(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rawAssetType.data(), 4); + result << rawAssetType.toHex(); + + // Skip separator + aZoneFileStream->skipRawData(4); + } + return result; +} + +AssetMap ZoneFile_COD4_Wii::pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) { + AssetMap result; + + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 8); + + for (int i = 0; i < assetOrder.size(); i++) { + const QString typeHex = assetOrder[i]; + const AssetType typeStr = AssetStrToEnum(typeHex); + + if (typeStr == ASSET_LOCAL_STRING) { // localized string asset + result.localStrings << pParseAsset_LocalString(aZoneFileStream); + } else if (typeStr == ASSET_RAW_FILE) { // gsc + auto rawFile = pParseAsset_RawFile(aZoneFileStream); + if (rawFile.length) { + result.rawFiles << rawFile; + } + } else if (typeStr == ASSET_PHYS_PRESET) { // physpreset + pParseAsset_PhysPreset(aZoneFileStream); + } else if (typeStr == ASSET_MODEL) { // xmodel + result.models << pParseAsset_Model(aZoneFileStream); + } else if (typeStr == ASSET_MATERIAL) { // material + pParseAsset_Material(aZoneFileStream); + } else if (typeStr == ASSET_SHADER) { // pixelshader + pParseAsset_Shader(aZoneFileStream); + } else if (typeStr == ASSET_TECH_SET) { // techset include + result.techSets << pParseAsset_TechSet(aZoneFileStream); + } else if (typeStr == ASSET_IMAGE) { // image + result.images << pParseAsset_Image(aZoneFileStream); + } else if (typeStr == ASSET_SOUND) { // loaded_sound + result.sounds << pParseAsset_Sound(aZoneFileStream); + } else if (typeStr == ASSET_COLLISION_MAP) { // col_map_mp + pParseAsset_ColMapMP(aZoneFileStream); + } else if (typeStr == ASSET_MP_MAP) { // game_map_sp + pParseAsset_GameMapSP(aZoneFileStream); + } else if (typeStr == ASSET_SP_MAP) { // game_map_mp + pParseAsset_GameMapMP(aZoneFileStream); + } else if (typeStr == ASSET_LIGHT_DEF) { // lightdef + pParseAsset_LightDef(aZoneFileStream); + } else if (typeStr == ASSET_UI_MAP) { // ui_map + pParseAsset_UIMap(aZoneFileStream); + } else if (typeStr == ASSET_SND_DRIVER_GLOBALS) { // snddriverglobals + pParseAsset_SNDDriverGlobals(aZoneFileStream); + } else if (typeStr == ASSET_AI_TYPE) { // aitype + pParseAsset_AIType(aZoneFileStream); + } else if (typeStr == ASSET_EFFECT) { // aitype + pParseAsset_FX(aZoneFileStream); + } else if (typeStr == ASSET_ANIMATION) { // aitype + result.animations << pParseAsset_Animation(aZoneFileStream); + } else if (typeStr == ASSET_STRING_TABLE) { // string_table + result.stringTables << pParseAsset_StringTable(aZoneFileStream); + } else if (typeStr == ASSET_MENU) { // string_table + result.menuFiles << pParseAsset_MenuFile(aZoneFileStream); + } else if (typeStr == ASSET_WEAPON) { // string_table + pParseAsset_Weapon(aZoneFileStream); + } else if (typeStr == ASSET_D3DBSP) { // string_table + pParseAsset_D3DBSP(aZoneFileStream); + } + } + return result; +} + +LocalString ZoneFile_COD4_Wii::pParseAsset_LocalString(QDataStream *aZoneFileStream) { + LocalString result; + + quint32 stringPtr, aliasPtr; + *aZoneFileStream >> stringPtr >> aliasPtr; + if (stringPtr == 4294967295) { + // Parse local string asset contents + QString localStr; + char localStrChar; + *aZoneFileStream >> localStrChar; + while (localStrChar != 0) { + result.string += localStrChar; + *aZoneFileStream >> localStrChar; + } + } else { + result.string = "String Ptr: " + QString::number(stringPtr); + } + + if (aliasPtr == 4294967295) { + // Parse rawfile name + QString aliasName; + char aliasNameChar; + *aZoneFileStream >> aliasNameChar; + while (aliasNameChar != 0) { + result.alias += aliasNameChar; + *aZoneFileStream >> aliasNameChar; + } + } else { + result.string = "Alias Ptr: " + QString::number(aliasPtr); + } + + return result; +} + +RawFile ZoneFile_COD4_Wii::pParseAsset_RawFile(QDataStream *aZoneFileStream) { + RawFile result; + + // Skip start separator FF FF FF FF (pointer?) + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.length; + + // Skip unknown 4 byte data + aZoneFileStream->skipRawData(4); + + // Parse rawfile path + char scriptPathChar; + *aZoneFileStream >> scriptPathChar; + while (scriptPathChar != 0) { + result.path += scriptPathChar; + *aZoneFileStream >> scriptPathChar; + } + result.path.replace(",", ""); + const QStringList pathParts = result.path.split('/'); + if (pathParts.size() == 0) { + qDebug() << "Failed to parse ff path! " << result.path; + exit(-1); + } + + // Parse gsc contents + char rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + while (rawFileContentsChar != 0 && rawFileContentsChar != -1) { + result.contents += rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + } + return result; +} + +void ZoneFile_COD4_Wii::pParseAsset_PhysPreset(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Model ZoneFile_COD4_Wii::pParseAsset_Model(QDataStream *aZoneFileStream) { + Model result; + + *aZoneFileStream >> result.namePtr >> result.tagCount >> result.rootTagCount + >> result.surfCount >> result.unknownCount >> result.boneNamePtr + >> result.parentListPtr >> result.quatsPtr >> result.transPtr + >> result.partClassPtr >> result.baseMatPtr + >> result.surfsPtr >> result.materialHandlesPtr; + + // Parse XModelLodInfo + for (int i = 1; i <= 4; i++) { + quint32 intDist; + *aZoneFileStream >> intDist; + + std::memcpy(&result.lodInfo[i].dist, &intDist, sizeof(result.lodInfo[i].dist)); + *aZoneFileStream >> result.lodInfo[i].numsurfs >> result.lodInfo[i].surfIndex; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.lodInfo[i].partBits[0] + >> result.lodInfo[i].partBits[1] + >> result.lodInfo[i].partBits[2] + >> result.lodInfo[i].partBits[3]; + } + + *aZoneFileStream >> result.collSurfsPtr >> result.numCollSurfs >> result.contents >> result.boneInfoPtr; + + quint32 intRadius, intMins[3], intMaxs[3]; + *aZoneFileStream >> intRadius >> intMins[0] >> intMins[1] + >> intMins[2] >> intMaxs[0] >> intMaxs[1] >> intMaxs[2]; + + std::memcpy(&result.radius, &intRadius, sizeof(result.radius)); + + std::memcpy(&result.mins[0], &intMins[0], sizeof(result.mins[0])); + std::memcpy(&result.mins[1], &intMins[1], sizeof(result.mins[1])); + std::memcpy(&result.mins[2], &intMins[2], sizeof(result.mins[2])); + + std::memcpy(&result.maxs[0], &intMaxs[0], sizeof(result.maxs[0])); + std::memcpy(&result.maxs[1], &intMaxs[1], sizeof(result.maxs[2])); + std::memcpy(&result.maxs[2], &intMaxs[2], sizeof(result.maxs[3])); + + *aZoneFileStream >> result.numLods >> result.collLod >> result.streamInfoPtr + >> result.memUsage >> result.flags >> result.physPresetPtr >> result.physGeomsPtr; + + // Parse model name + char modelNameChar; + *aZoneFileStream >> modelNameChar; + while (modelNameChar == 0) { + *aZoneFileStream >> modelNameChar; + } + while (modelNameChar != 0) { + result.modelName += modelNameChar; + *aZoneFileStream >> modelNameChar; + } + return result; +} + +Material ZoneFile_COD4_Wii::pParseAsset_Material(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); + + return Material(); +} + +Shader ZoneFile_COD4_Wii::pParseAsset_Shader(QDataStream *aZoneFileStream) { + Shader result = Shader(); + + quint8 minorVersion, majorVersion; + *aZoneFileStream >> minorVersion >> majorVersion; + + quint32 magic; + *aZoneFileStream >> magic; + + // Verify .fxc magic + if (magic != 65534 && magic != 65535) { return result; } + + SHADER_TYPE type = SHADER_NONE; + quint16 rawShaderType; + *aZoneFileStream >> rawShaderType; + if (rawShaderType == 65535) { // Pixel shader + type = SHADER_PIXEL; + } else if (rawShaderType == 65534) { // Vertex shader + type = SHADER_VERTEX; + } + Q_UNUSED(type); + + while (true) { + quint32 instructionToken; + *aZoneFileStream >> instructionToken; + + SHADER_OPCODE opCode = (SHADER_OPCODE)(instructionToken & 0xffff); + + int size; + if (opCode == OPCODE_End) { + break; + } else if (opCode == OPCODE_Comment) { + size = (int)((instructionToken >> 16) & 0x7FFF); + } else { + size = (int)((instructionToken >> 24) & 0x0f); + } + Q_UNUSED(size); + } + + + return result; +} + +TechSet ZoneFile_COD4_Wii::pParseAsset_TechSet(QDataStream *aZoneFileStream) { + TechSet result; + + for (int i = 1; i <= 62; i++) { + quint32 ptr; + *aZoneFileStream >> ptr; + + result.pointers << ptr; + } + qDebug() << aZoneFileStream->device()->pos(); + + // Parse techset name + char techSetNameChar; + *aZoneFileStream >> techSetNameChar; + while (techSetNameChar != 0) { + result.name += techSetNameChar; + *aZoneFileStream >> techSetNameChar; + } + result.name.replace(",", ""); + + return result; +} + +Image ZoneFile_COD4_Wii::pParseAsset_Image(QDataStream *aZoneFileStream) { + Image result; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknowna >> result.unknownb + >> result.unknownc >> result.unknownd + >> result.unknowne >> result.unknownf + >> result.unknowng; + + aZoneFileStream->skipRawData(15 * 4); + *aZoneFileStream >> result.unknownh >> result.unknowni; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknownj; + + aZoneFileStream->skipRawData(4); + + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + result.materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + result.materialName.replace(",", ""); + + if (result.unknowna) { + *aZoneFileStream >> result.unknownk; + *aZoneFileStream >> result.unknownl; + *aZoneFileStream >> result.unknownm; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown1; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown2 >> result.unknown3 + >> result.size1 >> result.size2 + >> result.unknown4 >> result.unknown5; + + aZoneFileStream->skipRawData(4); + + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + result.name += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + + *aZoneFileStream >> result.unknown6 >> result.unknown7; + + QByteArray compressionData(8, Qt::Uninitialized); + aZoneFileStream->readRawData(compressionData.data(), 8); + if (compressionData.contains("DXT1")) { + result.compression = COMPRESSION_DXT1; + } else if (compressionData.contains("DXT3")) { + result.compression = COMPRESSION_DXT3; + } else if (compressionData.contains("DXT5")) { + result.compression = COMPRESSION_DXT5; + } else { + result.compression = COMPRESSION_NONE; + } + + *aZoneFileStream >> result.unknown8 >> result.unknown9; + } + + return result; +} + +SoundAsset ZoneFile_COD4_Wii::pParseAsset_Sound(QDataStream *aZoneFileStream) { + SoundAsset result; + + qDebug() << aZoneFileStream->device()->pos(); + + QByteArray rootNamePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rootNamePtr.data(), 4); + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.count; + + if (rootNamePtr.toHex() == "ffffffff") { + // Read in sound file name + char soundNameChar; + *aZoneFileStream >> soundNameChar; + while (soundNameChar != 0) { + result.name += soundNameChar; + *aZoneFileStream >> soundNameChar; + } + } + + int tagCount = 0; + int resultCount = 0; + for (quint32 i = 0; i < result.count; i++) { + aZoneFileStream->skipRawData(12); + + QByteArray tagPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(tagPtr.data(), 4); + + if (tagPtr.toHex() == "ffffffff") { + tagCount++; + } + aZoneFileStream->skipRawData(4); + + QByteArray pathPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pathPtr.data(), 4); + + if (pathPtr.toHex() == "ffffffff") { + resultCount++; + } + + aZoneFileStream->skipRawData(160); + } + + for (int i = 0; i < tagCount; i++) { + // Read in tag? + QString tag; + char tagChar; + *aZoneFileStream >> tagChar; + while (tagChar != 0) { + tag += tagChar; + *aZoneFileStream >> tagChar; + } + } + + for (int i = 0; i < resultCount; i++) { + Sound sound; + + if (aZoneFileStream->device()->peek(12).toHex().contains("ffffffff00000000")) { + aZoneFileStream->skipRawData(12); + } + + aZoneFileStream->skipRawData(8); + + QByteArray aliasPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(aliasPtr.data(), 4); + + QByteArray namePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(namePtr.data(), 4); + + *aZoneFileStream >> sound.dataLength; + + if (aliasPtr.toHex() == "ffffffff") { + // Read in sound alias name + char soundAliasChar; + *aZoneFileStream >> soundAliasChar; + while (soundAliasChar != 0) { + sound.alias += soundAliasChar; + *aZoneFileStream >> soundAliasChar; + } + } + + if (aZoneFileStream->device()->peek(4) == "RIFF") { + sound.path = sound.alias; + sound.alias = ""; + } else if (namePtr.toHex() == "ffffffff") { + // Read in sound file path + char soundPathChar; + *aZoneFileStream >> soundPathChar; + while (soundPathChar != 0) { + sound.path += soundPathChar; + *aZoneFileStream >> soundPathChar; + } + sound.path.replace(",", ""); + } + + if (sound.dataLength) { + QByteArray data(sound.dataLength, Qt::Uninitialized); + aZoneFileStream->readRawData(data.data(), sound.dataLength); + sound.data = data; + } + result.sounds.append(sound); + } + + return result; +} + +void ZoneFile_COD4_Wii::pParseAsset_ColMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD4_Wii::pParseAsset_GameMapSP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD4_Wii::pParseAsset_GameMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD4_Wii::pParseAsset_LightDef(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD4_Wii::pParseAsset_UIMap(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD4_Wii::pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD4_Wii::pParseAsset_AIType(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD4_Wii::pParseAsset_FX(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Animation ZoneFile_COD4_Wii::pParseAsset_Animation(QDataStream *aZoneFileStream) { + Animation result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.dataByteCount + >> result.dataShortCount + >> result.dataIntCount + >> result.randomDataByteCount + >> result.randomDataIntCount + >> result.numframes + >> result.isLooped + >> result.isDelta + >> result.noneRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.normalTranslatedBoneCount + >> result.preciseTranslatedBoneCount + >> result.staticTranslatedBoneCount + >> result.noneTranslatedBoneCount + >> result.totalBoneCount + >> result.otherBoneCount1 + >> result.otherBoneCount2 + >> result.notifyCount + >> result.assetType + >> result.pad + >> result.randomDataShortCount + >> result.indexCount + >> result.frameRate + >> result.frequency + >> result.boneIDsPtr + >> result.dataBytePtr + >> result.dataShortPtr + >> result.dataIntPtr + >> result.randomDataShortPtr + >> result.randomDataBytePtr + >> result.randomDataIntPtr + >> result.longIndiciesPtr + >> result.notificationsPtr + >> result.deltaPartsPtr; + + // Read in x_anim file name + QString xAnimName; + char xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + while (xAnimNameChar != 0) { + result.name += xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + } + + // Parse x_anim index header + QVector sectionLengths; + for (int i = 0; i < result.numframes; i++) { + quint8 sectionlength; + *aZoneFileStream >> sectionlength; + sectionLengths.push_back(sectionlength); + // Skip padding + aZoneFileStream->skipRawData(1); + } + // Skip unknown section + aZoneFileStream->skipRawData(2 * 8); + + return result; +} + +MenuFile ZoneFile_COD4_Wii::pParseAsset_MenuFile(QDataStream *aZoneFileStream) { + //MENU_FILE + MenuFile result; + + aZoneFileStream->skipRawData(4); // Separator + + // Parse menu def count + *aZoneFileStream >> result.menuCount; + + // Clearly misparsed, never have this much + if (result.menuCount > 1000) { + qDebug() << "Failure reported when parsing menu file."; + return result; + } + for (uint i = 0; i < result.menuCount; i++) { + Menu menu; + + aZoneFileStream->skipRawData(4); // Separator + + // Read in x_anim file name + char menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + while (menuFilepathChar != 0) { + menu.filePath += menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + } + aZoneFileStream->skipRawData(4); // Separator + + *aZoneFileStream >> menu.menuNamePtr; + + float menuRectX, menuRectY, menuRectWidth, menuRectHeight; + *aZoneFileStream >> menuRectX >> menuRectY >> menuRectWidth >> menuRectHeight; + menu.rect = QRectF(menuRectX, menuRectY, menuRectWidth, menuRectHeight); + + quint32 hAlignInt, vAlignInt; + *aZoneFileStream >> hAlignInt >> vAlignInt; + menu.hAlign = (MENU_H_ALIGNMENT)hAlignInt; + menu.vAlign = (MENU_V_ALIGNMENT)vAlignInt; + + float rectClientX, rectClientY, rectClientWidth, rectClientHeight; + *aZoneFileStream >> rectClientX >> rectClientY >> rectClientWidth >> rectClientHeight; + menu.clientRect = QRectF(rectClientX, rectClientY, rectClientWidth, rectClientHeight); + + quint32 hClientAlignInt, vClientAlignInt, styleInt, borderInt; + *aZoneFileStream >> hClientAlignInt >> vClientAlignInt >> menu.groupPtr + >> styleInt >> borderInt >> menu.ownerDraw >> menu.ownerDrawFlags + >> menu.borderSize >> menu.staticFlags >> menu.dynamicFlags >> menu.nextTime; + menu.hClientAlign = (MENU_H_ALIGNMENT)hClientAlignInt; + menu.vClientAlign = (MENU_V_ALIGNMENT)vClientAlignInt; + menu.style = (MENU_WINDOW_STYLE)styleInt; + menu.border = (MENU_WINDOW_BORDER)borderInt; + + float foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA, + backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA, + borderColorR, borderColorG, borderColorB, borderColorA, + outlineColorR, outlineColorG, outlineColorB, outlineColorA; + *aZoneFileStream >> foregroundColorR >> foregroundColorG >> foregroundColorB >> foregroundColorA + >> backgroundColorR >> backgroundColorG >> backgroundColorB >> backgroundColorA + >> borderColorR >> borderColorG >> borderColorB >> borderColorA + >> outlineColorR >> outlineColorG >> outlineColorB >> outlineColorA; + + menu.foregroundColor = QColor(foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA); + menu.backgroundColor = QColor(backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA); + menu.borderColor = QColor(borderColorR, borderColorG, borderColorB, borderColorA); + menu.outlineColor = QColor(outlineColorR, outlineColorG, outlineColorB, outlineColorA); + + *aZoneFileStream >> menu.materialPtr >> menu.fontPtr >> menu.fullScreen >> menu.itemCount + >> menu.fontIndex >> menu.cursorItem >> menu.fadeCycle >> menu.fadeClamp + >> menu.fadeAmount >> menu.fadeInAmount >> menu.blurRadius >> menu.onOpenPtr + >> menu.onFocusPtr >> menu.onClosePtr >> menu.onESCPtr >> menu.onKeyPtr + >> menu.visibleExpCount >> menu.expEntryPtr >> menu.allowedBindingPtr + >> menu.soundNamePtr >> menu.imageTrack; + + float focusColorR, focusColorG, focusColorB, focusColorA, + disabledColorR, disabledColorG, disabledColorB, disabledColorA; + *aZoneFileStream >> focusColorR >> focusColorG >> focusColorB >> focusColorA + >> disabledColorR >> disabledColorG >> disabledColorB >> disabledColorA; + menu.focusColor = QColor(focusColorR, focusColorG, focusColorB, focusColorA); + menu.disabledColor = QColor(disabledColorR, disabledColorG, disabledColorB, disabledColorA); + + *aZoneFileStream >> menu.rectXExpCount >> menu.rectXExpPtr >> menu.rectYExpCount >> menu.rectYExpPtr; + + aZoneFileStream->skipRawData(4); // Separator + + char menuDefNameChar; + int menuDefNameLen = 0; + *aZoneFileStream >> menuDefNameChar; + while (menuDefNameChar != 0 && menuDefNameLen < 30) { + menuDefNameLen++; + menu.name += menuDefNameChar; + *aZoneFileStream >> menuDefNameChar; + } + + char defStringChar; + int defStringLen = 0; + *aZoneFileStream >> defStringChar; + while (defStringChar != 0 && defStringLen < 30) { + defStringLen++; + menu.definition += defStringChar; + *aZoneFileStream >> defStringChar; + } + aZoneFileStream->skipRawData(4 * 10); + + *aZoneFileStream >> menu.itemWindowDefNamePtr; + + float itemRectX, itemRectY, itemRectWidth, itemRectHeight; + *aZoneFileStream >> itemRectX >> itemRectY >> itemRectWidth >> itemRectHeight; + menu.itemRect = QRectF(itemRectX, itemRectY, itemRectWidth, itemRectHeight); + + *aZoneFileStream >> menu.itemHAlignment >> menu.itemVAlignment >> menu.itemGroupPtr + >> menu.itemWindowStyle >> menu.itemWindowBorder >> menu.itemOwnerDraw + >> menu.itemOwnerDrawFlags >> menu.itemBorderSize >> menu.itemStaticFlags + >> menu.itemDynamicFlags >> menu.itemNextTime; + + float itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA, + itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA, + itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA, + itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA; + *aZoneFileStream >> itemForegroundColorR >> itemForegroundColorG >> itemForegroundColorB >> itemForegroundColorA + >> itemBackgroundColorR >> itemBackgroundColorG >> itemBackgroundColorB >> itemBackgroundColorA + >> itemBorderColorR >> itemBorderColorG >> itemBorderColorB >> itemBorderColorA + >> itemOutlineColorR >> itemOutlineColorG >> itemOutlineColorB >> itemOutlineColorA; + + menu.itemForegroundColor = QColor(itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA); + menu.itemBackgroundColor = QColor(itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA); + menu.itemBorderColor = QColor(itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA); + menu.itemOutlineColor = QColor(itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA); + + *aZoneFileStream >> menu.itemMaterialPtr; + + float itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight; + *aZoneFileStream >> itemTextRectX >> itemTextRectY >> itemTextRectWidth >> itemTextRectHeight; + menu.itemTextRect = QRectF(itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight); + + quint32 hItemTextAlignInt, vItemTextAlignInt, itemType, fontTypeInt, textStyleInt; + *aZoneFileStream >> hItemTextAlignInt >> vItemTextAlignInt >> itemType >> menu.dataType + >> menu.alignment >> fontTypeInt >> menu.textAlignMode >> menu.textalignx >> menu.textaligny + >> menu.textscale >> textStyleInt >> menu.gameMsgWindowIndex >> menu.gameMsgWindowMode + >> menu.testPtr >> menu.textSavegameInfo >> menu.parentPtr; + menu.itemText_hAlign = (MENU_H_ALIGNMENT)hItemTextAlignInt; + menu.itemText_vAlign = (MENU_V_ALIGNMENT)vItemTextAlignInt; + menu.itemType = (MENU_ITEM_TYPE)itemType; + menu.fontEnum = (MENU_FONT_TYPE)fontTypeInt; + menu.textStyle = (MENU_ITEM_TEXTSTYLE)textStyleInt; + + *aZoneFileStream >> menu.mouseEnterText >> menu.mouseExitText >> menu.mouseEnter >> menu.mouseExit + >> menu.action >> menu.onAccept >> menu.onFocus >> menu.leaveFocus >> menu.dvar >> menu.dvarTest + >> menu.keyHandlerPtr >> menu.enableDvarPtr >> menu.dvarFlags >> menu.focusSoundPtr + >> menu.special >> menu.cursorPos; + + // itemDefData_t typeData; + + // listBoxDef_s *listBox; + + *aZoneFileStream >> menu.startPos >> menu.endPos >> menu.drawPadding; + + *aZoneFileStream >> menu.elementWidth >> menu.elementHeight; + + *aZoneFileStream >> menu.elementStyle >> menu.numColumns; + + //columnInfo_s columnInfo[16]; + + *aZoneFileStream >> menu.doubleClickPtr; + + + *aZoneFileStream >> menu.notselectable >> menu.noScrollBars >> menu.usePaging; + + float itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA, + itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA, + itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA; + *aZoneFileStream >> itemSelectBorderColorR >> itemSelectBorderColorG >> itemSelectBorderColorB >> itemSelectBorderColorA + >> itemDisableColorR >> itemDisableColorG >> itemDisableColorB >> itemDisableColorA + >> itemFocusColorR >> itemFocusColorG >> itemFocusColorB >> itemFocusColorA; + menu.itemSelectBorderColor = QColor(itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA); + menu.itemDisableColor = QColor(itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA); + menu.itemFocusColor = QColor(itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA); + + *aZoneFileStream >> menu.selectIconPtr >> menu.backgroundItemListboxPtr >> menu.highlightTexturePtr; + + // editFieldDef_s *editField; + + *aZoneFileStream >> menu.minVal >> menu.maxVal >> menu.defVal >> menu.range >> menu.maxChars + >> menu.maxCharsGotoNext >> menu.maxPaintChars >> menu.paintOffset; + + // multiDef_s *multi; + + for (int i = 0; i < 32; i++) { + quint32 dvarList; + *aZoneFileStream >> dvarList; + menu.dvarListPtrs.push_back(dvarList); + } + + for (int i = 0; i < 32; i++) { + quint32 dvarStr; + *aZoneFileStream >> dvarStr; + menu.dvarStrPtrs.push_back(dvarStr); + } + + for (int i = 0; i < 32; i++) { + float dvarValue; + *aZoneFileStream >> dvarValue; + menu.dvarValues.push_back(dvarValue); + } + + *aZoneFileStream >> menu.count >> menu.strDef >> menu.enumDvarNamePtr; + aZoneFileStream->skipRawData(4); + //>> menu.dataPtr + *aZoneFileStream >> menu.itemImageTrack; + + qDebug() << aZoneFileStream->device()->pos(); + + //statement_s visibleExp; + //statement_s textExp; + //statement_s materialExp; + //statement_s rectXExp; + //statement_s rectYExp; + //statement_s rectWExp; + //statement_s rectHExp; + //statement_s foreColorAExp; + result.menuDefs << menu; + } + return result; +} + +void ZoneFile_COD4_Wii::pParseAsset_Weapon(QDataStream *aZoneFileStream) { + //WEAPON_FILE + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD4_Wii::pParseAsset_D3DBSP(QDataStream *aZoneFileStream) { + //D3DBSP_DUMP + Q_UNUSED(aZoneFileStream); +} + +StringTable ZoneFile_COD4_Wii::pParseAsset_StringTable(QDataStream *aZoneFileStream) { + StringTable result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.columnCount + >> result.rowCount; + + // Todo fix this + result.columnCount = 0; + result.rowCount = 0; + + aZoneFileStream->skipRawData(4); + + QString stringTableName; + char stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + while (stringTableNameChar != 0) { + result.name += stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + } + + for (quint32 i = 0; i < result.rowCount; i++) { + QByteArray pointerData(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pointerData.data(), 4); + result.tablePointers.push_back(pointerData.toHex()); + + aZoneFileStream->skipRawData(4); + } + + for (const QString &pointerAddr : result.tablePointers) { + QString leadingContent = ""; + if (pointerAddr == "FFFFFFFF") { + char leadingContentChar; + *aZoneFileStream >> leadingContentChar; + while (leadingContentChar != 0) { + leadingContent += leadingContentChar; + *aZoneFileStream >> leadingContentChar; + } + } else { + leadingContent = pointerAddr; + } + + QString content; + char contentChar; + *aZoneFileStream >> contentChar; + while (contentChar != 0) { + content += contentChar; + *aZoneFileStream >> contentChar; + } + result.content[leadingContent] = content; + } + return result; +} + +AssetType ZoneFile_COD4_Wii::AssetStrToEnum(const QString aAssetType) { + const QString cleanedType = aAssetType.toUpper(); + if (cleanedType == "17000000") { // localized string PARTIALLY VERIFIED + return ASSET_LOCAL_STRING; + } else if (cleanedType == "20000000") { // raw_file PARTIALLY VERIFIED + return ASSET_RAW_FILE; + } else if (cleanedType == "1A000000") { // fx PARTIALLY VERIFIED + return ASSET_EFFECT; + } else if (cleanedType == "09000000") { // loaded_sound PARTIALLY VERIFIED + return ASSET_SOUND; + } else if (cleanedType == "04000000") { // x_anim PARTIALLY VERIFIED + return ASSET_ANIMATION; + } else if (cleanedType == "0C000000") { // collision_map PARTIALLY VERIFIED + return ASSET_COLLISION_MAP; + } else if (cleanedType == "21000000") { // string_table PARTIALLY VERIFIED + return ASSET_STRING_TABLE; + } else if (cleanedType == "15000000") { // menu_file PARTIALLY VERIFIED + return ASSET_MENU; + } else if (cleanedType == "07000000") { // tech set PARTIALLY VERIFIED + return ASSET_TECH_SET; + } else if (cleanedType == "18000000") { // weapon PARTIALLY VERIFIED + return ASSET_WEAPON; + } else if (cleanedType == "11000000") { // gfx map PARTIALLY VERIFIED + return ASSET_GFX_MAP; + } else if (cleanedType == "12000000") { // light_def PARTIALLY VERIFIED + return ASSET_LIGHT_DEF; + } else if (cleanedType == "14000000") { // font PARTIALLY VERIFIED + return ASSET_FONT; + } else if (cleanedType == "05000000") { // xmodel PARTIALLY VERIFIED + return ASSET_MODEL; + } else if (cleanedType == "0D000000") { // d3dbsp PARTIALLY VERIFIED + return ASSET_D3DBSP; + } else if (cleanedType == "06000000") { // image PARTIALLY VERIFIED + return ASSET_IMAGE; + } else if (cleanedType == "0E000000") { // game map sp PARTIALLY VERIFIED + return ASSET_GAME_MAP_SP; + } else if (cleanedType == "0B000000") { // col map sp PARTIALLY VERIFIED + return ASSET_COL_MAP_SP; + } + return ASSET_NONE; +} + +QByteArray ZoneFile_COD4_Wii::GetBinaryData() { + QByteArray result; + + return result; +} diff --git a/libs/zonefile/Wii/zonefile_cod4_wii.h b/libs/zonefile/Wii/zonefile_cod4_wii.h new file mode 100644 index 0000000..5f7d588 --- /dev/null +++ b/libs/zonefile/Wii/zonefile_cod4_wii.h @@ -0,0 +1,52 @@ +#ifndef ZONEFILE_COD4_WII_H +#define ZONEFILE_COD4_WII_H + +#include "zonefile.h" + +class ZoneFile_COD4_Wii : public ZoneFile +{ +public: + ZoneFile_COD4_Wii(); + ~ZoneFile_COD4_Wii(); + + bool Load(const QByteArray aFileData) override; + AssetType AssetStrToEnum(const QString aAssetType) override; + + QByteArray GetBinaryData() override; + +protected: + void pParseZoneHeader(QDataStream *aZoneFileStream) override; + quint32 pParseZoneSize(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsA(QDataStream *aZoneFileStream) override; + quint32 pParseZoneTagCount(QDataStream *aZoneFileStream) override; + quint32 pParseZoneRecordCount(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsB(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsC(QDataStream *aZoneFileStream) override; + QStringList pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) override; + QStringList pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) override; + AssetMap pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) override; + LocalString pParseAsset_LocalString(QDataStream *aZoneFileStream) override; + RawFile pParseAsset_RawFile(QDataStream *aZoneFileStream) override; + void pParseAsset_PhysPreset(QDataStream *aZoneFileStream) override; + Model pParseAsset_Model(QDataStream *aZoneFileStream) override; + Material pParseAsset_Material(QDataStream *aZoneFileStream) override; + Shader pParseAsset_Shader(QDataStream *aZoneFileStream) override; + TechSet pParseAsset_TechSet(QDataStream *aZoneFileStream) override; + Image pParseAsset_Image(QDataStream *aZoneFileStream) override; + SoundAsset pParseAsset_Sound(QDataStream *aZoneFileStream) override; + void pParseAsset_ColMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapSP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_LightDef(QDataStream *aZoneFileStream) override; + void pParseAsset_UIMap(QDataStream *aZoneFileStream) override; + void pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) override; + void pParseAsset_AIType(QDataStream *aZoneFileStream) override; + void pParseAsset_FX(QDataStream *aZoneFileStream) override; + Animation pParseAsset_Animation(QDataStream *aZoneFileStream) override; + MenuFile pParseAsset_MenuFile(QDataStream *aZoneFileStream) override; + void pParseAsset_Weapon(QDataStream *aZoneFileStream) override; + void pParseAsset_D3DBSP(QDataStream *aZoneFileStream) override; + StringTable pParseAsset_StringTable(QDataStream *aZoneFileStream) override; +}; + +#endif // ZONEFILE_COD4_WII_H diff --git a/libs/zonefile/Wii/zonefile_cod7_wii.cpp b/libs/zonefile/Wii/zonefile_cod7_wii.cpp new file mode 100644 index 0000000..6ad2e54 --- /dev/null +++ b/libs/zonefile/Wii/zonefile_cod7_wii.cpp @@ -0,0 +1,1077 @@ +#include "zonefile_cod7_wii.h" + +#include +#include +#include + +ZoneFile_COD7_Wii::ZoneFile_COD7_Wii() +{ + +} + +ZoneFile_COD7_Wii::~ZoneFile_COD7_Wii() +{ + +} + +bool ZoneFile_COD7_Wii::Load(const QByteArray aFileData) { + // Open zone file as little endian stream + QDataStream zoneFileStream(aFileData); + zoneFileStream.setByteOrder(QDataStream::BigEndian); + + // Parse data from zone file header + pParseZoneHeader(&zoneFileStream); + zoneFileStream.device()->seek(zoneFileStream.device()->pos() - 1); + SetRecords(pParseZoneIndex(&zoneFileStream, GetRecordCount())); + SetAssetMap(pParseAssets(&zoneFileStream, GetRecords())); + + return true; +} + +void ZoneFile_COD7_Wii::pParseZoneHeader(QDataStream *aZoneFileStream) { + quint32 size = pParseZoneSize(aZoneFileStream); + SetSize(size); + + aZoneFileStream->skipRawData(36); + + quint32 tagCount = pParseZoneTagCount(aZoneFileStream); + SetTagCount(tagCount - 1); + + pParseZoneUnknownsB(aZoneFileStream); + + quint32 recordCount = pParseZoneRecordCount(aZoneFileStream); + SetRecordCount(recordCount); + + if (tagCount) { + pParseZoneUnknownsC(aZoneFileStream); + SetTags(pParseZoneTags(aZoneFileStream, tagCount)); + } else { + aZoneFileStream->skipRawData(4); + } +} + +quint32 ZoneFile_COD7_Wii::pParseZoneSize(QDataStream *aZoneFileStream) { + quint32 zoneFileSize; + *aZoneFileStream >> zoneFileSize; + if (zoneFileSize <= 0) { + qDebug() << "Tried to open empty zone file!"; + exit(-1); + } + zoneFileSize += 36; + return zoneFileSize; +} + +/* + ParseZoneUnknownsA() + + Parses the 1st section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD7_Wii::pParseZoneUnknownsA(QDataStream *aZoneFileStream) { + // Byte 4-7, 8-11, 12-15: unknown + QByteArray unknown1(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown1.data(), 4); + + QByteArray unknown2(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown2.data(), 4); + + QByteArray unknown3(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown3.data(), 4); + + // Byte 16-19, 20-23: empty/unknown + QByteArray unknown4(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown4.data(), 4); + + QByteArray unknown5(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown5.data(), 4); + + // Byte 24-27: somehow related to the filesize, but smaller value + QByteArray unknown6(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown6.data(), 4); + + // Byte 28-31, 32-35: unknown + QByteArray unknown7(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown7.data(), 4); + + QByteArray unknown8(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown8.data(), 4); +} + +/* + ParseZoneTagCount() + + Parses the number of string tags in the zone index +*/ +quint32 ZoneFile_COD7_Wii::pParseZoneTagCount(QDataStream *aZoneFileStream) { + quint32 tagCount; + *aZoneFileStream >> tagCount; + return tagCount; +} + +/* + ParseZoneRecordCount() + + Parses the number of records in the zone index +*/ +quint32 ZoneFile_COD7_Wii::pParseZoneRecordCount(QDataStream *aZoneFileStream) { + quint32 recordCount; + *aZoneFileStream >> recordCount; + return recordCount; +} + +/* + ParseZoneUnknownsB() + + Parses the 2nd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD7_Wii::pParseZoneUnknownsB(QDataStream *aZoneFileStream) { + // Byte 44-47: Unknown/empty? + QByteArray unknown9(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown9.data(), 4); +} + +/* + pParseZoneUnknownsC() + + Parses the 3rd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD7_Wii::pParseZoneUnknownsC(QDataStream *aZoneFileStream) { + // Byte 40-43: Unknown/empty? + QByteArray unknown10(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown10.data(), 4); + + // Byte 44-47: Unknown/empty? + QByteArray unknown11(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown11.data(), 4); +} + +/* + ParseZoneTags() + + Parses the string tags ate the start of zone file +*/ +QStringList ZoneFile_COD7_Wii::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) { + QStringList tags; + + // Byte 48-51: Repeated separators? ÿÿÿÿ x i + aZoneFileStream->skipRawData(4 * (tagCount - 1)); + + // Parse tags/strings before index + QString zoneTag; + char zoneTagChar; + for (quint32 i = 0; i < tagCount; i++) { + *aZoneFileStream >> zoneTagChar; + while (zoneTagChar != 0) { + zoneTag += zoneTagChar; + *aZoneFileStream >> zoneTagChar; + } + tags << zoneTag; + zoneTag.clear(); + } + return tags; +} + +/* + ParseZoneIndex() + + Parse the binary zone index data and populate table +*/ +QStringList ZoneFile_COD7_Wii::pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) { + QStringList result; + + // Don't parse if no records + if (!recordCount) { return result; } + + if (aZoneFileStream->device()->peek(4).toHex().contains("ffff")) { + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 2); + } + + // Parse index & map found asset types + for (quint32 i = 0; i <= recordCount; i++) { + // Skip record start + QByteArray rawAssetType(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rawAssetType.data(), 4); + result << rawAssetType.toHex(); + + // Skip separator + aZoneFileStream->skipRawData(4); + } + return result; +} + +AssetMap ZoneFile_COD7_Wii::pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) { + AssetMap result; + + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 8); + + for (int i = 0; i < assetOrder.size(); i++) { + const QString typeHex = assetOrder[i]; + const AssetType typeStr = AssetStrToEnum(typeHex); + + if (typeStr == ASSET_LOCAL_STRING) { // localized string asset + result.localStrings << pParseAsset_LocalString(aZoneFileStream); + } else if (typeStr == ASSET_RAW_FILE) { // gsc + auto rawFile = pParseAsset_RawFile(aZoneFileStream); + if (rawFile.length) { + result.rawFiles << rawFile; + } + } else if (typeStr == ASSET_PHYS_PRESET) { // physpreset + pParseAsset_PhysPreset(aZoneFileStream); + } else if (typeStr == ASSET_MODEL) { // xmodel + result.models << pParseAsset_Model(aZoneFileStream); + } else if (typeStr == ASSET_MATERIAL) { // material + pParseAsset_Material(aZoneFileStream); + } else if (typeStr == ASSET_SHADER) { // pixelshader + pParseAsset_Shader(aZoneFileStream); + } else if (typeStr == ASSET_TECH_SET) { // techset include + result.techSets << pParseAsset_TechSet(aZoneFileStream); + } else if (typeStr == ASSET_IMAGE) { // image + result.images << pParseAsset_Image(aZoneFileStream); + } else if (typeStr == ASSET_SOUND) { // loaded_sound + result.sounds << pParseAsset_Sound(aZoneFileStream); + } else if (typeStr == ASSET_COLLISION_MAP) { // col_map_mp + pParseAsset_ColMapMP(aZoneFileStream); + } else if (typeStr == ASSET_MP_MAP) { // game_map_sp + pParseAsset_GameMapSP(aZoneFileStream); + } else if (typeStr == ASSET_SP_MAP) { // game_map_mp + pParseAsset_GameMapMP(aZoneFileStream); + } else if (typeStr == ASSET_LIGHT_DEF) { // lightdef + pParseAsset_LightDef(aZoneFileStream); + } else if (typeStr == ASSET_UI_MAP) { // ui_map + pParseAsset_UIMap(aZoneFileStream); + } else if (typeStr == ASSET_SND_DRIVER_GLOBALS) { // snddriverglobals + pParseAsset_SNDDriverGlobals(aZoneFileStream); + } else if (typeStr == ASSET_AI_TYPE) { // aitype + pParseAsset_AIType(aZoneFileStream); + } else if (typeStr == ASSET_EFFECT) { // aitype + pParseAsset_FX(aZoneFileStream); + } else if (typeStr == ASSET_ANIMATION) { // aitype + result.animations << pParseAsset_Animation(aZoneFileStream); + } else if (typeStr == ASSET_STRING_TABLE) { // string_table + result.stringTables << pParseAsset_StringTable(aZoneFileStream); + } else if (typeStr == ASSET_MENU) { // string_table + result.menuFiles << pParseAsset_MenuFile(aZoneFileStream); + } else if (typeStr == ASSET_WEAPON) { // string_table + pParseAsset_Weapon(aZoneFileStream); + } else if (typeStr == ASSET_D3DBSP) { // string_table + pParseAsset_D3DBSP(aZoneFileStream); + } + } + return result; +} + +LocalString ZoneFile_COD7_Wii::pParseAsset_LocalString(QDataStream *aZoneFileStream) { + LocalString result; + + quint32 stringPtr, aliasPtr; + *aZoneFileStream >> stringPtr >> aliasPtr; + if (stringPtr == 4294967295) { + // Parse local string asset contents + QString localStr; + char localStrChar; + *aZoneFileStream >> localStrChar; + while (localStrChar != 0) { + result.string += localStrChar; + *aZoneFileStream >> localStrChar; + } + } else { + result.string = "String Ptr: " + QString::number(stringPtr); + } + + if (aliasPtr == 4294967295) { + // Parse rawfile name + QString aliasName; + char aliasNameChar; + *aZoneFileStream >> aliasNameChar; + while (aliasNameChar != 0) { + result.alias += aliasNameChar; + *aZoneFileStream >> aliasNameChar; + } + } else { + result.string = "Alias Ptr: " + QString::number(aliasPtr); + } + + return result; +} + +RawFile ZoneFile_COD7_Wii::pParseAsset_RawFile(QDataStream *aZoneFileStream) { + RawFile result; + + // Skip start separator FF FF FF FF (pointer?) + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.length; + + // Skip unknown 4 byte data + aZoneFileStream->skipRawData(4); + + // Parse rawfile path + char scriptPathChar; + *aZoneFileStream >> scriptPathChar; + while (scriptPathChar != 0) { + result.path += scriptPathChar; + *aZoneFileStream >> scriptPathChar; + } + result.path.replace(",", ""); + const QStringList pathParts = result.path.split('/'); + if (pathParts.size() == 0) { + qDebug() << "Failed to parse ff path! " << result.path; + exit(-1); + } + + // Parse gsc contents + char rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + while (rawFileContentsChar != 0 && rawFileContentsChar != -1) { + result.contents += rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + } + return result; +} + +void ZoneFile_COD7_Wii::pParseAsset_PhysPreset(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Model ZoneFile_COD7_Wii::pParseAsset_Model(QDataStream *aZoneFileStream) { + Model result; + + *aZoneFileStream >> result.namePtr >> result.tagCount >> result.rootTagCount + >> result.surfCount >> result.unknownCount >> result.boneNamePtr + >> result.parentListPtr >> result.quatsPtr >> result.transPtr + >> result.partClassPtr >> result.baseMatPtr + >> result.surfsPtr >> result.materialHandlesPtr; + + // Parse XModelLodInfo + for (int i = 1; i <= 4; i++) { + quint32 intDist; + *aZoneFileStream >> intDist; + + std::memcpy(&result.lodInfo[i].dist, &intDist, sizeof(result.lodInfo[i].dist)); + *aZoneFileStream >> result.lodInfo[i].numsurfs >> result.lodInfo[i].surfIndex; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.lodInfo[i].partBits[0] + >> result.lodInfo[i].partBits[1] + >> result.lodInfo[i].partBits[2] + >> result.lodInfo[i].partBits[3]; + } + + *aZoneFileStream >> result.collSurfsPtr >> result.numCollSurfs >> result.contents >> result.boneInfoPtr; + + quint32 intRadius, intMins[3], intMaxs[3]; + *aZoneFileStream >> intRadius >> intMins[0] >> intMins[1] + >> intMins[2] >> intMaxs[0] >> intMaxs[1] >> intMaxs[2]; + + std::memcpy(&result.radius, &intRadius, sizeof(result.radius)); + + std::memcpy(&result.mins[0], &intMins[0], sizeof(result.mins[0])); + std::memcpy(&result.mins[1], &intMins[1], sizeof(result.mins[1])); + std::memcpy(&result.mins[2], &intMins[2], sizeof(result.mins[2])); + + std::memcpy(&result.maxs[0], &intMaxs[0], sizeof(result.maxs[0])); + std::memcpy(&result.maxs[1], &intMaxs[1], sizeof(result.maxs[2])); + std::memcpy(&result.maxs[2], &intMaxs[2], sizeof(result.maxs[3])); + + *aZoneFileStream >> result.numLods >> result.collLod >> result.streamInfoPtr + >> result.memUsage >> result.flags >> result.physPresetPtr >> result.physGeomsPtr; + + // Parse model name + char modelNameChar; + *aZoneFileStream >> modelNameChar; + while (modelNameChar == 0) { + *aZoneFileStream >> modelNameChar; + } + while (modelNameChar != 0) { + result.modelName += modelNameChar; + *aZoneFileStream >> modelNameChar; + } + return result; +} + +Material ZoneFile_COD7_Wii::pParseAsset_Material(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); + + return Material(); +} + +Shader ZoneFile_COD7_Wii::pParseAsset_Shader(QDataStream *aZoneFileStream) { + Shader result = Shader(); + + quint8 minorVersion, majorVersion; + *aZoneFileStream >> minorVersion >> majorVersion; + + quint32 magic; + *aZoneFileStream >> magic; + + // Verify .fxc magic + if (magic != 65534 && magic != 65535) { return result; } + + SHADER_TYPE type = SHADER_NONE; + quint16 rawShaderType; + *aZoneFileStream >> rawShaderType; + if (rawShaderType == 65535) { // Pixel shader + type = SHADER_PIXEL; + } else if (rawShaderType == 65534) { // Vertex shader + type = SHADER_VERTEX; + } + Q_UNUSED(type); + + while (true) { + quint32 instructionToken; + *aZoneFileStream >> instructionToken; + + SHADER_OPCODE opCode = (SHADER_OPCODE)(instructionToken & 0xffff); + + int size; + if (opCode == OPCODE_End) { + break; + } else if (opCode == OPCODE_Comment) { + size = (int)((instructionToken >> 16) & 0x7FFF); + } else { + size = (int)((instructionToken >> 24) & 0x0f); + } + Q_UNUSED(size); + } + + + return result; +} + +TechSet ZoneFile_COD7_Wii::pParseAsset_TechSet(QDataStream *aZoneFileStream) { + TechSet result; + + for (int i = 1; i <= 62; i++) { + quint32 ptr; + *aZoneFileStream >> ptr; + + result.pointers << ptr; + } + qDebug() << aZoneFileStream->device()->pos(); + + // Parse techset name + char techSetNameChar; + *aZoneFileStream >> techSetNameChar; + while (techSetNameChar != 0) { + result.name += techSetNameChar; + *aZoneFileStream >> techSetNameChar; + } + result.name.replace(",", ""); + + return result; +} + +Image ZoneFile_COD7_Wii::pParseAsset_Image(QDataStream *aZoneFileStream) { + Image result; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknowna >> result.unknownb + >> result.unknownc >> result.unknownd + >> result.unknowne >> result.unknownf + >> result.unknowng; + + aZoneFileStream->skipRawData(15 * 4); + *aZoneFileStream >> result.unknownh >> result.unknowni; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknownj; + + aZoneFileStream->skipRawData(4); + + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + result.materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + result.materialName.replace(",", ""); + + if (result.unknowna) { + *aZoneFileStream >> result.unknownk; + *aZoneFileStream >> result.unknownl; + *aZoneFileStream >> result.unknownm; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown1; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown2 >> result.unknown3 + >> result.size1 >> result.size2 + >> result.unknown4 >> result.unknown5; + + aZoneFileStream->skipRawData(4); + + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + result.name += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + + *aZoneFileStream >> result.unknown6 >> result.unknown7; + + QByteArray compressionData(8, Qt::Uninitialized); + aZoneFileStream->readRawData(compressionData.data(), 8); + if (compressionData.contains("DXT1")) { + result.compression = COMPRESSION_DXT1; + } else if (compressionData.contains("DXT3")) { + result.compression = COMPRESSION_DXT3; + } else if (compressionData.contains("DXT5")) { + result.compression = COMPRESSION_DXT5; + } else { + result.compression = COMPRESSION_NONE; + } + + *aZoneFileStream >> result.unknown8 >> result.unknown9; + } + + return result; +} + +SoundAsset ZoneFile_COD7_Wii::pParseAsset_Sound(QDataStream *aZoneFileStream) { + SoundAsset result; + + qDebug() << aZoneFileStream->device()->pos(); + + QByteArray rootNamePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rootNamePtr.data(), 4); + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.count; + + if (rootNamePtr.toHex() == "ffffffff") { + // Read in sound file name + char soundNameChar; + *aZoneFileStream >> soundNameChar; + while (soundNameChar != 0) { + result.name += soundNameChar; + *aZoneFileStream >> soundNameChar; + } + } + + int tagCount = 0; + int resultCount = 0; + for (quint32 i = 0; i < result.count; i++) { + aZoneFileStream->skipRawData(12); + + QByteArray tagPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(tagPtr.data(), 4); + + if (tagPtr.toHex() == "ffffffff") { + tagCount++; + } + aZoneFileStream->skipRawData(4); + + QByteArray pathPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pathPtr.data(), 4); + + if (pathPtr.toHex() == "ffffffff") { + resultCount++; + } + + aZoneFileStream->skipRawData(160); + } + + for (int i = 0; i < tagCount; i++) { + // Read in tag? + QString tag; + char tagChar; + *aZoneFileStream >> tagChar; + while (tagChar != 0) { + tag += tagChar; + *aZoneFileStream >> tagChar; + } + } + + for (int i = 0; i < resultCount; i++) { + Sound sound; + + if (aZoneFileStream->device()->peek(12).toHex().contains("ffffffff00000000")) { + aZoneFileStream->skipRawData(12); + } + + aZoneFileStream->skipRawData(8); + + QByteArray aliasPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(aliasPtr.data(), 4); + + QByteArray namePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(namePtr.data(), 4); + + *aZoneFileStream >> sound.dataLength; + + if (aliasPtr.toHex() == "ffffffff") { + // Read in sound alias name + char soundAliasChar; + *aZoneFileStream >> soundAliasChar; + while (soundAliasChar != 0) { + sound.alias += soundAliasChar; + *aZoneFileStream >> soundAliasChar; + } + } + + if (aZoneFileStream->device()->peek(4) == "RIFF") { + sound.path = sound.alias; + sound.alias = ""; + } else if (namePtr.toHex() == "ffffffff") { + // Read in sound file path + char soundPathChar; + *aZoneFileStream >> soundPathChar; + while (soundPathChar != 0) { + sound.path += soundPathChar; + *aZoneFileStream >> soundPathChar; + } + sound.path.replace(",", ""); + } + + if (sound.dataLength) { + QByteArray data(sound.dataLength, Qt::Uninitialized); + aZoneFileStream->readRawData(data.data(), sound.dataLength); + sound.data = data; + } + result.sounds.append(sound); + } + + return result; +} + +void ZoneFile_COD7_Wii::pParseAsset_ColMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD7_Wii::pParseAsset_GameMapSP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD7_Wii::pParseAsset_GameMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD7_Wii::pParseAsset_LightDef(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD7_Wii::pParseAsset_UIMap(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD7_Wii::pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD7_Wii::pParseAsset_AIType(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD7_Wii::pParseAsset_FX(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Animation ZoneFile_COD7_Wii::pParseAsset_Animation(QDataStream *aZoneFileStream) { + Animation result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.dataByteCount + >> result.dataShortCount + >> result.dataIntCount + >> result.randomDataByteCount + >> result.randomDataIntCount + >> result.numframes + >> result.isLooped + >> result.isDelta + >> result.noneRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.normalTranslatedBoneCount + >> result.preciseTranslatedBoneCount + >> result.staticTranslatedBoneCount + >> result.noneTranslatedBoneCount + >> result.totalBoneCount + >> result.otherBoneCount1 + >> result.otherBoneCount2 + >> result.notifyCount + >> result.assetType + >> result.pad + >> result.randomDataShortCount + >> result.indexCount + >> result.frameRate + >> result.frequency + >> result.boneIDsPtr + >> result.dataBytePtr + >> result.dataShortPtr + >> result.dataIntPtr + >> result.randomDataShortPtr + >> result.randomDataBytePtr + >> result.randomDataIntPtr + >> result.longIndiciesPtr + >> result.notificationsPtr + >> result.deltaPartsPtr; + + // Read in x_anim file name + QString xAnimName; + char xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + while (xAnimNameChar != 0) { + result.name += xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + } + + // Parse x_anim index header + QVector sectionLengths; + for (int i = 0; i < result.numframes; i++) { + quint8 sectionlength; + *aZoneFileStream >> sectionlength; + sectionLengths.push_back(sectionlength); + // Skip padding + aZoneFileStream->skipRawData(1); + } + // Skip unknown section + aZoneFileStream->skipRawData(2 * 8); + + return result; +} + +MenuFile ZoneFile_COD7_Wii::pParseAsset_MenuFile(QDataStream *aZoneFileStream) { + //MENU_FILE + MenuFile result; + + aZoneFileStream->skipRawData(4); // Separator + + // Parse menu def count + *aZoneFileStream >> result.menuCount; + + // Clearly misparsed, never have this much + if (result.menuCount > 1000) { + qDebug() << "Failure reported when parsing menu file."; + return result; + } + for (uint i = 0; i < result.menuCount; i++) { + Menu menu; + + aZoneFileStream->skipRawData(4); // Separator + + // Read in x_anim file name + char menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + while (menuFilepathChar != 0) { + menu.filePath += menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + } + aZoneFileStream->skipRawData(4); // Separator + + *aZoneFileStream >> menu.menuNamePtr; + + float menuRectX, menuRectY, menuRectWidth, menuRectHeight; + *aZoneFileStream >> menuRectX >> menuRectY >> menuRectWidth >> menuRectHeight; + menu.rect = QRectF(menuRectX, menuRectY, menuRectWidth, menuRectHeight); + + quint32 hAlignInt, vAlignInt; + *aZoneFileStream >> hAlignInt >> vAlignInt; + menu.hAlign = (MENU_H_ALIGNMENT)hAlignInt; + menu.vAlign = (MENU_V_ALIGNMENT)vAlignInt; + + float rectClientX, rectClientY, rectClientWidth, rectClientHeight; + *aZoneFileStream >> rectClientX >> rectClientY >> rectClientWidth >> rectClientHeight; + menu.clientRect = QRectF(rectClientX, rectClientY, rectClientWidth, rectClientHeight); + + quint32 hClientAlignInt, vClientAlignInt, styleInt, borderInt; + *aZoneFileStream >> hClientAlignInt >> vClientAlignInt >> menu.groupPtr + >> styleInt >> borderInt >> menu.ownerDraw >> menu.ownerDrawFlags + >> menu.borderSize >> menu.staticFlags >> menu.dynamicFlags >> menu.nextTime; + menu.hClientAlign = (MENU_H_ALIGNMENT)hClientAlignInt; + menu.vClientAlign = (MENU_V_ALIGNMENT)vClientAlignInt; + menu.style = (MENU_WINDOW_STYLE)styleInt; + menu.border = (MENU_WINDOW_BORDER)borderInt; + + float foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA, + backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA, + borderColorR, borderColorG, borderColorB, borderColorA, + outlineColorR, outlineColorG, outlineColorB, outlineColorA; + *aZoneFileStream >> foregroundColorR >> foregroundColorG >> foregroundColorB >> foregroundColorA + >> backgroundColorR >> backgroundColorG >> backgroundColorB >> backgroundColorA + >> borderColorR >> borderColorG >> borderColorB >> borderColorA + >> outlineColorR >> outlineColorG >> outlineColorB >> outlineColorA; + + menu.foregroundColor = QColor(foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA); + menu.backgroundColor = QColor(backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA); + menu.borderColor = QColor(borderColorR, borderColorG, borderColorB, borderColorA); + menu.outlineColor = QColor(outlineColorR, outlineColorG, outlineColorB, outlineColorA); + + *aZoneFileStream >> menu.materialPtr >> menu.fontPtr >> menu.fullScreen >> menu.itemCount + >> menu.fontIndex >> menu.cursorItem >> menu.fadeCycle >> menu.fadeClamp + >> menu.fadeAmount >> menu.fadeInAmount >> menu.blurRadius >> menu.onOpenPtr + >> menu.onFocusPtr >> menu.onClosePtr >> menu.onESCPtr >> menu.onKeyPtr + >> menu.visibleExpCount >> menu.expEntryPtr >> menu.allowedBindingPtr + >> menu.soundNamePtr >> menu.imageTrack; + + float focusColorR, focusColorG, focusColorB, focusColorA, + disabledColorR, disabledColorG, disabledColorB, disabledColorA; + *aZoneFileStream >> focusColorR >> focusColorG >> focusColorB >> focusColorA + >> disabledColorR >> disabledColorG >> disabledColorB >> disabledColorA; + menu.focusColor = QColor(focusColorR, focusColorG, focusColorB, focusColorA); + menu.disabledColor = QColor(disabledColorR, disabledColorG, disabledColorB, disabledColorA); + + *aZoneFileStream >> menu.rectXExpCount >> menu.rectXExpPtr >> menu.rectYExpCount >> menu.rectYExpPtr; + + aZoneFileStream->skipRawData(4); // Separator + + char menuDefNameChar; + int menuDefNameLen = 0; + *aZoneFileStream >> menuDefNameChar; + while (menuDefNameChar != 0 && menuDefNameLen < 30) { + menuDefNameLen++; + menu.name += menuDefNameChar; + *aZoneFileStream >> menuDefNameChar; + } + + char defStringChar; + int defStringLen = 0; + *aZoneFileStream >> defStringChar; + while (defStringChar != 0 && defStringLen < 30) { + defStringLen++; + menu.definition += defStringChar; + *aZoneFileStream >> defStringChar; + } + aZoneFileStream->skipRawData(4 * 10); + + *aZoneFileStream >> menu.itemWindowDefNamePtr; + + float itemRectX, itemRectY, itemRectWidth, itemRectHeight; + *aZoneFileStream >> itemRectX >> itemRectY >> itemRectWidth >> itemRectHeight; + menu.itemRect = QRectF(itemRectX, itemRectY, itemRectWidth, itemRectHeight); + + *aZoneFileStream >> menu.itemHAlignment >> menu.itemVAlignment >> menu.itemGroupPtr + >> menu.itemWindowStyle >> menu.itemWindowBorder >> menu.itemOwnerDraw + >> menu.itemOwnerDrawFlags >> menu.itemBorderSize >> menu.itemStaticFlags + >> menu.itemDynamicFlags >> menu.itemNextTime; + + float itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA, + itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA, + itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA, + itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA; + *aZoneFileStream >> itemForegroundColorR >> itemForegroundColorG >> itemForegroundColorB >> itemForegroundColorA + >> itemBackgroundColorR >> itemBackgroundColorG >> itemBackgroundColorB >> itemBackgroundColorA + >> itemBorderColorR >> itemBorderColorG >> itemBorderColorB >> itemBorderColorA + >> itemOutlineColorR >> itemOutlineColorG >> itemOutlineColorB >> itemOutlineColorA; + + menu.itemForegroundColor = QColor(itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA); + menu.itemBackgroundColor = QColor(itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA); + menu.itemBorderColor = QColor(itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA); + menu.itemOutlineColor = QColor(itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA); + + *aZoneFileStream >> menu.itemMaterialPtr; + + float itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight; + *aZoneFileStream >> itemTextRectX >> itemTextRectY >> itemTextRectWidth >> itemTextRectHeight; + menu.itemTextRect = QRectF(itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight); + + quint32 hItemTextAlignInt, vItemTextAlignInt, itemType, fontTypeInt, textStyleInt; + *aZoneFileStream >> hItemTextAlignInt >> vItemTextAlignInt >> itemType >> menu.dataType + >> menu.alignment >> fontTypeInt >> menu.textAlignMode >> menu.textalignx >> menu.textaligny + >> menu.textscale >> textStyleInt >> menu.gameMsgWindowIndex >> menu.gameMsgWindowMode + >> menu.testPtr >> menu.textSavegameInfo >> menu.parentPtr; + menu.itemText_hAlign = (MENU_H_ALIGNMENT)hItemTextAlignInt; + menu.itemText_vAlign = (MENU_V_ALIGNMENT)vItemTextAlignInt; + menu.itemType = (MENU_ITEM_TYPE)itemType; + menu.fontEnum = (MENU_FONT_TYPE)fontTypeInt; + menu.textStyle = (MENU_ITEM_TEXTSTYLE)textStyleInt; + + *aZoneFileStream >> menu.mouseEnterText >> menu.mouseExitText >> menu.mouseEnter >> menu.mouseExit + >> menu.action >> menu.onAccept >> menu.onFocus >> menu.leaveFocus >> menu.dvar >> menu.dvarTest + >> menu.keyHandlerPtr >> menu.enableDvarPtr >> menu.dvarFlags >> menu.focusSoundPtr + >> menu.special >> menu.cursorPos; + + // itemDefData_t typeData; + + // listBoxDef_s *listBox; + + *aZoneFileStream >> menu.startPos >> menu.endPos >> menu.drawPadding; + + *aZoneFileStream >> menu.elementWidth >> menu.elementHeight; + + *aZoneFileStream >> menu.elementStyle >> menu.numColumns; + + //columnInfo_s columnInfo[16]; + + *aZoneFileStream >> menu.doubleClickPtr; + + + *aZoneFileStream >> menu.notselectable >> menu.noScrollBars >> menu.usePaging; + + float itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA, + itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA, + itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA; + *aZoneFileStream >> itemSelectBorderColorR >> itemSelectBorderColorG >> itemSelectBorderColorB >> itemSelectBorderColorA + >> itemDisableColorR >> itemDisableColorG >> itemDisableColorB >> itemDisableColorA + >> itemFocusColorR >> itemFocusColorG >> itemFocusColorB >> itemFocusColorA; + menu.itemSelectBorderColor = QColor(itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA); + menu.itemDisableColor = QColor(itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA); + menu.itemFocusColor = QColor(itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA); + + *aZoneFileStream >> menu.selectIconPtr >> menu.backgroundItemListboxPtr >> menu.highlightTexturePtr; + + // editFieldDef_s *editField; + + *aZoneFileStream >> menu.minVal >> menu.maxVal >> menu.defVal >> menu.range >> menu.maxChars + >> menu.maxCharsGotoNext >> menu.maxPaintChars >> menu.paintOffset; + + // multiDef_s *multi; + + for (int i = 0; i < 32; i++) { + quint32 dvarList; + *aZoneFileStream >> dvarList; + menu.dvarListPtrs.push_back(dvarList); + } + + for (int i = 0; i < 32; i++) { + quint32 dvarStr; + *aZoneFileStream >> dvarStr; + menu.dvarStrPtrs.push_back(dvarStr); + } + + for (int i = 0; i < 32; i++) { + float dvarValue; + *aZoneFileStream >> dvarValue; + menu.dvarValues.push_back(dvarValue); + } + + *aZoneFileStream >> menu.count >> menu.strDef >> menu.enumDvarNamePtr; + aZoneFileStream->skipRawData(4); + //>> menu.dataPtr + *aZoneFileStream >> menu.itemImageTrack; + + qDebug() << aZoneFileStream->device()->pos(); + + //statement_s visibleExp; + //statement_s textExp; + //statement_s materialExp; + //statement_s rectXExp; + //statement_s rectYExp; + //statement_s rectWExp; + //statement_s rectHExp; + //statement_s foreColorAExp; + result.menuDefs << menu; + } + return result; +} + +void ZoneFile_COD7_Wii::pParseAsset_Weapon(QDataStream *aZoneFileStream) { + //WEAPON_FILE + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD7_Wii::pParseAsset_D3DBSP(QDataStream *aZoneFileStream) { + //D3DBSP_DUMP + Q_UNUSED(aZoneFileStream); +} + +StringTable ZoneFile_COD7_Wii::pParseAsset_StringTable(QDataStream *aZoneFileStream) { + StringTable result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.columnCount + >> result.rowCount; + + // Todo fix this + result.columnCount = 0; + result.rowCount = 0; + + aZoneFileStream->skipRawData(4); + + QString stringTableName; + char stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + while (stringTableNameChar != 0) { + result.name += stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + } + + for (quint32 i = 0; i < result.rowCount; i++) { + QByteArray pointerData(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pointerData.data(), 4); + result.tablePointers.push_back(pointerData.toHex()); + + aZoneFileStream->skipRawData(4); + } + + for (const QString &pointerAddr : result.tablePointers) { + QString leadingContent = ""; + if (pointerAddr == "FFFFFFFF") { + char leadingContentChar; + *aZoneFileStream >> leadingContentChar; + while (leadingContentChar != 0) { + leadingContent += leadingContentChar; + *aZoneFileStream >> leadingContentChar; + } + } else { + leadingContent = pointerAddr; + } + + QString content; + char contentChar; + *aZoneFileStream >> contentChar; + while (contentChar != 0) { + content += contentChar; + *aZoneFileStream >> contentChar; + } + result.content[leadingContent] = content; + } + return result; +} + +AssetType ZoneFile_COD7_Wii::AssetStrToEnum(const QString aAssetType) { + const QString cleanedType = aAssetType.toUpper(); + if (cleanedType == "17000000") { // localized string PARTIALLY VERIFIED + return ASSET_LOCAL_STRING; + } else if (cleanedType == "20000000") { // raw_file PARTIALLY VERIFIED + return ASSET_RAW_FILE; + } else if (cleanedType == "1A000000") { // fx PARTIALLY VERIFIED + return ASSET_EFFECT; + } else if (cleanedType == "09000000") { // loaded_sound PARTIALLY VERIFIED + return ASSET_SOUND; + } else if (cleanedType == "04000000") { // x_anim PARTIALLY VERIFIED + return ASSET_ANIMATION; + } else if (cleanedType == "0C000000") { // collision_map PARTIALLY VERIFIED + return ASSET_COLLISION_MAP; + } else if (cleanedType == "21000000") { // string_table PARTIALLY VERIFIED + return ASSET_STRING_TABLE; + } else if (cleanedType == "15000000") { // menu_file PARTIALLY VERIFIED + return ASSET_MENU; + } else if (cleanedType == "07000000") { // tech set PARTIALLY VERIFIED + return ASSET_TECH_SET; + } else if (cleanedType == "18000000") { // weapon PARTIALLY VERIFIED + return ASSET_WEAPON; + } else if (cleanedType == "11000000") { // gfx map PARTIALLY VERIFIED + return ASSET_GFX_MAP; + } else if (cleanedType == "12000000") { // light_def PARTIALLY VERIFIED + return ASSET_LIGHT_DEF; + } else if (cleanedType == "14000000") { // font PARTIALLY VERIFIED + return ASSET_FONT; + } else if (cleanedType == "05000000") { // xmodel PARTIALLY VERIFIED + return ASSET_MODEL; + } else if (cleanedType == "0D000000") { // d3dbsp PARTIALLY VERIFIED + return ASSET_D3DBSP; + } else if (cleanedType == "06000000") { // image PARTIALLY VERIFIED + return ASSET_IMAGE; + } else if (cleanedType == "0E000000") { // game map sp PARTIALLY VERIFIED + return ASSET_GAME_MAP_SP; + } else if (cleanedType == "0B000000") { // col map sp PARTIALLY VERIFIED + return ASSET_COL_MAP_SP; + } + return ASSET_NONE; +} + +QByteArray ZoneFile_COD7_Wii::GetBinaryData() { + QByteArray result; + + return result; +} diff --git a/libs/zonefile/Wii/zonefile_cod7_wii.h b/libs/zonefile/Wii/zonefile_cod7_wii.h new file mode 100644 index 0000000..da140df --- /dev/null +++ b/libs/zonefile/Wii/zonefile_cod7_wii.h @@ -0,0 +1,52 @@ +#ifndef ZONEFILE_COD7_WII_H +#define ZONEFILE_COD7_WII_H + +#include "zonefile.h" + +class ZoneFile_COD7_Wii : public ZoneFile +{ +public: + ZoneFile_COD7_Wii(); + ~ZoneFile_COD7_Wii(); + + bool Load(const QByteArray aFileData) override; + AssetType AssetStrToEnum(const QString aAssetType) override; + + QByteArray GetBinaryData() override; + +protected: + void pParseZoneHeader(QDataStream *aZoneFileStream) override; + quint32 pParseZoneSize(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsA(QDataStream *aZoneFileStream) override; + quint32 pParseZoneTagCount(QDataStream *aZoneFileStream) override; + quint32 pParseZoneRecordCount(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsB(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsC(QDataStream *aZoneFileStream) override; + QStringList pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) override; + QStringList pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) override; + AssetMap pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) override; + LocalString pParseAsset_LocalString(QDataStream *aZoneFileStream) override; + RawFile pParseAsset_RawFile(QDataStream *aZoneFileStream) override; + void pParseAsset_PhysPreset(QDataStream *aZoneFileStream) override; + Model pParseAsset_Model(QDataStream *aZoneFileStream) override; + Material pParseAsset_Material(QDataStream *aZoneFileStream) override; + Shader pParseAsset_Shader(QDataStream *aZoneFileStream) override; + TechSet pParseAsset_TechSet(QDataStream *aZoneFileStream) override; + Image pParseAsset_Image(QDataStream *aZoneFileStream) override; + SoundAsset pParseAsset_Sound(QDataStream *aZoneFileStream) override; + void pParseAsset_ColMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapSP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_LightDef(QDataStream *aZoneFileStream) override; + void pParseAsset_UIMap(QDataStream *aZoneFileStream) override; + void pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) override; + void pParseAsset_AIType(QDataStream *aZoneFileStream) override; + void pParseAsset_FX(QDataStream *aZoneFileStream) override; + Animation pParseAsset_Animation(QDataStream *aZoneFileStream) override; + MenuFile pParseAsset_MenuFile(QDataStream *aZoneFileStream) override; + void pParseAsset_Weapon(QDataStream *aZoneFileStream) override; + void pParseAsset_D3DBSP(QDataStream *aZoneFileStream) override; + StringTable pParseAsset_StringTable(QDataStream *aZoneFileStream) override; +}; + +#endif // ZONEFILE_COD7_WII_H diff --git a/libs/zonefile/Wii/zonefile_cod8_wii.cpp b/libs/zonefile/Wii/zonefile_cod8_wii.cpp new file mode 100644 index 0000000..710f933 --- /dev/null +++ b/libs/zonefile/Wii/zonefile_cod8_wii.cpp @@ -0,0 +1,1077 @@ +#include "zonefile_cod8_wii.h" + +#include +#include +#include + +ZoneFile_COD8_Wii::ZoneFile_COD8_Wii() +{ + +} + +ZoneFile_COD8_Wii::~ZoneFile_COD8_Wii() +{ + +} + +bool ZoneFile_COD8_Wii::Load(const QByteArray aFileData) { + // Open zone file as little endian stream + QDataStream zoneFileStream(aFileData); + zoneFileStream.setByteOrder(QDataStream::BigEndian); + + // Parse data from zone file header + pParseZoneHeader(&zoneFileStream); + zoneFileStream.device()->seek(zoneFileStream.device()->pos() - 1); + SetRecords(pParseZoneIndex(&zoneFileStream, GetRecordCount())); + SetAssetMap(pParseAssets(&zoneFileStream, GetRecords())); + + return true; +} + +void ZoneFile_COD8_Wii::pParseZoneHeader(QDataStream *aZoneFileStream) { + quint32 size = pParseZoneSize(aZoneFileStream); + SetSize(size); + + aZoneFileStream->skipRawData(36); + + quint32 tagCount = pParseZoneTagCount(aZoneFileStream); + SetTagCount(tagCount - 1); + + pParseZoneUnknownsB(aZoneFileStream); + + quint32 recordCount = pParseZoneRecordCount(aZoneFileStream); + SetRecordCount(recordCount); + + if (tagCount) { + pParseZoneUnknownsC(aZoneFileStream); + SetTags(pParseZoneTags(aZoneFileStream, tagCount)); + } else { + aZoneFileStream->skipRawData(4); + } +} + +quint32 ZoneFile_COD8_Wii::pParseZoneSize(QDataStream *aZoneFileStream) { + quint32 zoneFileSize; + *aZoneFileStream >> zoneFileSize; + if (zoneFileSize <= 0) { + qDebug() << "Tried to open empty zone file!"; + exit(-1); + } + zoneFileSize += 36; + return zoneFileSize; +} + +/* + ParseZoneUnknownsA() + + Parses the 1st section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD8_Wii::pParseZoneUnknownsA(QDataStream *aZoneFileStream) { + // Byte 4-7, 8-11, 12-15: unknown + QByteArray unknown1(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown1.data(), 4); + + QByteArray unknown2(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown2.data(), 4); + + QByteArray unknown3(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown3.data(), 4); + + // Byte 16-19, 20-23: empty/unknown + QByteArray unknown4(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown4.data(), 4); + + QByteArray unknown5(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown5.data(), 4); + + // Byte 24-27: somehow related to the filesize, but smaller value + QByteArray unknown6(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown6.data(), 4); + + // Byte 28-31, 32-35: unknown + QByteArray unknown7(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown7.data(), 4); + + QByteArray unknown8(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown8.data(), 4); +} + +/* + ParseZoneTagCount() + + Parses the number of string tags in the zone index +*/ +quint32 ZoneFile_COD8_Wii::pParseZoneTagCount(QDataStream *aZoneFileStream) { + quint32 tagCount; + *aZoneFileStream >> tagCount; + return tagCount; +} + +/* + ParseZoneRecordCount() + + Parses the number of records in the zone index +*/ +quint32 ZoneFile_COD8_Wii::pParseZoneRecordCount(QDataStream *aZoneFileStream) { + quint32 recordCount; + *aZoneFileStream >> recordCount; + return recordCount; +} + +/* + ParseZoneUnknownsB() + + Parses the 2nd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD8_Wii::pParseZoneUnknownsB(QDataStream *aZoneFileStream) { + // Byte 44-47: Unknown/empty? + QByteArray unknown9(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown9.data(), 4); +} + +/* + pParseZoneUnknownsC() + + Parses the 3rd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD8_Wii::pParseZoneUnknownsC(QDataStream *aZoneFileStream) { + // Byte 40-43: Unknown/empty? + QByteArray unknown10(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown10.data(), 4); + + // Byte 44-47: Unknown/empty? + QByteArray unknown11(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown11.data(), 4); +} + +/* + ParseZoneTags() + + Parses the string tags ate the start of zone file +*/ +QStringList ZoneFile_COD8_Wii::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) { + QStringList tags; + + // Byte 48-51: Repeated separators? ÿÿÿÿ x i + aZoneFileStream->skipRawData(4 * (tagCount - 1)); + + // Parse tags/strings before index + QString zoneTag; + char zoneTagChar; + for (quint32 i = 0; i < tagCount; i++) { + *aZoneFileStream >> zoneTagChar; + while (zoneTagChar != 0) { + zoneTag += zoneTagChar; + *aZoneFileStream >> zoneTagChar; + } + tags << zoneTag; + zoneTag.clear(); + } + return tags; +} + +/* + ParseZoneIndex() + + Parse the binary zone index data and populate table +*/ +QStringList ZoneFile_COD8_Wii::pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) { + QStringList result; + + // Don't parse if no records + if (!recordCount) { return result; } + + if (aZoneFileStream->device()->peek(4).toHex().contains("ffff")) { + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 2); + } + + // Parse index & map found asset types + for (quint32 i = 0; i <= recordCount; i++) { + // Skip record start + QByteArray rawAssetType(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rawAssetType.data(), 4); + result << rawAssetType.toHex(); + + // Skip separator + aZoneFileStream->skipRawData(4); + } + return result; +} + +AssetMap ZoneFile_COD8_Wii::pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) { + AssetMap result; + + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 8); + + for (int i = 0; i < assetOrder.size(); i++) { + const QString typeHex = assetOrder[i]; + const AssetType typeStr = AssetStrToEnum(typeHex); + + if (typeStr == ASSET_LOCAL_STRING) { // localized string asset + result.localStrings << pParseAsset_LocalString(aZoneFileStream); + } else if (typeStr == ASSET_RAW_FILE) { // gsc + auto rawFile = pParseAsset_RawFile(aZoneFileStream); + if (rawFile.length) { + result.rawFiles << rawFile; + } + } else if (typeStr == ASSET_PHYS_PRESET) { // physpreset + pParseAsset_PhysPreset(aZoneFileStream); + } else if (typeStr == ASSET_MODEL) { // xmodel + result.models << pParseAsset_Model(aZoneFileStream); + } else if (typeStr == ASSET_MATERIAL) { // material + pParseAsset_Material(aZoneFileStream); + } else if (typeStr == ASSET_SHADER) { // pixelshader + pParseAsset_Shader(aZoneFileStream); + } else if (typeStr == ASSET_TECH_SET) { // techset include + result.techSets << pParseAsset_TechSet(aZoneFileStream); + } else if (typeStr == ASSET_IMAGE) { // image + result.images << pParseAsset_Image(aZoneFileStream); + } else if (typeStr == ASSET_SOUND) { // loaded_sound + result.sounds << pParseAsset_Sound(aZoneFileStream); + } else if (typeStr == ASSET_COLLISION_MAP) { // col_map_mp + pParseAsset_ColMapMP(aZoneFileStream); + } else if (typeStr == ASSET_MP_MAP) { // game_map_sp + pParseAsset_GameMapSP(aZoneFileStream); + } else if (typeStr == ASSET_SP_MAP) { // game_map_mp + pParseAsset_GameMapMP(aZoneFileStream); + } else if (typeStr == ASSET_LIGHT_DEF) { // lightdef + pParseAsset_LightDef(aZoneFileStream); + } else if (typeStr == ASSET_UI_MAP) { // ui_map + pParseAsset_UIMap(aZoneFileStream); + } else if (typeStr == ASSET_SND_DRIVER_GLOBALS) { // snddriverglobals + pParseAsset_SNDDriverGlobals(aZoneFileStream); + } else if (typeStr == ASSET_AI_TYPE) { // aitype + pParseAsset_AIType(aZoneFileStream); + } else if (typeStr == ASSET_EFFECT) { // aitype + pParseAsset_FX(aZoneFileStream); + } else if (typeStr == ASSET_ANIMATION) { // aitype + result.animations << pParseAsset_Animation(aZoneFileStream); + } else if (typeStr == ASSET_STRING_TABLE) { // string_table + result.stringTables << pParseAsset_StringTable(aZoneFileStream); + } else if (typeStr == ASSET_MENU) { // string_table + result.menuFiles << pParseAsset_MenuFile(aZoneFileStream); + } else if (typeStr == ASSET_WEAPON) { // string_table + pParseAsset_Weapon(aZoneFileStream); + } else if (typeStr == ASSET_D3DBSP) { // string_table + pParseAsset_D3DBSP(aZoneFileStream); + } + } + return result; +} + +LocalString ZoneFile_COD8_Wii::pParseAsset_LocalString(QDataStream *aZoneFileStream) { + LocalString result; + + quint32 stringPtr, aliasPtr; + *aZoneFileStream >> stringPtr >> aliasPtr; + if (stringPtr == 4294967295) { + // Parse local string asset contents + QString localStr; + char localStrChar; + *aZoneFileStream >> localStrChar; + while (localStrChar != 0) { + result.string += localStrChar; + *aZoneFileStream >> localStrChar; + } + } else { + result.string = "String Ptr: " + QString::number(stringPtr); + } + + if (aliasPtr == 4294967295) { + // Parse rawfile name + QString aliasName; + char aliasNameChar; + *aZoneFileStream >> aliasNameChar; + while (aliasNameChar != 0) { + result.alias += aliasNameChar; + *aZoneFileStream >> aliasNameChar; + } + } else { + result.string = "Alias Ptr: " + QString::number(aliasPtr); + } + + return result; +} + +RawFile ZoneFile_COD8_Wii::pParseAsset_RawFile(QDataStream *aZoneFileStream) { + RawFile result; + + // Skip start separator FF FF FF FF (pointer?) + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.length; + + // Skip unknown 4 byte data + aZoneFileStream->skipRawData(4); + + // Parse rawfile path + char scriptPathChar; + *aZoneFileStream >> scriptPathChar; + while (scriptPathChar != 0) { + result.path += scriptPathChar; + *aZoneFileStream >> scriptPathChar; + } + result.path.replace(",", ""); + const QStringList pathParts = result.path.split('/'); + if (pathParts.size() == 0) { + qDebug() << "Failed to parse ff path! " << result.path; + exit(-1); + } + + // Parse gsc contents + char rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + while (rawFileContentsChar != 0 && rawFileContentsChar != -1) { + result.contents += rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + } + return result; +} + +void ZoneFile_COD8_Wii::pParseAsset_PhysPreset(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Model ZoneFile_COD8_Wii::pParseAsset_Model(QDataStream *aZoneFileStream) { + Model result; + + *aZoneFileStream >> result.namePtr >> result.tagCount >> result.rootTagCount + >> result.surfCount >> result.unknownCount >> result.boneNamePtr + >> result.parentListPtr >> result.quatsPtr >> result.transPtr + >> result.partClassPtr >> result.baseMatPtr + >> result.surfsPtr >> result.materialHandlesPtr; + + // Parse XModelLodInfo + for (int i = 1; i <= 4; i++) { + quint32 intDist; + *aZoneFileStream >> intDist; + + std::memcpy(&result.lodInfo[i].dist, &intDist, sizeof(result.lodInfo[i].dist)); + *aZoneFileStream >> result.lodInfo[i].numsurfs >> result.lodInfo[i].surfIndex; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.lodInfo[i].partBits[0] + >> result.lodInfo[i].partBits[1] + >> result.lodInfo[i].partBits[2] + >> result.lodInfo[i].partBits[3]; + } + + *aZoneFileStream >> result.collSurfsPtr >> result.numCollSurfs >> result.contents >> result.boneInfoPtr; + + quint32 intRadius, intMins[3], intMaxs[3]; + *aZoneFileStream >> intRadius >> intMins[0] >> intMins[1] + >> intMins[2] >> intMaxs[0] >> intMaxs[1] >> intMaxs[2]; + + std::memcpy(&result.radius, &intRadius, sizeof(result.radius)); + + std::memcpy(&result.mins[0], &intMins[0], sizeof(result.mins[0])); + std::memcpy(&result.mins[1], &intMins[1], sizeof(result.mins[1])); + std::memcpy(&result.mins[2], &intMins[2], sizeof(result.mins[2])); + + std::memcpy(&result.maxs[0], &intMaxs[0], sizeof(result.maxs[0])); + std::memcpy(&result.maxs[1], &intMaxs[1], sizeof(result.maxs[2])); + std::memcpy(&result.maxs[2], &intMaxs[2], sizeof(result.maxs[3])); + + *aZoneFileStream >> result.numLods >> result.collLod >> result.streamInfoPtr + >> result.memUsage >> result.flags >> result.physPresetPtr >> result.physGeomsPtr; + + // Parse model name + char modelNameChar; + *aZoneFileStream >> modelNameChar; + while (modelNameChar == 0) { + *aZoneFileStream >> modelNameChar; + } + while (modelNameChar != 0) { + result.modelName += modelNameChar; + *aZoneFileStream >> modelNameChar; + } + return result; +} + +Material ZoneFile_COD8_Wii::pParseAsset_Material(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); + + return Material(); +} + +Shader ZoneFile_COD8_Wii::pParseAsset_Shader(QDataStream *aZoneFileStream) { + Shader result = Shader(); + + quint8 minorVersion, majorVersion; + *aZoneFileStream >> minorVersion >> majorVersion; + + quint32 magic; + *aZoneFileStream >> magic; + + // Verify .fxc magic + if (magic != 65534 && magic != 65535) { return result; } + + SHADER_TYPE type = SHADER_NONE; + quint16 rawShaderType; + *aZoneFileStream >> rawShaderType; + if (rawShaderType == 65535) { // Pixel shader + type = SHADER_PIXEL; + } else if (rawShaderType == 65534) { // Vertex shader + type = SHADER_VERTEX; + } + Q_UNUSED(type); + + while (true) { + quint32 instructionToken; + *aZoneFileStream >> instructionToken; + + SHADER_OPCODE opCode = (SHADER_OPCODE)(instructionToken & 0xffff); + + int size; + if (opCode == OPCODE_End) { + break; + } else if (opCode == OPCODE_Comment) { + size = (int)((instructionToken >> 16) & 0x7FFF); + } else { + size = (int)((instructionToken >> 24) & 0x0f); + } + Q_UNUSED(size); + } + + + return result; +} + +TechSet ZoneFile_COD8_Wii::pParseAsset_TechSet(QDataStream *aZoneFileStream) { + TechSet result; + + for (int i = 1; i <= 62; i++) { + quint32 ptr; + *aZoneFileStream >> ptr; + + result.pointers << ptr; + } + qDebug() << aZoneFileStream->device()->pos(); + + // Parse techset name + char techSetNameChar; + *aZoneFileStream >> techSetNameChar; + while (techSetNameChar != 0) { + result.name += techSetNameChar; + *aZoneFileStream >> techSetNameChar; + } + result.name.replace(",", ""); + + return result; +} + +Image ZoneFile_COD8_Wii::pParseAsset_Image(QDataStream *aZoneFileStream) { + Image result; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknowna >> result.unknownb + >> result.unknownc >> result.unknownd + >> result.unknowne >> result.unknownf + >> result.unknowng; + + aZoneFileStream->skipRawData(15 * 4); + *aZoneFileStream >> result.unknownh >> result.unknowni; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknownj; + + aZoneFileStream->skipRawData(4); + + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + result.materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + result.materialName.replace(",", ""); + + if (result.unknowna) { + *aZoneFileStream >> result.unknownk; + *aZoneFileStream >> result.unknownl; + *aZoneFileStream >> result.unknownm; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown1; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown2 >> result.unknown3 + >> result.size1 >> result.size2 + >> result.unknown4 >> result.unknown5; + + aZoneFileStream->skipRawData(4); + + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + result.name += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + + *aZoneFileStream >> result.unknown6 >> result.unknown7; + + QByteArray compressionData(8, Qt::Uninitialized); + aZoneFileStream->readRawData(compressionData.data(), 8); + if (compressionData.contains("DXT1")) { + result.compression = COMPRESSION_DXT1; + } else if (compressionData.contains("DXT3")) { + result.compression = COMPRESSION_DXT3; + } else if (compressionData.contains("DXT5")) { + result.compression = COMPRESSION_DXT5; + } else { + result.compression = COMPRESSION_NONE; + } + + *aZoneFileStream >> result.unknown8 >> result.unknown9; + } + + return result; +} + +SoundAsset ZoneFile_COD8_Wii::pParseAsset_Sound(QDataStream *aZoneFileStream) { + SoundAsset result; + + qDebug() << aZoneFileStream->device()->pos(); + + QByteArray rootNamePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rootNamePtr.data(), 4); + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.count; + + if (rootNamePtr.toHex() == "ffffffff") { + // Read in sound file name + char soundNameChar; + *aZoneFileStream >> soundNameChar; + while (soundNameChar != 0) { + result.name += soundNameChar; + *aZoneFileStream >> soundNameChar; + } + } + + int tagCount = 0; + int resultCount = 0; + for (quint32 i = 0; i < result.count; i++) { + aZoneFileStream->skipRawData(12); + + QByteArray tagPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(tagPtr.data(), 4); + + if (tagPtr.toHex() == "ffffffff") { + tagCount++; + } + aZoneFileStream->skipRawData(4); + + QByteArray pathPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pathPtr.data(), 4); + + if (pathPtr.toHex() == "ffffffff") { + resultCount++; + } + + aZoneFileStream->skipRawData(160); + } + + for (int i = 0; i < tagCount; i++) { + // Read in tag? + QString tag; + char tagChar; + *aZoneFileStream >> tagChar; + while (tagChar != 0) { + tag += tagChar; + *aZoneFileStream >> tagChar; + } + } + + for (int i = 0; i < resultCount; i++) { + Sound sound; + + if (aZoneFileStream->device()->peek(12).toHex().contains("ffffffff00000000")) { + aZoneFileStream->skipRawData(12); + } + + aZoneFileStream->skipRawData(8); + + QByteArray aliasPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(aliasPtr.data(), 4); + + QByteArray namePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(namePtr.data(), 4); + + *aZoneFileStream >> sound.dataLength; + + if (aliasPtr.toHex() == "ffffffff") { + // Read in sound alias name + char soundAliasChar; + *aZoneFileStream >> soundAliasChar; + while (soundAliasChar != 0) { + sound.alias += soundAliasChar; + *aZoneFileStream >> soundAliasChar; + } + } + + if (aZoneFileStream->device()->peek(4) == "RIFF") { + sound.path = sound.alias; + sound.alias = ""; + } else if (namePtr.toHex() == "ffffffff") { + // Read in sound file path + char soundPathChar; + *aZoneFileStream >> soundPathChar; + while (soundPathChar != 0) { + sound.path += soundPathChar; + *aZoneFileStream >> soundPathChar; + } + sound.path.replace(",", ""); + } + + if (sound.dataLength) { + QByteArray data(sound.dataLength, Qt::Uninitialized); + aZoneFileStream->readRawData(data.data(), sound.dataLength); + sound.data = data; + } + result.sounds.append(sound); + } + + return result; +} + +void ZoneFile_COD8_Wii::pParseAsset_ColMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD8_Wii::pParseAsset_GameMapSP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD8_Wii::pParseAsset_GameMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD8_Wii::pParseAsset_LightDef(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD8_Wii::pParseAsset_UIMap(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD8_Wii::pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD8_Wii::pParseAsset_AIType(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD8_Wii::pParseAsset_FX(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Animation ZoneFile_COD8_Wii::pParseAsset_Animation(QDataStream *aZoneFileStream) { + Animation result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.dataByteCount + >> result.dataShortCount + >> result.dataIntCount + >> result.randomDataByteCount + >> result.randomDataIntCount + >> result.numframes + >> result.isLooped + >> result.isDelta + >> result.noneRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.normalTranslatedBoneCount + >> result.preciseTranslatedBoneCount + >> result.staticTranslatedBoneCount + >> result.noneTranslatedBoneCount + >> result.totalBoneCount + >> result.otherBoneCount1 + >> result.otherBoneCount2 + >> result.notifyCount + >> result.assetType + >> result.pad + >> result.randomDataShortCount + >> result.indexCount + >> result.frameRate + >> result.frequency + >> result.boneIDsPtr + >> result.dataBytePtr + >> result.dataShortPtr + >> result.dataIntPtr + >> result.randomDataShortPtr + >> result.randomDataBytePtr + >> result.randomDataIntPtr + >> result.longIndiciesPtr + >> result.notificationsPtr + >> result.deltaPartsPtr; + + // Read in x_anim file name + QString xAnimName; + char xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + while (xAnimNameChar != 0) { + result.name += xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + } + + // Parse x_anim index header + QVector sectionLengths; + for (int i = 0; i < result.numframes; i++) { + quint8 sectionlength; + *aZoneFileStream >> sectionlength; + sectionLengths.push_back(sectionlength); + // Skip padding + aZoneFileStream->skipRawData(1); + } + // Skip unknown section + aZoneFileStream->skipRawData(2 * 8); + + return result; +} + +MenuFile ZoneFile_COD8_Wii::pParseAsset_MenuFile(QDataStream *aZoneFileStream) { + //MENU_FILE + MenuFile result; + + aZoneFileStream->skipRawData(4); // Separator + + // Parse menu def count + *aZoneFileStream >> result.menuCount; + + // Clearly misparsed, never have this much + if (result.menuCount > 1000) { + qDebug() << "Failure reported when parsing menu file."; + return result; + } + for (uint i = 0; i < result.menuCount; i++) { + Menu menu; + + aZoneFileStream->skipRawData(4); // Separator + + // Read in x_anim file name + char menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + while (menuFilepathChar != 0) { + menu.filePath += menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + } + aZoneFileStream->skipRawData(4); // Separator + + *aZoneFileStream >> menu.menuNamePtr; + + float menuRectX, menuRectY, menuRectWidth, menuRectHeight; + *aZoneFileStream >> menuRectX >> menuRectY >> menuRectWidth >> menuRectHeight; + menu.rect = QRectF(menuRectX, menuRectY, menuRectWidth, menuRectHeight); + + quint32 hAlignInt, vAlignInt; + *aZoneFileStream >> hAlignInt >> vAlignInt; + menu.hAlign = (MENU_H_ALIGNMENT)hAlignInt; + menu.vAlign = (MENU_V_ALIGNMENT)vAlignInt; + + float rectClientX, rectClientY, rectClientWidth, rectClientHeight; + *aZoneFileStream >> rectClientX >> rectClientY >> rectClientWidth >> rectClientHeight; + menu.clientRect = QRectF(rectClientX, rectClientY, rectClientWidth, rectClientHeight); + + quint32 hClientAlignInt, vClientAlignInt, styleInt, borderInt; + *aZoneFileStream >> hClientAlignInt >> vClientAlignInt >> menu.groupPtr + >> styleInt >> borderInt >> menu.ownerDraw >> menu.ownerDrawFlags + >> menu.borderSize >> menu.staticFlags >> menu.dynamicFlags >> menu.nextTime; + menu.hClientAlign = (MENU_H_ALIGNMENT)hClientAlignInt; + menu.vClientAlign = (MENU_V_ALIGNMENT)vClientAlignInt; + menu.style = (MENU_WINDOW_STYLE)styleInt; + menu.border = (MENU_WINDOW_BORDER)borderInt; + + float foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA, + backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA, + borderColorR, borderColorG, borderColorB, borderColorA, + outlineColorR, outlineColorG, outlineColorB, outlineColorA; + *aZoneFileStream >> foregroundColorR >> foregroundColorG >> foregroundColorB >> foregroundColorA + >> backgroundColorR >> backgroundColorG >> backgroundColorB >> backgroundColorA + >> borderColorR >> borderColorG >> borderColorB >> borderColorA + >> outlineColorR >> outlineColorG >> outlineColorB >> outlineColorA; + + menu.foregroundColor = QColor(foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA); + menu.backgroundColor = QColor(backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA); + menu.borderColor = QColor(borderColorR, borderColorG, borderColorB, borderColorA); + menu.outlineColor = QColor(outlineColorR, outlineColorG, outlineColorB, outlineColorA); + + *aZoneFileStream >> menu.materialPtr >> menu.fontPtr >> menu.fullScreen >> menu.itemCount + >> menu.fontIndex >> menu.cursorItem >> menu.fadeCycle >> menu.fadeClamp + >> menu.fadeAmount >> menu.fadeInAmount >> menu.blurRadius >> menu.onOpenPtr + >> menu.onFocusPtr >> menu.onClosePtr >> menu.onESCPtr >> menu.onKeyPtr + >> menu.visibleExpCount >> menu.expEntryPtr >> menu.allowedBindingPtr + >> menu.soundNamePtr >> menu.imageTrack; + + float focusColorR, focusColorG, focusColorB, focusColorA, + disabledColorR, disabledColorG, disabledColorB, disabledColorA; + *aZoneFileStream >> focusColorR >> focusColorG >> focusColorB >> focusColorA + >> disabledColorR >> disabledColorG >> disabledColorB >> disabledColorA; + menu.focusColor = QColor(focusColorR, focusColorG, focusColorB, focusColorA); + menu.disabledColor = QColor(disabledColorR, disabledColorG, disabledColorB, disabledColorA); + + *aZoneFileStream >> menu.rectXExpCount >> menu.rectXExpPtr >> menu.rectYExpCount >> menu.rectYExpPtr; + + aZoneFileStream->skipRawData(4); // Separator + + char menuDefNameChar; + int menuDefNameLen = 0; + *aZoneFileStream >> menuDefNameChar; + while (menuDefNameChar != 0 && menuDefNameLen < 30) { + menuDefNameLen++; + menu.name += menuDefNameChar; + *aZoneFileStream >> menuDefNameChar; + } + + char defStringChar; + int defStringLen = 0; + *aZoneFileStream >> defStringChar; + while (defStringChar != 0 && defStringLen < 30) { + defStringLen++; + menu.definition += defStringChar; + *aZoneFileStream >> defStringChar; + } + aZoneFileStream->skipRawData(4 * 10); + + *aZoneFileStream >> menu.itemWindowDefNamePtr; + + float itemRectX, itemRectY, itemRectWidth, itemRectHeight; + *aZoneFileStream >> itemRectX >> itemRectY >> itemRectWidth >> itemRectHeight; + menu.itemRect = QRectF(itemRectX, itemRectY, itemRectWidth, itemRectHeight); + + *aZoneFileStream >> menu.itemHAlignment >> menu.itemVAlignment >> menu.itemGroupPtr + >> menu.itemWindowStyle >> menu.itemWindowBorder >> menu.itemOwnerDraw + >> menu.itemOwnerDrawFlags >> menu.itemBorderSize >> menu.itemStaticFlags + >> menu.itemDynamicFlags >> menu.itemNextTime; + + float itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA, + itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA, + itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA, + itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA; + *aZoneFileStream >> itemForegroundColorR >> itemForegroundColorG >> itemForegroundColorB >> itemForegroundColorA + >> itemBackgroundColorR >> itemBackgroundColorG >> itemBackgroundColorB >> itemBackgroundColorA + >> itemBorderColorR >> itemBorderColorG >> itemBorderColorB >> itemBorderColorA + >> itemOutlineColorR >> itemOutlineColorG >> itemOutlineColorB >> itemOutlineColorA; + + menu.itemForegroundColor = QColor(itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA); + menu.itemBackgroundColor = QColor(itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA); + menu.itemBorderColor = QColor(itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA); + menu.itemOutlineColor = QColor(itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA); + + *aZoneFileStream >> menu.itemMaterialPtr; + + float itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight; + *aZoneFileStream >> itemTextRectX >> itemTextRectY >> itemTextRectWidth >> itemTextRectHeight; + menu.itemTextRect = QRectF(itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight); + + quint32 hItemTextAlignInt, vItemTextAlignInt, itemType, fontTypeInt, textStyleInt; + *aZoneFileStream >> hItemTextAlignInt >> vItemTextAlignInt >> itemType >> menu.dataType + >> menu.alignment >> fontTypeInt >> menu.textAlignMode >> menu.textalignx >> menu.textaligny + >> menu.textscale >> textStyleInt >> menu.gameMsgWindowIndex >> menu.gameMsgWindowMode + >> menu.testPtr >> menu.textSavegameInfo >> menu.parentPtr; + menu.itemText_hAlign = (MENU_H_ALIGNMENT)hItemTextAlignInt; + menu.itemText_vAlign = (MENU_V_ALIGNMENT)vItemTextAlignInt; + menu.itemType = (MENU_ITEM_TYPE)itemType; + menu.fontEnum = (MENU_FONT_TYPE)fontTypeInt; + menu.textStyle = (MENU_ITEM_TEXTSTYLE)textStyleInt; + + *aZoneFileStream >> menu.mouseEnterText >> menu.mouseExitText >> menu.mouseEnter >> menu.mouseExit + >> menu.action >> menu.onAccept >> menu.onFocus >> menu.leaveFocus >> menu.dvar >> menu.dvarTest + >> menu.keyHandlerPtr >> menu.enableDvarPtr >> menu.dvarFlags >> menu.focusSoundPtr + >> menu.special >> menu.cursorPos; + + // itemDefData_t typeData; + + // listBoxDef_s *listBox; + + *aZoneFileStream >> menu.startPos >> menu.endPos >> menu.drawPadding; + + *aZoneFileStream >> menu.elementWidth >> menu.elementHeight; + + *aZoneFileStream >> menu.elementStyle >> menu.numColumns; + + //columnInfo_s columnInfo[16]; + + *aZoneFileStream >> menu.doubleClickPtr; + + + *aZoneFileStream >> menu.notselectable >> menu.noScrollBars >> menu.usePaging; + + float itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA, + itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA, + itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA; + *aZoneFileStream >> itemSelectBorderColorR >> itemSelectBorderColorG >> itemSelectBorderColorB >> itemSelectBorderColorA + >> itemDisableColorR >> itemDisableColorG >> itemDisableColorB >> itemDisableColorA + >> itemFocusColorR >> itemFocusColorG >> itemFocusColorB >> itemFocusColorA; + menu.itemSelectBorderColor = QColor(itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA); + menu.itemDisableColor = QColor(itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA); + menu.itemFocusColor = QColor(itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA); + + *aZoneFileStream >> menu.selectIconPtr >> menu.backgroundItemListboxPtr >> menu.highlightTexturePtr; + + // editFieldDef_s *editField; + + *aZoneFileStream >> menu.minVal >> menu.maxVal >> menu.defVal >> menu.range >> menu.maxChars + >> menu.maxCharsGotoNext >> menu.maxPaintChars >> menu.paintOffset; + + // multiDef_s *multi; + + for (int i = 0; i < 32; i++) { + quint32 dvarList; + *aZoneFileStream >> dvarList; + menu.dvarListPtrs.push_back(dvarList); + } + + for (int i = 0; i < 32; i++) { + quint32 dvarStr; + *aZoneFileStream >> dvarStr; + menu.dvarStrPtrs.push_back(dvarStr); + } + + for (int i = 0; i < 32; i++) { + float dvarValue; + *aZoneFileStream >> dvarValue; + menu.dvarValues.push_back(dvarValue); + } + + *aZoneFileStream >> menu.count >> menu.strDef >> menu.enumDvarNamePtr; + aZoneFileStream->skipRawData(4); + //>> menu.dataPtr + *aZoneFileStream >> menu.itemImageTrack; + + qDebug() << aZoneFileStream->device()->pos(); + + //statement_s visibleExp; + //statement_s textExp; + //statement_s materialExp; + //statement_s rectXExp; + //statement_s rectYExp; + //statement_s rectWExp; + //statement_s rectHExp; + //statement_s foreColorAExp; + result.menuDefs << menu; + } + return result; +} + +void ZoneFile_COD8_Wii::pParseAsset_Weapon(QDataStream *aZoneFileStream) { + //WEAPON_FILE + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD8_Wii::pParseAsset_D3DBSP(QDataStream *aZoneFileStream) { + //D3DBSP_DUMP + Q_UNUSED(aZoneFileStream); +} + +StringTable ZoneFile_COD8_Wii::pParseAsset_StringTable(QDataStream *aZoneFileStream) { + StringTable result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.columnCount + >> result.rowCount; + + // Todo fix this + result.columnCount = 0; + result.rowCount = 0; + + aZoneFileStream->skipRawData(4); + + QString stringTableName; + char stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + while (stringTableNameChar != 0) { + result.name += stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + } + + for (quint32 i = 0; i < result.rowCount; i++) { + QByteArray pointerData(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pointerData.data(), 4); + result.tablePointers.push_back(pointerData.toHex()); + + aZoneFileStream->skipRawData(4); + } + + for (const QString &pointerAddr : result.tablePointers) { + QString leadingContent = ""; + if (pointerAddr == "FFFFFFFF") { + char leadingContentChar; + *aZoneFileStream >> leadingContentChar; + while (leadingContentChar != 0) { + leadingContent += leadingContentChar; + *aZoneFileStream >> leadingContentChar; + } + } else { + leadingContent = pointerAddr; + } + + QString content; + char contentChar; + *aZoneFileStream >> contentChar; + while (contentChar != 0) { + content += contentChar; + *aZoneFileStream >> contentChar; + } + result.content[leadingContent] = content; + } + return result; +} + +AssetType ZoneFile_COD8_Wii::AssetStrToEnum(const QString aAssetType) { + const QString cleanedType = aAssetType.toUpper(); + if (cleanedType == "17000000") { // localized string PARTIALLY VERIFIED + return ASSET_LOCAL_STRING; + } else if (cleanedType == "20000000") { // raw_file PARTIALLY VERIFIED + return ASSET_RAW_FILE; + } else if (cleanedType == "1A000000") { // fx PARTIALLY VERIFIED + return ASSET_EFFECT; + } else if (cleanedType == "09000000") { // loaded_sound PARTIALLY VERIFIED + return ASSET_SOUND; + } else if (cleanedType == "04000000") { // x_anim PARTIALLY VERIFIED + return ASSET_ANIMATION; + } else if (cleanedType == "0C000000") { // collision_map PARTIALLY VERIFIED + return ASSET_COLLISION_MAP; + } else if (cleanedType == "21000000") { // string_table PARTIALLY VERIFIED + return ASSET_STRING_TABLE; + } else if (cleanedType == "15000000") { // menu_file PARTIALLY VERIFIED + return ASSET_MENU; + } else if (cleanedType == "07000000") { // tech set PARTIALLY VERIFIED + return ASSET_TECH_SET; + } else if (cleanedType == "18000000") { // weapon PARTIALLY VERIFIED + return ASSET_WEAPON; + } else if (cleanedType == "11000000") { // gfx map PARTIALLY VERIFIED + return ASSET_GFX_MAP; + } else if (cleanedType == "12000000") { // light_def PARTIALLY VERIFIED + return ASSET_LIGHT_DEF; + } else if (cleanedType == "14000000") { // font PARTIALLY VERIFIED + return ASSET_FONT; + } else if (cleanedType == "05000000") { // xmodel PARTIALLY VERIFIED + return ASSET_MODEL; + } else if (cleanedType == "0D000000") { // d3dbsp PARTIALLY VERIFIED + return ASSET_D3DBSP; + } else if (cleanedType == "06000000") { // image PARTIALLY VERIFIED + return ASSET_IMAGE; + } else if (cleanedType == "0E000000") { // game map sp PARTIALLY VERIFIED + return ASSET_GAME_MAP_SP; + } else if (cleanedType == "0B000000") { // col map sp PARTIALLY VERIFIED + return ASSET_COL_MAP_SP; + } + return ASSET_NONE; +} + +QByteArray ZoneFile_COD8_Wii::GetBinaryData() { + QByteArray result; + + return result; +} diff --git a/libs/zonefile/Wii/zonefile_cod8_wii.h b/libs/zonefile/Wii/zonefile_cod8_wii.h new file mode 100644 index 0000000..14284e0 --- /dev/null +++ b/libs/zonefile/Wii/zonefile_cod8_wii.h @@ -0,0 +1,52 @@ +#ifndef ZONEFILE_COD8_WII_H +#define ZONEFILE_COD8_WII_H + +#include "zonefile.h" + +class ZoneFile_COD8_Wii : public ZoneFile +{ +public: + ZoneFile_COD8_Wii(); + ~ZoneFile_COD8_Wii(); + + bool Load(const QByteArray aFileData) override; + AssetType AssetStrToEnum(const QString aAssetType) override; + + QByteArray GetBinaryData() override; + +protected: + void pParseZoneHeader(QDataStream *aZoneFileStream) override; + quint32 pParseZoneSize(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsA(QDataStream *aZoneFileStream) override; + quint32 pParseZoneTagCount(QDataStream *aZoneFileStream) override; + quint32 pParseZoneRecordCount(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsB(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsC(QDataStream *aZoneFileStream) override; + QStringList pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) override; + QStringList pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) override; + AssetMap pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) override; + LocalString pParseAsset_LocalString(QDataStream *aZoneFileStream) override; + RawFile pParseAsset_RawFile(QDataStream *aZoneFileStream) override; + void pParseAsset_PhysPreset(QDataStream *aZoneFileStream) override; + Model pParseAsset_Model(QDataStream *aZoneFileStream) override; + Material pParseAsset_Material(QDataStream *aZoneFileStream) override; + Shader pParseAsset_Shader(QDataStream *aZoneFileStream) override; + TechSet pParseAsset_TechSet(QDataStream *aZoneFileStream) override; + Image pParseAsset_Image(QDataStream *aZoneFileStream) override; + SoundAsset pParseAsset_Sound(QDataStream *aZoneFileStream) override; + void pParseAsset_ColMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapSP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_LightDef(QDataStream *aZoneFileStream) override; + void pParseAsset_UIMap(QDataStream *aZoneFileStream) override; + void pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) override; + void pParseAsset_AIType(QDataStream *aZoneFileStream) override; + void pParseAsset_FX(QDataStream *aZoneFileStream) override; + Animation pParseAsset_Animation(QDataStream *aZoneFileStream) override; + MenuFile pParseAsset_MenuFile(QDataStream *aZoneFileStream) override; + void pParseAsset_Weapon(QDataStream *aZoneFileStream) override; + void pParseAsset_D3DBSP(QDataStream *aZoneFileStream) override; + StringTable pParseAsset_StringTable(QDataStream *aZoneFileStream) override; +}; + +#endif // ZONEFILE_COD8_WII_H diff --git a/libs/zonefile/WiiU/zonefile_cod10_wiiu.cpp b/libs/zonefile/WiiU/zonefile_cod10_wiiu.cpp new file mode 100644 index 0000000..f11bbdb --- /dev/null +++ b/libs/zonefile/WiiU/zonefile_cod10_wiiu.cpp @@ -0,0 +1,1072 @@ +#include "zonefile_cod10_wiiu.h" + +#include +#include +#include + +ZoneFile_COD10_WiiU::ZoneFile_COD10_WiiU() +{ + +} + +ZoneFile_COD10_WiiU::~ZoneFile_COD10_WiiU() +{ + +} + +bool ZoneFile_COD10_WiiU::Load(const QByteArray aFileData) { + // Open zone file as little endian stream + QDataStream zoneFileStream(aFileData); + zoneFileStream.setByteOrder(QDataStream::BigEndian); + + // Parse data from zone file header + pParseZoneHeader(&zoneFileStream); + SetRecords(pParseZoneIndex(&zoneFileStream, GetRecordCount())); + SetAssetMap(pParseAssets(&zoneFileStream, GetRecords())); + + return true; +} + +void ZoneFile_COD10_WiiU::pParseZoneHeader(QDataStream *aZoneFileStream) { + SetSize(pParseZoneSize(aZoneFileStream)); + pParseZoneUnknownsA(aZoneFileStream); + + SetTagCount(pParseZoneTagCount(aZoneFileStream)); + pParseZoneUnknownsB(aZoneFileStream); + + SetRecordCount(pParseZoneRecordCount(aZoneFileStream)); + + quint32 tagCount = GetTagCount(); + if (tagCount) { + pParseZoneUnknownsC(aZoneFileStream); + SetTags(pParseZoneTags(aZoneFileStream, tagCount)); + } else { + aZoneFileStream->skipRawData(4); + } +} + +quint32 ZoneFile_COD10_WiiU::pParseZoneSize(QDataStream *aZoneFileStream) { + quint32 zoneFileSize; + *aZoneFileStream >> zoneFileSize; + if (zoneFileSize <= 0) { + qDebug() << "Tried to open empty zone file!"; + exit(-1); + } + zoneFileSize += 36; + return zoneFileSize; +} + +/* + ParseZoneUnknownsA() + + Parses the 1st section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD10_WiiU::pParseZoneUnknownsA(QDataStream *aZoneFileStream) { + // Byte 4-7, 8-11, 12-15: unknown + QByteArray unknown1(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown1.data(), 4); + + QByteArray unknown2(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown2.data(), 4); + + QByteArray unknown3(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown3.data(), 4); + + // Byte 16-19, 20-23: empty/unknown + QByteArray unknown4(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown4.data(), 4); + + QByteArray unknown5(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown5.data(), 4); + + // Byte 24-27: somehow related to the filesize, but smaller value + QByteArray unknown6(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown6.data(), 4); + + // Byte 28-31, 32-35: unknown + QByteArray unknown7(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown7.data(), 4); + + QByteArray unknown8(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown8.data(), 4); +} + +/* + ParseZoneTagCount() + + Parses the number of string tags in the zone index +*/ +quint32 ZoneFile_COD10_WiiU::pParseZoneTagCount(QDataStream *aZoneFileStream) { + quint32 tagCount; + *aZoneFileStream >> tagCount; + return tagCount; +} + +/* + ParseZoneRecordCount() + + Parses the number of records in the zone index +*/ +quint32 ZoneFile_COD10_WiiU::pParseZoneRecordCount(QDataStream *aZoneFileStream) { + quint32 recordCount; + *aZoneFileStream >> recordCount; + return recordCount; +} + +/* + ParseZoneUnknownsB() + + Parses the 2nd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD10_WiiU::pParseZoneUnknownsB(QDataStream *aZoneFileStream) { + // Byte 44-47: Unknown/empty? + QByteArray unknown9(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown9.data(), 4); +} + +/* + pParseZoneUnknownsC() + + Parses the 3rd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD10_WiiU::pParseZoneUnknownsC(QDataStream *aZoneFileStream) { + // Byte 40-43: Unknown/empty? + QByteArray unknown10(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown10.data(), 4); + + // Byte 44-47: Unknown/empty? + QByteArray unknown11(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown11.data(), 4); +} + +/* + ParseZoneTags() + + Parses the string tags ate the start of zone file +*/ +QStringList ZoneFile_COD10_WiiU::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) { + QStringList tags; + + // Byte 48-51: Repeated separators? ÿÿÿÿ x i + aZoneFileStream->skipRawData(4 * (tagCount - 1)); + + // Parse tags/strings before index + QString zoneTag; + char zoneTagChar; + for (quint32 i = 0; i < tagCount; i++) { + *aZoneFileStream >> zoneTagChar; + while (zoneTagChar != 0) { + zoneTag += zoneTagChar; + *aZoneFileStream >> zoneTagChar; + } + tags << zoneTag; + zoneTag.clear(); + } + return tags; +} + +/* + ParseZoneIndex() + + Parse the binary zone index data and populate table +*/ +QStringList ZoneFile_COD10_WiiU::pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) { + QStringList result; + + // Don't parse if no records + if (!recordCount) { return result; } + + if (aZoneFileStream->device()->peek(4).toHex().contains("ffff")) { + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 2); + } + + // Parse index & map found asset types + for (quint32 i = 0; i <= recordCount; i++) { + // Skip record start + QByteArray rawAssetType(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rawAssetType.data(), 4); + result << rawAssetType.toHex(); + + // Skip separator + aZoneFileStream->skipRawData(4); + } + return result; +} + +AssetMap ZoneFile_COD10_WiiU::pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) { + AssetMap result; + + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 8); + + for (int i = 0; i < assetOrder.size(); i++) { + const QString typeHex = assetOrder[i]; + const AssetType typeStr = AssetStrToEnum(typeHex); + + if (typeStr == ASSET_LOCAL_STRING) { // localized string asset + result.localStrings << pParseAsset_LocalString(aZoneFileStream); + } else if (typeStr == ASSET_RAW_FILE) { // gsc + auto rawFile = pParseAsset_RawFile(aZoneFileStream); + if (rawFile.length) { + result.rawFiles << rawFile; + } + } else if (typeStr == ASSET_PHYS_PRESET) { // physpreset + pParseAsset_PhysPreset(aZoneFileStream); + } else if (typeStr == ASSET_MODEL) { // xmodel + result.models << pParseAsset_Model(aZoneFileStream); + } else if (typeStr == ASSET_MATERIAL) { // material + pParseAsset_Material(aZoneFileStream); + } else if (typeStr == ASSET_SHADER) { // pixelshader + pParseAsset_Shader(aZoneFileStream); + } else if (typeStr == ASSET_TECH_SET) { // techset include + result.techSets << pParseAsset_TechSet(aZoneFileStream); + } else if (typeStr == ASSET_IMAGE) { // image + result.images << pParseAsset_Image(aZoneFileStream); + } else if (typeStr == ASSET_SOUND) { // loaded_sound + result.sounds << pParseAsset_Sound(aZoneFileStream); + } else if (typeStr == ASSET_COLLISION_MAP) { // col_map_mp + pParseAsset_ColMapMP(aZoneFileStream); + } else if (typeStr == ASSET_MP_MAP) { // game_map_sp + pParseAsset_GameMapSP(aZoneFileStream); + } else if (typeStr == ASSET_SP_MAP) { // game_map_mp + pParseAsset_GameMapMP(aZoneFileStream); + } else if (typeStr == ASSET_LIGHT_DEF) { // lightdef + pParseAsset_LightDef(aZoneFileStream); + } else if (typeStr == ASSET_UI_MAP) { // ui_map + pParseAsset_UIMap(aZoneFileStream); + } else if (typeStr == ASSET_SND_DRIVER_GLOBALS) { // snddriverglobals + pParseAsset_SNDDriverGlobals(aZoneFileStream); + } else if (typeStr == ASSET_AI_TYPE) { // aitype + pParseAsset_AIType(aZoneFileStream); + } else if (typeStr == ASSET_EFFECT) { // aitype + pParseAsset_FX(aZoneFileStream); + } else if (typeStr == ASSET_ANIMATION) { // aitype + result.animations << pParseAsset_Animation(aZoneFileStream); + } else if (typeStr == ASSET_STRING_TABLE) { // string_table + result.stringTables << pParseAsset_StringTable(aZoneFileStream); + } else if (typeStr == ASSET_MENU) { // string_table + result.menuFiles << pParseAsset_MenuFile(aZoneFileStream); + } else if (typeStr == ASSET_WEAPON) { // string_table + pParseAsset_Weapon(aZoneFileStream); + } else if (typeStr == ASSET_D3DBSP) { // string_table + pParseAsset_D3DBSP(aZoneFileStream); + } + } + return result; +} + +LocalString ZoneFile_COD10_WiiU::pParseAsset_LocalString(QDataStream *aZoneFileStream) { + LocalString result; + + quint32 stringPtr, aliasPtr; + *aZoneFileStream >> stringPtr >> aliasPtr; + if (stringPtr == 4294967295) { + // Parse local string asset contents + QString localStr; + char localStrChar; + *aZoneFileStream >> localStrChar; + while (localStrChar != 0) { + result.string += localStrChar; + *aZoneFileStream >> localStrChar; + } + } else { + result.string = "String Ptr: " + QString::number(stringPtr); + } + + if (aliasPtr == 4294967295) { + // Parse rawfile name + QString aliasName; + char aliasNameChar; + *aZoneFileStream >> aliasNameChar; + while (aliasNameChar != 0) { + result.alias += aliasNameChar; + *aZoneFileStream >> aliasNameChar; + } + } else { + result.string = "Alias Ptr: " + QString::number(aliasPtr); + } + + return result; +} + +RawFile ZoneFile_COD10_WiiU::pParseAsset_RawFile(QDataStream *aZoneFileStream) { + RawFile result; + + // Skip start separator FF FF FF FF (pointer?) + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.length; + + // Skip unknown 4 byte data + aZoneFileStream->skipRawData(4); + + // Parse rawfile path + char scriptPathChar; + *aZoneFileStream >> scriptPathChar; + while (scriptPathChar != 0) { + result.path += scriptPathChar; + *aZoneFileStream >> scriptPathChar; + } + result.path.replace(",", ""); + const QStringList pathParts = result.path.split('/'); + if (pathParts.size() == 0) { + qDebug() << "Failed to parse ff path! " << result.path; + exit(-1); + } + + // Parse gsc contents + char rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + while (rawFileContentsChar != 0 && rawFileContentsChar != -1) { + result.contents += rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + } + return result; +} + +void ZoneFile_COD10_WiiU::pParseAsset_PhysPreset(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Model ZoneFile_COD10_WiiU::pParseAsset_Model(QDataStream *aZoneFileStream) { + Model result; + + *aZoneFileStream >> result.namePtr >> result.tagCount >> result.rootTagCount + >> result.surfCount >> result.unknownCount >> result.boneNamePtr + >> result.parentListPtr >> result.quatsPtr >> result.transPtr + >> result.partClassPtr >> result.baseMatPtr + >> result.surfsPtr >> result.materialHandlesPtr; + + // Parse XModelLodInfo + for (int i = 1; i <= 4; i++) { + quint32 intDist; + *aZoneFileStream >> intDist; + + std::memcpy(&result.lodInfo[i].dist, &intDist, sizeof(result.lodInfo[i].dist)); + *aZoneFileStream >> result.lodInfo[i].numsurfs >> result.lodInfo[i].surfIndex; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.lodInfo[i].partBits[0] + >> result.lodInfo[i].partBits[1] + >> result.lodInfo[i].partBits[2] + >> result.lodInfo[i].partBits[3]; + } + + *aZoneFileStream >> result.collSurfsPtr >> result.numCollSurfs >> result.contents >> result.boneInfoPtr; + + quint32 intRadius, intMins[3], intMaxs[3]; + *aZoneFileStream >> intRadius >> intMins[0] >> intMins[1] + >> intMins[2] >> intMaxs[0] >> intMaxs[1] >> intMaxs[2]; + + std::memcpy(&result.radius, &intRadius, sizeof(result.radius)); + + std::memcpy(&result.mins[0], &intMins[0], sizeof(result.mins[0])); + std::memcpy(&result.mins[1], &intMins[1], sizeof(result.mins[1])); + std::memcpy(&result.mins[2], &intMins[2], sizeof(result.mins[2])); + + std::memcpy(&result.maxs[0], &intMaxs[0], sizeof(result.maxs[0])); + std::memcpy(&result.maxs[1], &intMaxs[1], sizeof(result.maxs[2])); + std::memcpy(&result.maxs[2], &intMaxs[2], sizeof(result.maxs[3])); + + *aZoneFileStream >> result.numLods >> result.collLod >> result.streamInfoPtr + >> result.memUsage >> result.flags >> result.physPresetPtr >> result.physGeomsPtr; + + // Parse model name + char modelNameChar; + *aZoneFileStream >> modelNameChar; + while (modelNameChar == 0) { + *aZoneFileStream >> modelNameChar; + } + while (modelNameChar != 0) { + result.modelName += modelNameChar; + *aZoneFileStream >> modelNameChar; + } + return result; +} + +Material ZoneFile_COD10_WiiU::pParseAsset_Material(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); + + return Material(); +} + +Shader ZoneFile_COD10_WiiU::pParseAsset_Shader(QDataStream *aZoneFileStream) { + Shader result = Shader(); + + quint8 minorVersion, majorVersion; + *aZoneFileStream >> minorVersion >> majorVersion; + + quint32 magic; + *aZoneFileStream >> magic; + + // Verify .fxc magic + if (magic != 65534 && magic != 65535) { return result; } + + SHADER_TYPE type = SHADER_NONE; + quint16 rawShaderType; + *aZoneFileStream >> rawShaderType; + if (rawShaderType == 65535) { // Pixel shader + type = SHADER_PIXEL; + } else if (rawShaderType == 65534) { // Vertex shader + type = SHADER_VERTEX; + } + Q_UNUSED(type); + + while (true) { + quint32 instructionToken; + *aZoneFileStream >> instructionToken; + + SHADER_OPCODE opCode = (SHADER_OPCODE)(instructionToken & 0xffff); + + int size; + if (opCode == OPCODE_End) { + break; + } else if (opCode == OPCODE_Comment) { + size = (int)((instructionToken >> 16) & 0x7FFF); + } else { + size = (int)((instructionToken >> 24) & 0x0f); + } + Q_UNUSED(size); + } + + + return result; +} + +TechSet ZoneFile_COD10_WiiU::pParseAsset_TechSet(QDataStream *aZoneFileStream) { + TechSet result; + + for (int i = 1; i <= 62; i++) { + quint32 ptr; + *aZoneFileStream >> ptr; + + result.pointers << ptr; + } + qDebug() << aZoneFileStream->device()->pos(); + + // Parse techset name + char techSetNameChar; + *aZoneFileStream >> techSetNameChar; + while (techSetNameChar != 0) { + result.name += techSetNameChar; + *aZoneFileStream >> techSetNameChar; + } + result.name.replace(",", ""); + + return result; +} + +Image ZoneFile_COD10_WiiU::pParseAsset_Image(QDataStream *aZoneFileStream) { + Image result; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknowna >> result.unknownb + >> result.unknownc >> result.unknownd + >> result.unknowne >> result.unknownf + >> result.unknowng; + + aZoneFileStream->skipRawData(15 * 4); + *aZoneFileStream >> result.unknownh >> result.unknowni; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknownj; + + aZoneFileStream->skipRawData(4); + + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + result.materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + result.materialName.replace(",", ""); + + if (result.unknowna) { + *aZoneFileStream >> result.unknownk; + *aZoneFileStream >> result.unknownl; + *aZoneFileStream >> result.unknownm; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown1; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown2 >> result.unknown3 + >> result.size1 >> result.size2 + >> result.unknown4 >> result.unknown5; + + aZoneFileStream->skipRawData(4); + + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + result.name += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + + *aZoneFileStream >> result.unknown6 >> result.unknown7; + + QByteArray compressionData(8, Qt::Uninitialized); + aZoneFileStream->readRawData(compressionData.data(), 8); + if (compressionData.contains("DXT1")) { + result.compression = COMPRESSION_DXT1; + } else if (compressionData.contains("DXT3")) { + result.compression = COMPRESSION_DXT3; + } else if (compressionData.contains("DXT5")) { + result.compression = COMPRESSION_DXT5; + } else { + result.compression = COMPRESSION_NONE; + } + + *aZoneFileStream >> result.unknown8 >> result.unknown9; + } + + return result; +} + +SoundAsset ZoneFile_COD10_WiiU::pParseAsset_Sound(QDataStream *aZoneFileStream) { + SoundAsset result; + + qDebug() << aZoneFileStream->device()->pos(); + + QByteArray rootNamePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rootNamePtr.data(), 4); + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.count; + + if (rootNamePtr.toHex() == "ffffffff") { + // Read in sound file name + char soundNameChar; + *aZoneFileStream >> soundNameChar; + while (soundNameChar != 0) { + result.name += soundNameChar; + *aZoneFileStream >> soundNameChar; + } + } + + int tagCount = 0; + int resultCount = 0; + for (quint32 i = 0; i < result.count; i++) { + aZoneFileStream->skipRawData(12); + + QByteArray tagPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(tagPtr.data(), 4); + + if (tagPtr.toHex() == "ffffffff") { + tagCount++; + } + aZoneFileStream->skipRawData(4); + + QByteArray pathPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pathPtr.data(), 4); + + if (pathPtr.toHex() == "ffffffff") { + resultCount++; + } + + aZoneFileStream->skipRawData(160); + } + + for (int i = 0; i < tagCount; i++) { + // Read in tag? + QString tag; + char tagChar; + *aZoneFileStream >> tagChar; + while (tagChar != 0) { + tag += tagChar; + *aZoneFileStream >> tagChar; + } + } + + for (int i = 0; i < resultCount; i++) { + Sound sound; + + if (aZoneFileStream->device()->peek(12).toHex().contains("ffffffff00000000")) { + aZoneFileStream->skipRawData(12); + } + + aZoneFileStream->skipRawData(8); + + QByteArray aliasPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(aliasPtr.data(), 4); + + QByteArray namePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(namePtr.data(), 4); + + *aZoneFileStream >> sound.dataLength; + + if (aliasPtr.toHex() == "ffffffff") { + // Read in sound alias name + char soundAliasChar; + *aZoneFileStream >> soundAliasChar; + while (soundAliasChar != 0) { + sound.alias += soundAliasChar; + *aZoneFileStream >> soundAliasChar; + } + } + + if (aZoneFileStream->device()->peek(4) == "RIFF") { + sound.path = sound.alias; + sound.alias = ""; + } else if (namePtr.toHex() == "ffffffff") { + // Read in sound file path + char soundPathChar; + *aZoneFileStream >> soundPathChar; + while (soundPathChar != 0) { + sound.path += soundPathChar; + *aZoneFileStream >> soundPathChar; + } + sound.path.replace(",", ""); + } + + if (sound.dataLength) { + QByteArray data(sound.dataLength, Qt::Uninitialized); + aZoneFileStream->readRawData(data.data(), sound.dataLength); + sound.data = data; + } + result.sounds.append(sound); + } + + return result; +} + +void ZoneFile_COD10_WiiU::pParseAsset_ColMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD10_WiiU::pParseAsset_GameMapSP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD10_WiiU::pParseAsset_GameMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD10_WiiU::pParseAsset_LightDef(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD10_WiiU::pParseAsset_UIMap(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD10_WiiU::pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD10_WiiU::pParseAsset_AIType(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD10_WiiU::pParseAsset_FX(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Animation ZoneFile_COD10_WiiU::pParseAsset_Animation(QDataStream *aZoneFileStream) { + Animation result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.dataByteCount + >> result.dataShortCount + >> result.dataIntCount + >> result.randomDataByteCount + >> result.randomDataIntCount + >> result.numframes + >> result.isLooped + >> result.isDelta + >> result.noneRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.normalTranslatedBoneCount + >> result.preciseTranslatedBoneCount + >> result.staticTranslatedBoneCount + >> result.noneTranslatedBoneCount + >> result.totalBoneCount + >> result.otherBoneCount1 + >> result.otherBoneCount2 + >> result.notifyCount + >> result.assetType + >> result.pad + >> result.randomDataShortCount + >> result.indexCount + >> result.frameRate + >> result.frequency + >> result.boneIDsPtr + >> result.dataBytePtr + >> result.dataShortPtr + >> result.dataIntPtr + >> result.randomDataShortPtr + >> result.randomDataBytePtr + >> result.randomDataIntPtr + >> result.longIndiciesPtr + >> result.notificationsPtr + >> result.deltaPartsPtr; + + // Read in x_anim file name + QString xAnimName; + char xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + while (xAnimNameChar != 0) { + result.name += xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + } + + // Parse x_anim index header + QVector sectionLengths; + for (int i = 0; i < result.numframes; i++) { + quint8 sectionlength; + *aZoneFileStream >> sectionlength; + sectionLengths.push_back(sectionlength); + // Skip padding + aZoneFileStream->skipRawData(1); + } + // Skip unknown section + aZoneFileStream->skipRawData(2 * 8); + + return result; +} + +MenuFile ZoneFile_COD10_WiiU::pParseAsset_MenuFile(QDataStream *aZoneFileStream) { + //MENU_FILE + MenuFile result; + + aZoneFileStream->skipRawData(4); // Separator + + // Parse menu def count + *aZoneFileStream >> result.menuCount; + + // Clearly misparsed, never have this much + if (result.menuCount > 1000) { + qDebug() << "Failure reported when parsing menu file."; + return result; + } + for (uint i = 0; i < result.menuCount; i++) { + Menu menu; + + aZoneFileStream->skipRawData(4); // Separator + + // Read in x_anim file name + char menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + while (menuFilepathChar != 0) { + menu.filePath += menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + } + aZoneFileStream->skipRawData(4); // Separator + + *aZoneFileStream >> menu.menuNamePtr; + + float menuRectX, menuRectY, menuRectWidth, menuRectHeight; + *aZoneFileStream >> menuRectX >> menuRectY >> menuRectWidth >> menuRectHeight; + menu.rect = QRectF(menuRectX, menuRectY, menuRectWidth, menuRectHeight); + + quint32 hAlignInt, vAlignInt; + *aZoneFileStream >> hAlignInt >> vAlignInt; + menu.hAlign = (MENU_H_ALIGNMENT)hAlignInt; + menu.vAlign = (MENU_V_ALIGNMENT)vAlignInt; + + float rectClientX, rectClientY, rectClientWidth, rectClientHeight; + *aZoneFileStream >> rectClientX >> rectClientY >> rectClientWidth >> rectClientHeight; + menu.clientRect = QRectF(rectClientX, rectClientY, rectClientWidth, rectClientHeight); + + quint32 hClientAlignInt, vClientAlignInt, styleInt, borderInt; + *aZoneFileStream >> hClientAlignInt >> vClientAlignInt >> menu.groupPtr + >> styleInt >> borderInt >> menu.ownerDraw >> menu.ownerDrawFlags + >> menu.borderSize >> menu.staticFlags >> menu.dynamicFlags >> menu.nextTime; + menu.hClientAlign = (MENU_H_ALIGNMENT)hClientAlignInt; + menu.vClientAlign = (MENU_V_ALIGNMENT)vClientAlignInt; + menu.style = (MENU_WINDOW_STYLE)styleInt; + menu.border = (MENU_WINDOW_BORDER)borderInt; + + float foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA, + backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA, + borderColorR, borderColorG, borderColorB, borderColorA, + outlineColorR, outlineColorG, outlineColorB, outlineColorA; + *aZoneFileStream >> foregroundColorR >> foregroundColorG >> foregroundColorB >> foregroundColorA + >> backgroundColorR >> backgroundColorG >> backgroundColorB >> backgroundColorA + >> borderColorR >> borderColorG >> borderColorB >> borderColorA + >> outlineColorR >> outlineColorG >> outlineColorB >> outlineColorA; + + menu.foregroundColor = QColor(foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA); + menu.backgroundColor = QColor(backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA); + menu.borderColor = QColor(borderColorR, borderColorG, borderColorB, borderColorA); + menu.outlineColor = QColor(outlineColorR, outlineColorG, outlineColorB, outlineColorA); + + *aZoneFileStream >> menu.materialPtr >> menu.fontPtr >> menu.fullScreen >> menu.itemCount + >> menu.fontIndex >> menu.cursorItem >> menu.fadeCycle >> menu.fadeClamp + >> menu.fadeAmount >> menu.fadeInAmount >> menu.blurRadius >> menu.onOpenPtr + >> menu.onFocusPtr >> menu.onClosePtr >> menu.onESCPtr >> menu.onKeyPtr + >> menu.visibleExpCount >> menu.expEntryPtr >> menu.allowedBindingPtr + >> menu.soundNamePtr >> menu.imageTrack; + + float focusColorR, focusColorG, focusColorB, focusColorA, + disabledColorR, disabledColorG, disabledColorB, disabledColorA; + *aZoneFileStream >> focusColorR >> focusColorG >> focusColorB >> focusColorA + >> disabledColorR >> disabledColorG >> disabledColorB >> disabledColorA; + menu.focusColor = QColor(focusColorR, focusColorG, focusColorB, focusColorA); + menu.disabledColor = QColor(disabledColorR, disabledColorG, disabledColorB, disabledColorA); + + *aZoneFileStream >> menu.rectXExpCount >> menu.rectXExpPtr >> menu.rectYExpCount >> menu.rectYExpPtr; + + aZoneFileStream->skipRawData(4); // Separator + + char menuDefNameChar; + int menuDefNameLen = 0; + *aZoneFileStream >> menuDefNameChar; + while (menuDefNameChar != 0 && menuDefNameLen < 30) { + menuDefNameLen++; + menu.name += menuDefNameChar; + *aZoneFileStream >> menuDefNameChar; + } + + char defStringChar; + int defStringLen = 0; + *aZoneFileStream >> defStringChar; + while (defStringChar != 0 && defStringLen < 30) { + defStringLen++; + menu.definition += defStringChar; + *aZoneFileStream >> defStringChar; + } + aZoneFileStream->skipRawData(4 * 10); + + *aZoneFileStream >> menu.itemWindowDefNamePtr; + + float itemRectX, itemRectY, itemRectWidth, itemRectHeight; + *aZoneFileStream >> itemRectX >> itemRectY >> itemRectWidth >> itemRectHeight; + menu.itemRect = QRectF(itemRectX, itemRectY, itemRectWidth, itemRectHeight); + + *aZoneFileStream >> menu.itemHAlignment >> menu.itemVAlignment >> menu.itemGroupPtr + >> menu.itemWindowStyle >> menu.itemWindowBorder >> menu.itemOwnerDraw + >> menu.itemOwnerDrawFlags >> menu.itemBorderSize >> menu.itemStaticFlags + >> menu.itemDynamicFlags >> menu.itemNextTime; + + float itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA, + itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA, + itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA, + itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA; + *aZoneFileStream >> itemForegroundColorR >> itemForegroundColorG >> itemForegroundColorB >> itemForegroundColorA + >> itemBackgroundColorR >> itemBackgroundColorG >> itemBackgroundColorB >> itemBackgroundColorA + >> itemBorderColorR >> itemBorderColorG >> itemBorderColorB >> itemBorderColorA + >> itemOutlineColorR >> itemOutlineColorG >> itemOutlineColorB >> itemOutlineColorA; + + menu.itemForegroundColor = QColor(itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA); + menu.itemBackgroundColor = QColor(itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA); + menu.itemBorderColor = QColor(itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA); + menu.itemOutlineColor = QColor(itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA); + + *aZoneFileStream >> menu.itemMaterialPtr; + + float itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight; + *aZoneFileStream >> itemTextRectX >> itemTextRectY >> itemTextRectWidth >> itemTextRectHeight; + menu.itemTextRect = QRectF(itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight); + + quint32 hItemTextAlignInt, vItemTextAlignInt, itemType, fontTypeInt, textStyleInt; + *aZoneFileStream >> hItemTextAlignInt >> vItemTextAlignInt >> itemType >> menu.dataType + >> menu.alignment >> fontTypeInt >> menu.textAlignMode >> menu.textalignx >> menu.textaligny + >> menu.textscale >> textStyleInt >> menu.gameMsgWindowIndex >> menu.gameMsgWindowMode + >> menu.testPtr >> menu.textSavegameInfo >> menu.parentPtr; + menu.itemText_hAlign = (MENU_H_ALIGNMENT)hItemTextAlignInt; + menu.itemText_vAlign = (MENU_V_ALIGNMENT)vItemTextAlignInt; + menu.itemType = (MENU_ITEM_TYPE)itemType; + menu.fontEnum = (MENU_FONT_TYPE)fontTypeInt; + menu.textStyle = (MENU_ITEM_TEXTSTYLE)textStyleInt; + + *aZoneFileStream >> menu.mouseEnterText >> menu.mouseExitText >> menu.mouseEnter >> menu.mouseExit + >> menu.action >> menu.onAccept >> menu.onFocus >> menu.leaveFocus >> menu.dvar >> menu.dvarTest + >> menu.keyHandlerPtr >> menu.enableDvarPtr >> menu.dvarFlags >> menu.focusSoundPtr + >> menu.special >> menu.cursorPos; + + // itemDefData_t typeData; + + // listBoxDef_s *listBox; + + *aZoneFileStream >> menu.startPos >> menu.endPos >> menu.drawPadding; + + *aZoneFileStream >> menu.elementWidth >> menu.elementHeight; + + *aZoneFileStream >> menu.elementStyle >> menu.numColumns; + + //columnInfo_s columnInfo[16]; + + *aZoneFileStream >> menu.doubleClickPtr; + + + *aZoneFileStream >> menu.notselectable >> menu.noScrollBars >> menu.usePaging; + + float itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA, + itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA, + itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA; + *aZoneFileStream >> itemSelectBorderColorR >> itemSelectBorderColorG >> itemSelectBorderColorB >> itemSelectBorderColorA + >> itemDisableColorR >> itemDisableColorG >> itemDisableColorB >> itemDisableColorA + >> itemFocusColorR >> itemFocusColorG >> itemFocusColorB >> itemFocusColorA; + menu.itemSelectBorderColor = QColor(itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA); + menu.itemDisableColor = QColor(itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA); + menu.itemFocusColor = QColor(itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA); + + *aZoneFileStream >> menu.selectIconPtr >> menu.backgroundItemListboxPtr >> menu.highlightTexturePtr; + + // editFieldDef_s *editField; + + *aZoneFileStream >> menu.minVal >> menu.maxVal >> menu.defVal >> menu.range >> menu.maxChars + >> menu.maxCharsGotoNext >> menu.maxPaintChars >> menu.paintOffset; + + // multiDef_s *multi; + + for (int i = 0; i < 32; i++) { + quint32 dvarList; + *aZoneFileStream >> dvarList; + menu.dvarListPtrs.push_back(dvarList); + } + + for (int i = 0; i < 32; i++) { + quint32 dvarStr; + *aZoneFileStream >> dvarStr; + menu.dvarStrPtrs.push_back(dvarStr); + } + + for (int i = 0; i < 32; i++) { + float dvarValue; + *aZoneFileStream >> dvarValue; + menu.dvarValues.push_back(dvarValue); + } + + *aZoneFileStream >> menu.count >> menu.strDef >> menu.enumDvarNamePtr; + aZoneFileStream->skipRawData(4); + //>> menu.dataPtr + *aZoneFileStream >> menu.itemImageTrack; + + qDebug() << aZoneFileStream->device()->pos(); + + //statement_s visibleExp; + //statement_s textExp; + //statement_s materialExp; + //statement_s rectXExp; + //statement_s rectYExp; + //statement_s rectWExp; + //statement_s rectHExp; + //statement_s foreColorAExp; + result.menuDefs << menu; + } + return result; +} + +void ZoneFile_COD10_WiiU::pParseAsset_Weapon(QDataStream *aZoneFileStream) { + //WEAPON_FILE + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD10_WiiU::pParseAsset_D3DBSP(QDataStream *aZoneFileStream) { + //D3DBSP_DUMP + Q_UNUSED(aZoneFileStream); +} + +StringTable ZoneFile_COD10_WiiU::pParseAsset_StringTable(QDataStream *aZoneFileStream) { + StringTable result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.columnCount + >> result.rowCount; + + // Todo fix this + result.columnCount = 0; + result.rowCount = 0; + + aZoneFileStream->skipRawData(4); + + QString stringTableName; + char stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + while (stringTableNameChar != 0) { + result.name += stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + } + + for (quint32 i = 0; i < result.rowCount; i++) { + QByteArray pointerData(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pointerData.data(), 4); + result.tablePointers.push_back(pointerData.toHex()); + + aZoneFileStream->skipRawData(4); + } + + for (const QString &pointerAddr : result.tablePointers) { + QString leadingContent = ""; + if (pointerAddr == "FFFFFFFF") { + char leadingContentChar; + *aZoneFileStream >> leadingContentChar; + while (leadingContentChar != 0) { + leadingContent += leadingContentChar; + *aZoneFileStream >> leadingContentChar; + } + } else { + leadingContent = pointerAddr; + } + + QString content; + char contentChar; + *aZoneFileStream >> contentChar; + while (contentChar != 0) { + content += contentChar; + *aZoneFileStream >> contentChar; + } + result.content[leadingContent] = content; + } + return result; +} + +AssetType ZoneFile_COD10_WiiU::AssetStrToEnum(const QString aAssetType) { + const QString cleanedType = aAssetType.toUpper(); + if (cleanedType == "17000000") { // localized string PARTIALLY VERIFIED + return ASSET_LOCAL_STRING; + } else if (cleanedType == "20000000") { // raw_file PARTIALLY VERIFIED + return ASSET_RAW_FILE; + } else if (cleanedType == "1A000000") { // fx PARTIALLY VERIFIED + return ASSET_EFFECT; + } else if (cleanedType == "09000000") { // loaded_sound PARTIALLY VERIFIED + return ASSET_SOUND; + } else if (cleanedType == "04000000") { // x_anim PARTIALLY VERIFIED + return ASSET_ANIMATION; + } else if (cleanedType == "0C000000") { // collision_map PARTIALLY VERIFIED + return ASSET_COLLISION_MAP; + } else if (cleanedType == "21000000") { // string_table PARTIALLY VERIFIED + return ASSET_STRING_TABLE; + } else if (cleanedType == "15000000") { // menu_file PARTIALLY VERIFIED + return ASSET_MENU; + } else if (cleanedType == "07000000") { // tech set PARTIALLY VERIFIED + return ASSET_TECH_SET; + } else if (cleanedType == "18000000") { // weapon PARTIALLY VERIFIED + return ASSET_WEAPON; + } else if (cleanedType == "11000000") { // gfx map PARTIALLY VERIFIED + return ASSET_GFX_MAP; + } else if (cleanedType == "12000000") { // light_def PARTIALLY VERIFIED + return ASSET_LIGHT_DEF; + } else if (cleanedType == "14000000") { // font PARTIALLY VERIFIED + return ASSET_FONT; + } else if (cleanedType == "05000000") { // xmodel PARTIALLY VERIFIED + return ASSET_MODEL; + } else if (cleanedType == "0D000000") { // d3dbsp PARTIALLY VERIFIED + return ASSET_D3DBSP; + } else if (cleanedType == "06000000") { // image PARTIALLY VERIFIED + return ASSET_IMAGE; + } else if (cleanedType == "0E000000") { // game map sp PARTIALLY VERIFIED + return ASSET_GAME_MAP_SP; + } else if (cleanedType == "0B000000") { // col map sp PARTIALLY VERIFIED + return ASSET_COL_MAP_SP; + } + return ASSET_NONE; +} + +QByteArray ZoneFile_COD10_WiiU::GetBinaryData() { + QByteArray result; + + return result; +} diff --git a/libs/zonefile/WiiU/zonefile_cod10_wiiu.h b/libs/zonefile/WiiU/zonefile_cod10_wiiu.h new file mode 100644 index 0000000..b51d706 --- /dev/null +++ b/libs/zonefile/WiiU/zonefile_cod10_wiiu.h @@ -0,0 +1,52 @@ +#ifndef ZONEFILE_COD10_WIIU_H +#define ZONEFILE_COD10_WIIU_H + +#include "zonefile.h" + +class ZoneFile_COD10_WiiU : public ZoneFile +{ +public: + ZoneFile_COD10_WiiU(); + ~ZoneFile_COD10_WiiU(); + + bool Load(const QByteArray aFileData) override; + AssetType AssetStrToEnum(const QString aAssetType) override; + + QByteArray GetBinaryData() override; + +protected: + void pParseZoneHeader(QDataStream *aZoneFileStream) override; + quint32 pParseZoneSize(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsA(QDataStream *aZoneFileStream) override; + quint32 pParseZoneTagCount(QDataStream *aZoneFileStream) override; + quint32 pParseZoneRecordCount(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsB(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsC(QDataStream *aZoneFileStream) override; + QStringList pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) override; + QStringList pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) override; + AssetMap pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) override; + LocalString pParseAsset_LocalString(QDataStream *aZoneFileStream) override; + RawFile pParseAsset_RawFile(QDataStream *aZoneFileStream) override; + void pParseAsset_PhysPreset(QDataStream *aZoneFileStream) override; + Model pParseAsset_Model(QDataStream *aZoneFileStream) override; + Material pParseAsset_Material(QDataStream *aZoneFileStream) override; + Shader pParseAsset_Shader(QDataStream *aZoneFileStream) override; + TechSet pParseAsset_TechSet(QDataStream *aZoneFileStream) override; + Image pParseAsset_Image(QDataStream *aZoneFileStream) override; + SoundAsset pParseAsset_Sound(QDataStream *aZoneFileStream) override; + void pParseAsset_ColMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapSP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_LightDef(QDataStream *aZoneFileStream) override; + void pParseAsset_UIMap(QDataStream *aZoneFileStream) override; + void pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) override; + void pParseAsset_AIType(QDataStream *aZoneFileStream) override; + void pParseAsset_FX(QDataStream *aZoneFileStream) override; + Animation pParseAsset_Animation(QDataStream *aZoneFileStream) override; + MenuFile pParseAsset_MenuFile(QDataStream *aZoneFileStream) override; + void pParseAsset_Weapon(QDataStream *aZoneFileStream) override; + void pParseAsset_D3DBSP(QDataStream *aZoneFileStream) override; + StringTable pParseAsset_StringTable(QDataStream *aZoneFileStream) override; +}; + +#endif // ZONEFILE_COD10_WIIU_H diff --git a/libs/zonefile/WiiU/zonefile_cod9_wiiu.cpp b/libs/zonefile/WiiU/zonefile_cod9_wiiu.cpp new file mode 100644 index 0000000..548d14c --- /dev/null +++ b/libs/zonefile/WiiU/zonefile_cod9_wiiu.cpp @@ -0,0 +1,1072 @@ +#include "zonefile_cod9_wiiu.h" + +#include +#include +#include + +ZoneFile_COD9_WiiU::ZoneFile_COD9_WiiU() +{ + +} + +ZoneFile_COD9_WiiU::~ZoneFile_COD9_WiiU() +{ + +} + +bool ZoneFile_COD9_WiiU::Load(const QByteArray aFileData) { + // Open zone file as little endian stream + QDataStream zoneFileStream(aFileData); + zoneFileStream.setByteOrder(QDataStream::BigEndian); + + // Parse data from zone file header + pParseZoneHeader(&zoneFileStream); + SetRecords(pParseZoneIndex(&zoneFileStream, GetRecordCount())); + SetAssetMap(pParseAssets(&zoneFileStream, GetRecords())); + + return true; +} + +void ZoneFile_COD9_WiiU::pParseZoneHeader(QDataStream *aZoneFileStream) { + SetSize(pParseZoneSize(aZoneFileStream)); + pParseZoneUnknownsA(aZoneFileStream); + + SetTagCount(pParseZoneTagCount(aZoneFileStream)); + pParseZoneUnknownsB(aZoneFileStream); + + SetRecordCount(pParseZoneRecordCount(aZoneFileStream)); + + quint32 tagCount = GetTagCount(); + if (tagCount) { + pParseZoneUnknownsC(aZoneFileStream); + SetTags(pParseZoneTags(aZoneFileStream, tagCount)); + } else { + aZoneFileStream->skipRawData(4); + } +} + +quint32 ZoneFile_COD9_WiiU::pParseZoneSize(QDataStream *aZoneFileStream) { + quint32 zoneFileSize; + *aZoneFileStream >> zoneFileSize; + if (zoneFileSize <= 0) { + qDebug() << "Tried to open empty zone file!"; + exit(-1); + } + zoneFileSize += 36; + return zoneFileSize; +} + +/* + ParseZoneUnknownsA() + + Parses the 1st section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD9_WiiU::pParseZoneUnknownsA(QDataStream *aZoneFileStream) { + // Byte 4-7, 8-11, 12-15: unknown + QByteArray unknown1(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown1.data(), 4); + + QByteArray unknown2(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown2.data(), 4); + + QByteArray unknown3(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown3.data(), 4); + + // Byte 16-19, 20-23: empty/unknown + QByteArray unknown4(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown4.data(), 4); + + QByteArray unknown5(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown5.data(), 4); + + // Byte 24-27: somehow related to the filesize, but smaller value + QByteArray unknown6(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown6.data(), 4); + + // Byte 28-31, 32-35: unknown + QByteArray unknown7(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown7.data(), 4); + + QByteArray unknown8(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown8.data(), 4); +} + +/* + ParseZoneTagCount() + + Parses the number of string tags in the zone index +*/ +quint32 ZoneFile_COD9_WiiU::pParseZoneTagCount(QDataStream *aZoneFileStream) { + quint32 tagCount; + *aZoneFileStream >> tagCount; + return tagCount; +} + +/* + ParseZoneRecordCount() + + Parses the number of records in the zone index +*/ +quint32 ZoneFile_COD9_WiiU::pParseZoneRecordCount(QDataStream *aZoneFileStream) { + quint32 recordCount; + *aZoneFileStream >> recordCount; + return recordCount; +} + +/* + ParseZoneUnknownsB() + + Parses the 2nd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD9_WiiU::pParseZoneUnknownsB(QDataStream *aZoneFileStream) { + // Byte 44-47: Unknown/empty? + QByteArray unknown9(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown9.data(), 4); +} + +/* + pParseZoneUnknownsC() + + Parses the 3rd section of unknowns as hex vals and uint32s +*/ +void ZoneFile_COD9_WiiU::pParseZoneUnknownsC(QDataStream *aZoneFileStream) { + // Byte 40-43: Unknown/empty? + QByteArray unknown10(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown10.data(), 4); + + // Byte 44-47: Unknown/empty? + QByteArray unknown11(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown11.data(), 4); +} + +/* + ParseZoneTags() + + Parses the string tags ate the start of zone file +*/ +QStringList ZoneFile_COD9_WiiU::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) { + QStringList tags; + + // Byte 48-51: Repeated separators? ÿÿÿÿ x i + aZoneFileStream->skipRawData(4 * (tagCount - 1)); + + // Parse tags/strings before index + QString zoneTag; + char zoneTagChar; + for (quint32 i = 0; i < tagCount; i++) { + *aZoneFileStream >> zoneTagChar; + while (zoneTagChar != 0) { + zoneTag += zoneTagChar; + *aZoneFileStream >> zoneTagChar; + } + tags << zoneTag; + zoneTag.clear(); + } + return tags; +} + +/* + ParseZoneIndex() + + Parse the binary zone index data and populate table +*/ +QStringList ZoneFile_COD9_WiiU::pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) { + QStringList result; + + // Don't parse if no records + if (!recordCount) { return result; } + + if (aZoneFileStream->device()->peek(4).toHex().contains("ffff")) { + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 2); + } + + // Parse index & map found asset types + for (quint32 i = 0; i <= recordCount; i++) { + // Skip record start + QByteArray rawAssetType(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rawAssetType.data(), 4); + result << rawAssetType.toHex(); + + // Skip separator + aZoneFileStream->skipRawData(4); + } + return result; +} + +AssetMap ZoneFile_COD9_WiiU::pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) { + AssetMap result; + + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 8); + + for (int i = 0; i < assetOrder.size(); i++) { + const QString typeHex = assetOrder[i]; + const AssetType typeStr = AssetStrToEnum(typeHex); + + if (typeStr == ASSET_LOCAL_STRING) { // localized string asset + result.localStrings << pParseAsset_LocalString(aZoneFileStream); + } else if (typeStr == ASSET_RAW_FILE) { // gsc + auto rawFile = pParseAsset_RawFile(aZoneFileStream); + if (rawFile.length) { + result.rawFiles << rawFile; + } + } else if (typeStr == ASSET_PHYS_PRESET) { // physpreset + pParseAsset_PhysPreset(aZoneFileStream); + } else if (typeStr == ASSET_MODEL) { // xmodel + result.models << pParseAsset_Model(aZoneFileStream); + } else if (typeStr == ASSET_MATERIAL) { // material + pParseAsset_Material(aZoneFileStream); + } else if (typeStr == ASSET_SHADER) { // pixelshader + pParseAsset_Shader(aZoneFileStream); + } else if (typeStr == ASSET_TECH_SET) { // techset include + result.techSets << pParseAsset_TechSet(aZoneFileStream); + } else if (typeStr == ASSET_IMAGE) { // image + result.images << pParseAsset_Image(aZoneFileStream); + } else if (typeStr == ASSET_SOUND) { // loaded_sound + result.sounds << pParseAsset_Sound(aZoneFileStream); + } else if (typeStr == ASSET_COLLISION_MAP) { // col_map_mp + pParseAsset_ColMapMP(aZoneFileStream); + } else if (typeStr == ASSET_MP_MAP) { // game_map_sp + pParseAsset_GameMapSP(aZoneFileStream); + } else if (typeStr == ASSET_SP_MAP) { // game_map_mp + pParseAsset_GameMapMP(aZoneFileStream); + } else if (typeStr == ASSET_LIGHT_DEF) { // lightdef + pParseAsset_LightDef(aZoneFileStream); + } else if (typeStr == ASSET_UI_MAP) { // ui_map + pParseAsset_UIMap(aZoneFileStream); + } else if (typeStr == ASSET_SND_DRIVER_GLOBALS) { // snddriverglobals + pParseAsset_SNDDriverGlobals(aZoneFileStream); + } else if (typeStr == ASSET_AI_TYPE) { // aitype + pParseAsset_AIType(aZoneFileStream); + } else if (typeStr == ASSET_EFFECT) { // aitype + pParseAsset_FX(aZoneFileStream); + } else if (typeStr == ASSET_ANIMATION) { // aitype + result.animations << pParseAsset_Animation(aZoneFileStream); + } else if (typeStr == ASSET_STRING_TABLE) { // string_table + result.stringTables << pParseAsset_StringTable(aZoneFileStream); + } else if (typeStr == ASSET_MENU) { // string_table + result.menuFiles << pParseAsset_MenuFile(aZoneFileStream); + } else if (typeStr == ASSET_WEAPON) { // string_table + pParseAsset_Weapon(aZoneFileStream); + } else if (typeStr == ASSET_D3DBSP) { // string_table + pParseAsset_D3DBSP(aZoneFileStream); + } + } + return result; +} + +LocalString ZoneFile_COD9_WiiU::pParseAsset_LocalString(QDataStream *aZoneFileStream) { + LocalString result; + + quint32 stringPtr, aliasPtr; + *aZoneFileStream >> stringPtr >> aliasPtr; + if (stringPtr == 4294967295) { + // Parse local string asset contents + QString localStr; + char localStrChar; + *aZoneFileStream >> localStrChar; + while (localStrChar != 0) { + result.string += localStrChar; + *aZoneFileStream >> localStrChar; + } + } else { + result.string = "String Ptr: " + QString::number(stringPtr); + } + + if (aliasPtr == 4294967295) { + // Parse rawfile name + QString aliasName; + char aliasNameChar; + *aZoneFileStream >> aliasNameChar; + while (aliasNameChar != 0) { + result.alias += aliasNameChar; + *aZoneFileStream >> aliasNameChar; + } + } else { + result.string = "Alias Ptr: " + QString::number(aliasPtr); + } + + return result; +} + +RawFile ZoneFile_COD9_WiiU::pParseAsset_RawFile(QDataStream *aZoneFileStream) { + RawFile result; + + // Skip start separator FF FF FF FF (pointer?) + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.length; + + // Skip unknown 4 byte data + aZoneFileStream->skipRawData(4); + + // Parse rawfile path + char scriptPathChar; + *aZoneFileStream >> scriptPathChar; + while (scriptPathChar != 0) { + result.path += scriptPathChar; + *aZoneFileStream >> scriptPathChar; + } + result.path.replace(",", ""); + const QStringList pathParts = result.path.split('/'); + if (pathParts.size() == 0) { + qDebug() << "Failed to parse ff path! " << result.path; + exit(-1); + } + + // Parse gsc contents + char rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + while (rawFileContentsChar != 0 && rawFileContentsChar != -1) { + result.contents += rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + } + return result; +} + +void ZoneFile_COD9_WiiU::pParseAsset_PhysPreset(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Model ZoneFile_COD9_WiiU::pParseAsset_Model(QDataStream *aZoneFileStream) { + Model result; + + *aZoneFileStream >> result.namePtr >> result.tagCount >> result.rootTagCount + >> result.surfCount >> result.unknownCount >> result.boneNamePtr + >> result.parentListPtr >> result.quatsPtr >> result.transPtr + >> result.partClassPtr >> result.baseMatPtr + >> result.surfsPtr >> result.materialHandlesPtr; + + // Parse XModelLodInfo + for (int i = 1; i <= 4; i++) { + quint32 intDist; + *aZoneFileStream >> intDist; + + std::memcpy(&result.lodInfo[i].dist, &intDist, sizeof(result.lodInfo[i].dist)); + *aZoneFileStream >> result.lodInfo[i].numsurfs >> result.lodInfo[i].surfIndex; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.lodInfo[i].partBits[0] + >> result.lodInfo[i].partBits[1] + >> result.lodInfo[i].partBits[2] + >> result.lodInfo[i].partBits[3]; + } + + *aZoneFileStream >> result.collSurfsPtr >> result.numCollSurfs >> result.contents >> result.boneInfoPtr; + + quint32 intRadius, intMins[3], intMaxs[3]; + *aZoneFileStream >> intRadius >> intMins[0] >> intMins[1] + >> intMins[2] >> intMaxs[0] >> intMaxs[1] >> intMaxs[2]; + + std::memcpy(&result.radius, &intRadius, sizeof(result.radius)); + + std::memcpy(&result.mins[0], &intMins[0], sizeof(result.mins[0])); + std::memcpy(&result.mins[1], &intMins[1], sizeof(result.mins[1])); + std::memcpy(&result.mins[2], &intMins[2], sizeof(result.mins[2])); + + std::memcpy(&result.maxs[0], &intMaxs[0], sizeof(result.maxs[0])); + std::memcpy(&result.maxs[1], &intMaxs[1], sizeof(result.maxs[2])); + std::memcpy(&result.maxs[2], &intMaxs[2], sizeof(result.maxs[3])); + + *aZoneFileStream >> result.numLods >> result.collLod >> result.streamInfoPtr + >> result.memUsage >> result.flags >> result.physPresetPtr >> result.physGeomsPtr; + + // Parse model name + char modelNameChar; + *aZoneFileStream >> modelNameChar; + while (modelNameChar == 0) { + *aZoneFileStream >> modelNameChar; + } + while (modelNameChar != 0) { + result.modelName += modelNameChar; + *aZoneFileStream >> modelNameChar; + } + return result; +} + +Material ZoneFile_COD9_WiiU::pParseAsset_Material(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); + + return Material(); +} + +Shader ZoneFile_COD9_WiiU::pParseAsset_Shader(QDataStream *aZoneFileStream) { + Shader result = Shader(); + + quint8 minorVersion, majorVersion; + *aZoneFileStream >> minorVersion >> majorVersion; + + quint32 magic; + *aZoneFileStream >> magic; + + // Verify .fxc magic + if (magic != 65534 && magic != 65535) { return result; } + + SHADER_TYPE type = SHADER_NONE; + quint16 rawShaderType; + *aZoneFileStream >> rawShaderType; + if (rawShaderType == 65535) { // Pixel shader + type = SHADER_PIXEL; + } else if (rawShaderType == 65534) { // Vertex shader + type = SHADER_VERTEX; + } + Q_UNUSED(type); + + while (true) { + quint32 instructionToken; + *aZoneFileStream >> instructionToken; + + SHADER_OPCODE opCode = (SHADER_OPCODE)(instructionToken & 0xffff); + + int size; + if (opCode == OPCODE_End) { + break; + } else if (opCode == OPCODE_Comment) { + size = (int)((instructionToken >> 16) & 0x7FFF); + } else { + size = (int)((instructionToken >> 24) & 0x0f); + } + Q_UNUSED(size); + } + + + return result; +} + +TechSet ZoneFile_COD9_WiiU::pParseAsset_TechSet(QDataStream *aZoneFileStream) { + TechSet result; + + for (int i = 1; i <= 62; i++) { + quint32 ptr; + *aZoneFileStream >> ptr; + + result.pointers << ptr; + } + qDebug() << aZoneFileStream->device()->pos(); + + // Parse techset name + char techSetNameChar; + *aZoneFileStream >> techSetNameChar; + while (techSetNameChar != 0) { + result.name += techSetNameChar; + *aZoneFileStream >> techSetNameChar; + } + result.name.replace(",", ""); + + return result; +} + +Image ZoneFile_COD9_WiiU::pParseAsset_Image(QDataStream *aZoneFileStream) { + Image result; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknowna >> result.unknownb + >> result.unknownc >> result.unknownd + >> result.unknowne >> result.unknownf + >> result.unknowng; + + aZoneFileStream->skipRawData(15 * 4); + *aZoneFileStream >> result.unknownh >> result.unknowni; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknownj; + + aZoneFileStream->skipRawData(4); + + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + result.materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + result.materialName.replace(",", ""); + + if (result.unknowna) { + *aZoneFileStream >> result.unknownk; + *aZoneFileStream >> result.unknownl; + *aZoneFileStream >> result.unknownm; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown1; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown2 >> result.unknown3 + >> result.size1 >> result.size2 + >> result.unknown4 >> result.unknown5; + + aZoneFileStream->skipRawData(4); + + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + result.name += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + + *aZoneFileStream >> result.unknown6 >> result.unknown7; + + QByteArray compressionData(8, Qt::Uninitialized); + aZoneFileStream->readRawData(compressionData.data(), 8); + if (compressionData.contains("DXT1")) { + result.compression = COMPRESSION_DXT1; + } else if (compressionData.contains("DXT3")) { + result.compression = COMPRESSION_DXT3; + } else if (compressionData.contains("DXT5")) { + result.compression = COMPRESSION_DXT5; + } else { + result.compression = COMPRESSION_NONE; + } + + *aZoneFileStream >> result.unknown8 >> result.unknown9; + } + + return result; +} + +SoundAsset ZoneFile_COD9_WiiU::pParseAsset_Sound(QDataStream *aZoneFileStream) { + SoundAsset result; + + qDebug() << aZoneFileStream->device()->pos(); + + QByteArray rootNamePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rootNamePtr.data(), 4); + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.count; + + if (rootNamePtr.toHex() == "ffffffff") { + // Read in sound file name + char soundNameChar; + *aZoneFileStream >> soundNameChar; + while (soundNameChar != 0) { + result.name += soundNameChar; + *aZoneFileStream >> soundNameChar; + } + } + + int tagCount = 0; + int resultCount = 0; + for (quint32 i = 0; i < result.count; i++) { + aZoneFileStream->skipRawData(12); + + QByteArray tagPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(tagPtr.data(), 4); + + if (tagPtr.toHex() == "ffffffff") { + tagCount++; + } + aZoneFileStream->skipRawData(4); + + QByteArray pathPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pathPtr.data(), 4); + + if (pathPtr.toHex() == "ffffffff") { + resultCount++; + } + + aZoneFileStream->skipRawData(160); + } + + for (int i = 0; i < tagCount; i++) { + // Read in tag? + QString tag; + char tagChar; + *aZoneFileStream >> tagChar; + while (tagChar != 0) { + tag += tagChar; + *aZoneFileStream >> tagChar; + } + } + + for (int i = 0; i < resultCount; i++) { + Sound sound; + + if (aZoneFileStream->device()->peek(12).toHex().contains("ffffffff00000000")) { + aZoneFileStream->skipRawData(12); + } + + aZoneFileStream->skipRawData(8); + + QByteArray aliasPtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(aliasPtr.data(), 4); + + QByteArray namePtr(4, Qt::Uninitialized); + aZoneFileStream->readRawData(namePtr.data(), 4); + + *aZoneFileStream >> sound.dataLength; + + if (aliasPtr.toHex() == "ffffffff") { + // Read in sound alias name + char soundAliasChar; + *aZoneFileStream >> soundAliasChar; + while (soundAliasChar != 0) { + sound.alias += soundAliasChar; + *aZoneFileStream >> soundAliasChar; + } + } + + if (aZoneFileStream->device()->peek(4) == "RIFF") { + sound.path = sound.alias; + sound.alias = ""; + } else if (namePtr.toHex() == "ffffffff") { + // Read in sound file path + char soundPathChar; + *aZoneFileStream >> soundPathChar; + while (soundPathChar != 0) { + sound.path += soundPathChar; + *aZoneFileStream >> soundPathChar; + } + sound.path.replace(",", ""); + } + + if (sound.dataLength) { + QByteArray data(sound.dataLength, Qt::Uninitialized); + aZoneFileStream->readRawData(data.data(), sound.dataLength); + sound.data = data; + } + result.sounds.append(sound); + } + + return result; +} + +void ZoneFile_COD9_WiiU::pParseAsset_ColMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD9_WiiU::pParseAsset_GameMapSP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD9_WiiU::pParseAsset_GameMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD9_WiiU::pParseAsset_LightDef(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD9_WiiU::pParseAsset_UIMap(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD9_WiiU::pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD9_WiiU::pParseAsset_AIType(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD9_WiiU::pParseAsset_FX(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Animation ZoneFile_COD9_WiiU::pParseAsset_Animation(QDataStream *aZoneFileStream) { + Animation result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.dataByteCount + >> result.dataShortCount + >> result.dataIntCount + >> result.randomDataByteCount + >> result.randomDataIntCount + >> result.numframes + >> result.isLooped + >> result.isDelta + >> result.noneRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.normalTranslatedBoneCount + >> result.preciseTranslatedBoneCount + >> result.staticTranslatedBoneCount + >> result.noneTranslatedBoneCount + >> result.totalBoneCount + >> result.otherBoneCount1 + >> result.otherBoneCount2 + >> result.notifyCount + >> result.assetType + >> result.pad + >> result.randomDataShortCount + >> result.indexCount + >> result.frameRate + >> result.frequency + >> result.boneIDsPtr + >> result.dataBytePtr + >> result.dataShortPtr + >> result.dataIntPtr + >> result.randomDataShortPtr + >> result.randomDataBytePtr + >> result.randomDataIntPtr + >> result.longIndiciesPtr + >> result.notificationsPtr + >> result.deltaPartsPtr; + + // Read in x_anim file name + QString xAnimName; + char xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + while (xAnimNameChar != 0) { + result.name += xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + } + + // Parse x_anim index header + QVector sectionLengths; + for (int i = 0; i < result.numframes; i++) { + quint8 sectionlength; + *aZoneFileStream >> sectionlength; + sectionLengths.push_back(sectionlength); + // Skip padding + aZoneFileStream->skipRawData(1); + } + // Skip unknown section + aZoneFileStream->skipRawData(2 * 8); + + return result; +} + +MenuFile ZoneFile_COD9_WiiU::pParseAsset_MenuFile(QDataStream *aZoneFileStream) { + //MENU_FILE + MenuFile result; + + aZoneFileStream->skipRawData(4); // Separator + + // Parse menu def count + *aZoneFileStream >> result.menuCount; + + // Clearly misparsed, never have this much + if (result.menuCount > 1000) { + qDebug() << "Failure reported when parsing menu file."; + return result; + } + for (uint i = 0; i < result.menuCount; i++) { + Menu menu; + + aZoneFileStream->skipRawData(4); // Separator + + // Read in x_anim file name + char menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + while (menuFilepathChar != 0) { + menu.filePath += menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + } + aZoneFileStream->skipRawData(4); // Separator + + *aZoneFileStream >> menu.menuNamePtr; + + float menuRectX, menuRectY, menuRectWidth, menuRectHeight; + *aZoneFileStream >> menuRectX >> menuRectY >> menuRectWidth >> menuRectHeight; + menu.rect = QRectF(menuRectX, menuRectY, menuRectWidth, menuRectHeight); + + quint32 hAlignInt, vAlignInt; + *aZoneFileStream >> hAlignInt >> vAlignInt; + menu.hAlign = (MENU_H_ALIGNMENT)hAlignInt; + menu.vAlign = (MENU_V_ALIGNMENT)vAlignInt; + + float rectClientX, rectClientY, rectClientWidth, rectClientHeight; + *aZoneFileStream >> rectClientX >> rectClientY >> rectClientWidth >> rectClientHeight; + menu.clientRect = QRectF(rectClientX, rectClientY, rectClientWidth, rectClientHeight); + + quint32 hClientAlignInt, vClientAlignInt, styleInt, borderInt; + *aZoneFileStream >> hClientAlignInt >> vClientAlignInt >> menu.groupPtr + >> styleInt >> borderInt >> menu.ownerDraw >> menu.ownerDrawFlags + >> menu.borderSize >> menu.staticFlags >> menu.dynamicFlags >> menu.nextTime; + menu.hClientAlign = (MENU_H_ALIGNMENT)hClientAlignInt; + menu.vClientAlign = (MENU_V_ALIGNMENT)vClientAlignInt; + menu.style = (MENU_WINDOW_STYLE)styleInt; + menu.border = (MENU_WINDOW_BORDER)borderInt; + + float foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA, + backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA, + borderColorR, borderColorG, borderColorB, borderColorA, + outlineColorR, outlineColorG, outlineColorB, outlineColorA; + *aZoneFileStream >> foregroundColorR >> foregroundColorG >> foregroundColorB >> foregroundColorA + >> backgroundColorR >> backgroundColorG >> backgroundColorB >> backgroundColorA + >> borderColorR >> borderColorG >> borderColorB >> borderColorA + >> outlineColorR >> outlineColorG >> outlineColorB >> outlineColorA; + + menu.foregroundColor = QColor(foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA); + menu.backgroundColor = QColor(backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA); + menu.borderColor = QColor(borderColorR, borderColorG, borderColorB, borderColorA); + menu.outlineColor = QColor(outlineColorR, outlineColorG, outlineColorB, outlineColorA); + + *aZoneFileStream >> menu.materialPtr >> menu.fontPtr >> menu.fullScreen >> menu.itemCount + >> menu.fontIndex >> menu.cursorItem >> menu.fadeCycle >> menu.fadeClamp + >> menu.fadeAmount >> menu.fadeInAmount >> menu.blurRadius >> menu.onOpenPtr + >> menu.onFocusPtr >> menu.onClosePtr >> menu.onESCPtr >> menu.onKeyPtr + >> menu.visibleExpCount >> menu.expEntryPtr >> menu.allowedBindingPtr + >> menu.soundNamePtr >> menu.imageTrack; + + float focusColorR, focusColorG, focusColorB, focusColorA, + disabledColorR, disabledColorG, disabledColorB, disabledColorA; + *aZoneFileStream >> focusColorR >> focusColorG >> focusColorB >> focusColorA + >> disabledColorR >> disabledColorG >> disabledColorB >> disabledColorA; + menu.focusColor = QColor(focusColorR, focusColorG, focusColorB, focusColorA); + menu.disabledColor = QColor(disabledColorR, disabledColorG, disabledColorB, disabledColorA); + + *aZoneFileStream >> menu.rectXExpCount >> menu.rectXExpPtr >> menu.rectYExpCount >> menu.rectYExpPtr; + + aZoneFileStream->skipRawData(4); // Separator + + char menuDefNameChar; + int menuDefNameLen = 0; + *aZoneFileStream >> menuDefNameChar; + while (menuDefNameChar != 0 && menuDefNameLen < 30) { + menuDefNameLen++; + menu.name += menuDefNameChar; + *aZoneFileStream >> menuDefNameChar; + } + + char defStringChar; + int defStringLen = 0; + *aZoneFileStream >> defStringChar; + while (defStringChar != 0 && defStringLen < 30) { + defStringLen++; + menu.definition += defStringChar; + *aZoneFileStream >> defStringChar; + } + aZoneFileStream->skipRawData(4 * 10); + + *aZoneFileStream >> menu.itemWindowDefNamePtr; + + float itemRectX, itemRectY, itemRectWidth, itemRectHeight; + *aZoneFileStream >> itemRectX >> itemRectY >> itemRectWidth >> itemRectHeight; + menu.itemRect = QRectF(itemRectX, itemRectY, itemRectWidth, itemRectHeight); + + *aZoneFileStream >> menu.itemHAlignment >> menu.itemVAlignment >> menu.itemGroupPtr + >> menu.itemWindowStyle >> menu.itemWindowBorder >> menu.itemOwnerDraw + >> menu.itemOwnerDrawFlags >> menu.itemBorderSize >> menu.itemStaticFlags + >> menu.itemDynamicFlags >> menu.itemNextTime; + + float itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA, + itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA, + itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA, + itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA; + *aZoneFileStream >> itemForegroundColorR >> itemForegroundColorG >> itemForegroundColorB >> itemForegroundColorA + >> itemBackgroundColorR >> itemBackgroundColorG >> itemBackgroundColorB >> itemBackgroundColorA + >> itemBorderColorR >> itemBorderColorG >> itemBorderColorB >> itemBorderColorA + >> itemOutlineColorR >> itemOutlineColorG >> itemOutlineColorB >> itemOutlineColorA; + + menu.itemForegroundColor = QColor(itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA); + menu.itemBackgroundColor = QColor(itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA); + menu.itemBorderColor = QColor(itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA); + menu.itemOutlineColor = QColor(itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA); + + *aZoneFileStream >> menu.itemMaterialPtr; + + float itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight; + *aZoneFileStream >> itemTextRectX >> itemTextRectY >> itemTextRectWidth >> itemTextRectHeight; + menu.itemTextRect = QRectF(itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight); + + quint32 hItemTextAlignInt, vItemTextAlignInt, itemType, fontTypeInt, textStyleInt; + *aZoneFileStream >> hItemTextAlignInt >> vItemTextAlignInt >> itemType >> menu.dataType + >> menu.alignment >> fontTypeInt >> menu.textAlignMode >> menu.textalignx >> menu.textaligny + >> menu.textscale >> textStyleInt >> menu.gameMsgWindowIndex >> menu.gameMsgWindowMode + >> menu.testPtr >> menu.textSavegameInfo >> menu.parentPtr; + menu.itemText_hAlign = (MENU_H_ALIGNMENT)hItemTextAlignInt; + menu.itemText_vAlign = (MENU_V_ALIGNMENT)vItemTextAlignInt; + menu.itemType = (MENU_ITEM_TYPE)itemType; + menu.fontEnum = (MENU_FONT_TYPE)fontTypeInt; + menu.textStyle = (MENU_ITEM_TEXTSTYLE)textStyleInt; + + *aZoneFileStream >> menu.mouseEnterText >> menu.mouseExitText >> menu.mouseEnter >> menu.mouseExit + >> menu.action >> menu.onAccept >> menu.onFocus >> menu.leaveFocus >> menu.dvar >> menu.dvarTest + >> menu.keyHandlerPtr >> menu.enableDvarPtr >> menu.dvarFlags >> menu.focusSoundPtr + >> menu.special >> menu.cursorPos; + + // itemDefData_t typeData; + + // listBoxDef_s *listBox; + + *aZoneFileStream >> menu.startPos >> menu.endPos >> menu.drawPadding; + + *aZoneFileStream >> menu.elementWidth >> menu.elementHeight; + + *aZoneFileStream >> menu.elementStyle >> menu.numColumns; + + //columnInfo_s columnInfo[16]; + + *aZoneFileStream >> menu.doubleClickPtr; + + + *aZoneFileStream >> menu.notselectable >> menu.noScrollBars >> menu.usePaging; + + float itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA, + itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA, + itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA; + *aZoneFileStream >> itemSelectBorderColorR >> itemSelectBorderColorG >> itemSelectBorderColorB >> itemSelectBorderColorA + >> itemDisableColorR >> itemDisableColorG >> itemDisableColorB >> itemDisableColorA + >> itemFocusColorR >> itemFocusColorG >> itemFocusColorB >> itemFocusColorA; + menu.itemSelectBorderColor = QColor(itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA); + menu.itemDisableColor = QColor(itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA); + menu.itemFocusColor = QColor(itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA); + + *aZoneFileStream >> menu.selectIconPtr >> menu.backgroundItemListboxPtr >> menu.highlightTexturePtr; + + // editFieldDef_s *editField; + + *aZoneFileStream >> menu.minVal >> menu.maxVal >> menu.defVal >> menu.range >> menu.maxChars + >> menu.maxCharsGotoNext >> menu.maxPaintChars >> menu.paintOffset; + + // multiDef_s *multi; + + for (int i = 0; i < 32; i++) { + quint32 dvarList; + *aZoneFileStream >> dvarList; + menu.dvarListPtrs.push_back(dvarList); + } + + for (int i = 0; i < 32; i++) { + quint32 dvarStr; + *aZoneFileStream >> dvarStr; + menu.dvarStrPtrs.push_back(dvarStr); + } + + for (int i = 0; i < 32; i++) { + float dvarValue; + *aZoneFileStream >> dvarValue; + menu.dvarValues.push_back(dvarValue); + } + + *aZoneFileStream >> menu.count >> menu.strDef >> menu.enumDvarNamePtr; + aZoneFileStream->skipRawData(4); + //>> menu.dataPtr + *aZoneFileStream >> menu.itemImageTrack; + + qDebug() << aZoneFileStream->device()->pos(); + + //statement_s visibleExp; + //statement_s textExp; + //statement_s materialExp; + //statement_s rectXExp; + //statement_s rectYExp; + //statement_s rectWExp; + //statement_s rectHExp; + //statement_s foreColorAExp; + result.menuDefs << menu; + } + return result; +} + +void ZoneFile_COD9_WiiU::pParseAsset_Weapon(QDataStream *aZoneFileStream) { + //WEAPON_FILE + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile_COD9_WiiU::pParseAsset_D3DBSP(QDataStream *aZoneFileStream) { + //D3DBSP_DUMP + Q_UNUSED(aZoneFileStream); +} + +StringTable ZoneFile_COD9_WiiU::pParseAsset_StringTable(QDataStream *aZoneFileStream) { + StringTable result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.columnCount + >> result.rowCount; + + // Todo fix this + result.columnCount = 0; + result.rowCount = 0; + + aZoneFileStream->skipRawData(4); + + QString stringTableName; + char stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + while (stringTableNameChar != 0) { + result.name += stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + } + + for (quint32 i = 0; i < result.rowCount; i++) { + QByteArray pointerData(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pointerData.data(), 4); + result.tablePointers.push_back(pointerData.toHex()); + + aZoneFileStream->skipRawData(4); + } + + for (const QString &pointerAddr : result.tablePointers) { + QString leadingContent = ""; + if (pointerAddr == "FFFFFFFF") { + char leadingContentChar; + *aZoneFileStream >> leadingContentChar; + while (leadingContentChar != 0) { + leadingContent += leadingContentChar; + *aZoneFileStream >> leadingContentChar; + } + } else { + leadingContent = pointerAddr; + } + + QString content; + char contentChar; + *aZoneFileStream >> contentChar; + while (contentChar != 0) { + content += contentChar; + *aZoneFileStream >> contentChar; + } + result.content[leadingContent] = content; + } + return result; +} + +AssetType ZoneFile_COD9_WiiU::AssetStrToEnum(const QString aAssetType) { + const QString cleanedType = aAssetType.toUpper(); + if (cleanedType == "17000000") { // localized string PARTIALLY VERIFIED + return ASSET_LOCAL_STRING; + } else if (cleanedType == "20000000") { // raw_file PARTIALLY VERIFIED + return ASSET_RAW_FILE; + } else if (cleanedType == "1A000000") { // fx PARTIALLY VERIFIED + return ASSET_EFFECT; + } else if (cleanedType == "09000000") { // loaded_sound PARTIALLY VERIFIED + return ASSET_SOUND; + } else if (cleanedType == "04000000") { // x_anim PARTIALLY VERIFIED + return ASSET_ANIMATION; + } else if (cleanedType == "0C000000") { // collision_map PARTIALLY VERIFIED + return ASSET_COLLISION_MAP; + } else if (cleanedType == "21000000") { // string_table PARTIALLY VERIFIED + return ASSET_STRING_TABLE; + } else if (cleanedType == "15000000") { // menu_file PARTIALLY VERIFIED + return ASSET_MENU; + } else if (cleanedType == "07000000") { // tech set PARTIALLY VERIFIED + return ASSET_TECH_SET; + } else if (cleanedType == "18000000") { // weapon PARTIALLY VERIFIED + return ASSET_WEAPON; + } else if (cleanedType == "11000000") { // gfx map PARTIALLY VERIFIED + return ASSET_GFX_MAP; + } else if (cleanedType == "12000000") { // light_def PARTIALLY VERIFIED + return ASSET_LIGHT_DEF; + } else if (cleanedType == "14000000") { // font PARTIALLY VERIFIED + return ASSET_FONT; + } else if (cleanedType == "05000000") { // xmodel PARTIALLY VERIFIED + return ASSET_MODEL; + } else if (cleanedType == "0D000000") { // d3dbsp PARTIALLY VERIFIED + return ASSET_D3DBSP; + } else if (cleanedType == "06000000") { // image PARTIALLY VERIFIED + return ASSET_IMAGE; + } else if (cleanedType == "0E000000") { // game map sp PARTIALLY VERIFIED + return ASSET_GAME_MAP_SP; + } else if (cleanedType == "0B000000") { // col map sp PARTIALLY VERIFIED + return ASSET_COL_MAP_SP; + } + return ASSET_NONE; +} + +QByteArray ZoneFile_COD9_WiiU::GetBinaryData() { + QByteArray result; + + return result; +} diff --git a/libs/zonefile/WiiU/zonefile_cod9_wiiu.h b/libs/zonefile/WiiU/zonefile_cod9_wiiu.h new file mode 100644 index 0000000..a69625b --- /dev/null +++ b/libs/zonefile/WiiU/zonefile_cod9_wiiu.h @@ -0,0 +1,52 @@ +#ifndef ZONEFILE_COD9_H +#define ZONEFILE_COD9_H + +#include "zonefile.h" + +class ZoneFile_COD9_WiiU : public ZoneFile +{ +public: + ZoneFile_COD9_WiiU(); + ~ZoneFile_COD9_WiiU(); + + bool Load(const QByteArray aFileData) override; + AssetType AssetStrToEnum(const QString aAssetType) override; + + QByteArray GetBinaryData() override; + +protected: + void pParseZoneHeader(QDataStream *aZoneFileStream) override; + quint32 pParseZoneSize(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsA(QDataStream *aZoneFileStream) override; + quint32 pParseZoneTagCount(QDataStream *aZoneFileStream) override; + quint32 pParseZoneRecordCount(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsB(QDataStream *aZoneFileStream) override; + void pParseZoneUnknownsC(QDataStream *aZoneFileStream) override; + QStringList pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) override; + QStringList pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) override; + AssetMap pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) override; + LocalString pParseAsset_LocalString(QDataStream *aZoneFileStream) override; + RawFile pParseAsset_RawFile(QDataStream *aZoneFileStream) override; + void pParseAsset_PhysPreset(QDataStream *aZoneFileStream) override; + Model pParseAsset_Model(QDataStream *aZoneFileStream) override; + Material pParseAsset_Material(QDataStream *aZoneFileStream) override; + Shader pParseAsset_Shader(QDataStream *aZoneFileStream) override; + TechSet pParseAsset_TechSet(QDataStream *aZoneFileStream) override; + Image pParseAsset_Image(QDataStream *aZoneFileStream) override; + SoundAsset pParseAsset_Sound(QDataStream *aZoneFileStream) override; + void pParseAsset_ColMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapSP(QDataStream *aZoneFileStream) override; + void pParseAsset_GameMapMP(QDataStream *aZoneFileStream) override; + void pParseAsset_LightDef(QDataStream *aZoneFileStream) override; + void pParseAsset_UIMap(QDataStream *aZoneFileStream) override; + void pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) override; + void pParseAsset_AIType(QDataStream *aZoneFileStream) override; + void pParseAsset_FX(QDataStream *aZoneFileStream) override; + Animation pParseAsset_Animation(QDataStream *aZoneFileStream) override; + MenuFile pParseAsset_MenuFile(QDataStream *aZoneFileStream) override; + void pParseAsset_Weapon(QDataStream *aZoneFileStream) override; + void pParseAsset_D3DBSP(QDataStream *aZoneFileStream) override; + StringTable pParseAsset_StringTable(QDataStream *aZoneFileStream) override; +}; + +#endif // ZONEFILE_COD9_H diff --git a/libs/zonefile/zonefile.pro b/libs/zonefile/zonefile.pro index 7cc7681..b296b04 100644 --- a/libs/zonefile/zonefile.pro +++ b/libs/zonefile/zonefile.pro @@ -3,37 +3,88 @@ TEMPLATE = lib CONFIG += staticlib c++17 SOURCES += \ + # Base class zonefile.cpp \ + # 360 classes 360/zonefile_cod2_360.cpp \ + 360/zonefile_cod4_360.cpp \ 360/zonefile_cod5_360.cpp \ + 360/zonefile_cod6_360.cpp \ 360/zonefile_cod7_360.cpp \ + 360/zonefile_cod8_360.cpp \ 360/zonefile_cod9_360.cpp \ + 360/zonefile_cod10_360.cpp \ + 360/zonefile_cod11_360.cpp \ + 360/zonefile_cod12_360.cpp \ + # PS3 classes + PS3/zonefile_cod4_ps3.cpp \ PS3/zonefile_cod5_ps3.cpp \ + PS3/zonefile_cod6_ps3.cpp \ PS3/zonefile_cod7_ps3.cpp \ + PS3/zonefile_cod8_ps3.cpp \ PS3/zonefile_cod9_ps3.cpp \ + PS3/zonefile_cod10_ps3.cpp \ + PS3/zonefile_cod11_ps3.cpp \ + PS3/zonefile_cod12_ps3.cpp \ + # PC classes + PC/zonefile_cod4_pc.cpp \ PC/zonefile_cod5_pc.cpp \ + PC/zonefile_cod6_pc.cpp \ PC/zonefile_cod7_pc.cpp \ + PC/zonefile_cod8_pc.cpp \ PC/zonefile_cod9_pc.cpp \ + PC/zonefile_cod10_pc.cpp \ + PC/zonefile_cod11_pc.cpp \ PC/zonefile_cod12_pc.cpp \ + # Wii classes + Wii/zonefile_cod4_wii.cpp \ Wii/zonefile_cod7_wii.cpp \ - WiiU/zonefile_cod9_wiiu.cpp + Wii/zonefile_cod8_wii.cpp \ + # WiiU classes + WiiU/zonefile_cod9_wiiu.cpp \ + WiiU/zonefile_cod10_wiiu.cpp HEADERS += \ + # Base class zonefile.h \ + # 360 classes 360/zonefile_cod2_360.h \ + 360/zonefile_cod4_360.h \ 360/zonefile_cod5_360.h \ + 360/zonefile_cod6_360.h \ 360/zonefile_cod7_360.h \ + 360/zonefile_cod8_360.h \ 360/zonefile_cod9_360.h \ + 360/zonefile_cod10_360.h \ + 360/zonefile_cod11_360.h \ + 360/zonefile_cod12_360.h \ + # PS3 classes + PS3/zonefile_cod4_ps3.h \ PS3/zonefile_cod5_ps3.h \ + PS3/zonefile_cod6_ps3.h \ PS3/zonefile_cod7_ps3.h \ + PS3/zonefile_cod8_ps3.h \ PS3/zonefile_cod9_ps3.h \ + PS3/zonefile_cod10_ps3.h \ + PS3/zonefile_cod11_ps3.h \ + PS3/zonefile_cod12_ps3.h \ + # PC classes + PC/zonefile_cod4_pc.h \ PC/zonefile_cod5_pc.h \ + PC/zonefile_cod6_pc.h \ PC/zonefile_cod7_pc.h \ + PC/zonefile_cod8_pc.h \ PC/zonefile_cod9_pc.h \ + PC/zonefile_cod10_pc.h \ + PC/zonefile_cod11_pc.h \ PC/zonefile_cod12_pc.h \ + # Wii classes + Wii/zonefile_cod4_wii.h \ Wii/zonefile_cod7_wii.h \ + Wii/zonefile_cod8_wii.h \ + # WiiU classes WiiU/zonefile_cod9_wiiu.h \ - zonefile_factory.h + WiiU/zonefile_cod10_wiiu.h LIBS += \ -L$$OUT_PWD/../libs/core -lcore