From 588d03ad8f63736dd66d1a79981852fa541edac6 Mon Sep 17 00:00:00 2001 From: = Date: Sat, 17 May 2025 22:54:28 -0400 Subject: [PATCH 1/3] Unify test factory methods and add Wii support --- libs/zonefile/zonefile_factory.h | 18 ---- tests/360/autotest_cod10_360.cpp | 74 +++++++++----- tests/360/autotest_cod11_360.cpp | 74 +++++++++----- tests/360/autotest_cod12_360.cpp | 74 +++++++++----- tests/360/autotest_cod2_360.cpp | 93 ++++++----------- tests/360/autotest_cod4_360.cpp | 74 +++++++++----- tests/360/autotest_cod5_360.cpp | 87 ++++++---------- tests/360/autotest_cod6_360.cpp | 74 +++++++++----- tests/360/autotest_cod7_360.cpp | 154 ++++++++++++++++++++--------- tests/360/autotest_cod8_360.cpp | 80 +++++++++------ tests/360/autotest_cod9_360.cpp | 74 +++++++++----- tests/PC/autotest_cod10_pc.cpp | 73 +++++++++----- tests/PC/autotest_cod11_pc.cpp | 73 +++++++++----- tests/PC/autotest_cod12_pc.cpp | 73 +++++++++----- tests/PC/autotest_cod4_pc.cpp | 72 +++++++++----- tests/PC/autotest_cod5_pc.cpp | 72 +++++++++----- tests/PC/autotest_cod6_pc.cpp | 72 +++++++++----- tests/PC/autotest_cod7_pc.cpp | 72 +++++++++----- tests/PC/autotest_cod8_pc.cpp | 73 +++++++++----- tests/PC/autotest_cod9_pc.cpp | 73 +++++++++----- tests/PS3/autotest_cod10_ps3.cpp | 72 +++++++++----- tests/PS3/autotest_cod11_ps3.cpp | 72 +++++++++----- tests/PS3/autotest_cod12_ps3.cpp | 62 ++++++++---- tests/PS3/autotest_cod4_ps3.cpp | 148 +++++++++++++++++++-------- tests/PS3/autotest_cod5_ps3.cpp | 150 +++++++++++++++++++--------- tests/PS3/autotest_cod6_ps3.cpp | 72 +++++++++----- tests/PS3/autotest_cod7_ps3.cpp | 145 +++++++++++++++++++++------ tests/PS3/autotest_cod8_ps3.cpp | 72 +++++++++----- tests/PS3/autotest_cod9_ps3.cpp | 72 +++++++++----- tests/Wii/autotest_cod4_wii.cpp | 147 +++++++++++++++++++++++++++ tests/Wii/autotest_cod7_wii.cpp | 72 +++++++++----- tests/Wii/autotest_cod8_wii.cpp | 147 +++++++++++++++++++++++++++ tests/WiiU/autotest_cod10_wiiu.cpp | 72 +++++++++----- tests/WiiU/autotest_cod9_wiiu.cpp | 72 +++++++++----- tests/autotest_cod.h | 96 ++++++++++++++---- tests/test_main.cpp | 98 +++++++++++------- tests/tests.pro | 11 +-- 37 files changed, 2101 insertions(+), 1008 deletions(-) delete mode 100644 libs/zonefile/zonefile_factory.h create mode 100644 tests/Wii/autotest_cod4_wii.cpp create mode 100644 tests/Wii/autotest_cod8_wii.cpp diff --git a/libs/zonefile/zonefile_factory.h b/libs/zonefile/zonefile_factory.h deleted file mode 100644 index c22339f..0000000 --- a/libs/zonefile/zonefile_factory.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef ZONEFILE_FACTORY_H -#define ZONEFILE_FACTORY_H - -#include -#include - -class ZoneFile; - -class ZoneFileFactory { -public: - static std::shared_ptr Create(const QByteArray& data) { - return nullptr; - } - -private: -}; - -#endif // ZONEFILE_FACTORY_H diff --git a/tests/360/autotest_cod10_360.cpp b/tests/360/autotest_cod10_360.cpp index 5bebf11..7da3e78 100644 --- a/tests/360/autotest_cod10_360.cpp +++ b/tests/360/autotest_cod10_360.cpp @@ -12,12 +12,16 @@ class AutoTest_COD10_360 : public AutoTest_COD { private slots: void initTestCase(); - // Data-driven test for decompression + void testDecompression_data(); void testDecompression(); - // Data-driven test for recompression (compression) + void testCompression_data(); void testCompression(); + + void testFactory_data(); + void testFactory(); + void cleanupTestCase(); }; @@ -27,24 +31,18 @@ void AutoTest_COD10_360::initTestCase() { } void AutoTest_COD10_360::testDecompression_data() { - QTest::addColumn("fastFilePath_cod10_360"); - - QStringList ffFiles = findFastFiles(getFastFileDirectory()); - for (const QString &filePath : ffFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testDecompression_data(); } void AutoTest_COD10_360::testDecompression() { - QFETCH(QString, fastFilePath_cod10_360); + QFETCH(QString, fastFilePath); - const QString testName = "Decompress: " + fastFilePath_cod10_360; + const QString testName = "Decompress: " + fastFilePath; // Open the original .ff file. - QFile testFastFile(fastFilePath_cod10_360); + QFile testFastFile(fastFilePath); QVERIFY2(testFastFile.open(QIODevice::ReadOnly), - qPrintable("Failed to open test fastfile: " + fastFilePath_cod10_360)); + qPrintable("Failed to open test fastfile: " + fastFilePath)); const QByteArray testFFData = testFastFile.readAll(); testFastFile.close(); @@ -58,10 +56,10 @@ void AutoTest_COD10_360::testDecompression() { quint32 zoneSize; zoneStream >> zoneSize; QVERIFY2(zoneSize + 44 == testZoneData.size(), - qPrintable("Decompression validation failed for: " + fastFilePath_cod10_360)); + qPrintable("Decompression validation failed for: " + fastFilePath)); // Write the decompressed zone data to the exports folder with a .zone extension. - QFileInfo fi(fastFilePath_cod10_360); + QFileInfo fi(fastFilePath); QString outputFileName = fi.completeBaseName() + ".zone"; QString outputFilePath = QDir(EXPORT_DIR).filePath(outputFileName); QFile outputFile(outputFilePath); @@ -72,24 +70,18 @@ void AutoTest_COD10_360::testDecompression() { } void AutoTest_COD10_360::testCompression_data() { - QTest::addColumn("zoneFilePath_cod10_360"); - - QStringList zoneFiles = findZoneFiles(getZoneFileDirectory()); - for (const QString &filePath : zoneFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testCompression_data(); } void AutoTest_COD10_360::testCompression() { - QFETCH(QString, zoneFilePath_cod10_360); + QFETCH(QString, zoneFilePath); - QFile zoneFile(zoneFilePath_cod10_360); - QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath_cod10_360)); + QFile zoneFile(zoneFilePath); + QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath)); QByteArray decompressedData = zoneFile.readAll(); zoneFile.close(); - QFileInfo fi(zoneFilePath_cod10_360); + QFileInfo fi(zoneFilePath); QString originalFFPath = QDir(getFastFileDirectory()).filePath(fi.completeBaseName() + ".ff"); QFile originalFile(originalFFPath); @@ -119,6 +111,36 @@ void AutoTest_COD10_360::testCompression() { QCOMPARE(recompressedData, originalFFData); } +void AutoTest_COD10_360::testFactory_data() { + AutoTest_COD::testFactory_data(); +} + +void AutoTest_COD10_360::testFactory() { + QFETCH(QString, fastFilePath); + + const QString testName = "Factory ingest: " + fastFilePath; + + std::shared_ptr fastFile = FastFileFactory::Create(fastFilePath); + + const QString game = fastFile->GetGame(); + bool correctGame = game == "COD10"; + if (!correctGame) { + recordResult(testName, false); + } + QVERIFY2(correctGame + , qPrintable("Factory parsed wrong game [" + game + "] for fastfile: " + fastFilePath)); + + const QString platform = fastFile->GetPlatform(); + bool correctPlatform = platform == "360"; + if (!correctPlatform) { + recordResult(testName, false); + } + QVERIFY2(correctPlatform + , qPrintable("Factory parsed wrong platform [" + platform + "] for fastfile: " + fastFilePath)); + + recordResult(testName, true); +} + void AutoTest_COD10_360::cleanupTestCase() { // Any cleanup if necessary. } diff --git a/tests/360/autotest_cod11_360.cpp b/tests/360/autotest_cod11_360.cpp index 9b2a37f..74fe896 100644 --- a/tests/360/autotest_cod11_360.cpp +++ b/tests/360/autotest_cod11_360.cpp @@ -12,12 +12,16 @@ class AutoTest_COD11_360 : public AutoTest_COD { private slots: void initTestCase(); - // Data-driven test for decompression + void testDecompression_data(); void testDecompression(); - // Data-driven test for recompression (compression) + void testCompression_data(); void testCompression(); + + void testFactory_data(); + void testFactory(); + void cleanupTestCase(); }; @@ -27,24 +31,18 @@ void AutoTest_COD11_360::initTestCase() { } void AutoTest_COD11_360::testDecompression_data() { - QTest::addColumn("fastFilePath_cod11_360"); - - QStringList ffFiles = findFastFiles(getFastFileDirectory()); - for (const QString &filePath : ffFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testDecompression_data(); } void AutoTest_COD11_360::testDecompression() { - QFETCH(QString, fastFilePath_cod11_360); + QFETCH(QString, fastFilePath); - const QString testName = "Decompress: " + fastFilePath_cod11_360; + const QString testName = "Decompress: " + fastFilePath; // Open the original .ff file. - QFile testFastFile(fastFilePath_cod11_360); + QFile testFastFile(fastFilePath); QVERIFY2(testFastFile.open(QIODevice::ReadOnly), - qPrintable("Failed to open test fastfile: " + fastFilePath_cod11_360)); + qPrintable("Failed to open test fastfile: " + fastFilePath)); const QByteArray testFFData = testFastFile.readAll(); testFastFile.close(); @@ -58,10 +56,10 @@ void AutoTest_COD11_360::testDecompression() { quint32 zoneSize; zoneStream >> zoneSize; QVERIFY2(zoneSize + 44 == testZoneData.size(), - qPrintable("Decompression validation failed for: " + fastFilePath_cod11_360)); + qPrintable("Decompression validation failed for: " + fastFilePath)); // Write the decompressed zone data to the exports folder with a .zone extension. - QFileInfo fi(fastFilePath_cod11_360); + QFileInfo fi(fastFilePath); QString outputFileName = fi.completeBaseName() + ".zone"; QString outputFilePath = QDir(EXPORT_DIR).filePath(outputFileName); QFile outputFile(outputFilePath); @@ -72,24 +70,18 @@ void AutoTest_COD11_360::testDecompression() { } void AutoTest_COD11_360::testCompression_data() { - QTest::addColumn("zoneFilePath_cod11_360"); - - QStringList zoneFiles = findZoneFiles(getZoneFileDirectory()); - for (const QString &filePath : zoneFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testCompression_data(); } void AutoTest_COD11_360::testCompression() { - QFETCH(QString, zoneFilePath_cod11_360); + QFETCH(QString, zoneFilePath); - QFile zoneFile(zoneFilePath_cod11_360); - QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath_cod11_360)); + QFile zoneFile(zoneFilePath); + QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath)); QByteArray decompressedData = zoneFile.readAll(); zoneFile.close(); - QFileInfo fi(zoneFilePath_cod11_360); + QFileInfo fi(zoneFilePath); QString originalFFPath = QDir(getFastFileDirectory()).filePath(fi.completeBaseName() + ".ff"); QFile originalFile(originalFFPath); @@ -119,6 +111,36 @@ void AutoTest_COD11_360::testCompression() { QCOMPARE(recompressedData, originalFFData); } +void AutoTest_COD11_360::testFactory_data() { + AutoTest_COD::testFactory_data(); +} + +void AutoTest_COD11_360::testFactory() { + QFETCH(QString, fastFilePath); + + const QString testName = "Factory ingest: " + fastFilePath; + + std::shared_ptr fastFile = FastFileFactory::Create(fastFilePath); + + const QString game = fastFile->GetGame(); + bool correctGame = game == "COD11"; + if (!correctGame) { + recordResult(testName, false); + } + QVERIFY2(correctGame + , qPrintable("Factory parsed wrong game [" + game + "] for fastfile: " + fastFilePath)); + + const QString platform = fastFile->GetPlatform(); + bool correctPlatform = platform == "360"; + if (!correctPlatform) { + recordResult(testName, false); + } + QVERIFY2(correctPlatform + , qPrintable("Factory parsed wrong platform [" + platform + "] for fastfile: " + fastFilePath)); + + recordResult(testName, true); +} + void AutoTest_COD11_360::cleanupTestCase() { // Any cleanup if necessary. } diff --git a/tests/360/autotest_cod12_360.cpp b/tests/360/autotest_cod12_360.cpp index dd7a1d0..5b90bea 100644 --- a/tests/360/autotest_cod12_360.cpp +++ b/tests/360/autotest_cod12_360.cpp @@ -12,12 +12,16 @@ class AutoTest_COD12_360 : public AutoTest_COD { private slots: void initTestCase(); - // Data-driven test for decompression + void testDecompression_data(); void testDecompression(); - // Data-driven test for recompression (compression) + void testCompression_data(); void testCompression(); + + void testFactory_data(); + void testFactory(); + void cleanupTestCase(); }; @@ -27,28 +31,22 @@ void AutoTest_COD12_360::initTestCase() { } void AutoTest_COD12_360::testDecompression_data() { - QTest::addColumn("fastFilePath_cod12_360"); - - QStringList ffFiles = findFastFiles(getFastFileDirectory()); - for (const QString &filePath : ffFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testDecompression_data(); } void AutoTest_COD12_360::testDecompression() { - QFETCH(QString, fastFilePath_cod12_360); + QFETCH(QString, fastFilePath); - const QString testName = "Decompress: " + fastFilePath_cod12_360; + const QString testName = "Decompress: " + fastFilePath; // Open the original .ff file. - QFile testFastFile(fastFilePath_cod12_360); + QFile testFastFile(fastFilePath); bool fastFileOpened = testFastFile.open(QIODevice::ReadOnly); if (!fastFileOpened) { recordResult(testName, false); } QVERIFY2(fastFileOpened, - qPrintable("Failed to open test fastfile: " + fastFilePath_cod12_360)); + qPrintable("Failed to open test fastfile: " + fastFilePath)); const QByteArray testFFData = testFastFile.readAll(); testFastFile.close(); @@ -66,10 +64,10 @@ void AutoTest_COD12_360::testDecompression() { recordResult(testName, false); } QVERIFY2(sizeMatches, - qPrintable("Decompression validation failed for: " + fastFilePath_cod12_360)); + qPrintable("Decompression validation failed for: " + fastFilePath)); // Write the decompressed zone data to the exports folder with a .zone extension. - QFileInfo fi(fastFilePath_cod12_360); + QFileInfo fi(fastFilePath); QString outputFileName = fi.completeBaseName() + ".zone"; QString outputFilePath = QDir(EXPORT_DIR).filePath(outputFileName); QFile outputFile(outputFilePath); @@ -84,24 +82,18 @@ void AutoTest_COD12_360::testDecompression() { } void AutoTest_COD12_360::testCompression_data() { - QTest::addColumn("zoneFilePath_cod12_360"); - - QStringList zoneFiles = findZoneFiles(getZoneFileDirectory()); - for (const QString &filePath : zoneFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testCompression_data(); } void AutoTest_COD12_360::testCompression() { - QFETCH(QString, zoneFilePath_cod12_360); + QFETCH(QString, zoneFilePath); - QFile zoneFile(zoneFilePath_cod12_360); - QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath_cod12_360)); + QFile zoneFile(zoneFilePath); + QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath)); QByteArray decompressedData = zoneFile.readAll(); zoneFile.close(); - QFileInfo fi(zoneFilePath_cod12_360); + QFileInfo fi(zoneFilePath); QString originalFFPath = QDir(getFastFileDirectory()).filePath(fi.completeBaseName() + ".ff"); QFile originalFile(originalFFPath); @@ -131,6 +123,36 @@ void AutoTest_COD12_360::testCompression() { QCOMPARE(recompressedData, originalFFData); } +void AutoTest_COD12_360::testFactory_data() { + AutoTest_COD::testFactory_data(); +} + +void AutoTest_COD12_360::testFactory() { + QFETCH(QString, fastFilePath); + + const QString testName = "Factory ingest: " + fastFilePath; + + std::shared_ptr fastFile = FastFileFactory::Create(fastFilePath); + + const QString game = fastFile->GetGame(); + bool correctGame = game == "COD12"; + if (!correctGame) { + recordResult(testName, false); + } + QVERIFY2(correctGame + , qPrintable("Factory parsed wrong game [" + game + "] for fastfile: " + fastFilePath)); + + const QString platform = fastFile->GetPlatform(); + bool correctPlatform = platform == "360"; + if (!correctPlatform) { + recordResult(testName, false); + } + QVERIFY2(correctPlatform + , qPrintable("Factory parsed wrong platform [" + platform + "] for fastfile: " + fastFilePath)); + + recordResult(testName, true); +} + void AutoTest_COD12_360::cleanupTestCase() { // Any cleanup if necessary. } diff --git a/tests/360/autotest_cod2_360.cpp b/tests/360/autotest_cod2_360.cpp index ab5a6d1..11a8cc2 100644 --- a/tests/360/autotest_cod2_360.cpp +++ b/tests/360/autotest_cod2_360.cpp @@ -13,10 +13,10 @@ class AutoTest_COD2_360 : public AutoTest_COD { private slots: void initTestCase(); - // Data-driven test for decompression + void testDecompression_data(); void testDecompression(); - // Data-driven test for recompression (compression) + void testCompression_data(); void testCompression(); @@ -32,28 +32,22 @@ void AutoTest_COD2_360::initTestCase() { } void AutoTest_COD2_360::testDecompression_data() { - QTest::addColumn("fastFilePath_cod2_360"); - - QStringList ffFiles = findFastFiles(getFastFileDirectory()); - for (const QString &filePath : ffFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testDecompression_data(); } void AutoTest_COD2_360::testDecompression() { - QFETCH(QString, fastFilePath_cod2_360); + QFETCH(QString, fastFilePath); - const QString testName = "Decompress: " + fastFilePath_cod2_360; + const QString testName = "Decompress: " + fastFilePath; // Open the original .ff file. - QFile testFastFile(fastFilePath_cod2_360); + QFile testFastFile(fastFilePath); bool fastFileOpened = testFastFile.open(QIODevice::ReadOnly); if (!fastFileOpened) { recordResult(testName, false); } QVERIFY2(fastFileOpened - , qPrintable("Failed to open test fastfile: " + fastFilePath_cod2_360)); + , qPrintable("Failed to open test fastfile: " + fastFilePath)); const QByteArray testFFData = testFastFile.readAll(); testFastFile.close(); @@ -68,10 +62,10 @@ void AutoTest_COD2_360::testDecompression() { zoneStream >> zoneSize; // TODO: Find new way to verify as cod2 doesn't store size in zone file //QVERIFY2(zoneSize + 44 == testZoneData.size(), - // qPrintable("Decompression validation failed for: " + fastFilePath_cod2_360)); + // qPrintable("Decompression validation failed for: " + fastFilePath)); // Write the decompressed zone data to the exports folder with a .zone extension. - QFileInfo fi(fastFilePath_cod2_360); + QFileInfo fi(fastFilePath); QString outputFileName = fi.completeBaseName() + ".zone"; QString outputFilePath = QDir(EXPORT_DIR).filePath(outputFileName); QFile outputFile(outputFilePath); @@ -88,31 +82,24 @@ void AutoTest_COD2_360::testDecompression() { } void AutoTest_COD2_360::testCompression_data() { - QTest::addColumn("zoneFilePath_cod2_360"); - - QStringList zoneFiles = findZoneFiles(getZoneFileDirectory()); - for (const QString &filePath : zoneFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - break; - } + AutoTest_COD::testCompression_data(); } void AutoTest_COD2_360::testCompression() { - QFETCH(QString, zoneFilePath_cod2_360); + QFETCH(QString, zoneFilePath); - const QString testName = "Compress: " + zoneFilePath_cod2_360; + const QString testName = "Compress: " + zoneFilePath; - QFile zoneFile(zoneFilePath_cod2_360); + QFile zoneFile(zoneFilePath); bool zoneFileOpened = zoneFile.open(QIODevice::ReadOnly); if (!zoneFileOpened) { recordResult(testName, false); } - QVERIFY2(zoneFileOpened, qPrintable("Failed to open zone file: " + zoneFilePath_cod2_360)); + QVERIFY2(zoneFileOpened, qPrintable("Failed to open zone file: " + zoneFilePath)); QByteArray decompressedData = zoneFile.readAll(); zoneFile.close(); - QFileInfo fi(zoneFilePath_cod2_360); + QFileInfo fi(zoneFilePath); QString originalFFPath = QDir(getFastFileDirectory()).filePath(fi.completeBaseName() + ".ff"); QFile originalFile(originalFFPath); @@ -126,10 +113,7 @@ void AutoTest_COD2_360::testCompression() { QByteArray header = originalFFData.left(20); - QByteArray newCompressedData;// = Compressor::CompressZLIB(decompressedData, Z_BEST_COMPRESSION); - newCompressedData = Compression::CompressZLIBWithSettings(decompressedData, Z_BEST_COMPRESSION, MAX_WBITS, 8, Z_DEFAULT_STRATEGY, {}); - - QByteArray recompressedData = header + newCompressedData; + QByteArray recompressedData = header + Compression::CompressZLIB(decompressedData); QString recompressedFilePath = QDir(EXPORT_DIR).filePath(fi.completeBaseName() + ".ff"); QFile recompressedFile(recompressedFilePath); @@ -151,46 +135,31 @@ void AutoTest_COD2_360::testCompression() { } void AutoTest_COD2_360::testFactory_data() { - QTest::addColumn("fastFilePath_cod2_360"); - - QStringList ffFiles = findFastFiles(getFastFileDirectory()); - for (const QString &filePath : ffFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testFactory_data(); } void AutoTest_COD2_360::testFactory() { - QFETCH(QString, fastFilePath_cod2_360); + QFETCH(QString, fastFilePath); - const QString testName = "Create w/ factory: " + fastFilePath_cod2_360; + const QString testName = "Factory ingest: " + fastFilePath; - // Open the original .ff file. - QFile testFastFile(fastFilePath_cod2_360); - bool fastFileOpened = testFastFile.open(QIODevice::ReadOnly); - if (!fastFileOpened) { - recordResult(testName, false); - } - QVERIFY2(fastFileOpened - , qPrintable("Failed to open test fastfile: " + fastFilePath_cod2_360)); - const QByteArray testFFData = testFastFile.readAll(); - testFastFile.close(); + std::shared_ptr fastFile = FastFileFactory::Create(fastFilePath); - std::shared_ptr fastFile = FastFileFactory::Create(testFFData); - - bool correctPlatform = fastFile->GetPlatform() == "360"; - if (!correctPlatform) { - recordResult(testName, false); - } - QVERIFY2(correctPlatform - , qPrintable("Factory created fastfile for platform: " + fastFile->GetPlatform())); - - bool correctGame = fastFile->GetGame() == "COD2"; + const QString game = fastFile->GetGame(); + bool correctGame = game == "COD2"; if (!correctGame) { recordResult(testName, false); } QVERIFY2(correctGame - , qPrintable("Factory created fastfile for game: " + fastFile->GetGame())); + , qPrintable("Factory parsed wrong game [" + game + "] for fastfile: " + fastFilePath)); + + const QString platform = fastFile->GetPlatform(); + bool correctPlatform = platform == "360"; + if (!correctPlatform) { + recordResult(testName, false); + } + QVERIFY2(correctPlatform + , qPrintable("Factory parsed wrong platform [" + platform + "] for fastfile: " + fastFilePath)); recordResult(testName, true); } diff --git a/tests/360/autotest_cod4_360.cpp b/tests/360/autotest_cod4_360.cpp index 9446a47..a27f2da 100644 --- a/tests/360/autotest_cod4_360.cpp +++ b/tests/360/autotest_cod4_360.cpp @@ -12,12 +12,16 @@ class AutoTest_COD4_360 : public AutoTest_COD { private slots: void initTestCase(); - // Data-driven test for decompression + void testDecompression_data(); void testDecompression(); - // Data-driven test for recompression (compression) + void testCompression_data(); void testCompression(); + + void testFactory_data(); + void testFactory(); + void cleanupTestCase(); }; @@ -27,24 +31,18 @@ void AutoTest_COD4_360::initTestCase() { } void AutoTest_COD4_360::testDecompression_data() { - QTest::addColumn("fastFilePath_cod4_360"); - - QStringList ffFiles = findFastFiles(getFastFileDirectory()); - for (const QString &filePath : ffFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testDecompression_data(); } void AutoTest_COD4_360::testDecompression() { - QFETCH(QString, fastFilePath_cod4_360); + QFETCH(QString, fastFilePath); - const QString testName = "Decompress: " + fastFilePath_cod4_360; + const QString testName = "Decompress: " + fastFilePath; // Open the original .ff file. - QFile testFastFile(fastFilePath_cod4_360); + QFile testFastFile(fastFilePath); QVERIFY2(testFastFile.open(QIODevice::ReadOnly), - qPrintable("Failed to open test fastfile: " + fastFilePath_cod4_360)); + qPrintable("Failed to open test fastfile: " + fastFilePath)); const QByteArray testFFData = testFastFile.readAll(); testFastFile.close(); @@ -66,10 +64,10 @@ void AutoTest_COD4_360::testDecompression() { qDebug() << "Test zone Size: " << testZoneData.size(); } QVERIFY2(abs(zoneSize - testZoneData.size()) == 36, - qPrintable("Decompression validation failed for: " + fastFilePath_cod4_360)); + qPrintable("Decompression validation failed for: " + fastFilePath)); // Write the decompressed zone data to the exports folder with a .zone extension. - QFileInfo fi(fastFilePath_cod4_360); + QFileInfo fi(fastFilePath); QString outputFileName = fi.completeBaseName() + ".zone"; QString outputFilePath = QDir(EXPORT_DIR).filePath(outputFileName); QFile outputFile(outputFilePath); @@ -80,24 +78,18 @@ void AutoTest_COD4_360::testDecompression() { } void AutoTest_COD4_360::testCompression_data() { - QTest::addColumn("zoneFilePath_cod4_360"); - - QStringList zoneFiles = findZoneFiles(getZoneFileDirectory()); - for (const QString &filePath : zoneFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testCompression_data(); } void AutoTest_COD4_360::testCompression() { - QFETCH(QString, zoneFilePath_cod4_360); + QFETCH(QString, zoneFilePath); - QFile zoneFile(zoneFilePath_cod4_360); - QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath_cod4_360)); + QFile zoneFile(zoneFilePath); + QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath)); QByteArray decompressedData = zoneFile.readAll(); zoneFile.close(); - QFileInfo fi(zoneFilePath_cod4_360); + QFileInfo fi(zoneFilePath); QString originalFFPath = QDir(getFastFileDirectory()).filePath(fi.completeBaseName() + ".ff"); QFile originalFile(originalFFPath); @@ -121,6 +113,36 @@ void AutoTest_COD4_360::testCompression() { QCOMPARE(recompressedData, originalFFData); } +void AutoTest_COD4_360::testFactory_data() { + AutoTest_COD::testFactory_data(); +} + +void AutoTest_COD4_360::testFactory() { + QFETCH(QString, fastFilePath); + + const QString testName = "Factory ingest: " + fastFilePath; + + std::shared_ptr fastFile = FastFileFactory::Create(fastFilePath); + + const QString game = fastFile->GetGame(); + bool correctGame = game == "COD4"; + if (!correctGame) { + recordResult(testName, false); + } + QVERIFY2(correctGame + , qPrintable("Factory parsed wrong game [" + game + "] for fastfile: " + fastFilePath)); + + const QString platform = fastFile->GetPlatform(); + bool correctPlatform = platform == "360"; + if (!correctPlatform) { + recordResult(testName, false); + } + QVERIFY2(correctPlatform + , qPrintable("Factory parsed wrong platform [" + platform + "] for fastfile: " + fastFilePath)); + + recordResult(testName, true); +} + void AutoTest_COD4_360::cleanupTestCase() { // Any cleanup if necessary. } diff --git a/tests/360/autotest_cod5_360.cpp b/tests/360/autotest_cod5_360.cpp index e0a3d92..039c8a5 100644 --- a/tests/360/autotest_cod5_360.cpp +++ b/tests/360/autotest_cod5_360.cpp @@ -13,10 +13,10 @@ class AutoTest_COD5_360 : public AutoTest_COD { private slots: void initTestCase(); - // Data-driven test for decompression + void testDecompression_data(); void testDecompression(); - // Data-driven test for recompression (compression) + void testCompression_data(); void testCompression(); @@ -32,29 +32,18 @@ void AutoTest_COD5_360::initTestCase() { } void AutoTest_COD5_360::testDecompression_data() { - QTest::addColumn("fastFilePath_cod5_360"); - - QStringList ffFiles = findFastFiles(getFastFileDirectory()); - int ffCount = 0; - for (const QString &filePath : ffFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - ffCount++; - - if (ffCount == FILE_MAX) { break; } - } + AutoTest_COD::testDecompression_data(); } void AutoTest_COD5_360::testDecompression() { - QFETCH(QString, fastFilePath_cod5_360); - return; + QFETCH(QString, fastFilePath); - const QString testName = "Decompress: " + fastFilePath_cod5_360; + const QString testName = "Decompress: " + fastFilePath; // Open the original .ff file. - QFile testFastFile(fastFilePath_cod5_360); + QFile testFastFile(fastFilePath); QVERIFY2(testFastFile.open(QIODevice::ReadOnly), - qPrintable("Failed to open test fastfile: " + fastFilePath_cod5_360)); + qPrintable("Failed to open test fastfile: " + fastFilePath)); const QByteArray testFFData = testFastFile.readAll(); testFastFile.close(); @@ -73,10 +62,10 @@ void AutoTest_COD5_360::testDecompression() { qDebug() << "Difference: " << abs(zoneSize - testZoneData.size()); } QVERIFY2(zoneSize + 36 == testZoneData.size(), - qPrintable("Decompression validation failed for: " + fastFilePath_cod5_360)); + qPrintable("Decompression validation failed for: " + fastFilePath)); // Write the decompressed zone data to the exports folder with a .zone extension. - QFileInfo fi(fastFilePath_cod5_360); + QFileInfo fi(fastFilePath); QString outputFileName = fi.completeBaseName() + ".zone"; QString outputFilePath = QDir(EXPORT_DIR).filePath(outputFileName); QFile outputFile(outputFilePath); @@ -87,28 +76,18 @@ void AutoTest_COD5_360::testDecompression() { } void AutoTest_COD5_360::testCompression_data() { - QTest::addColumn("zoneFilePath_cod5_360"); - - QStringList zoneFiles = findZoneFiles(getZoneFileDirectory()); - int zoneCount = 0; - for (const QString &filePath : zoneFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - zoneCount++; - - if (zoneCount == FILE_MAX) { break; } - } + AutoTest_COD::testCompression_data(); } void AutoTest_COD5_360::testCompression() { - QFETCH(QString, zoneFilePath_cod5_360); + QFETCH(QString, zoneFilePath); - QFile zoneFile(zoneFilePath_cod5_360); - QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath_cod5_360)); + QFile zoneFile(zoneFilePath); + QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath)); QByteArray decompressedData = zoneFile.readAll(); zoneFile.close(); - QFileInfo fi(zoneFilePath_cod5_360); + QFileInfo fi(zoneFilePath); QString originalFFPath = QDir(getFastFileDirectory()).filePath(fi.completeBaseName() + ".ff"); QFile originalFile(originalFFPath); @@ -139,39 +118,31 @@ void AutoTest_COD5_360::testCompression() { } void AutoTest_COD5_360::testFactory_data() { - QTest::addColumn("fastFilePath_cod5_360"); - - QStringList ffFiles = findFastFiles(getFastFileDirectory()); - int ffCount = 0; - for (const QString &filePath : ffFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - ffCount++; - - if (ffCount == FILE_MAX) { break; } - } + AutoTest_COD::testFactory_data(); } void AutoTest_COD5_360::testFactory() { - QFETCH(QString, fastFilePath_cod5_360); + QFETCH(QString, fastFilePath); - const QString testName = "Create w/ factory: " + fastFilePath_cod5_360; + const QString testName = "Factory ingest: " + fastFilePath; - std::shared_ptr fastFile = FastFileFactory::Create(fastFilePath_cod5_360); + std::shared_ptr fastFile = FastFileFactory::Create(fastFilePath); - bool correctPlatform = fastFile->GetPlatform() == "360"; - if (!correctPlatform) { - recordResult(testName, false); - } - QVERIFY2(correctPlatform - , qPrintable("Factory created fastfile for platform: " + fastFile->GetPlatform())); - - bool correctGame = fastFile->GetGame() == "COD5"; + const QString game = fastFile->GetGame(); + bool correctGame = game == "COD5"; if (!correctGame) { recordResult(testName, false); } QVERIFY2(correctGame - , qPrintable("Factory created fastfile for game: " + fastFile->GetGame())); + , qPrintable("Factory parsed wrong game [" + game + "] for fastfile: " + fastFilePath)); + + const QString platform = fastFile->GetPlatform(); + bool correctPlatform = platform == "360"; + if (!correctPlatform) { + recordResult(testName, false); + } + QVERIFY2(correctPlatform + , qPrintable("Factory parsed wrong platform [" + platform + "] for fastfile: " + fastFilePath)); recordResult(testName, true); } diff --git a/tests/360/autotest_cod6_360.cpp b/tests/360/autotest_cod6_360.cpp index 7d550eb..0c47322 100644 --- a/tests/360/autotest_cod6_360.cpp +++ b/tests/360/autotest_cod6_360.cpp @@ -12,12 +12,16 @@ class AutoTest_COD6_360 : public AutoTest_COD { private slots: void initTestCase(); - // Data-driven test for decompression + void testDecompression_data(); void testDecompression(); - // Data-driven test for recompression (compression) + void testCompression_data(); void testCompression(); + + void testFactory_data(); + void testFactory(); + void cleanupTestCase(); }; @@ -27,24 +31,18 @@ void AutoTest_COD6_360::initTestCase() { } void AutoTest_COD6_360::testDecompression_data() { - QTest::addColumn("fastFilePath_cod6_360"); - - QStringList ffFiles = findFastFiles(getFastFileDirectory()); - for (const QString &filePath : ffFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testDecompression_data(); } void AutoTest_COD6_360::testDecompression() { - QFETCH(QString, fastFilePath_cod6_360); + QFETCH(QString, fastFilePath); - const QString testName = "Decompress: " + fastFilePath_cod6_360; + const QString testName = "Decompress: " + fastFilePath; // Open the original .ff file. - QFile testFastFile(fastFilePath_cod6_360); + QFile testFastFile(fastFilePath); QVERIFY2(testFastFile.open(QIODevice::ReadOnly), - qPrintable("Failed to open test fastfile: " + fastFilePath_cod6_360)); + qPrintable("Failed to open test fastfile: " + fastFilePath)); const QByteArray testFFData = testFastFile.readAll(); testFastFile.close(); @@ -82,10 +80,10 @@ void AutoTest_COD6_360::testDecompression() { qDebug() << "Difference: " << abs(zoneSize - testZoneData.size()); } QVERIFY2(zoneSize + 32 == testZoneData.size(), - qPrintable("Decompression validation failed for: " + fastFilePath_cod6_360)); + qPrintable("Decompression validation failed for: " + fastFilePath)); // Write the decompressed zone data to the exports folder with a .zone extension. - QFileInfo fi(fastFilePath_cod6_360); + QFileInfo fi(fastFilePath); QString outputFileName = fi.completeBaseName() + ".zone"; QString outputFilePath = QDir(EXPORT_DIR).filePath(outputFileName); QFile outputFile(outputFilePath); @@ -96,24 +94,18 @@ void AutoTest_COD6_360::testDecompression() { } void AutoTest_COD6_360::testCompression_data() { - QTest::addColumn("zoneFilePath_cod6_360"); - - QStringList zoneFiles = findZoneFiles(getZoneFileDirectory()); - for (const QString &filePath : zoneFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testCompression_data(); } void AutoTest_COD6_360::testCompression() { - QFETCH(QString, zoneFilePath_cod6_360); + QFETCH(QString, zoneFilePath); - QFile zoneFile(zoneFilePath_cod6_360); - QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath_cod6_360)); + QFile zoneFile(zoneFilePath); + QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath)); QByteArray decompressedData = zoneFile.readAll(); zoneFile.close(); - QFileInfo fi(zoneFilePath_cod6_360); + QFileInfo fi(zoneFilePath); QString originalFFPath = QDir(getFastFileDirectory()).filePath(fi.completeBaseName() + ".ff"); QFile originalFile(originalFFPath); @@ -144,6 +136,36 @@ void AutoTest_COD6_360::testCompression() { QCOMPARE(recompressedData, originalFFData); } +void AutoTest_COD6_360::testFactory_data() { + AutoTest_COD::testFactory_data(); +} + +void AutoTest_COD6_360::testFactory() { + QFETCH(QString, fastFilePath); + + const QString testName = "Factory ingest: " + fastFilePath; + + std::shared_ptr fastFile = FastFileFactory::Create(fastFilePath); + + const QString game = fastFile->GetGame(); + bool correctGame = game == "COD6"; + if (!correctGame) { + recordResult(testName, false); + } + QVERIFY2(correctGame + , qPrintable("Factory parsed wrong game [" + game + "] for fastfile: " + fastFilePath)); + + const QString platform = fastFile->GetPlatform(); + bool correctPlatform = platform == "360"; + if (!correctPlatform) { + recordResult(testName, false); + } + QVERIFY2(correctPlatform + , qPrintable("Factory parsed wrong platform [" + platform + "] for fastfile: " + fastFilePath)); + + recordResult(testName, true); +} + void AutoTest_COD6_360::cleanupTestCase() { // Any cleanup if necessary. } diff --git a/tests/360/autotest_cod7_360.cpp b/tests/360/autotest_cod7_360.cpp index ebdd0dc..2b32e58 100644 --- a/tests/360/autotest_cod7_360.cpp +++ b/tests/360/autotest_cod7_360.cpp @@ -13,12 +13,16 @@ class AutoTest_COD7_360 : public AutoTest_COD { private slots: void initTestCase(); - // Data-driven test for decompression + void testDecompression_data(); void testDecompression(); - // Data-driven test for recompression (compression) + void testCompression_data(); void testCompression(); + + void testFactory_data(); + void testFactory(); + void cleanupTestCase(); }; @@ -28,24 +32,18 @@ void AutoTest_COD7_360::initTestCase() { } void AutoTest_COD7_360::testDecompression_data() { - QTest::addColumn("fastFilePath_cod7_360"); - - QStringList ffFiles = findFastFiles(getFastFileDirectory()); - for (const QString &filePath : ffFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testDecompression_data(); } void AutoTest_COD7_360::testDecompression() { - QFETCH(QString, fastFilePath_cod7_360); + QFETCH(QString, fastFilePath); - const QString testName = "Decompress: " + fastFilePath_cod7_360; + const QString testName = "Decompress: " + fastFilePath; // Open the original .ff file. - QFile testFastFile(fastFilePath_cod7_360); + QFile testFastFile(fastFilePath); QVERIFY2(testFastFile.open(QIODevice::ReadOnly), - qPrintable("Failed to open test fastfile: " + fastFilePath_cod7_360)); + qPrintable("Failed to open test fastfile: " + fastFilePath)); const QByteArray testFFData = testFastFile.readAll(); testFastFile.close(); @@ -120,10 +118,10 @@ void AutoTest_COD7_360::testDecompression() { qDebug() << "Difference: " << abs(zoneSize - testZoneData.size()); } QVERIFY2(zoneSize + 36 == testZoneData.size(), - qPrintable("Decompression validation failed for: " + fastFilePath_cod7_360)); + qPrintable("Decompression validation failed for: " + fastFilePath)); // Write the decompressed zone data to the exports folder with a .zone extension. - QFileInfo fi(fastFilePath_cod7_360); + QFileInfo fi(fastFilePath); QString outputFileName = fi.completeBaseName() + ".zone"; QString outputFilePath = QDir(EXPORT_DIR).filePath(outputFileName); QFile outputFile(outputFilePath); @@ -134,51 +132,115 @@ void AutoTest_COD7_360::testDecompression() { } void AutoTest_COD7_360::testCompression_data() { - QTest::addColumn("zoneFilePath_cod7_360"); - - QStringList zoneFiles = findZoneFiles(getZoneFileDirectory()); - for (const QString &filePath : zoneFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testCompression_data(); } void AutoTest_COD7_360::testCompression() { - QFETCH(QString, zoneFilePath_cod7_360); + QFETCH(QString, zoneFilePath); - QFile zoneFile(zoneFilePath_cod7_360); - QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath_cod7_360)); - QByteArray decompressedData = zoneFile.readAll(); + const QString testName = "Compress: " + zoneFilePath; + + // Open the original .zone file (decompressed zone data). + QFile zoneFile(zoneFilePath); + QVERIFY2(zoneFile.open(QIODevice::ReadOnly), + qPrintable("Failed to open zone file: " + zoneFilePath)); + const QByteArray zoneData = zoneFile.readAll(); zoneFile.close(); - QFileInfo fi(zoneFilePath_cod7_360); - QString originalFFPath = QDir(getFastFileDirectory()).filePath(fi.completeBaseName() + ".ff"); + QByteArray compressedData; + QByteArray key = QByteArray::fromHex("1ac1d12d527c59b40eca619120ff8217ccff09cd16896f81b829c7f52793405d"); - QFile originalFile(originalFFPath); - QVERIFY2(originalFile.open(QIODevice::ReadOnly), qPrintable("Failed to open original .ff file: " + originalFFPath)); - QByteArray originalFFData = originalFile.readAll(); - originalFile.close(); + // Read the original fastfile header to recover metadata (filename, IV table, etc.) + QString ffPath = zoneFilePath; + ffPath.replace(".zone", ".ff"); + QFile originalFF(ffPath); + QVERIFY2(originalFF.open(QIODevice::ReadOnly), + qPrintable("Failed to open original fastfile: " + ffPath)); + QByteArray header = originalFF.read(0x13C); // Everything up to section data + originalFF.seek(24); // IV Table starts at 24 (after magic + skip + filename) + QByteArray fileName(32, Qt::Uninitialized); + originalFF.read(fileName.data(), 32); + originalFF.close(); - QByteArray header = originalFFData.left(12); + QByteArray ivTable = Encryption::InitIVTable(fileName); - QByteArray newCompressedData;// = Compressor::CompressZLIB(decompressedData, Z_BEST_COMPRESSION); - newCompressedData = Compression::CompressZLIBWithSettings(decompressedData, Z_BEST_COMPRESSION, MAX_WBITS, 8, Z_DEFAULT_STRATEGY, {}); + // Rebuild sections from zone data + QDataStream zoneStream(zoneData); + zoneStream.setByteOrder(QDataStream::BigEndian); + quint32 zoneSize; + zoneStream >> zoneSize; - int remainder = (newCompressedData.size() + 12) % 32; - if (remainder != 0) { - int paddingNeeded = 32 - remainder; - newCompressedData.append(QByteArray(paddingNeeded, '\0')); + QByteArray remainingData = zoneData.mid(4); // exclude size field + const int chunkSize = 0x40000; // 256KB max section size + + QDataStream fastFileStreamOut(&compressedData, QIODevice::WriteOnly); + fastFileStreamOut.setByteOrder(QDataStream::BigEndian); + + int sectionIndex = 0; + int offset = 0; + while (offset < remainingData.size()) { + int sectionLen = qMin(chunkSize, remainingData.size() - offset); + QByteArray chunk = remainingData.mid(offset, sectionLen); + + QByteArray deflated = Compression::CompressDeflate(chunk); + + QByteArray iv = Encryption::GetIV(ivTable, sectionIndex); + QByteArray encrypted = Encryption::salsa20DecryptSection(deflated, key, iv); + QByteArray sha1 = QCryptographicHash::hash(chunk, QCryptographicHash::Sha1); + Encryption::UpdateIVTable(ivTable, sectionIndex, sha1); + + fastFileStreamOut << static_cast(encrypted.size()); + fastFileStreamOut.writeRawData(encrypted.constData(), encrypted.size()); + + offset += sectionLen; + sectionIndex++; } - QByteArray recompressedData = header + newCompressedData; + // Write 0 section size terminator + fastFileStreamOut << static_cast(0); - QString recompressedFilePath = QDir(EXPORT_DIR).filePath(fi.completeBaseName() + ".ff"); - QFile recompressedFile(recompressedFilePath); - QVERIFY2(recompressedFile.open(QIODevice::WriteOnly), qPrintable("Failed to write recompressed file.")); - recompressedFile.write(recompressedData); - recompressedFile.close(); + // Combine with header + QByteArray fullFastFile = header + compressedData; - QCOMPARE(recompressedData, originalFFData); + // Save re-encoded fastfile + QFileInfo fi(zoneFilePath); + QString outputFileName = fi.completeBaseName() + "_recompressed.ff"; + QString outputFilePath = QDir(EXPORT_DIR).filePath(outputFileName); + QFile outputFile(outputFilePath); + QVERIFY2(outputFile.open(QIODevice::WriteOnly), + qPrintable("Failed to open output file for writing: " + outputFilePath)); + outputFile.write(fullFastFile); + outputFile.close(); +} + +void AutoTest_COD7_360::testFactory_data() { + AutoTest_COD::testFactory_data(); +} + +void AutoTest_COD7_360::testFactory() { + QFETCH(QString, fastFilePath); + + const QString testName = "Factory ingest: " + fastFilePath; + + std::shared_ptr fastFile = FastFileFactory::Create(fastFilePath); + + const QString game = fastFile->GetGame(); + bool correctGame = game == "COD7"; + if (!correctGame) { + recordResult(testName, false); + } + QVERIFY2(correctGame + , qPrintable("Factory parsed wrong game [" + game + "] for fastfile: " + fastFilePath)); + + const QString platform = fastFile->GetPlatform(); + bool correctPlatform = platform == "360"; + if (!correctPlatform) { + recordResult(testName, false); + } + QVERIFY2(correctPlatform + , qPrintable("Factory parsed wrong platform [" + platform + "] for fastfile: " + fastFilePath)); + + recordResult(testName, true); } void AutoTest_COD7_360::cleanupTestCase() { diff --git a/tests/360/autotest_cod8_360.cpp b/tests/360/autotest_cod8_360.cpp index 954d95d..18bc90b 100644 --- a/tests/360/autotest_cod8_360.cpp +++ b/tests/360/autotest_cod8_360.cpp @@ -12,12 +12,16 @@ class AutoTest_COD8_360 : public AutoTest_COD { private slots: void initTestCase(); - // Data-driven test for decompression + void testDecompression_data(); void testDecompression(); - // Data-driven test for recompression (compression) + void testCompression_data(); void testCompression(); + + void testFactory_data(); + void testFactory(); + void cleanupTestCase(); }; @@ -27,32 +31,21 @@ void AutoTest_COD8_360::initTestCase() { } void AutoTest_COD8_360::testDecompression_data() { - QTest::addColumn("fastFilePath_cod8_360"); - - QStringList ffFiles = findFastFiles(getFastFileDirectory()); - for (const QString &filePath : ffFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - break; - } + AutoTest_COD::testDecompression_data(); } void AutoTest_COD8_360::testDecompression() { - QFETCH(QString, fastFilePath_cod8_360); + QFETCH(QString, fastFilePath); - const QString testName = "Decompress: " + fastFilePath_cod8_360; + const QString testName = "Decompress: " + fastFilePath; // Open the original .ff file. - QFile testFastFile(fastFilePath_cod8_360); + QFile testFastFile(fastFilePath); QVERIFY2(testFastFile.open(QIODevice::ReadOnly), - qPrintable("Failed to open test fastfile: " + fastFilePath_cod8_360)); + qPrintable("Failed to open test fastfile: " + fastFilePath)); const QByteArray testFFData = testFastFile.readAll(); testFastFile.close(); - //const QByteArray testData = Compression::CompressXMem("Hello World!"); - //const QByteArray testOutData = Compression::DecompressXMem(testData); - //qDebug() << "Input: Hello World! - Output: " << testData.toHex() << " - New: " << testOutData; - QByteArray pattern; pattern.append(static_cast(0xFF)); @@ -82,10 +75,10 @@ void AutoTest_COD8_360::testDecompression() { qDebug() << "Difference: " << abs(zoneSize - testZoneData.size()); } //QVERIFY2(zoneSize + 44 == testZoneData.size(), - // qPrintable("Decompression validation failed for: " + fastFilePath_cod8_360)); + // qPrintable("Decompression validation failed for: " + fastFilePath)); // Write the decompressed zone data to the exports folder with a .zone extension. - QFileInfo fi(fastFilePath_cod8_360); + QFileInfo fi(fastFilePath); QString outputFileName = fi.completeBaseName() + ".zone"; QString outputFilePath = QDir(EXPORT_DIR).filePath(outputFileName); QFile outputFile(outputFilePath); @@ -96,25 +89,18 @@ void AutoTest_COD8_360::testDecompression() { } void AutoTest_COD8_360::testCompression_data() { - QTest::addColumn("zoneFilePath_cod8_360"); - - QStringList zoneFiles = findZoneFiles(getZoneFileDirectory()); - for (const QString &filePath : zoneFiles) { - break; - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testCompression_data(); } void AutoTest_COD8_360::testCompression() { - QFETCH(QString, zoneFilePath_cod8_360); + QFETCH(QString, zoneFilePath); - QFile zoneFile(zoneFilePath_cod8_360); - QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath_cod8_360)); + QFile zoneFile(zoneFilePath); + QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath)); QByteArray decompressedData = zoneFile.readAll(); zoneFile.close(); - QFileInfo fi(zoneFilePath_cod8_360); + QFileInfo fi(zoneFilePath); QString originalFFPath = QDir(getFastFileDirectory()).filePath(fi.completeBaseName() + ".ff"); QFile originalFile(originalFFPath); @@ -144,6 +130,36 @@ void AutoTest_COD8_360::testCompression() { QCOMPARE(recompressedData, originalFFData); } +void AutoTest_COD8_360::testFactory_data() { + AutoTest_COD::testFactory_data(); +} + +void AutoTest_COD8_360::testFactory() { + QFETCH(QString, fastFilePath); + + const QString testName = "Factory ingest: " + fastFilePath; + + std::shared_ptr fastFile = FastFileFactory::Create(fastFilePath); + + const QString game = fastFile->GetGame(); + bool correctGame = game == "COD8"; + if (!correctGame) { + recordResult(testName, false); + } + QVERIFY2(correctGame + , qPrintable("Factory parsed wrong game [" + game + "] for fastfile: " + fastFilePath)); + + const QString platform = fastFile->GetPlatform(); + bool correctPlatform = platform == "360"; + if (!correctPlatform) { + recordResult(testName, false); + } + QVERIFY2(correctPlatform + , qPrintable("Factory parsed wrong platform [" + platform + "] for fastfile: " + fastFilePath)); + + recordResult(testName, true); +} + void AutoTest_COD8_360::cleanupTestCase() { // Any cleanup if necessary. } diff --git a/tests/360/autotest_cod9_360.cpp b/tests/360/autotest_cod9_360.cpp index 6807fa0..6df0cbc 100644 --- a/tests/360/autotest_cod9_360.cpp +++ b/tests/360/autotest_cod9_360.cpp @@ -12,12 +12,16 @@ class AutoTest_COD9_360 : public AutoTest_COD { private slots: void initTestCase(); - // Data-driven test for decompression + void testDecompression_data(); void testDecompression(); - // Data-driven test for recompression (compression) + void testCompression_data(); void testCompression(); + + void testFactory_data(); + void testFactory(); + void cleanupTestCase(); }; @@ -27,24 +31,18 @@ void AutoTest_COD9_360::initTestCase() { } void AutoTest_COD9_360::testDecompression_data() { - QTest::addColumn("fastFilePath_cod9_360"); - - QStringList ffFiles = findFastFiles(getFastFileDirectory()); - for (const QString &filePath : ffFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testDecompression_data(); } void AutoTest_COD9_360::testDecompression() { - QFETCH(QString, fastFilePath_cod9_360); + QFETCH(QString, fastFilePath); - const QString testName = "Decompress: " + fastFilePath_cod9_360; + const QString testName = "Decompress: " + fastFilePath; // Open the original .ff file. - QFile testFastFile(fastFilePath_cod9_360); + QFile testFastFile(fastFilePath); QVERIFY2(testFastFile.open(QIODevice::ReadOnly), - qPrintable("Failed to open test fastfile: " + fastFilePath_cod9_360)); + qPrintable("Failed to open test fastfile: " + fastFilePath)); const QByteArray testFFData = testFastFile.readAll(); testFastFile.close(); @@ -58,10 +56,10 @@ void AutoTest_COD9_360::testDecompression() { quint32 zoneSize; zoneStream >> zoneSize; QVERIFY2(zoneSize + 44 == testZoneData.size(), - qPrintable("Decompression validation failed for: " + fastFilePath_cod9_360)); + qPrintable("Decompression validation failed for: " + fastFilePath)); // Write the decompressed zone data to the exports folder with a .zone extension. - QFileInfo fi(fastFilePath_cod9_360); + QFileInfo fi(fastFilePath); QString outputFileName = fi.completeBaseName() + ".zone"; QString outputFilePath = QDir(EXPORT_DIR).filePath(outputFileName); QFile outputFile(outputFilePath); @@ -72,24 +70,18 @@ void AutoTest_COD9_360::testDecompression() { } void AutoTest_COD9_360::testCompression_data() { - QTest::addColumn("zoneFilePath_cod9_360"); - - QStringList zoneFiles = findZoneFiles(getZoneFileDirectory()); - for (const QString &filePath : zoneFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testCompression_data(); } void AutoTest_COD9_360::testCompression() { - QFETCH(QString, zoneFilePath_cod9_360); + QFETCH(QString, zoneFilePath); - QFile zoneFile(zoneFilePath_cod9_360); - QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath_cod9_360)); + QFile zoneFile(zoneFilePath); + QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath)); QByteArray decompressedData = zoneFile.readAll(); zoneFile.close(); - QFileInfo fi(zoneFilePath_cod9_360); + QFileInfo fi(zoneFilePath); QString originalFFPath = QDir(getFastFileDirectory()).filePath(fi.completeBaseName() + ".ff"); QFile originalFile(originalFFPath); @@ -119,6 +111,36 @@ void AutoTest_COD9_360::testCompression() { QCOMPARE(recompressedData, originalFFData); } +void AutoTest_COD9_360::testFactory_data() { + AutoTest_COD::testFactory_data(); +} + +void AutoTest_COD9_360::testFactory() { + QFETCH(QString, fastFilePath); + + const QString testName = "Factory ingest: " + fastFilePath; + + std::shared_ptr fastFile = FastFileFactory::Create(fastFilePath); + + const QString game = fastFile->GetGame(); + bool correctGame = game == "COD9"; + if (!correctGame) { + recordResult(testName, false); + } + QVERIFY2(correctGame + , qPrintable("Factory parsed wrong game [" + game + "] for fastfile: " + fastFilePath)); + + const QString platform = fastFile->GetPlatform(); + bool correctPlatform = platform == "360"; + if (!correctPlatform) { + recordResult(testName, false); + } + QVERIFY2(correctPlatform + , qPrintable("Factory parsed wrong platform [" + platform + "] for fastfile: " + fastFilePath)); + + recordResult(testName, true); +} + void AutoTest_COD9_360::cleanupTestCase() { // Any cleanup if necessary. } diff --git a/tests/PC/autotest_cod10_pc.cpp b/tests/PC/autotest_cod10_pc.cpp index ad2a304..ab58eef 100644 --- a/tests/PC/autotest_cod10_pc.cpp +++ b/tests/PC/autotest_cod10_pc.cpp @@ -12,12 +12,16 @@ class AutoTest_COD10_PC : public AutoTest_COD { private slots: void initTestCase(); - // Data-driven test for decompression + void testDecompression_data(); void testDecompression(); - // Data-driven test for recompression (compression) + void testCompression_data(); void testCompression(); + + void testFactory_data(); + void testFactory(); + void cleanupTestCase(); }; @@ -27,23 +31,16 @@ void AutoTest_COD10_PC::initTestCase() { } void AutoTest_COD10_PC::testDecompression_data() { - QTest::addColumn("fastFilePath_cod10_pc"); - - QStringList ffFiles = findFastFiles(getFastFileDirectory()); - for (const QString &filePath : ffFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testDecompression_data(); } - void AutoTest_COD10_PC::testDecompression() { - QFETCH(QString, fastFilePath_cod10_pc); + QFETCH(QString, fastFilePath); // Open the original .ff file. - QFile testFastFile(fastFilePath_cod10_pc); + QFile testFastFile(fastFilePath); QVERIFY2(testFastFile.open(QIODevice::ReadOnly), - qPrintable("Failed to open test fastfile: " + fastFilePath_cod10_pc)); + qPrintable("Failed to open test fastfile: " + fastFilePath)); const QByteArray testFFData = testFastFile.readAll(); testFastFile.close(); @@ -57,10 +54,10 @@ void AutoTest_COD10_PC::testDecompression() { quint32 zoneSize; zoneStream >> zoneSize; QVERIFY2(zoneSize + 36 == testZoneData.size(), - qPrintable("Decompression validation failed for: " + fastFilePath_cod10_pc)); + qPrintable("Decompression validation failed for: " + fastFilePath)); // Write the decompressed zone data to the exports folder with a .zone extension. - QFileInfo fi(fastFilePath_cod10_pc); + QFileInfo fi(fastFilePath); QString outputFileName = fi.completeBaseName() + ".zone"; QString outputFilePath = QDir(EXPORT_DIR).filePath(outputFileName); QFile outputFile(outputFilePath); @@ -71,24 +68,18 @@ void AutoTest_COD10_PC::testDecompression() { } void AutoTest_COD10_PC::testCompression_data() { - QTest::addColumn("zoneFilePath_cod10_pc"); - - QStringList zoneFiles = findZoneFiles(getZoneFileDirectory()); - for (const QString &filePath : zoneFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testCompression_data(); } void AutoTest_COD10_PC::testCompression() { - QFETCH(QString, zoneFilePath_cod10_pc); + QFETCH(QString, zoneFilePath); - QFile zoneFile(zoneFilePath_cod10_pc); - QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath_cod10_pc)); + QFile zoneFile(zoneFilePath); + QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath)); QByteArray decompressedData = zoneFile.readAll(); zoneFile.close(); - QFileInfo fi(zoneFilePath_cod10_pc); + QFileInfo fi(zoneFilePath); QString originalFFPath = QDir(getFastFileDirectory()).filePath(fi.completeBaseName() + ".ff"); QFile originalFile(originalFFPath); @@ -116,6 +107,36 @@ void AutoTest_COD10_PC::testCompression() { QCOMPARE(recompressedData, originalFFData); } +void AutoTest_COD10_PC::testFactory_data() { + AutoTest_COD::testFactory_data(); +} + +void AutoTest_COD10_PC::testFactory() { + QFETCH(QString, fastFilePath); + + const QString testName = "Factory ingest: " + fastFilePath; + + std::shared_ptr fastFile = FastFileFactory::Create(fastFilePath); + + const QString game = fastFile->GetGame(); + bool correctGame = game == "COD10"; + if (!correctGame) { + recordResult(testName, false); + } + QVERIFY2(correctGame + , qPrintable("Factory parsed wrong game [" + game + "] for fastfile: " + fastFilePath)); + + const QString platform = fastFile->GetPlatform(); + bool correctPlatform = platform == "PC"; + if (!correctPlatform) { + recordResult(testName, false); + } + QVERIFY2(correctPlatform + , qPrintable("Factory parsed wrong platform [" + platform + "] for fastfile: " + fastFilePath)); + + recordResult(testName, true); +} + void AutoTest_COD10_PC::cleanupTestCase() { // Any cleanup if necessary. } diff --git a/tests/PC/autotest_cod11_pc.cpp b/tests/PC/autotest_cod11_pc.cpp index 999a038..9874b66 100644 --- a/tests/PC/autotest_cod11_pc.cpp +++ b/tests/PC/autotest_cod11_pc.cpp @@ -12,12 +12,16 @@ class AutoTest_COD11_PC : public AutoTest_COD { private slots: void initTestCase(); - // Data-driven test for decompression + void testDecompression_data(); void testDecompression(); - // Data-driven test for recompression (compression) + void testCompression_data(); void testCompression(); + + void testFactory_data(); + void testFactory(); + void cleanupTestCase(); }; @@ -27,23 +31,16 @@ void AutoTest_COD11_PC::initTestCase() { } void AutoTest_COD11_PC::testDecompression_data() { - QTest::addColumn("fastFilePath_cod11_pc"); - - QStringList ffFiles = findFastFiles(getFastFileDirectory()); - for (const QString &filePath : ffFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testDecompression_data(); } - void AutoTest_COD11_PC::testDecompression() { - QFETCH(QString, fastFilePath_cod11_pc); + QFETCH(QString, fastFilePath); // Open the original .ff file. - QFile testFastFile(fastFilePath_cod11_pc); + QFile testFastFile(fastFilePath); QVERIFY2(testFastFile.open(QIODevice::ReadOnly), - qPrintable("Failed to open test fastfile: " + fastFilePath_cod11_pc)); + qPrintable("Failed to open test fastfile: " + fastFilePath)); const QByteArray testFFData = testFastFile.readAll(); testFastFile.close(); @@ -57,10 +54,10 @@ void AutoTest_COD11_PC::testDecompression() { quint32 zoneSize; zoneStream >> zoneSize; QVERIFY2(zoneSize + 36 == testZoneData.size(), - qPrintable("Decompression validation failed for: " + fastFilePath_cod11_pc)); + qPrintable("Decompression validation failed for: " + fastFilePath)); // Write the decompressed zone data to the exports folder with a .zone extension. - QFileInfo fi(fastFilePath_cod11_pc); + QFileInfo fi(fastFilePath); QString outputFileName = fi.completeBaseName() + ".zone"; QString outputFilePath = QDir(EXPORT_DIR).filePath(outputFileName); QFile outputFile(outputFilePath); @@ -71,24 +68,18 @@ void AutoTest_COD11_PC::testDecompression() { } void AutoTest_COD11_PC::testCompression_data() { - QTest::addColumn("zoneFilePath_cod11_pc"); - - QStringList zoneFiles = findZoneFiles(getZoneFileDirectory()); - for (const QString &filePath : zoneFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testCompression_data(); } void AutoTest_COD11_PC::testCompression() { - QFETCH(QString, zoneFilePath_cod11_pc); + QFETCH(QString, zoneFilePath); - QFile zoneFile(zoneFilePath_cod11_pc); - QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath_cod11_pc)); + QFile zoneFile(zoneFilePath); + QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath)); QByteArray decompressedData = zoneFile.readAll(); zoneFile.close(); - QFileInfo fi(zoneFilePath_cod11_pc); + QFileInfo fi(zoneFilePath); QString originalFFPath = QDir(getFastFileDirectory()).filePath(fi.completeBaseName() + ".ff"); QFile originalFile(originalFFPath); @@ -116,6 +107,36 @@ void AutoTest_COD11_PC::testCompression() { QCOMPARE(recompressedData, originalFFData); } +void AutoTest_COD11_PC::testFactory_data() { + AutoTest_COD::testFactory_data(); +} + +void AutoTest_COD11_PC::testFactory() { + QFETCH(QString, fastFilePath); + + const QString testName = "Factory ingest: " + fastFilePath; + + std::shared_ptr fastFile = FastFileFactory::Create(fastFilePath); + + const QString game = fastFile->GetGame(); + bool correctGame = game == "COD11"; + if (!correctGame) { + recordResult(testName, false); + } + QVERIFY2(correctGame + , qPrintable("Factory parsed wrong game [" + game + "] for fastfile: " + fastFilePath)); + + const QString platform = fastFile->GetPlatform(); + bool correctPlatform = platform == "PC"; + if (!correctPlatform) { + recordResult(testName, false); + } + QVERIFY2(correctPlatform + , qPrintable("Factory parsed wrong platform [" + platform + "] for fastfile: " + fastFilePath)); + + recordResult(testName, true); +} + void AutoTest_COD11_PC::cleanupTestCase() { // Any cleanup if necessary. } diff --git a/tests/PC/autotest_cod12_pc.cpp b/tests/PC/autotest_cod12_pc.cpp index ef8b276..f0677df 100644 --- a/tests/PC/autotest_cod12_pc.cpp +++ b/tests/PC/autotest_cod12_pc.cpp @@ -12,12 +12,16 @@ class AutoTest_COD12_PC : public AutoTest_COD { private slots: void initTestCase(); - // Data-driven test for decompression + void testDecompression_data(); void testDecompression(); - // Data-driven test for recompression (compression) + void testCompression_data(); void testCompression(); + + void testFactory_data(); + void testFactory(); + void cleanupTestCase(); }; @@ -27,23 +31,16 @@ void AutoTest_COD12_PC::initTestCase() { } void AutoTest_COD12_PC::testDecompression_data() { - QTest::addColumn("fastFilePath_cod12_pc"); - - QStringList ffFiles = findFastFiles(getFastFileDirectory()); - for (const QString &filePath : ffFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testDecompression_data(); } - void AutoTest_COD12_PC::testDecompression() { - QFETCH(QString, fastFilePath_cod12_pc); + QFETCH(QString, fastFilePath); // Open the original .ff file. - QFile testFastFile(fastFilePath_cod12_pc); + QFile testFastFile(fastFilePath); QVERIFY2(testFastFile.open(QIODevice::ReadOnly), - qPrintable("Failed to open test fastfile: " + fastFilePath_cod12_pc)); + qPrintable("Failed to open test fastfile: " + fastFilePath)); const QByteArray testFFData = testFastFile.readAll(); testFastFile.close(); @@ -57,10 +54,10 @@ void AutoTest_COD12_PC::testDecompression() { quint32 zoneSize; zoneStream >> zoneSize; QVERIFY2(zoneSize + 36 == testZoneData.size(), - qPrintable("Decompression validation failed for: " + fastFilePath_cod12_pc)); + qPrintable("Decompression validation failed for: " + fastFilePath)); // Write the decompressed zone data to the exports folder with a .zone extension. - QFileInfo fi(fastFilePath_cod12_pc); + QFileInfo fi(fastFilePath); QString outputFileName = fi.completeBaseName() + ".zone"; QString outputFilePath = QDir(EXPORT_DIR).filePath(outputFileName); QFile outputFile(outputFilePath); @@ -71,24 +68,18 @@ void AutoTest_COD12_PC::testDecompression() { } void AutoTest_COD12_PC::testCompression_data() { - QTest::addColumn("zoneFilePath_cod12_pc"); - - QStringList zoneFiles = findZoneFiles(getZoneFileDirectory()); - for (const QString &filePath : zoneFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testCompression_data(); } void AutoTest_COD12_PC::testCompression() { - QFETCH(QString, zoneFilePath_cod12_pc); + QFETCH(QString, zoneFilePath); - QFile zoneFile(zoneFilePath_cod12_pc); - QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath_cod12_pc)); + QFile zoneFile(zoneFilePath); + QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath)); QByteArray decompressedData = zoneFile.readAll(); zoneFile.close(); - QFileInfo fi(zoneFilePath_cod12_pc); + QFileInfo fi(zoneFilePath); QString originalFFPath = QDir(getFastFileDirectory()).filePath(fi.completeBaseName() + ".ff"); QFile originalFile(originalFFPath); @@ -116,6 +107,36 @@ void AutoTest_COD12_PC::testCompression() { QCOMPARE(recompressedData, originalFFData); } +void AutoTest_COD12_PC::testFactory_data() { + AutoTest_COD::testFactory_data(); +} + +void AutoTest_COD12_PC::testFactory() { + QFETCH(QString, fastFilePath); + + const QString testName = "Factory ingest: " + fastFilePath; + + std::shared_ptr fastFile = FastFileFactory::Create(fastFilePath); + + const QString game = fastFile->GetGame(); + bool correctGame = game == "COD12"; + if (!correctGame) { + recordResult(testName, false); + } + QVERIFY2(correctGame + , qPrintable("Factory parsed wrong game [" + game + "] for fastfile: " + fastFilePath)); + + const QString platform = fastFile->GetPlatform(); + bool correctPlatform = platform == "PC"; + if (!correctPlatform) { + recordResult(testName, false); + } + QVERIFY2(correctPlatform + , qPrintable("Factory parsed wrong platform [" + platform + "] for fastfile: " + fastFilePath)); + + recordResult(testName, true); +} + void AutoTest_COD12_PC::cleanupTestCase() { // Any cleanup if necessary. } diff --git a/tests/PC/autotest_cod4_pc.cpp b/tests/PC/autotest_cod4_pc.cpp index b89ae4f..ab3cc1f 100644 --- a/tests/PC/autotest_cod4_pc.cpp +++ b/tests/PC/autotest_cod4_pc.cpp @@ -13,12 +13,16 @@ class AutoTest_COD4_PC : public AutoTest_COD { private slots: void initTestCase(); - // Data-driven test for decompression + void testDecompression_data(); void testDecompression(); - // Data-driven test for recompression (compression) + void testCompression_data(); void testCompression(); + + void testFactory_data(); + void testFactory(); + void cleanupTestCase(); }; @@ -28,22 +32,16 @@ void AutoTest_COD4_PC::initTestCase() { } void AutoTest_COD4_PC::testDecompression_data() { - QTest::addColumn("fastFilePath_cod4_pc"); - - QStringList fastFiles = findFastFiles(getFastFileDirectory()); - for (const QString &filePath : fastFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testDecompression_data(); } void AutoTest_COD4_PC::testDecompression() { - QFETCH(QString, fastFilePath_cod4_pc); + QFETCH(QString, fastFilePath); // Open the original .ff file. - QFile testFastFile(fastFilePath_cod4_pc); + QFile testFastFile(fastFilePath); QVERIFY2(testFastFile.open(QIODevice::ReadOnly), - qPrintable("Failed to open test fastfile: " + fastFilePath_cod4_pc)); + qPrintable("Failed to open test fastfile: " + fastFilePath)); const QByteArray testFFData = testFastFile.readAll(); testFastFile.close(); @@ -57,10 +55,10 @@ void AutoTest_COD4_PC::testDecompression() { quint32 zoneSize; zoneStream >> zoneSize; QVERIFY2(zoneSize + 44 == testZoneData.size(), - qPrintable("Decompression validation failed for: " + fastFilePath_cod4_pc)); + qPrintable("Decompression validation failed for: " + fastFilePath)); // Write the decompressed zone data to the exports folder with a .zone extension. - QFileInfo fi(fastFilePath_cod4_pc); + QFileInfo fi(fastFilePath); QString outputFileName = fi.completeBaseName() + ".zone"; QString outputFilePath = QDir(EXPORT_DIR).filePath(outputFileName); QFile outputFile(outputFilePath); @@ -71,24 +69,18 @@ void AutoTest_COD4_PC::testDecompression() { } void AutoTest_COD4_PC::testCompression_data() { - QTest::addColumn("zoneFilePath_cod4_pc"); - - QStringList zoneFiles = findZoneFiles(getZoneFileDirectory()); - for (const QString &filePath : zoneFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testCompression_data(); } void AutoTest_COD4_PC::testCompression() { - QFETCH(QString, zoneFilePath_cod4_pc); + QFETCH(QString, zoneFilePath); - QFile zoneFile(zoneFilePath_cod4_pc); - QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath_cod4_pc)); + QFile zoneFile(zoneFilePath); + QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath)); QByteArray decompressedData = zoneFile.readAll(); zoneFile.close(); - QFileInfo fi(zoneFilePath_cod4_pc); + QFileInfo fi(zoneFilePath); QString originalFFPath = QDir(getFastFileDirectory()).filePath(fi.completeBaseName() + ".ff"); QFile originalFile(originalFFPath); @@ -112,6 +104,36 @@ void AutoTest_COD4_PC::testCompression() { QCOMPARE(recompressedData, originalFFData); } +void AutoTest_COD4_PC::testFactory_data() { + AutoTest_COD::testFactory_data(); +} + +void AutoTest_COD4_PC::testFactory() { + QFETCH(QString, fastFilePath); + + const QString testName = "Factory ingest: " + fastFilePath; + + std::shared_ptr fastFile = FastFileFactory::Create(fastFilePath); + + const QString game = fastFile->GetGame(); + bool correctGame = game == "COD4"; + if (!correctGame) { + recordResult(testName, false); + } + QVERIFY2(correctGame + , qPrintable("Factory parsed wrong game [" + game + "] for fastfile: " + fastFilePath)); + + const QString platform = fastFile->GetPlatform(); + bool correctPlatform = platform == "PC"; + if (!correctPlatform) { + recordResult(testName, false); + } + QVERIFY2(correctPlatform + , qPrintable("Factory parsed wrong platform [" + platform + "] for fastfile: " + fastFilePath)); + + recordResult(testName, true); +} + void AutoTest_COD4_PC::cleanupTestCase() { // Any cleanup if necessary. } diff --git a/tests/PC/autotest_cod5_pc.cpp b/tests/PC/autotest_cod5_pc.cpp index 4a1608e..6a8e3c4 100644 --- a/tests/PC/autotest_cod5_pc.cpp +++ b/tests/PC/autotest_cod5_pc.cpp @@ -12,12 +12,16 @@ class AutoTest_COD5_PC : public AutoTest_COD { private slots: void initTestCase(); - // Data-driven test for decompression + void testDecompression_data(); void testDecompression(); - // Data-driven test for recompression (compression) + void testCompression_data(); void testCompression(); + + void testFactory_data(); + void testFactory(); + void cleanupTestCase(); }; @@ -27,22 +31,16 @@ void AutoTest_COD5_PC::initTestCase() { } void AutoTest_COD5_PC::testDecompression_data() { - QTest::addColumn("fastFilePath_cod5_pc"); - - QStringList ffFiles = findFastFiles(getFastFileDirectory()); - for (const QString &filePath : ffFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testDecompression_data(); } void AutoTest_COD5_PC::testDecompression() { - QFETCH(QString, fastFilePath_cod5_pc); + QFETCH(QString, fastFilePath); // Open the original .ff file. - QFile testFastFile(fastFilePath_cod5_pc); + QFile testFastFile(fastFilePath); QVERIFY2(testFastFile.open(QIODevice::ReadOnly), - qPrintable("Failed to open test fastfile: " + fastFilePath_cod5_pc)); + qPrintable("Failed to open test fastfile: " + fastFilePath)); const QByteArray testFFData = testFastFile.readAll(); testFastFile.close(); @@ -56,10 +54,10 @@ void AutoTest_COD5_PC::testDecompression() { quint32 zoneSize; zoneStream >> zoneSize; QVERIFY2(zoneSize + 36 == testZoneData.size(), - qPrintable("Decompression validation failed for: " + fastFilePath_cod5_pc)); + qPrintable("Decompression validation failed for: " + fastFilePath)); // Write the decompressed zone data to the exports folder with a .zone extension. - QFileInfo fi(fastFilePath_cod5_pc); + QFileInfo fi(fastFilePath); QString outputFileName = fi.completeBaseName() + ".zone"; QString outputFilePath = QDir(EXPORT_DIR).filePath(outputFileName); QFile outputFile(outputFilePath); @@ -70,24 +68,18 @@ void AutoTest_COD5_PC::testDecompression() { } void AutoTest_COD5_PC::testCompression_data() { - QTest::addColumn("zoneFilePath_cod5_pc"); - - QStringList zoneFiles = findZoneFiles(getZoneFileDirectory()); - for (const QString &filePath : zoneFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testCompression_data(); } void AutoTest_COD5_PC::testCompression() { - QFETCH(QString, zoneFilePath_cod5_pc); + QFETCH(QString, zoneFilePath); - QFile zoneFile(zoneFilePath_cod5_pc); - QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath_cod5_pc)); + QFile zoneFile(zoneFilePath); + QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath)); QByteArray decompressedData = zoneFile.readAll(); zoneFile.close(); - QFileInfo fi(zoneFilePath_cod5_pc); + QFileInfo fi(zoneFilePath); QString originalFFPath = QDir(getFastFileDirectory()).filePath(fi.completeBaseName() + ".ff"); QFile originalFile(originalFFPath); @@ -116,6 +108,36 @@ void AutoTest_COD5_PC::testCompression() { QCOMPARE(recompressedData, originalFFData); } +void AutoTest_COD5_PC::testFactory_data() { + AutoTest_COD::testFactory_data(); +} + +void AutoTest_COD5_PC::testFactory() { + QFETCH(QString, fastFilePath); + + const QString testName = "Factory ingest: " + fastFilePath; + + std::shared_ptr fastFile = FastFileFactory::Create(fastFilePath, true); + + const QString game = fastFile->GetGame(); + bool correctGame = game == "COD5"; + if (!correctGame) { + recordResult(testName, false); + } + QVERIFY2(correctGame + , qPrintable("Factory parsed wrong game [" + game + "] for fastfile: " + fastFilePath)); + + const QString platform = fastFile->GetPlatform(); + bool correctPlatform = platform == "PC"; + if (!correctPlatform) { + recordResult(testName, false); + } + QVERIFY2(correctPlatform + , qPrintable("Factory parsed wrong platform [" + platform + "] for fastfile: " + fastFilePath)); + + recordResult(testName, true); +} + void AutoTest_COD5_PC::cleanupTestCase() { // Any cleanup if necessary. } diff --git a/tests/PC/autotest_cod6_pc.cpp b/tests/PC/autotest_cod6_pc.cpp index 33d0f48..4d0b75f 100644 --- a/tests/PC/autotest_cod6_pc.cpp +++ b/tests/PC/autotest_cod6_pc.cpp @@ -12,12 +12,16 @@ class AutoTest_COD6_PC : public AutoTest_COD { private slots: void initTestCase(); - // Data-driven test for decompression + void testDecompression_data(); void testDecompression(); - // Data-driven test for recompression (compression) + void testCompression_data(); void testCompression(); + + void testFactory_data(); + void testFactory(); + void cleanupTestCase(); }; @@ -27,22 +31,16 @@ void AutoTest_COD6_PC::initTestCase() { } void AutoTest_COD6_PC::testDecompression_data() { - QTest::addColumn("fastFilePath_cod6_pc"); - - QStringList ffFiles = findFastFiles(getFastFileDirectory()); - for (const QString &filePath : ffFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testDecompression_data(); } void AutoTest_COD6_PC::testDecompression() { - QFETCH(QString, fastFilePath_cod6_pc); + QFETCH(QString, fastFilePath); // Open the original .ff file. - QFile testFastFile(fastFilePath_cod6_pc); + QFile testFastFile(fastFilePath); QVERIFY2(testFastFile.open(QIODevice::ReadOnly), - qPrintable("Failed to open test fastfile: " + fastFilePath_cod6_pc)); + qPrintable("Failed to open test fastfile: " + fastFilePath)); const QByteArray testFFData = testFastFile.readAll(); testFastFile.close(); @@ -56,10 +54,10 @@ void AutoTest_COD6_PC::testDecompression() { quint32 zoneSize; zoneStream >> zoneSize; QVERIFY2(zoneSize + 40 == testZoneData.size(), - qPrintable("Decompression validation failed for: " + fastFilePath_cod6_pc)); + qPrintable("Decompression validation failed for: " + fastFilePath)); // Write the decompressed zone data to the exports folder with a .zone extension. - QFileInfo fi(fastFilePath_cod6_pc); + QFileInfo fi(fastFilePath); QString outputFileName = fi.completeBaseName() + ".zone"; QString outputFilePath = QDir(EXPORT_DIR).filePath(outputFileName); QFile outputFile(outputFilePath); @@ -70,24 +68,18 @@ void AutoTest_COD6_PC::testDecompression() { } void AutoTest_COD6_PC::testCompression_data() { - QTest::addColumn("zoneFilePath_cod6_pc"); - - QStringList zoneFiles = findZoneFiles(getZoneFileDirectory()); - for (const QString &filePath : zoneFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testCompression_data(); } void AutoTest_COD6_PC::testCompression() { - QFETCH(QString, zoneFilePath_cod6_pc); + QFETCH(QString, zoneFilePath); - QFile zoneFile(zoneFilePath_cod6_pc); - QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath_cod6_pc)); + QFile zoneFile(zoneFilePath); + QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath)); QByteArray decompressedData = zoneFile.readAll(); zoneFile.close(); - QFileInfo fi(zoneFilePath_cod6_pc); + QFileInfo fi(zoneFilePath); QString originalFFPath = QDir(getFastFileDirectory()).filePath(fi.completeBaseName() + ".ff"); QFile originalFile(originalFFPath); @@ -108,6 +100,36 @@ void AutoTest_COD6_PC::testCompression() { QCOMPARE(recompressedData, originalFFData); } +void AutoTest_COD6_PC::testFactory_data() { + AutoTest_COD::testFactory_data(); +} + +void AutoTest_COD6_PC::testFactory() { + QFETCH(QString, fastFilePath); + + const QString testName = "Factory ingest: " + fastFilePath; + + std::shared_ptr fastFile = FastFileFactory::Create(fastFilePath); + + const QString game = fastFile->GetGame(); + bool correctGame = game == "COD6"; + if (!correctGame) { + recordResult(testName, false); + } + QVERIFY2(correctGame + , qPrintable("Factory parsed wrong game [" + game + "] for fastfile: " + fastFilePath)); + + const QString platform = fastFile->GetPlatform(); + bool correctPlatform = platform == "PC"; + if (!correctPlatform) { + recordResult(testName, false); + } + QVERIFY2(correctPlatform + , qPrintable("Factory parsed wrong platform [" + platform + "] for fastfile: " + fastFilePath)); + + recordResult(testName, true); +} + void AutoTest_COD6_PC::cleanupTestCase() { // Any cleanup if necessary. } diff --git a/tests/PC/autotest_cod7_pc.cpp b/tests/PC/autotest_cod7_pc.cpp index 3d26478..465d053 100644 --- a/tests/PC/autotest_cod7_pc.cpp +++ b/tests/PC/autotest_cod7_pc.cpp @@ -12,12 +12,16 @@ class AutoTest_COD7_PC : public AutoTest_COD { private slots: void initTestCase(); - // Data-driven test for decompression + void testDecompression_data(); void testDecompression(); - // Data-driven test for recompression (compression) + void testCompression_data(); void testCompression(); + + void testFactory_data(); + void testFactory(); + void cleanupTestCase(); }; @@ -27,22 +31,16 @@ void AutoTest_COD7_PC::initTestCase() { } void AutoTest_COD7_PC::testDecompression_data() { - QTest::addColumn("fastFilePath_cod7_pc"); - - QStringList ffFiles = findFastFiles(getFastFileDirectory()); - for (const QString &filePath : ffFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testDecompression_data(); } void AutoTest_COD7_PC::testDecompression() { - QFETCH(QString, fastFilePath_cod7_pc); + QFETCH(QString, fastFilePath); // Open the original .ff file. - QFile testFastFile(fastFilePath_cod7_pc); + QFile testFastFile(fastFilePath); QVERIFY2(testFastFile.open(QIODevice::ReadOnly), - qPrintable("Failed to open test fastfile: " + fastFilePath_cod7_pc)); + qPrintable("Failed to open test fastfile: " + fastFilePath)); const QByteArray testFFData = testFastFile.readAll(); testFastFile.close(); @@ -56,10 +54,10 @@ void AutoTest_COD7_PC::testDecompression() { quint32 zoneSize; zoneStream >> zoneSize; QVERIFY2(zoneSize + 36 == testZoneData.size(), - qPrintable("Decompression validation failed for: " + fastFilePath_cod7_pc)); + qPrintable("Decompression validation failed for: " + fastFilePath)); // Write the decompressed zone data to the exports folder with a .zone extension. - QFileInfo fi(fastFilePath_cod7_pc); + QFileInfo fi(fastFilePath); QString outputFileName = fi.completeBaseName() + ".zone"; QString outputFilePath = QDir(EXPORT_DIR).filePath(outputFileName); QFile outputFile(outputFilePath); @@ -70,24 +68,18 @@ void AutoTest_COD7_PC::testDecompression() { } void AutoTest_COD7_PC::testCompression_data() { - QTest::addColumn("zoneFilePath_cod7_pc"); - - QStringList zoneFiles = findZoneFiles(getZoneFileDirectory()); - for (const QString &filePath : zoneFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testCompression_data(); } void AutoTest_COD7_PC::testCompression() { - QFETCH(QString, zoneFilePath_cod7_pc); + QFETCH(QString, zoneFilePath); - QFile zoneFile(zoneFilePath_cod7_pc); - QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath_cod7_pc)); + QFile zoneFile(zoneFilePath); + QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath)); QByteArray decompressedData = zoneFile.readAll(); zoneFile.close(); - QFileInfo fi(zoneFilePath_cod7_pc); + QFileInfo fi(zoneFilePath); QString originalFFPath = QDir(getFastFileDirectory()).filePath(fi.completeBaseName() + ".ff"); QFile originalFile(originalFFPath); @@ -115,6 +107,36 @@ void AutoTest_COD7_PC::testCompression() { QCOMPARE(recompressedData, originalFFData); } +void AutoTest_COD7_PC::testFactory_data() { + AutoTest_COD::testFactory_data(); +} + +void AutoTest_COD7_PC::testFactory() { + QFETCH(QString, fastFilePath); + + const QString testName = "Factory ingest: " + fastFilePath; + + std::shared_ptr fastFile = FastFileFactory::Create(fastFilePath); + + const QString game = fastFile->GetGame(); + bool correctGame = game == "COD7"; + if (!correctGame) { + recordResult(testName, false); + } + QVERIFY2(correctGame + , qPrintable("Factory parsed wrong game [" + game + "] for fastfile: " + fastFilePath)); + + const QString platform = fastFile->GetPlatform(); + bool correctPlatform = platform == "PC"; + if (!correctPlatform) { + recordResult(testName, false); + } + QVERIFY2(correctPlatform + , qPrintable("Factory parsed wrong platform [" + platform + "] for fastfile: " + fastFilePath)); + + recordResult(testName, true); +} + void AutoTest_COD7_PC::cleanupTestCase() { // Any cleanup if necessary. } diff --git a/tests/PC/autotest_cod8_pc.cpp b/tests/PC/autotest_cod8_pc.cpp index decf3b3..e4df99c 100644 --- a/tests/PC/autotest_cod8_pc.cpp +++ b/tests/PC/autotest_cod8_pc.cpp @@ -12,12 +12,16 @@ class AutoTest_COD8_PC : public AutoTest_COD { private slots: void initTestCase(); - // Data-driven test for decompression + void testDecompression_data(); void testDecompression(); - // Data-driven test for recompression (compression) + void testCompression_data(); void testCompression(); + + void testFactory_data(); + void testFactory(); + void cleanupTestCase(); }; @@ -27,23 +31,16 @@ void AutoTest_COD8_PC::initTestCase() { } void AutoTest_COD8_PC::testDecompression_data() { - QTest::addColumn("fastFilePath_cod8_pc"); - - QStringList ffFiles = findFastFiles(getFastFileDirectory()); - for (const QString &filePath : ffFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testDecompression_data(); } - void AutoTest_COD8_PC::testDecompression() { - QFETCH(QString, fastFilePath_cod8_pc); + QFETCH(QString, fastFilePath); // Open the original .ff file. - QFile testFastFile(fastFilePath_cod8_pc); + QFile testFastFile(fastFilePath); QVERIFY2(testFastFile.open(QIODevice::ReadOnly), - qPrintable("Failed to open test fastfile: " + fastFilePath_cod8_pc)); + qPrintable("Failed to open test fastfile: " + fastFilePath)); const QByteArray testFFData = testFastFile.readAll(); testFastFile.close(); @@ -57,10 +54,10 @@ void AutoTest_COD8_PC::testDecompression() { quint32 zoneSize; zoneStream >> zoneSize; QVERIFY2(zoneSize + 36 == testZoneData.size(), - qPrintable("Decompression validation failed for: " + fastFilePath_cod8_pc)); + qPrintable("Decompression validation failed for: " + fastFilePath)); // Write the decompressed zone data to the exports folder with a .zone extension. - QFileInfo fi(fastFilePath_cod8_pc); + QFileInfo fi(fastFilePath); QString outputFileName = fi.completeBaseName() + ".zone"; QString outputFilePath = QDir(EXPORT_DIR).filePath(outputFileName); QFile outputFile(outputFilePath); @@ -71,24 +68,18 @@ void AutoTest_COD8_PC::testDecompression() { } void AutoTest_COD8_PC::testCompression_data() { - QTest::addColumn("zoneFilePath_cod8_pc"); - - QStringList zoneFiles = findZoneFiles(getZoneFileDirectory()); - for (const QString &filePath : zoneFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testCompression_data(); } void AutoTest_COD8_PC::testCompression() { - QFETCH(QString, zoneFilePath_cod8_pc); + QFETCH(QString, zoneFilePath); - QFile zoneFile(zoneFilePath_cod8_pc); - QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath_cod8_pc)); + QFile zoneFile(zoneFilePath); + QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath)); QByteArray decompressedData = zoneFile.readAll(); zoneFile.close(); - QFileInfo fi(zoneFilePath_cod8_pc); + QFileInfo fi(zoneFilePath); QString originalFFPath = QDir(getFastFileDirectory()).filePath(fi.completeBaseName() + ".ff"); QFile originalFile(originalFFPath); @@ -116,6 +107,36 @@ void AutoTest_COD8_PC::testCompression() { QCOMPARE(recompressedData, originalFFData); } +void AutoTest_COD8_PC::testFactory_data() { + AutoTest_COD::testFactory_data(); +} + +void AutoTest_COD8_PC::testFactory() { + QFETCH(QString, fastFilePath); + + const QString testName = "Factory ingest: " + fastFilePath; + + std::shared_ptr fastFile = FastFileFactory::Create(fastFilePath); + + const QString game = fastFile->GetGame(); + bool correctGame = game == "COD8"; + if (!correctGame) { + recordResult(testName, false); + } + QVERIFY2(correctGame + , qPrintable("Factory parsed wrong game [" + game + "] for fastfile: " + fastFilePath)); + + const QString platform = fastFile->GetPlatform(); + bool correctPlatform = platform == "PC"; + if (!correctPlatform) { + recordResult(testName, false); + } + QVERIFY2(correctPlatform + , qPrintable("Factory parsed wrong platform [" + platform + "] for fastfile: " + fastFilePath)); + + recordResult(testName, true); +} + void AutoTest_COD8_PC::cleanupTestCase() { // Any cleanup if necessary. } diff --git a/tests/PC/autotest_cod9_pc.cpp b/tests/PC/autotest_cod9_pc.cpp index f8a1e64..2d578e4 100644 --- a/tests/PC/autotest_cod9_pc.cpp +++ b/tests/PC/autotest_cod9_pc.cpp @@ -12,12 +12,16 @@ class AutoTest_COD9_PC : public AutoTest_COD { private slots: void initTestCase(); - // Data-driven test for decompression + void testDecompression_data(); void testDecompression(); - // Data-driven test for recompression (compression) + void testCompression_data(); void testCompression(); + + void testFactory_data(); + void testFactory(); + void cleanupTestCase(); }; @@ -27,23 +31,16 @@ void AutoTest_COD9_PC::initTestCase() { } void AutoTest_COD9_PC::testDecompression_data() { - QTest::addColumn("fastFilePath_cod9_pc"); - - QStringList ffFiles = findFastFiles(getFastFileDirectory()); - for (const QString &filePath : ffFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testDecompression_data(); } - void AutoTest_COD9_PC::testDecompression() { - QFETCH(QString, fastFilePath_cod9_pc); + QFETCH(QString, fastFilePath); // Open the original .ff file. - QFile testFastFile(fastFilePath_cod9_pc); + QFile testFastFile(fastFilePath); QVERIFY2(testFastFile.open(QIODevice::ReadOnly), - qPrintable("Failed to open test fastfile: " + fastFilePath_cod9_pc)); + qPrintable("Failed to open test fastfile: " + fastFilePath)); const QByteArray testFFData = testFastFile.readAll(); testFastFile.close(); @@ -57,10 +54,10 @@ void AutoTest_COD9_PC::testDecompression() { quint32 zoneSize; zoneStream >> zoneSize; QVERIFY2(zoneSize + 36 == testZoneData.size(), - qPrintable("Decompression validation failed for: " + fastFilePath_cod9_pc)); + qPrintable("Decompression validation failed for: " + fastFilePath)); // Write the decompressed zone data to the exports folder with a .zone extension. - QFileInfo fi(fastFilePath_cod9_pc); + QFileInfo fi(fastFilePath); QString outputFileName = fi.completeBaseName() + ".zone"; QString outputFilePath = QDir(EXPORT_DIR).filePath(outputFileName); QFile outputFile(outputFilePath); @@ -71,24 +68,18 @@ void AutoTest_COD9_PC::testDecompression() { } void AutoTest_COD9_PC::testCompression_data() { - QTest::addColumn("zoneFilePath_cod9_pc"); - - QStringList zoneFiles = findZoneFiles(getZoneFileDirectory()); - for (const QString &filePath : zoneFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testCompression_data(); } void AutoTest_COD9_PC::testCompression() { - QFETCH(QString, zoneFilePath_cod9_pc); + QFETCH(QString, zoneFilePath); - QFile zoneFile(zoneFilePath_cod9_pc); - QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath_cod9_pc)); + QFile zoneFile(zoneFilePath); + QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath)); QByteArray decompressedData = zoneFile.readAll(); zoneFile.close(); - QFileInfo fi(zoneFilePath_cod9_pc); + QFileInfo fi(zoneFilePath); QString originalFFPath = QDir(getFastFileDirectory()).filePath(fi.completeBaseName() + ".ff"); QFile originalFile(originalFFPath); @@ -116,6 +107,36 @@ void AutoTest_COD9_PC::testCompression() { QCOMPARE(recompressedData, originalFFData); } +void AutoTest_COD9_PC::testFactory_data() { + AutoTest_COD::testFactory_data(); +} + +void AutoTest_COD9_PC::testFactory() { + QFETCH(QString, fastFilePath); + + const QString testName = "Factory ingest: " + fastFilePath; + + std::shared_ptr fastFile = FastFileFactory::Create(fastFilePath); + + const QString game = fastFile->GetGame(); + bool correctGame = game == "COD9"; + if (!correctGame) { + recordResult(testName, false); + } + QVERIFY2(correctGame + , qPrintable("Factory parsed wrong game [" + game + "] for fastfile: " + fastFilePath)); + + const QString platform = fastFile->GetPlatform(); + bool correctPlatform = platform == "PC"; + if (!correctPlatform) { + recordResult(testName, false); + } + QVERIFY2(correctPlatform + , qPrintable("Factory parsed wrong platform [" + platform + "] for fastfile: " + fastFilePath)); + + recordResult(testName, true); +} + void AutoTest_COD9_PC::cleanupTestCase() { // Any cleanup if necessary. } diff --git a/tests/PS3/autotest_cod10_ps3.cpp b/tests/PS3/autotest_cod10_ps3.cpp index 6432d3b..204417d 100644 --- a/tests/PS3/autotest_cod10_ps3.cpp +++ b/tests/PS3/autotest_cod10_ps3.cpp @@ -12,12 +12,16 @@ class AutoTest_COD10_PS3 : public AutoTest_COD { private slots: void initTestCase(); - // Data-driven test for decompression + void testDecompression_data(); void testDecompression(); - // Data-driven test for recompression (compression) + void testCompression_data(); void testCompression(); + + void testFactory_data(); + void testFactory(); + void cleanupTestCase(); }; @@ -27,22 +31,16 @@ void AutoTest_COD10_PS3::initTestCase() { } void AutoTest_COD10_PS3::testDecompression_data() { - QTest::addColumn("fastFilePath_cod10_ps3"); - - QStringList ffFiles = findFastFiles(getFastFileDirectory()); - for (const QString &filePath : ffFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testDecompression_data(); } void AutoTest_COD10_PS3::testDecompression() { - QFETCH(QString, fastFilePath_cod10_ps3); + QFETCH(QString, fastFilePath); // Open the original .ff file. - QFile testFastFile(fastFilePath_cod10_ps3); + QFile testFastFile(fastFilePath); QVERIFY2(testFastFile.open(QIODevice::ReadOnly), - qPrintable("Failed to open test fastfile: " + fastFilePath_cod10_ps3)); + qPrintable("Failed to open test fastfile: " + fastFilePath)); const QByteArray testFFData = testFastFile.readAll(); testFastFile.close(); @@ -56,10 +54,10 @@ void AutoTest_COD10_PS3::testDecompression() { quint32 zoneSize; zoneStream >> zoneSize; QVERIFY2(zoneSize + 44 == testZoneData.size(), - qPrintable("Decompression validation failed for: " + fastFilePath_cod10_ps3)); + qPrintable("Decompression validation failed for: " + fastFilePath)); // Write the decompressed zone data to the exports folder with a .zone extension. - QFileInfo fi(fastFilePath_cod10_ps3); + QFileInfo fi(fastFilePath); QString outputFileName = fi.completeBaseName() + ".zone"; QString outputFilePath = QDir(EXPORT_DIR).filePath(outputFileName); QFile outputFile(outputFilePath); @@ -70,24 +68,18 @@ void AutoTest_COD10_PS3::testDecompression() { } void AutoTest_COD10_PS3::testCompression_data() { - QTest::addColumn("zoneFilePath_cod10_ps3"); - - QStringList zoneFiles = findZoneFiles(getZoneFileDirectory()); - for (const QString &filePath : zoneFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testCompression_data(); } void AutoTest_COD10_PS3::testCompression() { - QFETCH(QString, zoneFilePath_cod10_ps3); + QFETCH(QString, zoneFilePath); - QFile zoneFile(zoneFilePath_cod10_ps3); - QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath_cod10_ps3)); + QFile zoneFile(zoneFilePath); + QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath)); QByteArray decompressedData = zoneFile.readAll(); zoneFile.close(); - QFileInfo fi(zoneFilePath_cod10_ps3); + QFileInfo fi(zoneFilePath); QString originalFFPath = QDir(getFastFileDirectory()).filePath(fi.completeBaseName() + ".ff"); QFile originalFile(originalFFPath); @@ -117,6 +109,36 @@ void AutoTest_COD10_PS3::testCompression() { QCOMPARE(recompressedData, originalFFData); } +void AutoTest_COD10_PS3::testFactory_data() { + AutoTest_COD::testFactory_data(); +} + +void AutoTest_COD10_PS3::testFactory() { + QFETCH(QString, fastFilePath); + + const QString testName = "Factory ingest: " + fastFilePath; + + std::shared_ptr fastFile = FastFileFactory::Create(fastFilePath); + + const QString game = fastFile->GetGame(); + bool correctGame = game == "COD10"; + if (!correctGame) { + recordResult(testName, false); + } + QVERIFY2(correctGame + , qPrintable("Factory parsed wrong game [" + game + "] for fastfile: " + fastFilePath)); + + const QString platform = fastFile->GetPlatform(); + bool correctPlatform = platform == "PS3"; + if (!correctPlatform) { + recordResult(testName, false); + } + QVERIFY2(correctPlatform + , qPrintable("Factory parsed wrong platform [" + platform + "] for fastfile: " + fastFilePath)); + + recordResult(testName, true); +} + void AutoTest_COD10_PS3::cleanupTestCase() { // Any cleanup if necessary. } diff --git a/tests/PS3/autotest_cod11_ps3.cpp b/tests/PS3/autotest_cod11_ps3.cpp index e20a48b..06d5af0 100644 --- a/tests/PS3/autotest_cod11_ps3.cpp +++ b/tests/PS3/autotest_cod11_ps3.cpp @@ -12,12 +12,16 @@ class AutoTest_COD11_PS3 : public AutoTest_COD { private slots: void initTestCase(); - // Data-driven test for decompression + void testDecompression_data(); void testDecompression(); - // Data-driven test for recompression (compression) + void testCompression_data(); void testCompression(); + + void testFactory_data(); + void testFactory(); + void cleanupTestCase(); }; @@ -27,22 +31,16 @@ void AutoTest_COD11_PS3::initTestCase() { } void AutoTest_COD11_PS3::testDecompression_data() { - QTest::addColumn("fastFilePath_cod11_ps3"); - - QStringList ffFiles = findFastFiles(getFastFileDirectory()); - for (const QString &filePath : ffFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testDecompression_data(); } void AutoTest_COD11_PS3::testDecompression() { - QFETCH(QString, fastFilePath_cod11_ps3); + QFETCH(QString, fastFilePath); // Open the original .ff file. - QFile testFastFile(fastFilePath_cod11_ps3); + QFile testFastFile(fastFilePath); QVERIFY2(testFastFile.open(QIODevice::ReadOnly), - qPrintable("Failed to open test fastfile: " + fastFilePath_cod11_ps3)); + qPrintable("Failed to open test fastfile: " + fastFilePath)); const QByteArray testFFData = testFastFile.readAll(); testFastFile.close(); @@ -56,10 +54,10 @@ void AutoTest_COD11_PS3::testDecompression() { quint32 zoneSize; zoneStream >> zoneSize; QVERIFY2(zoneSize + 44 == testZoneData.size(), - qPrintable("Decompression validation failed for: " + fastFilePath_cod11_ps3)); + qPrintable("Decompression validation failed for: " + fastFilePath)); // Write the decompressed zone data to the exports folder with a .zone extension. - QFileInfo fi(fastFilePath_cod11_ps3); + QFileInfo fi(fastFilePath); QString outputFileName = fi.completeBaseName() + ".zone"; QString outputFilePath = QDir(EXPORT_DIR).filePath(outputFileName); QFile outputFile(outputFilePath); @@ -70,24 +68,18 @@ void AutoTest_COD11_PS3::testDecompression() { } void AutoTest_COD11_PS3::testCompression_data() { - QTest::addColumn("zoneFilePath_cod11_ps3"); - - QStringList zoneFiles = findZoneFiles(getZoneFileDirectory()); - for (const QString &filePath : zoneFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testCompression_data(); } void AutoTest_COD11_PS3::testCompression() { - QFETCH(QString, zoneFilePath_cod11_ps3); + QFETCH(QString, zoneFilePath); - QFile zoneFile(zoneFilePath_cod11_ps3); - QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath_cod11_ps3)); + QFile zoneFile(zoneFilePath); + QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath)); QByteArray decompressedData = zoneFile.readAll(); zoneFile.close(); - QFileInfo fi(zoneFilePath_cod11_ps3); + QFileInfo fi(zoneFilePath); QString originalFFPath = QDir(getFastFileDirectory()).filePath(fi.completeBaseName() + ".ff"); QFile originalFile(originalFFPath); @@ -117,6 +109,36 @@ void AutoTest_COD11_PS3::testCompression() { QCOMPARE(recompressedData, originalFFData); } +void AutoTest_COD11_PS3::testFactory_data() { + AutoTest_COD::testFactory_data(); +} + +void AutoTest_COD11_PS3::testFactory() { + QFETCH(QString, fastFilePath); + + const QString testName = "Factory ingest: " + fastFilePath; + + std::shared_ptr fastFile = FastFileFactory::Create(fastFilePath); + + const QString game = fastFile->GetGame(); + bool correctGame = game == "COD11"; + if (!correctGame) { + recordResult(testName, false); + } + QVERIFY2(correctGame + , qPrintable("Factory parsed wrong game [" + game + "] for fastfile: " + fastFilePath)); + + const QString platform = fastFile->GetPlatform(); + bool correctPlatform = platform == "PS3"; + if (!correctPlatform) { + recordResult(testName, false); + } + QVERIFY2(correctPlatform + , qPrintable("Factory parsed wrong platform [" + platform + "] for fastfile: " + fastFilePath)); + + recordResult(testName, true); +} + void AutoTest_COD11_PS3::cleanupTestCase() { // Any cleanup if necessary. } diff --git a/tests/PS3/autotest_cod12_ps3.cpp b/tests/PS3/autotest_cod12_ps3.cpp index 8a23cd2..1e10167 100644 --- a/tests/PS3/autotest_cod12_ps3.cpp +++ b/tests/PS3/autotest_cod12_ps3.cpp @@ -12,12 +12,16 @@ class AutoTest_COD12_PS3 : public AutoTest_COD { private slots: void initTestCase(); - // Data-driven test for decompression + void testDecompression_data(); void testDecompression(); - // Data-driven test for recompression (compression) + void testCompression_data(); void testCompression(); + + void testFactory_data(); + void testFactory(); + void cleanupTestCase(); }; @@ -27,13 +31,7 @@ void AutoTest_COD12_PS3::initTestCase() { } void AutoTest_COD12_PS3::testDecompression_data() { - QTest::addColumn("fastFilePath_cod12_ps3"); - - QStringList ffFiles = findFastFiles(getFastFileDirectory()); - for (const QString &filePath : ffFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testDecompression_data(); } void AutoTest_COD12_PS3::testDecompression() { @@ -70,24 +68,18 @@ void AutoTest_COD12_PS3::testDecompression() { } void AutoTest_COD12_PS3::testCompression_data() { - QTest::addColumn("zoneFilePath_cod12_ps3"); - - QStringList zoneFiles = findZoneFiles(getZoneFileDirectory()); - for (const QString &filePath : zoneFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testCompression_data(); } void AutoTest_COD12_PS3::testCompression() { - QFETCH(QString, zoneFilePath_cod12_ps3); + QFETCH(QString, zoneFilePath); - QFile zoneFile(zoneFilePath_cod12_ps3); - QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath_cod12_ps3)); + QFile zoneFile(zoneFilePath); + QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath)); QByteArray decompressedData = zoneFile.readAll(); zoneFile.close(); - QFileInfo fi(zoneFilePath_cod12_ps3); + QFileInfo fi(zoneFilePath); QString originalFFPath = QDir(getFastFileDirectory()).filePath(fi.completeBaseName() + ".ff"); QFile originalFile(originalFFPath); @@ -117,6 +109,36 @@ void AutoTest_COD12_PS3::testCompression() { QCOMPARE(recompressedData, originalFFData); } +void AutoTest_COD12_PS3::testFactory_data() { + AutoTest_COD::testFactory_data(); +} + +void AutoTest_COD12_PS3::testFactory() { + QFETCH(QString, fastFilePath); + + const QString testName = "Factory ingest: " + fastFilePath; + + std::shared_ptr fastFile = FastFileFactory::Create(fastFilePath); + + const QString game = fastFile->GetGame(); + bool correctGame = game == "COD12"; + if (!correctGame) { + recordResult(testName, false); + } + QVERIFY2(correctGame + , qPrintable("Factory parsed wrong game [" + game + "] for fastfile: " + fastFilePath)); + + const QString platform = fastFile->GetPlatform(); + bool correctPlatform = platform == "PS3"; + if (!correctPlatform) { + recordResult(testName, false); + } + QVERIFY2(correctPlatform + , qPrintable("Factory parsed wrong platform [" + platform + "] for fastfile: " + fastFilePath)); + + recordResult(testName, true); +} + void AutoTest_COD12_PS3::cleanupTestCase() { // Any cleanup if necessary. } diff --git a/tests/PS3/autotest_cod4_ps3.cpp b/tests/PS3/autotest_cod4_ps3.cpp index 8ca2dc2..8b1ae15 100644 --- a/tests/PS3/autotest_cod4_ps3.cpp +++ b/tests/PS3/autotest_cod4_ps3.cpp @@ -12,12 +12,16 @@ class AutoTest_COD4_PS3 : public AutoTest_COD { private slots: void initTestCase(); - // Data-driven test for decompression + void testDecompression_data(); void testDecompression(); - // Data-driven test for recompression (compression) + void testCompression_data(); void testCompression(); + + void testFactory_data(); + void testFactory(); + void cleanupTestCase(); }; @@ -27,67 +31,80 @@ void AutoTest_COD4_PS3::initTestCase() { } void AutoTest_COD4_PS3::testDecompression_data() { - QTest::addColumn("fastFilePath_cod4_ps3"); - - QStringList ffFiles = findFastFiles(getFastFileDirectory()); - for (const QString &filePath : ffFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testDecompression_data(); } void AutoTest_COD4_PS3::testDecompression() { - QFETCH(QString, fastFilePath_cod4_ps3); + QFETCH(QString, fastFilePath); - // Open the original .ff file. - QFile testFastFile(fastFilePath_cod4_ps3); + QFile testFastFile(fastFilePath); QVERIFY2(testFastFile.open(QIODevice::ReadOnly), - qPrintable("Failed to open test fastfile: " + fastFilePath_cod4_ps3)); + qPrintable("Failed to open test fastfile: " + fastFilePath)); const QByteArray testFFData = testFastFile.readAll(); testFastFile.close(); - // Assume the first 12 bytes are a header; the rest is zlib-compressed zone data. - const QByteArray compressedData = testFFData.mid(12); - const QByteArray testZoneData = Compression::DecompressDeflate(compressedData); + // Validate header + QVERIFY2(testFFData.size() > 12, "FastFile too small to contain header"); + QByteArray header = testFFData.left(8); + QVERIFY2(header == "IWffu100", "Invalid FastFile header!"); - // Verify the decompressed data via its embedded zone size. - QDataStream zoneStream(testZoneData); - zoneStream.setByteOrder(QDataStream::LittleEndian); - quint32 zoneSize; - zoneStream >> zoneSize; - //QVERIFY2(zoneSize + 44 == testZoneData.size(), - // qPrintable("Decompression validation failed for: " + fastFilePath_cod4_ps3)); + QDataStream headerStream(testFFData.mid(8, 6)); + headerStream.setByteOrder(QDataStream::BigEndian); + qint32 version; + qint16 identifier; + headerStream >> version >> identifier; + QVERIFY2(version == 1, "Unsupported game version"); - // Write the decompressed zone data to the exports folder with a .zone extension. - QFileInfo fi(fastFilePath_cod4_ps3); + QByteArray decompressed; + int pos = 12; + + // Loop until EOF or invalid chunk + while (pos <= testFFData.size()) { + // Read 2-byte BIG-ENDIAN chunk size + quint16 chunkSize; + QDataStream chunkStream(testFFData.mid(pos, 2)); + chunkStream.setByteOrder(QDataStream::BigEndian); + chunkStream >> chunkSize; + + pos += 2; + + if (chunkSize == 0 || pos + chunkSize > testFFData.size()) { + qWarning() << "Invalid or incomplete chunk detected, stopping."; + break; + } + + const QByteArray compressedChunk = testFFData.mid(pos, chunkSize); + + decompressed.append(Compression::DecompressDeflate(compressedChunk)); + + pos += chunkSize; + } + + // Write decompressed .zone file + QFileInfo fi(fastFilePath); QString outputFileName = fi.completeBaseName() + ".zone"; QString outputFilePath = QDir(EXPORT_DIR).filePath(outputFileName); QFile outputFile(outputFilePath); QVERIFY2(outputFile.open(QIODevice::WriteOnly), qPrintable("Failed to open output file for writing: " + outputFilePath)); - outputFile.write(testZoneData); + outputFile.write(decompressed); outputFile.close(); } -void AutoTest_COD4_PS3::testCompression_data() { - QTest::addColumn("zoneFilePath_cod4_ps3"); - QStringList zoneFiles = findZoneFiles(getZoneFileDirectory()); - for (const QString &filePath : zoneFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } +void AutoTest_COD4_PS3::testCompression_data() { + AutoTest_COD::testCompression_data(); } void AutoTest_COD4_PS3::testCompression() { - QFETCH(QString, zoneFilePath_cod4_ps3); + QFETCH(QString, zoneFilePath); - QFile zoneFile(zoneFilePath_cod4_ps3); - QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath_cod4_ps3)); + QFile zoneFile(zoneFilePath); + QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath)); QByteArray decompressedData = zoneFile.readAll(); zoneFile.close(); - QFileInfo fi(zoneFilePath_cod4_ps3); + QFileInfo fi(zoneFilePath); QString originalFFPath = QDir(getFastFileDirectory()).filePath(fi.completeBaseName() + ".ff"); QFile originalFile(originalFFPath); @@ -96,26 +113,71 @@ void AutoTest_COD4_PS3::testCompression() { originalFile.close(); QByteArray header = originalFFData.left(12); + QByteArray recompressedData = header; - QByteArray newCompressedData = Compression::CompressDeflateWithSettings(decompressedData, Z_BEST_COMPRESSION); + // Split decompressed data into chunks (optional: same size as original or fixed 0x4000) + const int chunkSize = 0x4000; + int offset = 0; - int remainder = (newCompressedData.size() + 12) % 32; - if (remainder != 0) { - int paddingNeeded = 32 - remainder; - newCompressedData.append(QByteArray(paddingNeeded, '\0')); + while (offset < decompressedData.size()) { + QByteArray chunk = decompressedData.mid(offset, chunkSize); + offset += chunk.size(); + + QByteArray compressedChunk = Compression::CompressDeflate(chunk); + quint16 length = static_cast(compressedChunk.size()); + + // Write 2-byte big-endian chunk size + recompressedData.append(static_cast((length >> 8) & 0xFF)); + recompressedData.append(static_cast(length & 0xFF)); + + // Write compressed chunk + recompressedData.append(compressedChunk); } - QByteArray recompressedData = header + newCompressedData; + // No terminator chunk needed if original didn't have one + // Save new file QString recompressedFilePath = QDir(EXPORT_DIR).filePath(fi.completeBaseName() + ".ff"); QFile recompressedFile(recompressedFilePath); QVERIFY2(recompressedFile.open(QIODevice::WriteOnly), qPrintable("Failed to write recompressed file.")); recompressedFile.write(recompressedData); recompressedFile.close(); + // Validate byte-for-byte match QCOMPARE(recompressedData, originalFFData); } + +void AutoTest_COD4_PS3::testFactory_data() { + AutoTest_COD::testFactory_data(); +} + +void AutoTest_COD4_PS3::testFactory() { + QFETCH(QString, fastFilePath); + + const QString testName = "Factory ingest: " + fastFilePath; + + std::shared_ptr fastFile = FastFileFactory::Create(fastFilePath); + + const QString game = fastFile->GetGame(); + bool correctGame = game == "COD4"; + if (!correctGame) { + recordResult(testName, false); + } + QVERIFY2(correctGame + , qPrintable("Factory parsed wrong game [" + game + "] for fastfile: " + fastFilePath)); + + const QString platform = fastFile->GetPlatform(); + bool correctPlatform = platform == "PS3"; + if (!correctPlatform) { + recordResult(testName, false); + } + QVERIFY2(correctPlatform + , qPrintable("Factory parsed wrong platform [" + platform + "] for fastfile: " + fastFilePath)); + + recordResult(testName, true); +} + void AutoTest_COD4_PS3::cleanupTestCase() { // Any cleanup if necessary. } diff --git a/tests/PS3/autotest_cod5_ps3.cpp b/tests/PS3/autotest_cod5_ps3.cpp index 7b1ed14..df8e22a 100644 --- a/tests/PS3/autotest_cod5_ps3.cpp +++ b/tests/PS3/autotest_cod5_ps3.cpp @@ -12,12 +12,16 @@ class AutoTest_COD5_PS3 : public AutoTest_COD { private slots: void initTestCase(); - // Data-driven test for decompression + void testDecompression_data(); void testDecompression(); - // Data-driven test for recompression (compression) + void testCompression_data(); void testCompression(); + + void testFactory_data(); + void testFactory(); + void cleanupTestCase(); }; @@ -27,72 +31,79 @@ void AutoTest_COD5_PS3::initTestCase() { } void AutoTest_COD5_PS3::testDecompression_data() { - QTest::addColumn("fastFilePath_cod5_ps3"); - - QStringList ffFiles = findFastFiles(getFastFileDirectory()); - for (const QString &filePath : ffFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testDecompression_data(); } void AutoTest_COD5_PS3::testDecompression() { - QFETCH(QString, fastFilePath_cod5_ps3); + QFETCH(QString, fastFilePath); - // Open the original .ff file. - QFile testFastFile(fastFilePath_cod5_ps3); + QFile testFastFile(fastFilePath); QVERIFY2(testFastFile.open(QIODevice::ReadOnly), - qPrintable("Failed to open test fastfile: " + fastFilePath_cod5_ps3)); + qPrintable("Failed to open test fastfile: " + fastFilePath)); const QByteArray testFFData = testFastFile.readAll(); testFastFile.close(); - // Assume the first 12 bytes are a header; the rest is zlib-compressed zone data. - const QByteArray compressedData = testFFData.mid(12); - const QByteArray testZoneData = Compression::DecompressZLIB(compressedData); + // Validate header + QVERIFY2(testFFData.size() > 12, "FastFile too small to contain header"); + QByteArray header = testFFData.left(8); + QVERIFY2(header == "IWffu100", "Invalid FastFile header!"); - // Verify the decompressed data via its embedded zone size. - QDataStream zoneStream(testZoneData); - zoneStream.setByteOrder(QDataStream::LittleEndian); - quint32 zoneSize; - zoneStream >> zoneSize; - if (abs(zoneSize - testZoneData.size()) != 36) { - qDebug() << "Zone Size: " << zoneSize; - qDebug() << "Test zone Size: " << testZoneData.size(); - qDebug() << "Difference: " << abs(zoneSize - testZoneData.size()); + QDataStream headerStream(testFFData.mid(8, 6)); + headerStream.setByteOrder(QDataStream::BigEndian); + qint32 version; + qint16 identifier; + headerStream >> version >> identifier; + QVERIFY2(version == 387, "Unsupported game version"); + + QByteArray decompressed; + int pos = 12; + + // Loop until EOF or invalid chunk + while (pos <= testFFData.size()) { + // Read 2-byte BIG-ENDIAN chunk size + quint16 chunkSize; + QDataStream chunkStream(testFFData.mid(pos, 2)); + chunkStream.setByteOrder(QDataStream::BigEndian); + chunkStream >> chunkSize; + + pos += 2; + + if (chunkSize == 0 || pos + chunkSize > testFFData.size()) { + qWarning() << "Invalid or incomplete chunk detected, stopping."; + break; + } + + const QByteArray compressedChunk = testFFData.mid(pos, chunkSize); + + decompressed.append(Compression::DecompressDeflate(compressedChunk)); + + pos += chunkSize; } - QVERIFY2(zoneSize + 36 == testZoneData.size(), - qPrintable("Decompression validation failed for: " + fastFilePath_cod5_ps3)); - // Write the decompressed zone data to the exports folder with a .zone extension. - QFileInfo fi(fastFilePath_cod5_ps3); + // Write decompressed .zone file + QFileInfo fi(fastFilePath); QString outputFileName = fi.completeBaseName() + ".zone"; QString outputFilePath = QDir(EXPORT_DIR).filePath(outputFileName); QFile outputFile(outputFilePath); QVERIFY2(outputFile.open(QIODevice::WriteOnly), qPrintable("Failed to open output file for writing: " + outputFilePath)); - outputFile.write(testZoneData); + outputFile.write(decompressed); outputFile.close(); } void AutoTest_COD5_PS3::testCompression_data() { - QTest::addColumn("zoneFilePath_cod5_ps3"); - - QStringList zoneFiles = findZoneFiles(getZoneFileDirectory()); - for (const QString &filePath : zoneFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testCompression_data(); } void AutoTest_COD5_PS3::testCompression() { - QFETCH(QString, zoneFilePath_cod5_ps3); + QFETCH(QString, zoneFilePath); - QFile zoneFile(zoneFilePath_cod5_ps3); - QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath_cod5_ps3)); + QFile zoneFile(zoneFilePath); + QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath)); QByteArray decompressedData = zoneFile.readAll(); zoneFile.close(); - QFileInfo fi(zoneFilePath_cod5_ps3); + QFileInfo fi(zoneFilePath); QString originalFFPath = QDir(getFastFileDirectory()).filePath(fi.completeBaseName() + ".ff"); QFile originalFile(originalFFPath); @@ -101,27 +112,70 @@ void AutoTest_COD5_PS3::testCompression() { originalFile.close(); QByteArray header = originalFFData.left(12); + QByteArray recompressedData = header; - QByteArray newCompressedData;// = Compressor::CompressZLIB(decompressedData, Z_BEST_COMPRESSION); - newCompressedData = Compression::CompressZLIBWithSettings(decompressedData, Z_BEST_COMPRESSION, MAX_WBITS, 8, Z_DEFAULT_STRATEGY, {}); + // Split decompressed data into chunks (optional: same size as original or fixed 0x4000) + const int chunkSize = 0x4000; + int offset = 0; - int remainder = (newCompressedData.size() + 12) % 32; - if (remainder != 0) { - int paddingNeeded = 32 - remainder; - newCompressedData.append(QByteArray(paddingNeeded, '\0')); + while (offset < decompressedData.size()) { + QByteArray chunk = decompressedData.mid(offset, chunkSize); + offset += chunk.size(); + + QByteArray compressedChunk = Compression::CompressDeflate(chunk); + quint16 length = static_cast(compressedChunk.size()); + + // Write 2-byte big-endian chunk size + recompressedData.append(static_cast((length >> 8) & 0xFF)); + recompressedData.append(static_cast(length & 0xFF)); + + // Write compressed chunk + recompressedData.append(compressedChunk); } - QByteArray recompressedData = header + newCompressedData; + // No terminator chunk needed if original didn't have one + // Save new file QString recompressedFilePath = QDir(EXPORT_DIR).filePath(fi.completeBaseName() + ".ff"); QFile recompressedFile(recompressedFilePath); QVERIFY2(recompressedFile.open(QIODevice::WriteOnly), qPrintable("Failed to write recompressed file.")); recompressedFile.write(recompressedData); recompressedFile.close(); + // Validate byte-for-byte match QCOMPARE(recompressedData, originalFFData); } +void AutoTest_COD5_PS3::testFactory_data() { + AutoTest_COD::testFactory_data(); +} + +void AutoTest_COD5_PS3::testFactory() { + QFETCH(QString, fastFilePath); + + const QString testName = "Factory ingest: " + fastFilePath; + + std::shared_ptr fastFile = FastFileFactory::Create(fastFilePath); + + const QString game = fastFile->GetGame(); + bool correctGame = game == "COD5"; + if (!correctGame) { + recordResult(testName, false); + } + QVERIFY2(correctGame + , qPrintable("Factory parsed wrong game [" + game + "] for fastfile: " + fastFilePath)); + + const QString platform = fastFile->GetPlatform(); + bool correctPlatform = platform == "PS3"; + if (!correctPlatform) { + recordResult(testName, false); + } + QVERIFY2(correctPlatform + , qPrintable("Factory parsed wrong platform [" + platform + "] for fastfile: " + fastFilePath)); + + recordResult(testName, true); +} + void AutoTest_COD5_PS3::cleanupTestCase() { // Any cleanup if necessary. } diff --git a/tests/PS3/autotest_cod6_ps3.cpp b/tests/PS3/autotest_cod6_ps3.cpp index b5b5234..42fbcac 100644 --- a/tests/PS3/autotest_cod6_ps3.cpp +++ b/tests/PS3/autotest_cod6_ps3.cpp @@ -12,12 +12,16 @@ class AutoTest_COD6_PS3 : public AutoTest_COD { private slots: void initTestCase(); - // Data-driven test for decompression + void testDecompression_data(); void testDecompression(); - // Data-driven test for recompression (compression) + void testCompression_data(); void testCompression(); + + void testFactory_data(); + void testFactory(); + void cleanupTestCase(); }; @@ -27,22 +31,16 @@ void AutoTest_COD6_PS3::initTestCase() { } void AutoTest_COD6_PS3::testDecompression_data() { - QTest::addColumn("fastFilePath_cod6_ps3"); - - QStringList ffFiles = findFastFiles(getFastFileDirectory()); - for (const QString &filePath : ffFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testDecompression_data(); } void AutoTest_COD6_PS3::testDecompression() { - QFETCH(QString, fastFilePath_cod6_ps3); + QFETCH(QString, fastFilePath); // Open the original .ff file. - QFile testFastFile(fastFilePath_cod6_ps3); + QFile testFastFile(fastFilePath); QVERIFY2(testFastFile.open(QIODevice::ReadOnly), - qPrintable("Failed to open test fastfile: " + fastFilePath_cod6_ps3)); + qPrintable("Failed to open test fastfile: " + fastFilePath)); const QByteArray testFFData = testFastFile.readAll(); testFastFile.close(); @@ -56,10 +54,10 @@ void AutoTest_COD6_PS3::testDecompression() { quint32 zoneSize; zoneStream >> zoneSize; QVERIFY2(zoneSize + 44 == testZoneData.size(), - qPrintable("Decompression validation failed for: " + fastFilePath_cod6_ps3)); + qPrintable("Decompression validation failed for: " + fastFilePath)); // Write the decompressed zone data to the exports folder with a .zone extension. - QFileInfo fi(fastFilePath_cod6_ps3); + QFileInfo fi(fastFilePath); QString outputFileName = fi.completeBaseName() + ".zone"; QString outputFilePath = QDir(EXPORT_DIR).filePath(outputFileName); QFile outputFile(outputFilePath); @@ -70,24 +68,18 @@ void AutoTest_COD6_PS3::testDecompression() { } void AutoTest_COD6_PS3::testCompression_data() { - QTest::addColumn("zoneFilePath_cod6_ps3"); - - QStringList zoneFiles = findZoneFiles(getZoneFileDirectory()); - for (const QString &filePath : zoneFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testCompression_data(); } void AutoTest_COD6_PS3::testCompression() { - QFETCH(QString, zoneFilePath_cod6_ps3); + QFETCH(QString, zoneFilePath); - QFile zoneFile(zoneFilePath_cod6_ps3); - QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath_cod6_ps3)); + QFile zoneFile(zoneFilePath); + QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath)); QByteArray decompressedData = zoneFile.readAll(); zoneFile.close(); - QFileInfo fi(zoneFilePath_cod6_ps3); + QFileInfo fi(zoneFilePath); QString originalFFPath = QDir(getFastFileDirectory()).filePath(fi.completeBaseName() + ".ff"); QFile originalFile(originalFFPath); @@ -117,6 +109,36 @@ void AutoTest_COD6_PS3::testCompression() { QCOMPARE(recompressedData, originalFFData); } +void AutoTest_COD6_PS3::testFactory_data() { + AutoTest_COD::testFactory_data(); +} + +void AutoTest_COD6_PS3::testFactory() { + QFETCH(QString, fastFilePath); + + const QString testName = "Factory ingest: " + fastFilePath; + + std::shared_ptr fastFile = FastFileFactory::Create(fastFilePath); + + const QString game = fastFile->GetGame(); + bool correctGame = game == "COD6"; + if (!correctGame) { + recordResult(testName, false); + } + QVERIFY2(correctGame + , qPrintable("Factory parsed wrong game [" + game + "] for fastfile: " + fastFilePath)); + + const QString platform = fastFile->GetPlatform(); + bool correctPlatform = platform == "PS3"; + if (!correctPlatform) { + recordResult(testName, false); + } + QVERIFY2(correctPlatform + , qPrintable("Factory parsed wrong platform [" + platform + "] for fastfile: " + fastFilePath)); + + recordResult(testName, true); +} + void AutoTest_COD6_PS3::cleanupTestCase() { // Any cleanup if necessary. } diff --git a/tests/PS3/autotest_cod7_ps3.cpp b/tests/PS3/autotest_cod7_ps3.cpp index a49fa55..488c30b 100644 --- a/tests/PS3/autotest_cod7_ps3.cpp +++ b/tests/PS3/autotest_cod7_ps3.cpp @@ -4,6 +4,7 @@ #include "autotest_cod.h" #include "compression.h" +#include "encryption.h" class AutoTest_COD7_PS3 : public AutoTest_COD { Q_OBJECT @@ -12,12 +13,16 @@ class AutoTest_COD7_PS3 : public AutoTest_COD { private slots: void initTestCase(); - // Data-driven test for decompression + void testDecompression_data(); void testDecompression(); - // Data-driven test for recompression (compression) + void testCompression_data(); void testCompression(); + + void testFactory_data(); + void testFactory(); + void cleanupTestCase(); }; @@ -27,39 +32,95 @@ void AutoTest_COD7_PS3::initTestCase() { } void AutoTest_COD7_PS3::testDecompression_data() { - QTest::addColumn("fastFilePath_cod7_ps3"); - - QStringList ffFiles = findFastFiles(getFastFileDirectory()); - for (const QString &filePath : ffFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testDecompression_data(); } void AutoTest_COD7_PS3::testDecompression() { - QFETCH(QString, fastFilePath_cod7_ps3); + QFETCH(QString, fastFilePath); + + const QString testName = "Decompress: " + fastFilePath; // Open the original .ff file. - QFile testFastFile(fastFilePath_cod7_ps3); + QFile testFastFile(fastFilePath); QVERIFY2(testFastFile.open(QIODevice::ReadOnly), - qPrintable("Failed to open test fastfile: " + fastFilePath_cod7_ps3)); + qPrintable("Failed to open test fastfile: " + fastFilePath)); const QByteArray testFFData = testFastFile.readAll(); testFastFile.close(); - // Assume the first 12 bytes are a header; the rest is zlib-compressed zone data. - const QByteArray compressedData = testFFData.mid(12); - const QByteArray testZoneData = Compression::DecompressZLIB(compressedData); + QByteArray decompressedData; + QByteArray key = QByteArray::fromHex("46D3F997F29C9ACE175B0DAE3AB8C0C1B8E423E2E3BF7E3C311EA35245BF193A"); + + // Create a QDataStream on the input data. + QDataStream fastFileStream(testFFData); + fastFileStream.setByteOrder(QDataStream::BigEndian); + fastFileStream.skipRawData(16); + + // Read the 8-byte magic. + QByteArray fileMagic(8, Qt::Uninitialized); + fastFileStream.readRawData(fileMagic.data(), 8); + QVERIFY2(fileMagic == "PHEEBs71", + qPrintable("Invalid fast file magic: " + fileMagic)); + 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; + 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. + decompressedData.append(Compression::DecompressDeflate(decData)); + + sectionIndex++; + } + + const QByteArray testZoneData = decompressedData; // Verify the decompressed data via its embedded zone size. QDataStream zoneStream(testZoneData); - zoneStream.setByteOrder(QDataStream::LittleEndian); + zoneStream.setByteOrder(QDataStream::BigEndian); quint32 zoneSize; zoneStream >> zoneSize; - QVERIFY2(zoneSize + 44 == testZoneData.size(), - qPrintable("Decompression validation failed for: " + fastFilePath_cod7_ps3)); + if (abs(zoneSize - testZoneData.size()) != 36) { + qDebug() << "Zone Size: " << zoneSize; + qDebug() << "Test zone Size: " << testZoneData.size(); + qDebug() << "Difference: " << abs(zoneSize - testZoneData.size()); + } + QVERIFY2(zoneSize + 36 == testZoneData.size(), + qPrintable("Decompression validation failed for: " + fastFilePath)); // Write the decompressed zone data to the exports folder with a .zone extension. - QFileInfo fi(fastFilePath_cod7_ps3); + QFileInfo fi(fastFilePath); QString outputFileName = fi.completeBaseName() + ".zone"; QString outputFilePath = QDir(EXPORT_DIR).filePath(outputFileName); QFile outputFile(outputFilePath); @@ -70,24 +131,18 @@ void AutoTest_COD7_PS3::testDecompression() { } void AutoTest_COD7_PS3::testCompression_data() { - QTest::addColumn("zoneFilePath_cod7_ps3"); - - QStringList zoneFiles = findZoneFiles(getZoneFileDirectory()); - for (const QString &filePath : zoneFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testCompression_data(); } void AutoTest_COD7_PS3::testCompression() { - QFETCH(QString, zoneFilePath_cod7_ps3); + QFETCH(QString, zoneFilePath); - QFile zoneFile(zoneFilePath_cod7_ps3); - QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath_cod7_ps3)); + QFile zoneFile(zoneFilePath); + QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath)); QByteArray decompressedData = zoneFile.readAll(); zoneFile.close(); - QFileInfo fi(zoneFilePath_cod7_ps3); + QFileInfo fi(zoneFilePath); QString originalFFPath = QDir(getFastFileDirectory()).filePath(fi.completeBaseName() + ".ff"); QFile originalFile(originalFFPath); @@ -117,6 +172,36 @@ void AutoTest_COD7_PS3::testCompression() { QCOMPARE(recompressedData, originalFFData); } +void AutoTest_COD7_PS3::testFactory_data() { + AutoTest_COD::testFactory_data(); +} + +void AutoTest_COD7_PS3::testFactory() { + QFETCH(QString, fastFilePath); + + const QString testName = "Factory ingest: " + fastFilePath; + + std::shared_ptr fastFile = FastFileFactory::Create(fastFilePath); + + const QString game = fastFile->GetGame(); + bool correctGame = game == "COD7"; + if (!correctGame) { + recordResult(testName, false); + } + QVERIFY2(correctGame + , qPrintable("Factory parsed wrong game [" + game + "] for fastfile: " + fastFilePath)); + + const QString platform = fastFile->GetPlatform(); + bool correctPlatform = platform == "PS3"; + if (!correctPlatform) { + recordResult(testName, false); + } + QVERIFY2(correctPlatform + , qPrintable("Factory parsed wrong platform [" + platform + "] for fastfile: " + fastFilePath)); + + recordResult(testName, true); +} + void AutoTest_COD7_PS3::cleanupTestCase() { // Any cleanup if necessary. } diff --git a/tests/PS3/autotest_cod8_ps3.cpp b/tests/PS3/autotest_cod8_ps3.cpp index fdae339..99d1bff 100644 --- a/tests/PS3/autotest_cod8_ps3.cpp +++ b/tests/PS3/autotest_cod8_ps3.cpp @@ -12,12 +12,16 @@ class AutoTest_COD8_PS3 : public AutoTest_COD { private slots: void initTestCase(); - // Data-driven test for decompression + void testDecompression_data(); void testDecompression(); - // Data-driven test for recompression (compression) + void testCompression_data(); void testCompression(); + + void testFactory_data(); + void testFactory(); + void cleanupTestCase(); }; @@ -27,22 +31,16 @@ void AutoTest_COD8_PS3::initTestCase() { } void AutoTest_COD8_PS3::testDecompression_data() { - QTest::addColumn("fastFilePath_cod8_ps3"); - - QStringList ffFiles = findFastFiles(getFastFileDirectory()); - for (const QString &filePath : ffFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testDecompression_data(); } void AutoTest_COD8_PS3::testDecompression() { - QFETCH(QString, fastFilePath_cod8_ps3); + QFETCH(QString, fastFilePath); // Open the original .ff file. - QFile testFastFile(fastFilePath_cod8_ps3); + QFile testFastFile(fastFilePath); QVERIFY2(testFastFile.open(QIODevice::ReadOnly), - qPrintable("Failed to open test fastfile: " + fastFilePath_cod8_ps3)); + qPrintable("Failed to open test fastfile: " + fastFilePath)); const QByteArray testFFData = testFastFile.readAll(); testFastFile.close(); @@ -56,10 +54,10 @@ void AutoTest_COD8_PS3::testDecompression() { quint32 zoneSize; zoneStream >> zoneSize; QVERIFY2(zoneSize + 44 == testZoneData.size(), - qPrintable("Decompression validation failed for: " + fastFilePath_cod8_ps3)); + qPrintable("Decompression validation failed for: " + fastFilePath)); // Write the decompressed zone data to the exports folder with a .zone extension. - QFileInfo fi(fastFilePath_cod8_ps3); + QFileInfo fi(fastFilePath); QString outputFileName = fi.completeBaseName() + ".zone"; QString outputFilePath = QDir(EXPORT_DIR).filePath(outputFileName); QFile outputFile(outputFilePath); @@ -70,24 +68,18 @@ void AutoTest_COD8_PS3::testDecompression() { } void AutoTest_COD8_PS3::testCompression_data() { - QTest::addColumn("zoneFilePath_cod8_ps3"); - - QStringList zoneFiles = findZoneFiles(getZoneFileDirectory()); - for (const QString &filePath : zoneFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testCompression_data(); } void AutoTest_COD8_PS3::testCompression() { - QFETCH(QString, zoneFilePath_cod8_ps3); + QFETCH(QString, zoneFilePath); - QFile zoneFile(zoneFilePath_cod8_ps3); - QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath_cod8_ps3)); + QFile zoneFile(zoneFilePath); + QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath)); QByteArray decompressedData = zoneFile.readAll(); zoneFile.close(); - QFileInfo fi(zoneFilePath_cod8_ps3); + QFileInfo fi(zoneFilePath); QString originalFFPath = QDir(getFastFileDirectory()).filePath(fi.completeBaseName() + ".ff"); QFile originalFile(originalFFPath); @@ -117,6 +109,36 @@ void AutoTest_COD8_PS3::testCompression() { QCOMPARE(recompressedData, originalFFData); } +void AutoTest_COD8_PS3::testFactory_data() { + AutoTest_COD::testFactory_data(); +} + +void AutoTest_COD8_PS3::testFactory() { + QFETCH(QString, fastFilePath); + + const QString testName = "Factory ingest: " + fastFilePath; + + std::shared_ptr fastFile = FastFileFactory::Create(fastFilePath); + + const QString game = fastFile->GetGame(); + bool correctGame = game == "COD8"; + if (!correctGame) { + recordResult(testName, false); + } + QVERIFY2(correctGame + , qPrintable("Factory parsed wrong game [" + game + "] for fastfile: " + fastFilePath)); + + const QString platform = fastFile->GetPlatform(); + bool correctPlatform = platform == "PS3"; + if (!correctPlatform) { + recordResult(testName, false); + } + QVERIFY2(correctPlatform + , qPrintable("Factory parsed wrong platform [" + platform + "] for fastfile: " + fastFilePath)); + + recordResult(testName, true); +} + void AutoTest_COD8_PS3::cleanupTestCase() { // Any cleanup if necessary. } diff --git a/tests/PS3/autotest_cod9_ps3.cpp b/tests/PS3/autotest_cod9_ps3.cpp index 660f16b..c3b3f78 100644 --- a/tests/PS3/autotest_cod9_ps3.cpp +++ b/tests/PS3/autotest_cod9_ps3.cpp @@ -12,12 +12,16 @@ class AutoTest_COD9_PS3 : public AutoTest_COD { private slots: void initTestCase(); - // Data-driven test for decompression + void testDecompression_data(); void testDecompression(); - // Data-driven test for recompression (compression) + void testCompression_data(); void testCompression(); + + void testFactory_data(); + void testFactory(); + void cleanupTestCase(); }; @@ -27,22 +31,16 @@ void AutoTest_COD9_PS3::initTestCase() { } void AutoTest_COD9_PS3::testDecompression_data() { - QTest::addColumn("fastFilePath_cod9_ps3"); - - QStringList ffFiles = findFastFiles(getFastFileDirectory()); - for (const QString &filePath : ffFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testDecompression_data(); } void AutoTest_COD9_PS3::testDecompression() { - QFETCH(QString, fastFilePath_cod9_ps3); + QFETCH(QString, fastFilePath); // Open the original .ff file. - QFile testFastFile(fastFilePath_cod9_ps3); + QFile testFastFile(fastFilePath); QVERIFY2(testFastFile.open(QIODevice::ReadOnly), - qPrintable("Failed to open test fastfile: " + fastFilePath_cod9_ps3)); + qPrintable("Failed to open test fastfile: " + fastFilePath)); const QByteArray testFFData = testFastFile.readAll(); testFastFile.close(); @@ -56,10 +54,10 @@ void AutoTest_COD9_PS3::testDecompression() { quint32 zoneSize; zoneStream >> zoneSize; QVERIFY2(zoneSize + 44 == testZoneData.size(), - qPrintable("Decompression validation failed for: " + fastFilePath_cod9_ps3)); + qPrintable("Decompression validation failed for: " + fastFilePath)); // Write the decompressed zone data to the exports folder with a .zone extension. - QFileInfo fi(fastFilePath_cod9_ps3); + QFileInfo fi(fastFilePath); QString outputFileName = fi.completeBaseName() + ".zone"; QString outputFilePath = QDir(EXPORT_DIR).filePath(outputFileName); QFile outputFile(outputFilePath); @@ -70,24 +68,18 @@ void AutoTest_COD9_PS3::testDecompression() { } void AutoTest_COD9_PS3::testCompression_data() { - QTest::addColumn("zoneFilePath_cod9_ps3"); - - QStringList zoneFiles = findZoneFiles(getZoneFileDirectory()); - for (const QString &filePath : zoneFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testCompression_data(); } void AutoTest_COD9_PS3::testCompression() { - QFETCH(QString, zoneFilePath_cod9_ps3); + QFETCH(QString, zoneFilePath); - QFile zoneFile(zoneFilePath_cod9_ps3); - QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath_cod9_ps3)); + QFile zoneFile(zoneFilePath); + QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath)); QByteArray decompressedData = zoneFile.readAll(); zoneFile.close(); - QFileInfo fi(zoneFilePath_cod9_ps3); + QFileInfo fi(zoneFilePath); QString originalFFPath = QDir(getFastFileDirectory()).filePath(fi.completeBaseName() + ".ff"); QFile originalFile(originalFFPath); @@ -117,6 +109,36 @@ void AutoTest_COD9_PS3::testCompression() { QCOMPARE(recompressedData, originalFFData); } +void AutoTest_COD9_PS3::testFactory_data() { + AutoTest_COD::testFactory_data(); +} + +void AutoTest_COD9_PS3::testFactory() { + QFETCH(QString, fastFilePath); + + const QString testName = "Factory ingest: " + fastFilePath; + + std::shared_ptr fastFile = FastFileFactory::Create(fastFilePath); + + const QString game = fastFile->GetGame(); + bool correctGame = game == "COD9"; + if (!correctGame) { + recordResult(testName, false); + } + QVERIFY2(correctGame + , qPrintable("Factory parsed wrong game [" + game + "] for fastfile: " + fastFilePath)); + + const QString platform = fastFile->GetPlatform(); + bool correctPlatform = platform == "PS3"; + if (!correctPlatform) { + recordResult(testName, false); + } + QVERIFY2(correctPlatform + , qPrintable("Factory parsed wrong platform [" + platform + "] for fastfile: " + fastFilePath)); + + recordResult(testName, true); +} + void AutoTest_COD9_PS3::cleanupTestCase() { // Any cleanup if necessary. } diff --git a/tests/Wii/autotest_cod4_wii.cpp b/tests/Wii/autotest_cod4_wii.cpp new file mode 100644 index 0000000..a3ee6f0 --- /dev/null +++ b/tests/Wii/autotest_cod4_wii.cpp @@ -0,0 +1,147 @@ +#include +#include +#include + +#include "autotest_cod.h" +#include "compression.h" + +class AutoTest_COD4_Wii : public AutoTest_COD { + Q_OBJECT + + const QString EXPORT_DIR = "./exports/cod7/Wii"; + +private slots: + void initTestCase(); + + void testDecompression_data(); + void testDecompression(); + + void testCompression_data(); + void testCompression(); + + void testFactory_data(); + void testFactory(); + + void cleanupTestCase(); +}; + +void AutoTest_COD4_Wii::initTestCase() { + // Ensure the exports directory exists. + createDirectory(EXPORT_DIR); +} + +void AutoTest_COD4_Wii::testDecompression_data() { + AutoTest_COD::testDecompression_data(); +} + +void AutoTest_COD4_Wii::testDecompression() { + QFETCH(QString, fastFilePath); + + // Open the original .ff file. + QFile testFastFile(fastFilePath); + QVERIFY2(testFastFile.open(QIODevice::ReadOnly), + qPrintable("Failed to open test fastfile: " + fastFilePath)); + const QByteArray testFFData = testFastFile.readAll(); + testFastFile.close(); + + // Assume the first 12 bytes are a header; the rest is zlib-compressed zone data. + const QByteArray compressedData = testFFData.mid(12); + const QByteArray testZoneData = Compression::DecompressZLIB(compressedData); + + // Verify the decompressed data via its embedded zone size. + QDataStream zoneStream(testZoneData); + zoneStream.setByteOrder(QDataStream::LittleEndian); + quint32 zoneSize; + zoneStream >> zoneSize; + QVERIFY2(zoneSize + 44 == testZoneData.size(), + qPrintable("Decompression validation failed for: " + fastFilePath)); + + // Write the decompressed zone data to the exports folder with a .zone extension. + QFileInfo fi(fastFilePath); + QString outputFileName = fi.completeBaseName() + ".zone"; + QString outputFilePath = QDir(EXPORT_DIR).filePath(outputFileName); + QFile outputFile(outputFilePath); + QVERIFY2(outputFile.open(QIODevice::WriteOnly), + qPrintable("Failed to open output file for writing: " + outputFilePath)); + outputFile.write(testZoneData); + outputFile.close(); +} + +void AutoTest_COD4_Wii::testCompression_data() { + AutoTest_COD::testCompression_data(); +} + +void AutoTest_COD4_Wii::testCompression() { + QFETCH(QString, zoneFilePath); + + QFile zoneFile(zoneFilePath); + QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath)); + QByteArray decompressedData = zoneFile.readAll(); + zoneFile.close(); + + QFileInfo fi(zoneFilePath); + QString originalFFPath = QDir(getFastFileDirectory()).filePath(fi.completeBaseName() + ".ff"); + + QFile originalFile(originalFFPath); + QVERIFY2(originalFile.open(QIODevice::ReadOnly), qPrintable("Failed to open original .ff file: " + originalFFPath)); + QByteArray originalFFData = originalFile.readAll(); + originalFile.close(); + + QByteArray header = originalFFData.left(12); + + QByteArray newCompressedData;// = Compressor::CompressZLIB(decompressedData, Z_BEST_COMPRESSION); + newCompressedData = Compression::CompressZLIBWithSettings(decompressedData, Z_BEST_COMPRESSION, MAX_WBITS, 8, Z_DEFAULT_STRATEGY, {}); + + int remainder = (newCompressedData.size() + 12) % 32; + if (remainder != 0) { + int paddingNeeded = 32 - remainder; + newCompressedData.append(QByteArray(paddingNeeded, '\0')); + } + + QByteArray recompressedData = header + newCompressedData; + + QString recompressedFilePath = QDir(EXPORT_DIR).filePath(fi.completeBaseName() + ".ff"); + QFile recompressedFile(recompressedFilePath); + QVERIFY2(recompressedFile.open(QIODevice::WriteOnly), qPrintable("Failed to write recompressed file.")); + recompressedFile.write(recompressedData); + recompressedFile.close(); + + QCOMPARE(recompressedData, originalFFData); +} + +void AutoTest_COD4_Wii::testFactory_data() { + AutoTest_COD::testFactory_data(); +} + +void AutoTest_COD4_Wii::testFactory() { + QFETCH(QString, fastFilePath); + + const QString testName = "Factory ingest: " + fastFilePath; + + std::shared_ptr fastFile = FastFileFactory::Create(fastFilePath); + + const QString game = fastFile->GetGame(); + bool correctGame = game == "COD7"; + if (!correctGame) { + recordResult(testName, false); + } + QVERIFY2(correctGame + , qPrintable("Factory parsed wrong game [" + game + "] for fastfile: " + fastFilePath)); + + const QString platform = fastFile->GetPlatform(); + bool correctPlatform = platform == "Wii"; + if (!correctPlatform) { + recordResult(testName, false); + } + QVERIFY2(correctPlatform + , qPrintable("Factory parsed wrong platform [" + platform + "] for fastfile: " + fastFilePath)); + + recordResult(testName, true); +} + +void AutoTest_COD4_Wii::cleanupTestCase() { + // Any cleanup if necessary. +} + +// Don't generate a main() function +#include "AutoTest_COD4_Wii.moc" diff --git a/tests/Wii/autotest_cod7_wii.cpp b/tests/Wii/autotest_cod7_wii.cpp index 69948a5..c3a4251 100644 --- a/tests/Wii/autotest_cod7_wii.cpp +++ b/tests/Wii/autotest_cod7_wii.cpp @@ -12,12 +12,16 @@ class AutoTest_COD7_Wii : public AutoTest_COD { private slots: void initTestCase(); - // Data-driven test for decompression + void testDecompression_data(); void testDecompression(); - // Data-driven test for recompression (compression) + void testCompression_data(); void testCompression(); + + void testFactory_data(); + void testFactory(); + void cleanupTestCase(); }; @@ -27,22 +31,16 @@ void AutoTest_COD7_Wii::initTestCase() { } void AutoTest_COD7_Wii::testDecompression_data() { - QTest::addColumn("fastFilePath_cod7_wii"); - - QStringList ffFiles = findFastFiles(getFastFileDirectory()); - for (const QString &filePath : ffFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testDecompression_data(); } void AutoTest_COD7_Wii::testDecompression() { - QFETCH(QString, fastFilePath_cod7_wii); + QFETCH(QString, fastFilePath); // Open the original .ff file. - QFile testFastFile(fastFilePath_cod7_wii); + QFile testFastFile(fastFilePath); QVERIFY2(testFastFile.open(QIODevice::ReadOnly), - qPrintable("Failed to open test fastfile: " + fastFilePath_cod7_wii)); + qPrintable("Failed to open test fastfile: " + fastFilePath)); const QByteArray testFFData = testFastFile.readAll(); testFastFile.close(); @@ -56,10 +54,10 @@ void AutoTest_COD7_Wii::testDecompression() { quint32 zoneSize; zoneStream >> zoneSize; QVERIFY2(zoneSize + 44 == testZoneData.size(), - qPrintable("Decompression validation failed for: " + fastFilePath_cod7_wii)); + qPrintable("Decompression validation failed for: " + fastFilePath)); // Write the decompressed zone data to the exports folder with a .zone extension. - QFileInfo fi(fastFilePath_cod7_wii); + QFileInfo fi(fastFilePath); QString outputFileName = fi.completeBaseName() + ".zone"; QString outputFilePath = QDir(EXPORT_DIR).filePath(outputFileName); QFile outputFile(outputFilePath); @@ -70,24 +68,18 @@ void AutoTest_COD7_Wii::testDecompression() { } void AutoTest_COD7_Wii::testCompression_data() { - QTest::addColumn("zoneFilePath_cod7_wii"); - - QStringList zoneFiles = findZoneFiles(getZoneFileDirectory()); - for (const QString &filePath : zoneFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testCompression_data(); } void AutoTest_COD7_Wii::testCompression() { - QFETCH(QString, zoneFilePath_cod2_360); + QFETCH(QString, zoneFilePath); - QFile zoneFile(zoneFilePath_cod2_360); - QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath_cod2_360)); + QFile zoneFile(zoneFilePath); + QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath)); QByteArray decompressedData = zoneFile.readAll(); zoneFile.close(); - QFileInfo fi(zoneFilePath_cod2_360); + QFileInfo fi(zoneFilePath); QString originalFFPath = QDir(getFastFileDirectory()).filePath(fi.completeBaseName() + ".ff"); QFile originalFile(originalFFPath); @@ -117,6 +109,36 @@ void AutoTest_COD7_Wii::testCompression() { QCOMPARE(recompressedData, originalFFData); } +void AutoTest_COD7_Wii::testFactory_data() { + AutoTest_COD::testFactory_data(); +} + +void AutoTest_COD7_Wii::testFactory() { + QFETCH(QString, fastFilePath); + + const QString testName = "Factory ingest: " + fastFilePath; + + std::shared_ptr fastFile = FastFileFactory::Create(fastFilePath); + + const QString game = fastFile->GetGame(); + bool correctGame = game == "COD7"; + if (!correctGame) { + recordResult(testName, false); + } + QVERIFY2(correctGame + , qPrintable("Factory parsed wrong game [" + game + "] for fastfile: " + fastFilePath)); + + const QString platform = fastFile->GetPlatform(); + bool correctPlatform = platform == "Wii"; + if (!correctPlatform) { + recordResult(testName, false); + } + QVERIFY2(correctPlatform + , qPrintable("Factory parsed wrong platform [" + platform + "] for fastfile: " + fastFilePath)); + + recordResult(testName, true); +} + void AutoTest_COD7_Wii::cleanupTestCase() { // Any cleanup if necessary. } diff --git a/tests/Wii/autotest_cod8_wii.cpp b/tests/Wii/autotest_cod8_wii.cpp new file mode 100644 index 0000000..fce0ccc --- /dev/null +++ b/tests/Wii/autotest_cod8_wii.cpp @@ -0,0 +1,147 @@ +#include +#include +#include + +#include "autotest_cod.h" +#include "compression.h" + +class AutoTest_COD8_Wii : public AutoTest_COD { + Q_OBJECT + + const QString EXPORT_DIR = "./exports/cod7/Wii"; + +private slots: + void initTestCase(); + + void testDecompression_data(); + void testDecompression(); + + void testCompression_data(); + void testCompression(); + + void testFactory_data(); + void testFactory(); + + void cleanupTestCase(); +}; + +void AutoTest_COD8_Wii::initTestCase() { + // Ensure the exports directory exists. + createDirectory(EXPORT_DIR); +} + +void AutoTest_COD8_Wii::testDecompression_data() { + AutoTest_COD::testDecompression_data(); +} + +void AutoTest_COD8_Wii::testDecompression() { + QFETCH(QString, fastFilePath); + + // Open the original .ff file. + QFile testFastFile(fastFilePath); + QVERIFY2(testFastFile.open(QIODevice::ReadOnly), + qPrintable("Failed to open test fastfile: " + fastFilePath)); + const QByteArray testFFData = testFastFile.readAll(); + testFastFile.close(); + + // Assume the first 12 bytes are a header; the rest is zlib-compressed zone data. + const QByteArray compressedData = testFFData.mid(12); + const QByteArray testZoneData = Compression::DecompressZLIB(compressedData); + + // Verify the decompressed data via its embedded zone size. + QDataStream zoneStream(testZoneData); + zoneStream.setByteOrder(QDataStream::LittleEndian); + quint32 zoneSize; + zoneStream >> zoneSize; + QVERIFY2(zoneSize + 44 == testZoneData.size(), + qPrintable("Decompression validation failed for: " + fastFilePath)); + + // Write the decompressed zone data to the exports folder with a .zone extension. + QFileInfo fi(fastFilePath); + QString outputFileName = fi.completeBaseName() + ".zone"; + QString outputFilePath = QDir(EXPORT_DIR).filePath(outputFileName); + QFile outputFile(outputFilePath); + QVERIFY2(outputFile.open(QIODevice::WriteOnly), + qPrintable("Failed to open output file for writing: " + outputFilePath)); + outputFile.write(testZoneData); + outputFile.close(); +} + +void AutoTest_COD8_Wii::testCompression_data() { + AutoTest_COD::testCompression_data(); +} + +void AutoTest_COD8_Wii::testCompression() { + QFETCH(QString, zoneFilePath); + + QFile zoneFile(zoneFilePath); + QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath)); + QByteArray decompressedData = zoneFile.readAll(); + zoneFile.close(); + + QFileInfo fi(zoneFilePath); + QString originalFFPath = QDir(getFastFileDirectory()).filePath(fi.completeBaseName() + ".ff"); + + QFile originalFile(originalFFPath); + QVERIFY2(originalFile.open(QIODevice::ReadOnly), qPrintable("Failed to open original .ff file: " + originalFFPath)); + QByteArray originalFFData = originalFile.readAll(); + originalFile.close(); + + QByteArray header = originalFFData.left(12); + + QByteArray newCompressedData;// = Compressor::CompressZLIB(decompressedData, Z_BEST_COMPRESSION); + newCompressedData = Compression::CompressZLIBWithSettings(decompressedData, Z_BEST_COMPRESSION, MAX_WBITS, 8, Z_DEFAULT_STRATEGY, {}); + + int remainder = (newCompressedData.size() + 12) % 32; + if (remainder != 0) { + int paddingNeeded = 32 - remainder; + newCompressedData.append(QByteArray(paddingNeeded, '\0')); + } + + QByteArray recompressedData = header + newCompressedData; + + QString recompressedFilePath = QDir(EXPORT_DIR).filePath(fi.completeBaseName() + ".ff"); + QFile recompressedFile(recompressedFilePath); + QVERIFY2(recompressedFile.open(QIODevice::WriteOnly), qPrintable("Failed to write recompressed file.")); + recompressedFile.write(recompressedData); + recompressedFile.close(); + + QCOMPARE(recompressedData, originalFFData); +} + +void AutoTest_COD8_Wii::testFactory_data() { + AutoTest_COD::testFactory_data(); +} + +void AutoTest_COD8_Wii::testFactory() { + QFETCH(QString, fastFilePath); + + const QString testName = "Factory ingest: " + fastFilePath; + + std::shared_ptr fastFile = FastFileFactory::Create(fastFilePath); + + const QString game = fastFile->GetGame(); + bool correctGame = game == "COD7"; + if (!correctGame) { + recordResult(testName, false); + } + QVERIFY2(correctGame + , qPrintable("Factory parsed wrong game [" + game + "] for fastfile: " + fastFilePath)); + + const QString platform = fastFile->GetPlatform(); + bool correctPlatform = platform == "Wii"; + if (!correctPlatform) { + recordResult(testName, false); + } + QVERIFY2(correctPlatform + , qPrintable("Factory parsed wrong platform [" + platform + "] for fastfile: " + fastFilePath)); + + recordResult(testName, true); +} + +void AutoTest_COD8_Wii::cleanupTestCase() { + // Any cleanup if necessary. +} + +// Don't generate a main() function +#include "AutoTest_COD8_Wii.moc" diff --git a/tests/WiiU/autotest_cod10_wiiu.cpp b/tests/WiiU/autotest_cod10_wiiu.cpp index ec487f4..2eb61b0 100644 --- a/tests/WiiU/autotest_cod10_wiiu.cpp +++ b/tests/WiiU/autotest_cod10_wiiu.cpp @@ -12,12 +12,16 @@ class AutoTest_COD10_WiiU : public AutoTest_COD { private slots: void initTestCase(); - // Data-driven test for decompression + void testDecompression_data(); void testDecompression(); - // Data-driven test for recompression (compression) + void testCompression_data(); void testCompression(); + + void testFactory_data(); + void testFactory(); + void cleanupTestCase(); }; @@ -27,22 +31,16 @@ void AutoTest_COD10_WiiU::initTestCase() { } void AutoTest_COD10_WiiU::testDecompression_data() { - QTest::addColumn("fastFilePath_cod10_wiiu"); - - QStringList ffFiles = findFastFiles(getFastFileDirectory()); - for (const QString &filePath : ffFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testDecompression_data(); } void AutoTest_COD10_WiiU::testDecompression() { - QFETCH(QString, fastFilePath_cod10_wiiu); + QFETCH(QString, fastFilePath); // Open the original .ff file. - QFile testFastFile(fastFilePath_cod10_wiiu); + QFile testFastFile(fastFilePath); QVERIFY2(testFastFile.open(QIODevice::ReadOnly), - qPrintable("Failed to open test fastfile: " + fastFilePath_cod10_wiiu)); + qPrintable("Failed to open test fastfile: " + fastFilePath)); const QByteArray testFFData = testFastFile.readAll(); testFastFile.close(); @@ -56,10 +54,10 @@ void AutoTest_COD10_WiiU::testDecompression() { quint32 zoneSize; zoneStream >> zoneSize; QVERIFY2(zoneSize + 44 == testZoneData.size(), - qPrintable("Decompression validation failed for: " + fastFilePath_cod10_wiiu)); + qPrintable("Decompression validation failed for: " + fastFilePath)); // Write the decompressed zone data to the exports folder with a .zone extension. - QFileInfo fi(fastFilePath_cod10_wiiu); + QFileInfo fi(fastFilePath); QString outputFileName = fi.completeBaseName() + ".zone"; QString outputFilePath = QDir(EXPORT_DIR).filePath(outputFileName); QFile outputFile(outputFilePath); @@ -70,24 +68,18 @@ void AutoTest_COD10_WiiU::testDecompression() { } void AutoTest_COD10_WiiU::testCompression_data() { - QTest::addColumn("zoneFilePath_cod10_wiiu"); - - QStringList zoneFiles = findZoneFiles(getZoneFileDirectory()); - for (const QString &filePath : zoneFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testCompression_data(); } void AutoTest_COD10_WiiU::testCompression() { - QFETCH(QString, zoneFilePath_cod10_wiiu); + QFETCH(QString, zoneFilePath); - QFile zoneFile(zoneFilePath_cod10_wiiu); - QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath_cod10_wiiu)); + QFile zoneFile(zoneFilePath); + QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath)); QByteArray decompressedData = zoneFile.readAll(); zoneFile.close(); - QFileInfo fi(zoneFilePath_cod10_wiiu); + QFileInfo fi(zoneFilePath); QString originalFFPath = QDir(getFastFileDirectory()).filePath(fi.completeBaseName() + ".ff"); QFile originalFile(originalFFPath); @@ -117,6 +109,36 @@ void AutoTest_COD10_WiiU::testCompression() { QCOMPARE(recompressedData, originalFFData); } +void AutoTest_COD10_WiiU::testFactory_data() { + AutoTest_COD::testFactory_data(); +} + +void AutoTest_COD10_WiiU::testFactory() { + QFETCH(QString, fastFilePath); + + const QString testName = "Factory ingest: " + fastFilePath; + + std::shared_ptr fastFile = FastFileFactory::Create(fastFilePath); + + const QString game = fastFile->GetGame(); + bool correctGame = game == "COD10"; + if (!correctGame) { + recordResult(testName, false); + } + QVERIFY2(correctGame + , qPrintable("Factory parsed wrong game [" + game + "] for fastfile: " + fastFilePath)); + + const QString platform = fastFile->GetPlatform(); + bool correctPlatform = platform == "WiiU"; + if (!correctPlatform) { + recordResult(testName, false); + } + QVERIFY2(correctPlatform + , qPrintable("Factory parsed wrong platform [" + platform + "] for fastfile: " + fastFilePath)); + + recordResult(testName, true); +} + void AutoTest_COD10_WiiU::cleanupTestCase() { // Any cleanup if necessary. } diff --git a/tests/WiiU/autotest_cod9_wiiu.cpp b/tests/WiiU/autotest_cod9_wiiu.cpp index 819f170..8025fc6 100644 --- a/tests/WiiU/autotest_cod9_wiiu.cpp +++ b/tests/WiiU/autotest_cod9_wiiu.cpp @@ -12,12 +12,16 @@ class AutoTest_COD9_WiiU : public AutoTest_COD { private slots: void initTestCase(); - // Data-driven test for decompression + void testDecompression_data(); void testDecompression(); - // Data-driven test for recompression (compression) + void testCompression_data(); void testCompression(); + + void testFactory_data(); + void testFactory(); + void cleanupTestCase(); }; @@ -27,22 +31,16 @@ void AutoTest_COD9_WiiU::initTestCase() { } void AutoTest_COD9_WiiU::testDecompression_data() { - QTest::addColumn("fastFilePath_cod9_wiiu"); - - QStringList ffFiles = findFastFiles(getFastFileDirectory()); - for (const QString &filePath : ffFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testDecompression_data(); } void AutoTest_COD9_WiiU::testDecompression() { - QFETCH(QString, fastFilePath_cod9_wiiu); + QFETCH(QString, fastFilePath); // Open the original .ff file. - QFile testFastFile(fastFilePath_cod9_wiiu); + QFile testFastFile(fastFilePath); QVERIFY2(testFastFile.open(QIODevice::ReadOnly), - qPrintable("Failed to open test fastfile: " + fastFilePath_cod9_wiiu)); + qPrintable("Failed to open test fastfile: " + fastFilePath)); const QByteArray testFFData = testFastFile.readAll(); testFastFile.close(); @@ -56,10 +54,10 @@ void AutoTest_COD9_WiiU::testDecompression() { quint32 zoneSize; zoneStream >> zoneSize; QVERIFY2(zoneSize + 44 == testZoneData.size(), - qPrintable("Decompression validation failed for: " + fastFilePath_cod9_wiiu)); + qPrintable("Decompression validation failed for: " + fastFilePath)); // Write the decompressed zone data to the exports folder with a .zone extension. - QFileInfo fi(fastFilePath_cod9_wiiu); + QFileInfo fi(fastFilePath); QString outputFileName = fi.completeBaseName() + ".zone"; QString outputFilePath = QDir(EXPORT_DIR).filePath(outputFileName); QFile outputFile(outputFilePath); @@ -70,24 +68,18 @@ void AutoTest_COD9_WiiU::testDecompression() { } void AutoTest_COD9_WiiU::testCompression_data() { - QTest::addColumn("zoneFilePath_cod9_wiiu"); - - QStringList zoneFiles = findZoneFiles(getZoneFileDirectory()); - for (const QString &filePath : zoneFiles) { - QString fileName = QFileInfo(filePath).fileName(); - QTest::newRow(qPrintable(fileName)) << filePath; - } + AutoTest_COD::testCompression_data(); } void AutoTest_COD9_WiiU::testCompression() { - QFETCH(QString, zoneFilePath_cod9_wiiu); + QFETCH(QString, zoneFilePath); - QFile zoneFile(zoneFilePath_cod9_wiiu); - QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath_cod9_wiiu)); + QFile zoneFile(zoneFilePath); + QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath)); QByteArray decompressedData = zoneFile.readAll(); zoneFile.close(); - QFileInfo fi(zoneFilePath_cod9_wiiu); + QFileInfo fi(zoneFilePath); QString originalFFPath = QDir(getFastFileDirectory()).filePath(fi.completeBaseName() + ".ff"); QFile originalFile(originalFFPath); @@ -117,6 +109,36 @@ void AutoTest_COD9_WiiU::testCompression() { QCOMPARE(recompressedData, originalFFData); } +void AutoTest_COD9_WiiU::testFactory_data() { + AutoTest_COD::testFactory_data(); +} + +void AutoTest_COD9_WiiU::testFactory() { + QFETCH(QString, fastFilePath); + + const QString testName = "Factory ingest: " + fastFilePath; + + std::shared_ptr fastFile = FastFileFactory::Create(fastFilePath); + + const QString game = fastFile->GetGame(); + bool correctGame = game == "COD9"; + if (!correctGame) { + recordResult(testName, false); + } + QVERIFY2(correctGame + , qPrintable("Factory parsed wrong game [" + game + "] for fastfile: " + fastFilePath)); + + const QString platform = fastFile->GetPlatform(); + bool correctPlatform = platform == "WiiU"; + if (!correctPlatform) { + recordResult(testName, false); + } + QVERIFY2(correctPlatform + , qPrintable("Factory parsed wrong platform [" + platform + "] for fastfile: " + fastFilePath)); + + recordResult(testName, true); +} + void AutoTest_COD9_WiiU::cleanupTestCase() { // Any cleanup if necessary. } diff --git a/tests/autotest_cod.h b/tests/autotest_cod.h index acb47d7..5f09702 100644 --- a/tests/autotest_cod.h +++ b/tests/autotest_cod.h @@ -3,6 +3,8 @@ #include +#include "fastfile_factory.h" + #define FILE_MAX 1 class AutoTest_COD : public QObject { @@ -36,41 +38,93 @@ public: QDir newDir("."); newDir.mkpath(aDir); } - QStringList findFastFiles(const QString &aBaseDir, int aMaxIter = MAX_ITER) { - QStringList fastFiles; - - QDirIterator it(aBaseDir, QStringList() << "*.ff", QDir::Files, QDirIterator::Subdirectories); - - int i = 0; - while (it.hasNext() && i < aMaxIter) { - fastFiles << it.next(); - ++i; - } - - return fastFiles; - } - QStringList findZoneFiles(const QString &aBaseDir, int aMaxIter = MAX_ITER) { - QStringList zoneFiles; + QStringList findZoneFiles(const QString &aBaseDir, int aMaxIter = FILE_MAX) { + QList> fileList; QDirIterator it(aBaseDir, QStringList() << "*.zone", QDir::Files, QDirIterator::Subdirectories); - int i = 0; while (it.hasNext() && i < aMaxIter) { - zoneFiles << it.next(); + QString path = it.next(); + QFileInfo fi(path); + fileList.append(qMakePair(fi.size(), path)); ++i; } - return zoneFiles; + std::sort(fileList.begin(), fileList.end(), + [](const QPair &a, const QPair &b) { + return a.first < b.first; // sort by size + }); + + QStringList sorted; + for (const auto &pair : fileList) + sorted << pair.second; + + return sorted; } + + QStringList findFastFiles(const QString &aBaseDir, int aMaxIter = FILE_MAX) { + QList> fileList; + + QDirIterator it(aBaseDir, QStringList() << "*.ff", QDir::Files, QDirIterator::Subdirectories); + int i = 0; + while (it.hasNext() && i < aMaxIter) { + QString path = it.next(); + QFileInfo fi(path); + fileList.append(qMakePair(fi.size(), path)); + ++i; + } + + std::sort(fileList.begin(), fileList.end(), + [](const QPair &a, const QPair &b) { + return a.first < b.first; // sort by size + }); + + QStringList sorted; + for (const auto &pair : fileList) + sorted << pair.second; + + return sorted; + } + virtual void initTestCase() = 0; - virtual void testDecompression_data() = 0; + + void testDecompression_data() { + QTest::addColumn("fastFilePath"); + + QStringList ffFiles = findFastFiles(getFastFileDirectory()); + for (const QString &filePath : ffFiles) { + QString fileName = QFileInfo(filePath).fileName(); + QTest::newRow(qPrintable(fileName)) << filePath; + } + } virtual void testDecompression() = 0; - virtual void testCompression_data() = 0; + + void testCompression_data() { + QTest::addColumn("zoneFilePath"); + + QStringList zoneFiles = findZoneFiles(getZoneFileDirectory()); + for (const QString &filePath : zoneFiles) { + QString fileName = QFileInfo(filePath).fileName(); + QTest::newRow(qPrintable(fileName)) << filePath; + break; + } + } virtual void testCompression() = 0; + + void testFactory_data() { + QTest::addColumn("fastFilePath"); + + QStringList ffFiles = findFastFiles(getFastFileDirectory()); + for (const QString &filePath : ffFiles) { + QString fileName = QFileInfo(filePath).fileName(); + QTest::newRow(qPrintable(fileName)) << filePath; + } + } + virtual void testFactory() = 0; + virtual void cleanupTestCase() = 0; private: - static const int MAX_ITER = 10000; QString mFastFileDirectory; QString mZoneFileDirectory; }; diff --git a/tests/test_main.cpp b/tests/test_main.cpp index acf3b48..2fc99fd 100644 --- a/tests/test_main.cpp +++ b/tests/test_main.cpp @@ -32,7 +32,9 @@ #include "PS3/autotest_cod11_ps3.cpp" #include "PS3/autotest_cod12_ps3.cpp" +#include "Wii/autotest_cod4_wii.cpp" #include "Wii/autotest_cod7_wii.cpp" +#include "Wii/autotest_cod8_wii.cpp" #include "WiiU/autotest_cod9_wiiu.cpp" #include "WiiU/autotest_cod10_wiiu.cpp" @@ -47,10 +49,10 @@ // individual games #define TEST_COD2 0 #define TEST_COD4 0 -#define TEST_COD5 1 +#define TEST_COD5 0 #define TEST_COD6 0 #define TEST_COD7 0 -#define TEST_COD8 0 +#define TEST_COD8 1 #define TEST_COD9 0 #define TEST_COD10 0 #define TEST_COD11 0 @@ -185,7 +187,7 @@ int main(int argc, char *argv[]) { AutoTest_COD8_PC *test_cod8_pc = new AutoTest_COD8_PC(); test_cod8_pc->setFastFileDirectory("G:/Fast Files/PC/COD8"); test_cod8_pc->setZoneFileDirectory("./exports/cod8/PC"); - //cod8Tests << test_cod8_pc; + cod8Tests << test_cod8_pc; pcTests << test_cod8_pc; AutoTest_COD9_PC *test_cod9_pc = new AutoTest_COD9_PC(); @@ -225,7 +227,7 @@ int main(int argc, char *argv[]) { AutoTest_COD5_PS3 *test_cod5_ps3 = new AutoTest_COD5_PS3(); test_cod5_ps3->setFastFileDirectory("G:/Fast Files/PS3/COD5"); test_cod5_ps3->setZoneFileDirectory("./exports/cod5/PS3"); - //cod5Tests << test_cod5_ps3; + cod5Tests << test_cod5_ps3; ps3Tests << test_cod5_ps3; AutoTest_COD6_PS3 *test_cod6_ps3 = new AutoTest_COD6_PS3(); @@ -243,7 +245,7 @@ int main(int argc, char *argv[]) { AutoTest_COD8_PS3 *test_cod8_ps3 = new AutoTest_COD8_PS3(); test_cod8_ps3->setFastFileDirectory("G:/Fast Files/PS3/COD8"); test_cod8_ps3->setZoneFileDirectory("./exports/cod8/PS3"); - //cod8Tests << test_cod8_ps3; + cod8Tests << test_cod8_ps3; ps3Tests << test_cod8_ps3; AutoTest_COD9_PS3 *test_cod9_ps3 = new AutoTest_COD9_PS3(); @@ -274,12 +276,24 @@ int main(int argc, char *argv[]) { /********* Wii COD TESTS *********/ /**********************************/ + AutoTest_COD4_Wii *test_cod4_wii = new AutoTest_COD4_Wii(); + test_cod4_wii->setFastFileDirectory("G:/Fast Files/Wii/COD4"); + test_cod4_wii->setZoneFileDirectory("./exports/cod4/Wii"); + cod4Tests << test_cod4_wii; + wiiTests << test_cod4_wii; + AutoTest_COD7_Wii *test_cod7_wii = new AutoTest_COD7_Wii(); test_cod7_wii->setFastFileDirectory("G:/Fast Files/Wii/COD7"); test_cod7_wii->setZoneFileDirectory("./exports/cod7/Wii"); cod7Tests << test_cod7_wii; wiiTests << test_cod7_wii; + AutoTest_COD8_Wii *test_cod8_wii = new AutoTest_COD8_Wii(); + test_cod8_wii->setFastFileDirectory("G:/Fast Files/Wii/COD8"); + test_cod8_wii->setZoneFileDirectory("./exports/cod8/Wii"); + cod8Tests << test_cod8_wii; + wiiTests << test_cod8_wii; + /**********************************/ /********* WiiU COD TESTS *********/ /**********************************/ @@ -309,87 +323,101 @@ int main(int argc, char *argv[]) { qDebug() << "-- RUNNING TEST_COD4 --"; foreach (auto test, cod4Tests) { QTest::qExec(test, argc, argv); + allResults.append({ test->metaObject()->className(), test->getCollectedTestResults() }); } } if (TEST_EVERYTHING || TEST_ALL_COD_GAMES || TEST_COD5) { qDebug() << "-- RUNNING TEST_COD5 --"; foreach (auto test, cod5Tests) { QTest::qExec(test, argc, argv); + allResults.append({ test->metaObject()->className(), test->getCollectedTestResults() }); } } if (TEST_EVERYTHING || TEST_ALL_COD_GAMES || TEST_COD6) { qDebug() << "-- RUNNING TEST_COD6 --"; foreach (auto test, cod6Tests) { QTest::qExec(test, argc, argv); + allResults.append({ test->metaObject()->className(), test->getCollectedTestResults() }); } } if (TEST_EVERYTHING || TEST_ALL_COD_GAMES || TEST_COD7) { qDebug() << "-- RUNNING TEST_COD7 --"; foreach (auto test, cod7Tests) { QTest::qExec(test, argc, argv); + allResults.append({ test->metaObject()->className(), test->getCollectedTestResults() }); } } if (TEST_EVERYTHING || TEST_ALL_COD_GAMES || TEST_COD8) { qDebug() << "-- RUNNING TEST_COD8 --"; foreach (auto test, cod8Tests) { QTest::qExec(test, argc, argv); + allResults.append({ test->metaObject()->className(), test->getCollectedTestResults() }); } } if (TEST_EVERYTHING || TEST_ALL_COD_GAMES || TEST_COD9) { qDebug() << "-- RUNNING TEST_COD9 --"; foreach (auto test, cod9Tests) { QTest::qExec(test, argc, argv); + allResults.append({ test->metaObject()->className(), test->getCollectedTestResults() }); } } if (TEST_EVERYTHING || TEST_ALL_COD_GAMES || TEST_COD10) { qDebug() << "-- RUNNING TEST_COD10 --"; foreach (auto test, cod10Tests) { QTest::qExec(test, argc, argv); + allResults.append({ test->metaObject()->className(), test->getCollectedTestResults() }); } } if (TEST_EVERYTHING || TEST_ALL_COD_GAMES || TEST_COD11) { qDebug() << "-- RUNNING TEST_COD11 --"; foreach (auto test, cod11Tests) { QTest::qExec(test, argc, argv); + allResults.append({ test->metaObject()->className(), test->getCollectedTestResults() }); } } if (TEST_EVERYTHING || TEST_ALL_COD_GAMES || TEST_COD12) { qDebug() << "-- RUNNING TEST_COD12 --"; foreach (auto test, cod12Tests) { QTest::qExec(test, argc, argv); + allResults.append({ test->metaObject()->className(), test->getCollectedTestResults() }); } } - if (TEST_EVERYTHING || TEST_ALL_PLATFORMS || TEST_360) { - qDebug() << "-- RUNNING TEST_360 --"; - foreach (auto test, xbox360Tests) { - QTest::qExec(test, argc, argv); - } - } - if (TEST_EVERYTHING || TEST_ALL_PLATFORMS || TEST_PC) { - qDebug() << "-- RUNNING TEST_PC --"; - foreach (auto test, pcTests) { - QTest::qExec(test, argc, argv); - } - } - if (TEST_EVERYTHING || TEST_ALL_PLATFORMS || TEST_PS3) { - qDebug() << "-- RUNNING TEST_PS3 --"; - foreach (auto test, ps3Tests) { - QTest::qExec(test, argc, argv); - } - } - if (TEST_EVERYTHING || TEST_ALL_PLATFORMS || TEST_WII) { - qDebug() << "-- RUNNING TEST_WII --"; - foreach (auto test, wiiTests) { - QTest::qExec(test, argc, argv); - } - } - if (TEST_EVERYTHING || TEST_ALL_PLATFORMS || TEST_WIIU) { - qDebug() << "-- RUNNING TEST_WIIU --"; - foreach (auto test, wiiUTests) { - QTest::qExec(test, argc, argv); - } - } + // if (TEST_EVERYTHING || TEST_ALL_PLATFORMS || TEST_360) { + // qDebug() << "-- RUNNING TEST_360 --"; + // foreach (auto test, xbox360Tests) { + // QTest::qExec(test, argc, argv); + // allResults.append({ test->metaObject()->className(), test->getCollectedTestResults() }); + // } + // } + // if (TEST_EVERYTHING || TEST_ALL_PLATFORMS || TEST_PC) { + // qDebug() << "-- RUNNING TEST_PC --"; + // foreach (auto test, pcTests) { + // QTest::qExec(test, argc, argv); + // allResults.append({ test->metaObject()->className(), test->getCollectedTestResults() }); + // } + // } + // if (TEST_EVERYTHING || TEST_ALL_PLATFORMS || TEST_PS3) { + // qDebug() << "-- RUNNING TEST_PS3 --"; + // foreach (auto test, ps3Tests) { + // QTest::qExec(test, argc, argv); + // allResults.append({ test->metaObject()->className(), test->getCollectedTestResults() }); + // } + // } + // if (TEST_EVERYTHING || TEST_ALL_PLATFORMS || TEST_WII) { + // qDebug() << "-- RUNNING TEST_WII --"; + // foreach (auto test, wiiTests) { + // QTest::qExec(test, argc, argv); + // allResults.append({ test->metaObject()->className(), test->getCollectedTestResults() }); + // } + // } + // if (TEST_EVERYTHING || TEST_ALL_PLATFORMS || TEST_WIIU) { + // qDebug() << "-- RUNNING TEST_WIIU --"; + // foreach (auto test, wiiUTests) { + // QTest::qExec(test, argc, argv); + // allResults.append({ test->metaObject()->className(), test->getCollectedTestResults() }); + // } + // } QJsonObject root; root["project"] = "XPlor"; diff --git a/tests/tests.pro b/tests/tests.pro index 2374a7c..c0bbfc6 100644 --- a/tests/tests.pro +++ b/tests/tests.pro @@ -43,7 +43,9 @@ SOURCES += \ PS3/autotest_cod11_ps3.cpp \ PS3/autotest_cod12_ps3.cpp \ # Wii autotests + Wii/autotest_cod4_wii.cpp \ Wii/autotest_cod7_wii.cpp \ + Wii/autotest_cod8_wii.cpp \ # WiiU autotests WiiU/autotest_cod9_wiiu.cpp \ WiiU/autotest_cod10_wiiu.cpp \ @@ -63,13 +65,6 @@ HEADERS += \ # SOURCES -= autotest_cod5.cpp # } -app.depends += \ - libs/core \ - libs/compression \ - libs/encryption \ - libs/zonefile \ - libs/fastfile - LIBS += \ -L$$OUT_PWD/../libs/ -lcore -lencryption -lcompression -lfastfile -lzonefile \ -L$$PWD/../third_party/xbox_sdk/lib -lxcompress64 @@ -90,8 +85,6 @@ DEPENDPATH += \ $$PWD/../libs/fastfile \ $$PWD/../libs/zonefile -RESOURCES += - # Copy DLLs to Debug & Release folder QMAKE_POST_LINK += xcopy /Y /E /I \"$$PWD/../third_party/xbox_sdk/lib\\*.dll\" \"$$OUT_PWD/debug/\" $$escape_expand(\\n\\t) QMAKE_POST_LINK += xcopy /Y /E /I \"$$PWD/../third_party/xbox_sdk/lib\\*.dll\" \"$$OUT_PWD/release/\" $$escape_expand(\\n\\t) From a90f1017f7e48a2d4e017ab26e3ef91d482d1f58 Mon Sep 17 00:00:00 2001 From: = Date: Sat, 17 May 2025 22:56:57 -0400 Subject: [PATCH 2/3] 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 From 87cbdeeefc5b720ab73502fae221d8ce42524e1e Mon Sep 17 00:00:00 2001 From: = Date: Sat, 17 May 2025 23:42:30 -0400 Subject: [PATCH 3/3] feat(XPlor): Add dependencies for libs in app, tests and tools projects Added dependencies for the libs in the app, tests and tools projects. This change ensures that these components depend on the correct libraries. --- XPlor.pro | 4 +++- app/app.pro | 12 ------------ data/icons/Icon_COD10.png | Bin 0 -> 2945 bytes data/icons/Icon_COD11.png | Bin 0 -> 2080 bytes data/icons/Icon_COD12.png | Bin 0 -> 2483 bytes tools/zentry/zentry.pro | 5 ----- 6 files changed, 3 insertions(+), 18 deletions(-) create mode 100644 data/icons/Icon_COD10.png create mode 100644 data/icons/Icon_COD11.png create mode 100644 data/icons/Icon_COD12.png diff --git a/XPlor.pro b/XPlor.pro index 6ab867d..4cf1c89 100644 --- a/XPlor.pro +++ b/XPlor.pro @@ -5,4 +5,6 @@ SUBDIRS += libs \ tools \ tests -QMAKE_PRE_BUILD += make clean +tests.depends = libs +app.depends = libs +tools.depends = libs diff --git a/app/app.pro b/app/app.pro index 362fc8c..f10aa63 100644 --- a/app/app.pro +++ b/app/app.pro @@ -60,18 +60,6 @@ FORMS += \ RESOURCES += ../data/data.qrc -app.depends += \ - libs/core \ - libs/compression \ - libs/encryption \ - libs/fastfile \ - libs/ddsfile \ - libs/ipakfile \ - libs/iwifile \ - libs/zonefile - -QMAKE_PRE_BUILD += make clean - LIBS += \ -L$$PWD/../third_party/devil_sdk/lib/ -lDevIL -lILU -lILUT \ -L$$PWD/../third_party/zlib/lib/ -lzlib \ diff --git a/data/icons/Icon_COD10.png b/data/icons/Icon_COD10.png new file mode 100644 index 0000000000000000000000000000000000000000..3f1cd3d18b3736d65e5ace235b0af8c0f98ef8b9 GIT binary patch literal 2945 zcmV-{3x4#8P)L9zP!SgqB@2k)6_opsOF$45K~Y3e2!cvHP$LE+ifFQGB;vgbYOGxjK~z8y z5AH+!?)$!Rdft28^XAPABdOi}R&`C)^mqF8_w&Bp{q1k}eDHxpK8Y)X|K=jKmy*8j zV4nf#>yGs~h`#Pnp8@FWj`Ver1u!nY9F`q^1d*rfA?ZQ`1b$x&_L&c1d_sAjcif}^ z(D2lv=kTJn8(7lT(FsY13Sg9NFbr9?55}y&-RFk%8h|f$RKndS?M%a^($vxpb377w z2v`j5#N_Q2V3{cIRTC2{VE@%dD64OUmiA6)eBA=K?^nUP-6vttf*2U#mD@W2PThH} z$au9pdG-QE%?|{#nLaRd>{x;z-e9d=;18_W0Lp6TmUL{Ohxd{eYdBfBd8)4^>Lg?y#BhpDaSO6b>xf=S- zUJGNQ{-Nl>e@(B3Qh}#gt=`PF;m$)4>MiArZ|!^|?G`09b z>%;tVYN7TO+aMNz+*199BTC4QY`%>F3u5&HVDn8i)mUKSAp&5qOPc7177;gKi0fWb zFD%lB%-a0`u2!|mc3cWzYH}s?ynU-TfLd-&Qn#aIP9gwY4?Ut9Te5BsF=}-9RqDrs zT~aCI@jG?>`1mr|b?G^@cj+F(QUJ*p8}v3_EsFwosD{GqK;;0uPduR-vhz>U`c`$7 zC8rOW5;Bsef&bb|l{ za3Qn4BJ=>S?`UsCu@6ilI=I}KJEuVW;Y&>2PZkF8dUBI8wF>k|=A3}U!%P5{+#7P^ zTwGXi$?7ctS=U}r^>qy|Nj(;Iz=M+|OIB^zORXxh0I)oIDIT*&&Rih?J`TA|^n6ax z22NQPLnc9E0bH(Vrs|IuUM2PYti+QWYiZq@l~44?M3*Q7kXhU)Y6JtJ362rGVdhS| zh~72HlGeoO^_%WNU}*zz{cZ*LCS)<|gmXY;13j*z_M9N~=8ii>MqDbB2gVAonE=p@ zo7==RYdO~o-*p@u!%`vU*e$qMM|Ung=kJ1m$%g`f?z?(pCf}L4+~$cTLJ#PE(?iv- zh)yTh9*l=AmE);^e7Z|j?=bxiMI#0qQe6Mve>P3S>L`8mKDEBt3@`lwcyeoTWi36nP%dA+1rx0t;CG{^!iUp5c;kn;AEnwD;gioB zkDu!AoU+&e)E+R;YYVe}l5->zz*w#nKWJh8#%$VZ)o-S)(GNhvkI$G53Z=QF6|7yj zu|3@rhPY+QuC>CV3&6sFBxe2ROV|LUE0<7&QKMo2m;hBOm>b0PAGgXwTr+wF07iQ( zVR?WrWB($Q5jKAM0hpQcfXco+c>D~4ld{1vbT>q&=0JOgI9MtzdkFn!c!JqBN@u1>ZvawvYJAnq#ni!qi7o`3!}d@Qa*a&m>-*1-d@lejx0Wl~Y3dC? z8VZX7oLPQkqARI6>-wD(hq{<0Hsh8W^)N9NfW>Q*sqb?y+ywX7 z4C4WK9H(bgoZML3VdrmYBgWVTsdQ!5Tw?%Wnyaa$P4pcmNCwaL?i~Puj2)b|M5i6Y zTPC|iF?D+j046(yf}yUZQw0ATlX<{!Yd@w@cwj0O3){6O1t653o*r-tO(Dju-gLlt z0E;r|w`%DW$uue`PaJ#W{y;qkybl1vWCuRaC+&jq0KQ0~XHsoBK|I+J3I;=R=K{S6 z;L^?eq8%nCJA(7*&5+&zut$@NcA&nPOj-DfWx`H8H0POs?Yc(FX-^1r= zj2gHwj!$<5<+3wS!>oPv1CUlEezTbBn&`YpnAXID3Txnd(R z9{2uo#w!7UZZXiK75wcTS#uDU8$sVf*B_-5dA@mw;B$>J3dP^%VRly?i!_c z`~Cw`FLz^034k;Any7kV03^MU_Ke{%5h=%szT8XE3BV`eTPnhv6kWux08*Lxb)0H7 zu#Gkf04phrbJ0i}e-Z$x+q27{Z?>S!_ufj{V_ohr$ODAB1*LQ+H>91^84fD};INP0 zm!L$as?P^C?X$)|<|hVOdFqS-4E6vl`xxnH)y<4|S8CQ38w>z*{Vg4I!n32Z3)~`8 zRl{IuI;=VNn7LeEyHl=-0l4MaC;-|#AnqLP0fkpeiSFPf>=i)?0Mt7zGa*;h)Nw|# z(_knXPr-A+7}EfVK0^l|KV82^bO$clVibTCN9de`5z8{D#-rq46fVR6r+5|U1QmqA-!&9-=SXpzwXuw1;O9Kx>bLeU0jR6wC=0I(9Mc#}j)T1;O6 zcwX^q)l=qggo5`5h5LV{2ex`og8nCKp{avjdScUai5}h>?=1jWCWQY4=Wmv2HU41! zWs&g%?c>2BQa&%C7(m&>IzH)9@~>)m)y%%Vi6=9{GXy1fbcM+ZX<_LPUvmP!irCM` z_=Q(WAphsvyvqy6JQj23-7wPstRmwT0njCwryK7OMvTWR^-3PBx@SxqFSnx{6>ts) zF5bfY9lAUkKRWam#l{;2ptZdNwjRjmTu*#WMt!B;lm%mZ+~6RLK@N$$@k(9ZU;w!J zsi|+|-92pQG0~w3=IFFtlliR|>i>gyx+~rOYAfjOXuQ(fA-|=f^`E17zAp=b+g#wa rGc^8vxchqp@W1j;(*OT^Tq6Ggx60h-v@5WX00000NkvXXu0mjf3*>l2 literal 0 HcmV?d00001 diff --git a/data/icons/Icon_COD11.png b/data/icons/Icon_COD11.png new file mode 100644 index 0000000000000000000000000000000000000000..b160db3338a46163716ec238374e6342f191d560 GIT binary patch literal 2080 zcmV+*2;cXKP)S&82Wx86D1k=h zsvIqHict8=|JL1i%-h|!yXfxHPV#4yeKY^e|Gjzt{PVwgLxyn5(9eg$U>2^uL^1RL z4FF-U1%$Jtzn$ z12G`mJ+?3=WsJ`4?GM=N2cSq+B*=J0sjjbvv3_GgG*1K;t1a|0enZIyXlQEyk7N%J zdG+fH6RyuX#Tt&>J_1#LSAjTK45In{?bm2-&jR3;=S3KJ_wikr9Wfg$=UakvxHF`m zNr ZdRSNQ)yuCW=?fFG+ukdopYSwe${=YKDQ`0xxRh~LfWr8w+`xB>ZrE0jkQ!; z<#@CKkpCc`Wms!RD~y(orWN{$sNd|OY*xLe&z~ymSbQk_u37D}f}EQ<1W*M46m{*V zXH18if81oXt!-cc@YVtVI=<%4W|p$Nl02m{bI*R`qU6T;9P%M%iqje=d8blgcP;E} z7*sb`^FCIZ0N^TwPP(hRi)gDe0H-V`LRrlI7^O0Nu9yuapGiO*BBlW`L|umt2OQvf z<#k@eg#ZXR8351zdZx0i&H#Lm`4Y+k69SdWB%8>k4xw<3=Ymqm$mEfb`co=&zUfqJ zyea^b(k8*h-!5uwt22O*f)GNPZ=A27yQ)brn5t~7)HrxP0K=1p!}hD&p{=V;P+Oe= z;MC%lg`X_c8^E%Y%LE&)D6Ubi%6^aka$KvnHT5;R0dUN8B$S0Fh3XApP0<>y0WfDk z@uOm`+Um6m^!D|#lrfzkvk^vWe#iY-Vv}lP+5k|v-ZlSnKJ5hKXeYR;U=`7^Vj1K* zL6ZWIbt8+V3FI&P z-yVjeB}a*CI{N?=oW`x4t!#x2HLy8nGx%@yhb;wLKvp9oI?X+w%Ll#(s4it|0B@d-3{4=*)U2v zN?F(QW8nbm8tWh;HG&m$WSq|!cmS3=EMfOIyP@Zw9*xFVR8@dum?Nu0j1aj1FkYV? zI-MObtrCORE^_n51yCp}goEE7WP!tea9@)7L*~E(P>5Ti8D%>X_yquJ>=6_Q%8Iv6o4vuCjc-3Dzsp3kXrveb%S7Z z0POeM6Pu38>Pm>qh=YJF0g!ko5jwlryE$383?%a;)J(95&@LrrbO5*tn_e}6oxdHe zaDfPxZ(UAw8oWJNe%)7CGQ?;Ba6@5cfI}rI-#WSn6%SbT3a=H?A#<$o6uD6Wz$lPg znE3!^fV1t&HdZ}+OqBHkh5G`d0x&msE}?A7$|>}nWh_5og<-6EnA8-xi0l@cu+`#b&XMX#;RQWhD zkgCVUWB{O4G*+;boxXaSUIjMNs{l7%$T*upcdA7&WOM-VbrZ8-s%u)vH2M1eHYFBW z97%NQv(bmO&o@~B_-?-bRXs~#`HOOhO^=13q#!tR>kQE$<_wtAU$WUmBS92=byfDf zjCW9crRz->%nF}HcevQZ_X5lWBzksDMY>iBW>d_-+({k)F_Rr84}cE@CN{ZcrsqsB zb1);a!Gi{Xkg_y-sXQ~J;?1zh05~T*rxO62C5oM+HV}*s0N)IV-W$#G@+bvA77+FB z{eDk*-6B$$FEBX(ihAP{#`7Leafx)1ckCx@H845=e2)Mh0F(=|3q;+-!--mj!$t={ z=nO!~F3l$DG7nWrKGhr$865y^W;)uG}?p~t- z_z!Xb+>H~K6PHfV0G14L00m{_QkZfqg$A&45Cg#TL@!%k5_P4qQrZc|nV=IC3V<(x ziYH05O^cZ%fYpVoq2+Z8Q7zfz>8=*Qf8|Tk|GysRlz#yt&XzSugAH#00000< KMNUMnLSTa6U9|rI literal 0 HcmV?d00001 diff --git a/data/icons/Icon_COD12.png b/data/icons/Icon_COD12.png new file mode 100644 index 0000000000000000000000000000000000000000..119fb0693b035139667b34701f1e9c9c04c275d9 GIT binary patch literal 2483 zcmV;k2~75hP)@l~ojexFpj!Rtz>e%{V$` zj#(~a<}!|Hj*gm+C|gRFxICg1F(FC8)Fc%gr@*BY3R9=V5;F%1HE?54Nyimba={Hj z9Z>{?^mfkk{lE9W|M|Dai>KB%bLP#wcka3OeE(g}Isbh&n}BqijXlXC`m2Jc2k0>Z zJUuXv6XEFrd5i#055&`=OTfk^O<3-L0qnqp3G7Hr49g1+X4zf4vY(!M%Hsq7R|!DJ zkI$daYRbzQg_=8e*v9yH_WrZave}@Y_6RuQHUfU}^<~%h?QFZeso7uCcgM`^` z8c@b_&#_I-o9pTvu-jSr-o5Phl`D>MTseK3?MY8(Ukn_`BH;Jr`Veq-?OIdLODMl^ zfsOO=VS&*0v-&vi<;C{HQmZa2V=Lcyg9XEPv4YNTue`!;fwOwZ&&Xgio_?B50sXJ6 z60jYfrih}vJT@KHeUP^|i|pK){k&)qtE;V5=xkiDfcZiDF(7MPa2_4IzHgswFB%9y zd%^tJdi7$pFyqYN6wF|3k0dOzLcp1n6osLxTesLdFdfkt$|UFK<|RuMdKZg|WF0F@ z;b(YKMTv>*Z-G#W06(YRW|(0(Gpt}!LV~0H1dwmd5P%!s-5WO)MlzQzlLrz2ve>Dc z*|)E%!-!6u9D3tSI=|Q7pH-HWkb@TqxSW}3$$1GMzWlPo#;0Zo$m-BRWncwtHqt;o z5gMj~#5jKwMbGiAZQHV|J9g*}oF`!Cpg}GcD73Y+NDdfewZEsD7Vj?Q8eDp?V>9=y}f>Zs*WOFeU;ndqT(@DRZ+o4H)=%A7A*pB9VbKRO9A(Q z)e#Z8&Y-Lk`ohhY!q{h?(Ok+30&p7FfHORS1=b_iJhuB$V2{_?3)YznZ> zuQBncK?1Jk=CThV(&V2W?#Qcj2>2cz#GlaaC?{K!lH~Ri2xoqSaGXMD>(=H8kR<8# z*V!@XwEFgKhmrgD??3p2lL9lub+cx%z-G;4!n9upMI@F+-e zz)%|my^SW!@1kl_8`JS=jUtKktEUSd?NSV z4xJew4S0#O9WUs73em?Acqk$;ZqVB|NCLEu6CRatLQI77AJ1aFY)enf5Mae#>9%bu zTex)ixWSNs0~$vY1*{F?`5)jS3GO5SPcRCb;Aod@*^LPJ6?V~D=bD#*^|o)q!`T8@ zUujWM?5>c_{dMpl3xFsR+5N(U1QdjYk+$Z;@h#b!Wki4&2vwAqE8^~VLE?uGS9P** z)F{XAp&lgQ=JDeyJJm2l1HHXvTi+QGAcn$xfP?ipX`?FZqN*2#LyJwSj~(Pa0A z4Z7=JK>)Re_<8^z;2fGhU7?4|MAD1&00CFwRHCo|W~*c;!ia$EE?rax>}}hUxpbbt zzd{eAyis0W@-k^i0<>(Doj0+|RYq`gqXx30Pal=;_~)N@=#6S%0<;RI ztENuX4VzU2;Cnw2S^>oGoja>^KjK2&h9V%lTQ{=(&9XA)-?XW0W3Cwjs2MP}MGJBu z_`+1gdo5cwI05*2j6w=zt^DS#XXD`>K(P72i!YJ`$saRDp@;c_v$Z+ZNYmL?nH zOJZWYkimtUR)Qf{2`I4J$#$hMEg84ZBBF5B9wWq5P-%@iJG4lYHMm(Bm_`;*_JyAz-U!W)+Bt=tC!q{sur0d z;N1H4vcY@8I|2$}F!j4ZyMeX`g^@%H9lJun>EvWmA1_7lPk*612%w0l72e|`26pPi zdfL?0V0ROM15G1b?X)xilMLV9IA(TxO9ISK-U9zNuy%3W?* z0{jf%b&J!}Rk~@>(U!ttLjoYG(+YX{peMvd=UtuwD1`|LD&5TG%Vk~aN{v+llAv!b z{4jT}EV&@Z3`Fboy~{J;;MA!q-Thm($hu}u1S10QMXI}CcfREo$7N{~pMQEsH%C1c;kpUO)hOYkO@>jI2jpMtVF5AdbNcg@uly2VPIPBV4AI zfES+lcL-MhHz0=E|F&3~0Y<=UGLyJVNRuo&kD_%8BwFV;S4BS#u#gSn&5Iu)!U}X= zMn=J#B4!hzM@38%faR~UbLSk>eKkaZ{7Vymo4IQ;kD{plKNx9YI!$sq@9GtqN5XND xfaL}xVC^r&>HOn1-E|50ul$qr|9_7Q_y@lqQ!Rv&paK8@002ovPDHLkV1mnIsw)5h literal 0 HcmV?d00001 diff --git a/tools/zentry/zentry.pro b/tools/zentry/zentry.pro index 06c4b31..68b8e1e 100644 --- a/tools/zentry/zentry.pro +++ b/tools/zentry/zentry.pro @@ -13,11 +13,6 @@ SOURCES += \ HEADERS += \ zentrywindow.h -FORMS += - -app.depends += \ - libs/compression - LIBS += \ -L$$OUT_PWD/../../libs/ -lcompression \ -L$$PWD/../../third_party/xbox_sdk/lib -lxcompress64