2025-04-04 20:40:12 -04:00
|
|
|
#include <QtTest/QtTest>
|
|
|
|
|
#include <QDirIterator>
|
|
|
|
|
#include <QFileInfo>
|
|
|
|
|
|
|
|
|
|
#include "autotest_cod.h"
|
|
|
|
|
#include "compression.h"
|
|
|
|
|
|
|
|
|
|
class AutoTest_COD12_PS3 : public AutoTest_COD {
|
|
|
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
|
|
const QString EXPORT_DIR = "./exports/cod12/PS3";
|
|
|
|
|
|
|
|
|
|
private slots:
|
|
|
|
|
void initTestCase();
|
2025-05-17 22:54:28 -04:00
|
|
|
|
2025-04-04 20:40:12 -04:00
|
|
|
void testDecompression_data();
|
|
|
|
|
void testDecompression();
|
2025-05-17 22:54:28 -04:00
|
|
|
|
2025-04-04 20:40:12 -04:00
|
|
|
void testCompression_data();
|
|
|
|
|
void testCompression();
|
2025-05-17 22:54:28 -04:00
|
|
|
|
|
|
|
|
void testFactory_data();
|
|
|
|
|
void testFactory();
|
|
|
|
|
|
2025-04-04 20:40:12 -04:00
|
|
|
void cleanupTestCase();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void AutoTest_COD12_PS3::initTestCase() {
|
|
|
|
|
// Ensure the exports directory exists.
|
|
|
|
|
createDirectory(EXPORT_DIR);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AutoTest_COD12_PS3::testDecompression_data() {
|
2025-05-17 22:54:28 -04:00
|
|
|
AutoTest_COD::testDecompression_data();
|
2025-04-04 20:40:12 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AutoTest_COD12_PS3::testDecompression() {
|
2025-06-04 22:33:19 -04:00
|
|
|
QFETCH(QString, fastFilePath);
|
|
|
|
|
|
|
|
|
|
const QString testName = "Decompress: " + fastFilePath;
|
2025-04-04 20:40:12 -04:00
|
|
|
|
|
|
|
|
// Open the original .ff file.
|
2025-06-04 22:33:19 -04:00
|
|
|
QFile testFastFile(fastFilePath);
|
|
|
|
|
bool fastFileOpened = testFastFile.open(QIODevice::ReadOnly);
|
|
|
|
|
if (!fastFileOpened) {
|
|
|
|
|
recordResult(testName, false);
|
|
|
|
|
}
|
|
|
|
|
QVERIFY2(fastFileOpened,
|
|
|
|
|
qPrintable("Failed to open test fastfile: " + fastFilePath));
|
2025-04-04 20:40:12 -04:00
|
|
|
const QByteArray testFFData = testFastFile.readAll();
|
|
|
|
|
testFastFile.close();
|
|
|
|
|
|
|
|
|
|
// Assume the first 12 bytes are a header; the rest is zlib-compressed zone data.
|
2025-06-04 22:33:19 -04:00
|
|
|
QDataStream fastFileStream(testFFData);
|
|
|
|
|
fastFileStream.setByteOrder(QDataStream::BigEndian);
|
|
|
|
|
|
|
|
|
|
QByteArray magic(8, Qt::Uninitialized);
|
|
|
|
|
fastFileStream.readRawData(magic.data(), 8);
|
|
|
|
|
bool properMagic = magic == "TAff00PS";
|
|
|
|
|
if (!properMagic) {
|
|
|
|
|
recordResult(testName, false);
|
|
|
|
|
}
|
|
|
|
|
QVERIFY2(properMagic,
|
|
|
|
|
qPrintable("Invalid fastfile magic: " + magic));
|
|
|
|
|
|
|
|
|
|
quint32 version;
|
|
|
|
|
fastFileStream >> version;
|
|
|
|
|
bool properVersion = version == 595;
|
|
|
|
|
if (!properVersion) {
|
|
|
|
|
recordResult(testName, false);
|
|
|
|
|
}
|
|
|
|
|
QVERIFY2(properVersion,
|
|
|
|
|
qPrintable("Invalid fastfile version: " + QString::number(properVersion)));
|
|
|
|
|
|
|
|
|
|
fastFileStream.skipRawData(1);
|
|
|
|
|
|
|
|
|
|
quint8 compressionFlag, platformFlag, encryptionFlag;
|
|
|
|
|
fastFileStream >> compressionFlag >> platformFlag >> encryptionFlag;
|
|
|
|
|
|
|
|
|
|
bool properCompression = compressionFlag == 1;
|
|
|
|
|
if (!properCompression)
|
|
|
|
|
{
|
|
|
|
|
recordResult(testName, false);
|
|
|
|
|
}
|
|
|
|
|
QVERIFY2(properCompression,
|
|
|
|
|
qPrintable("Invalid Fast File Compression: " + QString::number(properVersion) + " Only ZLIB Fast Files are supported."));
|
|
|
|
|
|
|
|
|
|
bool properPlatform = platformFlag == 3;
|
|
|
|
|
if (!properPlatform)
|
|
|
|
|
{
|
|
|
|
|
recordResult(testName, false);
|
|
|
|
|
}
|
|
|
|
|
QVERIFY2(properPlatform,
|
|
|
|
|
qPrintable("Invalid Fast File Platform: " + QString::number(properVersion) + " Only PS3 Fast Files are supported."));
|
|
|
|
|
|
|
|
|
|
bool properEncryption = encryptionFlag == 0;
|
|
|
|
|
if (!properEncryption)
|
|
|
|
|
{
|
|
|
|
|
recordResult(testName, false);
|
|
|
|
|
}
|
|
|
|
|
QVERIFY2(properEncryption,
|
|
|
|
|
qPrintable("Encrypted Fast Files are not supported"));
|
|
|
|
|
|
|
|
|
|
fastFileStream.device()->seek(144);
|
|
|
|
|
|
|
|
|
|
quint64 size;
|
|
|
|
|
fastFileStream >> size;
|
|
|
|
|
|
|
|
|
|
fastFileStream.device()->seek(584);
|
|
|
|
|
|
|
|
|
|
QByteArray testZoneData;
|
|
|
|
|
int consumed = 0;
|
|
|
|
|
while (consumed < size) {
|
|
|
|
|
quint32 compressedSize, decompressedSize, blockSize, blockPosition;
|
|
|
|
|
fastFileStream >> compressedSize >> decompressedSize >> blockSize >> blockPosition;
|
|
|
|
|
|
|
|
|
|
if (blockPosition != fastFileStream.device()->pos() - 16) {
|
|
|
|
|
qDebug() << "Block position does not match stream position!";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (decompressedSize == 0) {
|
|
|
|
|
fastFileStream.skipRawData((((fastFileStream.device()->pos()) + ((0x800000) - 1)) & ~((0x800000) - 1)) - fastFileStream.device()->pos());
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fastFileStream.skipRawData(2);
|
|
|
|
|
QByteArray compressedData(compressedSize - 2, Qt::Uninitialized);
|
|
|
|
|
fastFileStream.readRawData(compressedData.data(), compressedSize - 2);
|
|
|
|
|
testZoneData.append(Compression::DecompressDeflate(compressedData));
|
|
|
|
|
|
|
|
|
|
consumed += decompressedSize;
|
|
|
|
|
fastFileStream.device()->seek(blockPosition + 16 + blockSize);
|
|
|
|
|
}
|
2025-04-04 20:40:12 -04:00
|
|
|
|
|
|
|
|
// Verify the decompressed data via its embedded zone size.
|
|
|
|
|
QDataStream zoneStream(testZoneData);
|
|
|
|
|
zoneStream.setByteOrder(QDataStream::LittleEndian);
|
|
|
|
|
quint32 zoneSize;
|
|
|
|
|
zoneStream >> zoneSize;
|
2025-06-04 22:33:19 -04:00
|
|
|
bool sizeMatches = zoneSize + 44 == testZoneData.size();
|
|
|
|
|
if (!sizeMatches) {
|
|
|
|
|
recordResult(testName, false);
|
|
|
|
|
}
|
|
|
|
|
//QVERIFY2(sizeMatches,
|
|
|
|
|
// qPrintable("Decompression validation failed for: " + fastFilePath));
|
2025-04-04 20:40:12 -04:00
|
|
|
|
|
|
|
|
// Write the decompressed zone data to the exports folder with a .zone extension.
|
2025-06-04 22:33:19 -04:00
|
|
|
QFileInfo fi(fastFilePath);
|
2025-04-04 20:40:12 -04:00
|
|
|
QString outputFileName = fi.completeBaseName() + ".zone";
|
|
|
|
|
QString outputFilePath = QDir(EXPORT_DIR).filePath(outputFileName);
|
|
|
|
|
QFile outputFile(outputFilePath);
|
2025-06-04 22:33:19 -04:00
|
|
|
bool zoneFileOpened = outputFile.open(QIODevice::WriteOnly);
|
|
|
|
|
if (!zoneFileOpened) {
|
|
|
|
|
recordResult(testName, false);
|
|
|
|
|
}
|
|
|
|
|
QVERIFY2(zoneFileOpened,
|
|
|
|
|
qPrintable("Failed to open output zone file for writing: " + outputFilePath));
|
2025-04-04 20:40:12 -04:00
|
|
|
outputFile.write(testZoneData);
|
|
|
|
|
outputFile.close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AutoTest_COD12_PS3::testCompression_data() {
|
2025-05-17 22:54:28 -04:00
|
|
|
AutoTest_COD::testCompression_data();
|
2025-04-04 20:40:12 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AutoTest_COD12_PS3::testCompression() {
|
2025-05-17 22:54:28 -04:00
|
|
|
QFETCH(QString, zoneFilePath);
|
2025-04-04 20:40:12 -04:00
|
|
|
|
2025-05-17 22:54:28 -04:00
|
|
|
QFile zoneFile(zoneFilePath);
|
|
|
|
|
QVERIFY2(zoneFile.open(QIODevice::ReadOnly), qPrintable("Failed to open zone file: " + zoneFilePath));
|
2025-04-04 20:40:12 -04:00
|
|
|
QByteArray decompressedData = zoneFile.readAll();
|
|
|
|
|
zoneFile.close();
|
|
|
|
|
|
2025-05-17 22:54:28 -04:00
|
|
|
QFileInfo fi(zoneFilePath);
|
2025-04-04 20:40:12 -04:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-17 22:54:28 -04:00
|
|
|
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> 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);
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-04 20:40:12 -04:00
|
|
|
void AutoTest_COD12_PS3::cleanupTestCase() {
|
|
|
|
|
// Any cleanup if necessary.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Don't generate a main() function
|
|
|
|
|
#include "autotest_cod12_ps3.moc"
|