Compare commits

..

No commits in common. "main" and "feature/test" have entirely different histories.

611 changed files with 5762 additions and 5767 deletions

3
.gitignore vendored
View File

@ -3,9 +3,6 @@
/data/fastfiles/
/releases/
.vscode/*
.qmake.stash
# Ignore Qt Creator user files
*.pro.user
*.pro.user.*

23
.qmake.stash Normal file
View File

@ -0,0 +1,23 @@
QMAKE_CXX.QT_COMPILER_STDCXX = 199711L
QMAKE_CXX.QMAKE_MSC_VER = 1943
QMAKE_CXX.QMAKE_MSC_FULL_VER = 194334810
QMAKE_CXX.COMPILER_MACROS = \
QT_COMPILER_STDCXX \
QMAKE_MSC_VER \
QMAKE_MSC_FULL_VER
QMAKE_CXX.INCDIRS = \
"C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\MSVC\\14.43.34808\\include" \
"C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\MSVC\\14.43.34808\\ATLMFC\\include" \
"C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Auxiliary\\VS\\include" \
"C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.26100.0\\ucrt" \
"C:\\Program Files (x86)\\Windows Kits\\10\\\\include\\10.0.26100.0\\\\um" \
"C:\\Program Files (x86)\\Windows Kits\\10\\\\include\\10.0.26100.0\\\\shared" \
"C:\\Program Files (x86)\\Windows Kits\\10\\\\include\\10.0.26100.0\\\\winrt" \
"C:\\Program Files (x86)\\Windows Kits\\10\\\\include\\10.0.26100.0\\\\cppwinrt" \
"C:\\Program Files (x86)\\Windows Kits\\NETFXSDK\\4.8\\include\\um"
QMAKE_CXX.LIBDIRS = \
"C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\MSVC\\14.43.34808\\ATLMFC\\lib\\x64" \
"C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\MSVC\\14.43.34808\\lib\\x64" \
"C:\\Program Files (x86)\\Windows Kits\\NETFXSDK\\4.8\\lib\\um\\x64" \
"C:\\Program Files (x86)\\Windows Kits\\10\\lib\\10.0.26100.0\\ucrt\\x64" \
"C:\\Program Files (x86)\\Windows Kits\\10\\\\lib\\10.0.26100.0\\\\um\\x64"

4
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,4 @@
{
"workbench.colorTheme": "Default Dark Modern",
"workbench.startupEditor": "none"
}

View File

@ -2,9 +2,9 @@ TEMPLATE = subdirs
SUBDIRS += libs \
app \
#tools \
#tests
tools \
tests
#tests.depends = libs
tests.depends = libs
app.depends = libs
#tools.depends = libs
tools.depends = libs

View File

@ -1,36 +0,0 @@
#!/bin/bash
set -e
# 1. Stage everything
git add -A
# 2. Get list of staged files
FILES=$(git diff --cached --name-only)
if [ -z "$FILES" ]; then
echo "No changes to commit."
exit 0
fi
# 3. Loop file by file
for FILE in $FILES; do
# Get diff for this file
DIFF=$(git diff --cached -- "$FILE")
if [ -z "$DIFF" ]; then
continue
fi
# Ask Ollama for a commit message describing this file change
MSG=$(echo "$DIFF" | ollama run gemma3 \
"You are a commit bot. Write a SHORT, clear, concise Git commit message for changes in file: $FILE.
Only output the commit message, nothing else.
Diff:
$DIFF")
# Commit just this file with its message
git commit -m "$MSG" -- "$FILE"
echo "✅ Committed $FILE with message:"
echo "$MSG"
done

View File

@ -13,9 +13,9 @@ FORMS += $$files($$PWD/*.ui)
RESOURCES += ../data/data.qrc
LIBS += \
-L$$PWD/../third_party/devil_sdk/lib/ -lDevIL -lILU -lILUT \
-L$$PWD/../third_party/zlib/lib/ -lzlib \
-L$$PWD/../third_party/xbox_sdk/lib -lxcompress64 \
#-L$$PWD/../third_party/devil_sdk/lib/ -lDevIL -lILU -lILUT \
#-L$$PWD/../third_party/zlib/lib/ -lzlib \
#-L$$PWD/../third_party/xbox_sdk/lib -lxcompress64 \
-L$$OUT_PWD/../libs/ -lcore \
-L$$OUT_PWD/../libs/ -lxassets\
-L$$OUT_PWD/../libs/ -lcompression \
@ -27,9 +27,9 @@ LIBS += \
-L$$OUT_PWD/../libs/ -lzonefile
INCLUDEPATH += \
$$PWD/../third_party/devil_sdk/include/ \
$$PWD/../third_party/zlib/include \
$$PWD/../third_party/xbox_sdk/include \
#$$PWD/../third_party/devil_sdk/include/ \
#$$PWD/../third_party/zlib/include \
#$$PWD/../third_party/xbox_sdk/include \
$$PWD/../libs/core \
$$PWD/../libs/compression \
$$PWD/../libs/encryption \
@ -41,9 +41,9 @@ INCLUDEPATH += \
$$PWD/../libs/zonefile
DEPENDPATH += \
$$PWD/../third_party/devil_sdk/include/ \
$$PWD/../third_party/zlib/include \
$$PWD/../third_party/xbox_sdk/include \
#$$PWD/../third_party/devil_sdk/include/ \
#$$PWD/../third_party/zlib/include \
#$$PWD/../third_party/xbox_sdk/include \
$$PWD/../libs/core \
$$PWD/../libs/compression \
$$PWD/../libs/encryption \

View File

@ -533,7 +533,7 @@ bool MainWindow::OpenFastFile(const QString aFastFilePath) {
return false;
}
FastFile* fastFile = FastFile::Open(aFastFilePath);
FastFile* fastFile = FastFileFactory::Create(aFastFilePath);
fastFile->SetStem(fastFileStem);
mTreeWidget->AddFastFile(fastFile);
@ -548,7 +548,7 @@ bool MainWindow::OpenFastFile(const QByteArray& aFastFileData, const QString aFa
return false;
}
FastFile* fastFile = FastFile::Open(aFastFileData);
FastFile* fastFile = FastFileFactory::Create(aFastFileData);
fastFile->SetStem(fastFileStem);
mTreeWidget->AddFastFile(fastFile);
@ -789,7 +789,7 @@ int MainWindow::LoadFile_IPAK(const QString aFilePath) {
QVector<IPAKIndexEntry> entries = QVector<IPAKIndexEntry>();
QVector<IPAKSection> sections = QVector<IPAKSection>(header.sectionCount);
for (quint32 i = 0; i < header.sectionCount; i++) {
for (uint i = 0; i < header.sectionCount; i++) {
IPAKSection currentSection;
stream >> currentSection;
sections << currentSection;
@ -811,7 +811,7 @@ int MainWindow::LoadFile_IPAK(const QString aFilePath) {
<< " - Count: " << chunkHeader.count << "\n"
<< " - Offset: " << chunkHeader.offset;
for (quint32 j = 0; j < 31; j++) {
for (uint j = 0; j < 31; j++) {
IPAKDataChunkCommand command;
stream >> command;
if (!command.size) { continue; }
@ -821,7 +821,7 @@ int MainWindow::LoadFile_IPAK(const QString aFilePath) {
<< " - Compressed: " << command.compressed;
}
for (quint32 j = 0; j < chunkHeader.count; j++) {
for (uint j = 0; j < chunkHeader.count; j++) {
auto command = chunkHeader.commands[j];
qDebug() << "Reading from " << stream.device()->pos();
@ -846,7 +846,7 @@ int MainWindow::LoadFile_IPAK(const QString aFilePath) {
stream.skipRawData(sizeof(quint32) * (31 - chunkHeader.count));
qDebug() << stream.device()->pos();
} else if (sectionType == "Index") {
for (quint32 j = 0; j < currentSection.itemCount; j++) {
for (uint j = 0; j < currentSection.itemCount; j++) {
IPAKIndexEntry entry;
stream >> entry;

View File

@ -3,27 +3,19 @@
MaterialViewer::MaterialViewer(QWidget *parent)
: QWidget(parent)
, ui(new Ui::MaterialViewer)
{
, ui(new Ui::MaterialViewer) {
ui->setupUi(this);
}
MaterialViewer::~MaterialViewer()
{
MaterialViewer::~MaterialViewer() {
delete ui;
}
QString ToHexStr(quint32 in)
{
QString ToHexStr(quint32 in) {
return QString("%1").arg(in, 8, 16, QChar('0')).toUpper();
}
void MaterialViewer::SetMaterial(const XMaterial* aMaterial)
{
Q_UNUSED(aMaterial);
// TODO: Fill in MaterialViewer::SetMaterial
void MaterialViewer::SetMaterial(const XMaterial* aMaterial) {
// ui->lineEdit_NamePtr->setText(ToHexStr(aMaterial->namePtr));
// ui->lineEdit_Name->setText(aMaterial->name);
// ui->lineEdit_RefPtr->setText(ToHexStr(aMaterial->refNamePtr));

View File

@ -22,7 +22,7 @@ RumbleGraphViewer::~RumbleGraphViewer() {
void RumbleGraphViewer::SetRumbleGraphFile(const XRawFile* aRawFile) {
mRumbleGraphFile = aRawFile;
XDataStream rawFileStream;//(mRumbleGraphFile->contents.toLatin1());
QDataStream rawFileStream;//(mRumbleGraphFile->contents.toLatin1());
QByteArray magic(15, Qt::Uninitialized);
rawFileStream.readRawData(magic.data(), 15);

View File

@ -490,12 +490,12 @@ void XTreeWidget::PrepareContextMenu(const QPoint &pos) {
});
QAction *exportZoneFileAction = new QAction("Export Zone File");
exportSubmenu->addAction(exportZoneFileAction);
connect(exportZoneFileAction, &QAction::triggered, this, [](bool checked) {
connect(exportZoneFileAction, &QAction::triggered, this, [fastFile](bool checked) {
Q_UNUSED(checked);
// const QString zoneFilePath = QFileDialog::getSaveFileName(
// nullptr, "Export Zone File...", QDir::currentPath(),
// "Zone File (*.zone);;All Files(*.*)");
const QString zoneFilePath = QFileDialog::getSaveFileName(
nullptr, "Export Zone File...", QDir::currentPath(),
"Zone File (*.zone);;All Files(*.*)");
//fastFile->GetZoneFile()->SaveZoneFile(zoneFilePath);
});
} else if (activeText.contains(".zone")) {
@ -508,7 +508,7 @@ void XTreeWidget::PrepareContextMenu(const QPoint &pos) {
QMenu *exportSubmenu = new QMenu("Export...", this);
contextMenu->addMenu(exportSubmenu);
//const ZoneFile* zoneFile = mZoneFiles[fileStem];
const ZoneFile* zoneFile = mZoneFiles[fileStem];
QAction *exportZoneFileAction = new QAction("Export Zone File");
exportSubmenu->addAction(exportZoneFileAction);
@ -530,7 +530,7 @@ void XTreeWidget::PrepareContextMenu(const QPoint &pos) {
}
}
if (parentItem && parentItem != invisibleRootItem() && parentItem->text(0).contains(".zone")) {
//const QString fileStem = parentItem->text(0).section('.', 0, 0);
const QString fileStem = parentItem->text(0).section('.', 0, 0);
// QVector<LoadedSound> LoadedSounds = mZoneFiles[fileStem]->GetAssetMap().sounds;
// for (LoadedSound LoadedSound : LoadedSounds) {
// for (Sound sound : LoadedSound.sounds) {
@ -577,14 +577,14 @@ void XTreeWidget::PrepareContextMenu(const QPoint &pos) {
}
if (parentItem && parentItem != invisibleRootItem() && parentItem->text(0).contains(".zone")) {
const QString fileStem = parentItem->text(0).section('.', 0, 0);
//auto zoneFile = mZoneFiles[fileStem];
auto zoneFile = mZoneFiles[fileStem];
QMenu *exportSubmenu = new QMenu("Export...", this);
contextMenu->addMenu(exportSubmenu);
QAction *exportAllWAVAction = new QAction("Export ALL as WAV Files");
exportSubmenu->addAction(exportAllWAVAction);
connect(exportAllWAVAction, &QAction::triggered, this, [](bool checked) {
connect(exportAllWAVAction, &QAction::triggered, this, [zoneFile](bool checked) {
Q_UNUSED(checked);
// for (LoadedSound LoadedSound : zoneFile->GetAssetMap().sounds) {

View File

@ -1,91 +1,73 @@
#include "compression.h"
#include "minilzo.h"
#include "xcompress.h"
//#include "minilzo.h"
//#define XBOXAPI __declspec(dllimport)
//#include "xcompress.h"
#include <QLibrary>
#include <QDebug>
#include <QFile>
#include <QDataStream>
QByteArray Compression::CompressXMem(const QByteArray &data)
{
XMEMCODEC_PARAMETERS_LZX lzxParams = {};
lzxParams.Flags = 0;
lzxParams.WindowSize = 0x20000;
lzxParams.CompressionPartitionSize = 0x80000;
// XMEMCODEC_PARAMETERS_LZX lzxParams = {};
// lzxParams.Flags = 0;
// lzxParams.WindowSize = 0x20000;
// lzxParams.CompressionPartitionSize = 0x80000;
XMEMCOMPRESSION_CONTEXT ctx = nullptr;
if (FAILED(XMemCreateCompressionContext(XMEMCODEC_LZX, &lzxParams, 0, &ctx)) || !ctx)
// XMEMCOMPRESSION_CONTEXT ctx = nullptr;
// if (FAILED(XMemCreateCompressionContext(XMEMCODEC_LZX, &lzxParams, 0, &ctx)) || !ctx)
// return QByteArray();
// SIZE_T estimatedSize = data.size() + XCOMPRESS_LZX_BLOCK_GROWTH_SIZE_MAX;
// QByteArray output(static_cast<int>(estimatedSize), 0);
// SIZE_T actualSize = estimatedSize;
// HRESULT hr = XMemCompress(ctx, output.data(), &actualSize, data.constData(), data.size());
// XMemDestroyCompressionContext(ctx);
// if (FAILED(hr))
// return QByteArray();
// output.resize(static_cast<int>(actualSize));
// return output;
return QByteArray();
SIZE_T estimatedSize = data.size() + XCOMPRESS_LZX_BLOCK_GROWTH_SIZE_MAX;
QByteArray output(static_cast<int>(estimatedSize), 0);
SIZE_T actualSize = estimatedSize;
HRESULT hr = XMemCompress(ctx, output.data(), &actualSize, data.constData(), data.size());
XMemDestroyCompressionContext(ctx);
if (FAILED(hr))
return QByteArray();
output.resize(static_cast<int>(actualSize));
return output;
}
QByteArray Compression::DecompressXMem(const QByteArray &data,
int flags, int windowSize, int partSize)
QByteArray Compression::DecompressXMem(const QByteArray &data, int flags, int windowSize, int partSize)
{
if (data.isEmpty())
return {};
// if (data.isEmpty())
// return {};
XMEMCODEC_PARAMETERS_LZX lzxParams = {};
lzxParams.Flags = flags;
lzxParams.WindowSize = windowSize;
lzxParams.CompressionPartitionSize = partSize;
// XMEMCODEC_PARAMETERS_LZX lzxParams = {};
// lzxParams.Flags = flags;
// lzxParams.WindowSize = windowSize;
// lzxParams.CompressionPartitionSize = partSize;
QByteArray internalState(0x94933, Qt::Uninitialized);
// XMEMDECOMPRESSION_CONTEXT ctx = nullptr;
// if (FAILED(XMemCreateDecompressionContext(XMEMCODEC_LZX, &lzxParams, 0, &ctx)) || !ctx)
// return {};
XMEMDECOMPRESSION_CONTEXT ctx = XMemInitializeDecompressionContext(
XMEMCODEC_LZX, &lzxParams, 1,
internalState.data(), internalState.size());
// // Allocate large enough buffer for decompression (16 MB is a safe upper bound)
// const SIZE_T kMaxOutSize = 16 * 1024 * 1024;
// QByteArray output(static_cast<int>(kMaxOutSize), Qt::Uninitialized);
// SIZE_T actualSize = kMaxOutSize;
if (!ctx || XMemResetDecompressionContext(ctx)) {
qWarning() << "Failed to init LZX context";
return {};
}
// HRESULT hr = XMemDecompress(ctx,
// output.data(), &actualSize,
// data.constData(), data.size() + 16);
QByteArray output;
output.reserve(16 * 1024 * 1024); // rough guess
// XMemDestroyDecompressionContext(ctx);
const quint8 *nextIn = reinterpret_cast<const quint8*>(data.constData());
SIZE_T availIn = data.size();
// if (FAILED(hr)) {
// qWarning() << "XMemDecompress failed with HRESULT:" << hr;
// return {};
// }
QByteArray scratch(0x10000, Qt::Uninitialized); // 64 KB chunks
while (availIn > 0) {
SIZE_T inSize = availIn; // let XMem tell us how much it will consume
SIZE_T outSize = scratch.size(); // max 64 KB per call
HRESULT hr = XMemDecompressStream(ctx,
scratch.data(), &outSize,
nextIn, &inSize);
if (FAILED(hr)) {
qWarning() << "XMemDecompressStream failed, hr=" << hr;
XMemDestroyDecompressionContext(ctx);
return {};
}
if (inSize == 0 && outSize == 0)
break; // no progress
output.append(scratch.constData(), static_cast<int>(outSize));
nextIn += inSize;
availIn -= inSize;
}
XMemDestroyDecompressionContext(ctx);
return output;
// output.resize(static_cast<int>(actualSize));
// return output;
return QByteArray();
}
quint32 Compression::CalculateAdler32Checksum(const QByteArray &data) {
@ -100,18 +82,19 @@ quint32 Compression::CalculateAdler32Checksum(const QByteArray &data) {
qint64 Compression::FindZlibOffset(const QByteArray &bytes)
{
QDataStream stream(bytes);
static const QByteArray iwffs("IWffs");
auto idx = bytes.indexOf(iwffs);
if (idx != -1)
return idx + 0x4000;
while (!stream.atEnd())
const char header = 0x78; // z-lib: 0x78 [FLG]
int pos = -1;
while ((pos = bytes.indexOf(header, pos + 1)) != -1)
{
QByteArray testSegment = stream.device()->peek(2).toHex().toUpper();
if (testSegment == "7801" ||
testSegment == "785E" ||
testSegment == "789C" ||
testSegment == "78DA") {
return stream.device()->pos();
}
stream.skipRawData(1);
QByteArray window = bytes.mid(pos, 0x20);
if (!window.contains(QByteArray::fromHex("000000")) &&
!window.contains(QByteArray::fromHex("FFFFFF")))
return pos;
}
return -1;
}
@ -315,22 +298,22 @@ QByteArray Compression::CompressDeflateWithSettings(const QByteArray &aData, int
QByteArray Compression::DecompressLZO(const QByteArray &aCompressedData, quint32 aDestSize) {
QByteArray dst;
static bool ok = (lzo_init() == LZO_E_OK);
if (!ok)
throw std::runtime_error("lzo_init failed");
// static bool ok = (lzo_init() == LZO_E_OK);
// if (!ok)
// throw std::runtime_error("lzo_init failed");
dst = QByteArray(aDestSize, Qt::Uninitialized);
lzo_uint out = aDestSize;
// dst = QByteArray(aDestSize, Qt::Uninitialized);
// lzo_uint out = aDestSize;
int rc = lzo1x_decompress_safe(
reinterpret_cast<const lzo_bytep>(aCompressedData.constData()),
static_cast<lzo_uint>(aCompressedData.size()),
reinterpret_cast<lzo_bytep>(dst.data()),
&out,
nullptr);
// int rc = lzo1x_decompress_safe(
// reinterpret_cast<const lzo_bytep>(aCompressedData.constData()),
// static_cast<lzo_uint>(aCompressedData.size()),
// reinterpret_cast<lzo_bytep>(dst.data()),
// &out,
// nullptr);
if (rc != LZO_E_OK || out != aDestSize)
throw std::runtime_error("LZO decompression error");
// if (rc != LZO_E_OK || out != aDestSize)
// throw std::runtime_error("LZO decompression error");
return dst;
}

View File

@ -3,8 +3,7 @@ TEMPLATE = lib
CONFIG += staticlib c++17
DEFINES += MINILZO_USE_STATIC
SOURCES += $$files($$PWD/*.cpp, true) \
$$files($$PWD/*.c, true)
SOURCES += $$files($$PWD/*.cpp, true)
HEADERS += $$files($$PWD/*.h, true)
LIBS += \

View File

@ -57,7 +57,7 @@
/* get OS and architecture defines */
#ifndef __LZODEFS_H_INCLUDED
#include <lzodefs.h>
#include <lzo/lzodefs.h>
#endif

View File

@ -25,6 +25,12 @@
http://www.oberhumer.com/opensource/lzo/
*/
/*
* NOTE:
* the full LZO package can be found at
* http://www.oberhumer.com/opensource/lzo/
*/
#define __LZO_IN_MINILZO 1
#if defined(LZO_CFG_FREESTANDING)

View File

@ -25,6 +25,13 @@
http://www.oberhumer.com/opensource/lzo/
*/
/*
* NOTE:
* the full LZO package can be found at
* http://www.oberhumer.com/opensource/lzo/
*/
#ifndef __MINILZO_H_INCLUDED
#define __MINILZO_H_INCLUDED 1

View File

@ -2,10 +2,8 @@ QT += core widgets
TEMPLATE = lib
CONFIG += staticlib c++17
SOURCES += $$files($$PWD/*.cpp, true) \
xdatastream.cpp
HEADERS += $$files($$PWD/*.h, true) \
xdatastream.h
SOURCES += $$files($$PWD/*.cpp, true)
HEADERS += $$files($$PWD/*.h, true)
LIBS += -L$$OUT_PWD/../libs/xassets -lxassets

View File

@ -223,7 +223,7 @@ public:
return color;
}
static bool ReadUntilString(XDataStream* stream, const QString& targetString) {
static bool ReadUntilString(QDataStream* stream, const QString& targetString) {
if (!stream || targetString.isEmpty()) {
return false; // Invalid input
}
@ -257,7 +257,7 @@ public:
return false;
}
static bool ReadUntilHex(XDataStream* stream, const QString& hexString) {
static bool ReadUntilHex(QDataStream* stream, const QString& hexString) {
if (!stream || hexString.isEmpty() || hexString.size() % 2 != 0) {
return false; // Invalid input
}

View File

@ -1,243 +0,0 @@
#include "xdatastream.h"
#include <QIODevice>
#include <QDebug>
XDataStream::XDataStream(QIODevice *aDevice)
: QDataStream(aDevice)
, mDebug(false)
{
}
XDataStream::XDataStream()
: QDataStream()
, mDebug(false)
{
}
XDataStream::XDataStream(const QByteArray &aData)
: QDataStream(aData)
, mDebug(false)
{
}
XDataStream::XDataStream(QByteArray *aData, OpenMode aFlags)
: QDataStream(aData, aFlags)
, mDebug(false)
{
}
XDataStream::~XDataStream()
{
}
void XDataStream::SetDebug(bool aDebug)
{
mDebug = aDebug;
}
qint8 XDataStream::ParseInt8(const QString& aDebugString)
{
qint64 start = this->device()->pos();
qint8 val;
*this >> val;
if (mDebug)
{
qDebug() << QString("[%1-%2] Parsed %3: %4")
.arg(start, 10, 10, QChar('0'))
.arg(this->device()->pos(), 10, 10, QChar('0'))
.arg(aDebugString)
.arg(val);
}
return val;
}
quint8 XDataStream::ParseUInt8(const QString& aDebugString)
{
qint64 start = this->device()->pos();
quint8 val;
*this >> val;
if (mDebug)
{
qDebug() << QString("[%1-%2] Parsed %3: %4")
.arg(start, 10, 10, QChar('0'))
.arg(this->device()->pos(), 10, 10, QChar('0'))
.arg(aDebugString)
.arg(val);
}
return val;
}
qint16 XDataStream::ParseInt16(const QString& aDebugString)
{
qint64 start = this->device()->pos();
qint16 val;
*this >> val;
if (mDebug)
{
qDebug() << QString("[%1-%2] Parsed %3: %4")
.arg(start, 10, 10, QChar('0'))
.arg(this->device()->pos(), 10, 10, QChar('0'))
.arg(aDebugString)
.arg(val);
}
return val;
}
quint16 XDataStream::ParseUInt16(const QString& aDebugString)
{
qint64 start = this->device()->pos();
quint16 val;
*this >> val;
if (mDebug)
{
qDebug() << QString("[%1-%2] Parsed %3: %4")
.arg(start, 10, 10, QChar('0'))
.arg(this->device()->pos(), 10, 10, QChar('0'))
.arg(aDebugString)
.arg(val);
}
return val;
}
qint32 XDataStream::ParseInt32(const QString& aDebugString)
{
qint64 start = this->device()->pos();
qint32 val;
*this >> val;
if (mDebug)
{
qDebug() << QString("[%1-%2] Parsed %3: %4")
.arg(start, 10, 10, QChar('0'))
.arg(this->device()->pos(), 10, 10, QChar('0'))
.arg(aDebugString)
.arg(val);
}
return val;
}
quint32 XDataStream::ParseUInt32(const QString& aDebugString)
{
qint64 start = this->device()->pos();
quint32 val;
*this >> val;
if (mDebug)
{
qDebug() << QString("[%1-%2] Parsed %3: %4")
.arg(start, 10, 10, QChar('0'))
.arg(this->device()->pos(), 10, 10, QChar('0'))
.arg(aDebugString)
.arg(val);
}
return val;
}
qint64 XDataStream::ParseInt64(const QString& aDebugString)
{
qint64 start = this->device()->pos();
qint64 val;
*this >> val;
if (mDebug)
{
qDebug() << QString("[%1-%2] Parsed %3: %4")
.arg(start, 10, 10, QChar('0'))
.arg(this->device()->pos(), 10, 10, QChar('0'))
.arg(aDebugString)
.arg(val);
}
return val;
}
quint64 XDataStream::ParseUInt64(const QString& aDebugString)
{
qint64 start = this->device()->pos();
quint64 val;
*this >> val;
if (mDebug)
{
qDebug() << QString("[%1-%2] Parsed %3: %4")
.arg(start, 10, 10, QChar('0'))
.arg(this->device()->pos(), 10, 10, QChar('0'))
.arg(aDebugString)
.arg(val);
}
return val;
}
float XDataStream::ParseSingle(const QString& aDebugString)
{
qint64 start = this->device()->pos();
float val;
quint32 rawVal;
*this >> rawVal;
memcpy(&val, &rawVal, sizeof(val));
if (mDebug)
{
qDebug() << QString("[%1-%2] Parsed %3: %4")
.arg(start, 10, 10, QChar('0'))
.arg(this->device()->pos(), 10, 10, QChar('0'))
.arg(aDebugString)
.arg(val);
}
return val;
}
double XDataStream::ParseDouble(const QString& aDebugString)
{
qint64 start = this->device()->pos();
float val;
*this >> val;
if (mDebug)
{
qDebug() << QString("[%1-%2] Parsed %3: %4")
.arg(start, 10, 10, QChar('0'))
.arg(this->device()->pos(), 10, 10, QChar('0'))
.arg(aDebugString)
.arg(val);
}
return val;
}
bool XDataStream::ParseBool(const QString &aDebugString)
{
qint64 start = this->device()->pos();
char val;
*this >> val;
if (mDebug)
{
qDebug() << QString("[%1-%2] Parsed %3: %4")
.arg(start, 10, 10, QChar('0'))
.arg(this->device()->pos(), 10, 10, QChar('0'))
.arg(aDebugString)
.arg(val);
}
return val;
}

View File

@ -1,34 +0,0 @@
#ifndef XDATASTREAM_H
#define XDATASTREAM_H
#include <QDataStream>
#include <QString>
class XDataStream : public QDataStream
{
public:
explicit XDataStream(QIODevice* aDevice);
XDataStream();
XDataStream(const QByteArray& aData);
XDataStream(QByteArray* aData, OpenMode aFlags);
~XDataStream();
void SetDebug(bool aDebug = true);
qint8 ParseInt8(const QString& aDebugString = "");
quint8 ParseUInt8(const QString& aDebugString = "");
qint16 ParseInt16(const QString& aDebugString = "");
quint16 ParseUInt16(const QString& aDebugString = "");
qint32 ParseInt32(const QString& aDebugString = "");
quint32 ParseUInt32(const QString& aDebugString = "");
qint64 ParseInt64(const QString& aDebugString = "");
quint64 ParseUInt64(const QString& aDebugString = "");
float ParseSingle(const QString& aDebugString = "");
double ParseDouble(const QString& aDebugString = "");
bool ParseBool(const QString& aDebugString = "");
private:
bool mDebug;
};
#endif // XDATASTREAM_H

View File

@ -1,5 +1,15 @@
/* ecrypt-portable.h */
/*
* WARNING: the conversions defined below are implemented as macros,
* and should be used carefully. They should NOT be used with
* parameters which perform some action. E.g., the following two lines
* are not equivalent:
*
* 1) ++x; y = ROTL32(x, n);
* 2) y = ROTL32(++x, n);
*/
/*
* *** Please do not edit this file. ***
*

View File

@ -1,35 +1,27 @@
#include <QtCore>
#include "encryption.h"
#include "QtZlib/zlib.h"
#include "ecrypt-sync.h"
#include "sha1.h"
#include "encryption.h"
#include "compression.h"
static QVector<quint32> ivCounter(4, 1); // start all counters at 1
void Encryption::Convert32BitTo8Bit(quint32 value, quint8 *array)
{
void Encryption::Convert32BitTo8Bit(quint32 value, quint8 *array) {
array[0] = static_cast<quint8>(value >> 0);
array[1] = static_cast<quint8>(value >> 8);
array[2] = static_cast<quint8>(value >> 16);
array[3] = static_cast<quint8>(value >> 24);
}
quint32 Encryption::ConvertArrayTo32Bit(const QByteArray &array)
{
quint32 Encryption::ConvertArrayTo32Bit(const QByteArray &array) {
return ((static_cast<quint32>(static_cast<uchar>(array[0])) << 0) |
(static_cast<quint32>(static_cast<uchar>(array[1])) << 8) |
(static_cast<quint32>(static_cast<uchar>(array[2])) << 16) |
(static_cast<quint32>(static_cast<uchar>(array[3])) << 24));
}
quint32 Encryption::Rotate(quint32 value, quint32 numBits)
{
quint32 Encryption::Rotate(quint32 value, quint32 numBits) {
return (value << numBits) | (value >> (32 - numBits));
}
QByteArray Encryption::InitIVTable(const QByteArray &feed)
{
QByteArray Encryption::InitIVTable(const QByteArray &feed) {
const int tableSize = 0xFB0;
QByteArray table;
table.resize(tableSize);
@ -56,23 +48,22 @@ QByteArray Encryption::InitIVTable(const QByteArray &feed)
return table;
}
int Encryption::unk(quint64 arg1, quint8 arg2)
{
int Encryption::unk(quint64 arg1, quint8 arg2) {
if (arg2 >= 0x40)
return 0;
return static_cast<int>(arg1 >> arg2);
}
QByteArray Encryption::GetIV(const QByteArray &table, int index)
{
int num1 = (4 * index % 4 + 0xFA0) + index % 4 + (index - (index % 4));
QByteArray Encryption::GetIV(const QByteArray &table, int index) {
int num1 = 0xFA0 + index;
int num2 = unk(0x51EB851FLL * num1, 0x20);
int startIndex = 20 * (num1 - 200 * ((num2 >> 6) + (num2 >> 31)));
int adjust = ((num2 >> 6) + (num2 >> 31));
int startIndex = 20 * (num1 - 200 * adjust);
// Return 8 bytes from that location.
return table.mid(startIndex, 8);
}
void Encryption::UpdateIVTable(QByteArray &table, int index, const QByteArray &sectionHash)
{
void Encryption::UpdateIVTable(QByteArray &table, int index, const QByteArray &sectionHash) {
int blockNumIndex = index % 4;
int baseOffset = 0xFA0 + blockNumIndex * 4;
quint32 blockNumVal = (static_cast<uchar>(table.at(baseOffset)) ) |
@ -95,8 +86,7 @@ void Encryption::UpdateIVTable(QByteArray &table, int index, const QByteArray &s
}
}
quint32 Encryption::ToUInt32(const QByteArray &data, int offset)
{
quint32 Encryption::ToUInt32(const QByteArray &data, int offset) {
// Converts 4 bytes (starting at offset) from data into a 32-bit quint32eger (little-endian)
return ((static_cast<quint32>(static_cast<uchar>(data[offset])) ) |
(static_cast<quint32>(static_cast<uchar>(data[offset+1])) << 8 ) |
@ -361,8 +351,96 @@ void Encryption::generateNewIV(int index, const QByteArray &hash, QByteArray &iv
ivCounter[index]++;
}
QByteArray Encryption::decryptFastFile_BO3(const QByteArray &fastFileData)
QByteArray Encryption::decryptFastFile_BO2(const QByteArray &fastFileData)
{
const QByteArray bo2_salsa20_key = QByteArray::fromHex("641D8A2FE31D3AA63622BBC9CE8587229D42B0F8ED9B924130BF88B65EDC50BE");
QByteArray fileData = fastFileData;
QByteArray finalFastFile;
QByteArray ivTable(16000, 0);
fillIVTable(fileData, ivTable, 16000 - 1);
QVector<quint32> ivCounter(4, 1);
QDataStream stream(fileData);
stream.setByteOrder(QDataStream::LittleEndian);
stream.skipRawData(0x138);
QByteArray sha1Hash(20, 0);
QByteArray ivPtr(8, 0);
int chunkIndex = 0;
while (!stream.atEnd()) {
quint32 dataLength;
stream >> dataLength;
if (dataLength == 0 || dataLength > fileData.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<const u8*>(bo2_salsa20_key.constData()), 256, 0);
ECRYPT_ivsetup(&x, reinterpret_cast<const u8*>(ivPtr.constData()));
QByteArray encryptedBlock = fileData.mid(stream.device()->pos(), dataLength);
QByteArray decryptedBlock;
decryptedBlock.resize(dataLength);
ECRYPT_decrypt_bytes(&x, reinterpret_cast<const u8*>(encryptedBlock.constData()),
reinterpret_cast<u8*>(decryptedBlock.data()), dataLength);
QCryptographicHash sha1(QCryptographicHash::Sha1);
sha1.addData(decryptedBlock);
sha1Hash = sha1.result();
z_stream strm = {};
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = static_cast<uInt>(decryptedBlock.size());
strm.next_in = reinterpret_cast<Bytef*>(decryptedBlock.data());
QByteArray decompressedData;
decompressedData.resize(fmax(dataLength * 2, 4096));
strm.avail_out = decompressedData.size();
strm.next_out = reinterpret_cast<Bytef*>(decompressedData.data());
int zReturn = inflateInit2(&strm, -15);
if (zReturn != Z_OK) {
qWarning() << "inflateInit2 failed with error code" << zReturn;
break;
}
zReturn = inflate(&strm, Z_FINISH);
inflateEnd(&strm);
if (zReturn != Z_STREAM_END) {
qDebug() << "Error decompressing at offset: " << stream.device()->pos() << " : " << zReturn;
decompressedData.clear();
} else {
decompressedData.resize(strm.total_out);
}
finalFastFile.append(decompressedData);
generateNewIV(chunkIndex % 4, sha1Hash, ivTable, ivCounter);
if (stream.device()->pos() + static_cast<qint64>(dataLength) > fileData.size()) {
qWarning() << "Skipping past file size!";
break;
}
stream.skipRawData(dataLength);
chunkIndex++;
}
return finalFastFile;
}
QByteArray Encryption::decryptFastFile_BO3(const QByteArray &fastFileData) {
const QByteArray salsaKey = QByteArray::fromHex("0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3");
QByteArray ivTable(0xFB0, 0);
@ -426,71 +504,3 @@ QByteArray Encryption::decryptFastFile_BO3(const QByteArray &fastFileData)
return finalFastFile;
}
QByteArray Encryption::DecryptFile(const QByteArray &fastFileData, const QString &aFileName, const QByteArray &aKey)
{
Q_UNUSED(aFileName);
const QByteArray salsaKey = QByteArray::fromHex(aKey);
QByteArray ivTable(0xFB0, 0);
fillIVTable(fastFileData, ivTable, 0xFB0 - 1);
QVector<quint32> 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<const u8*>(salsaKey.constData()), 256, 0);
ECRYPT_ivsetup(&x, reinterpret_cast<const u8*>(ivPtr.constData()));
QByteArray encryptedBlock = fastFileData.mid(stream.device()->pos(), dataLength);
QByteArray decryptedBlock(dataLength, Qt::Uninitialized);
ECRYPT_decrypt_bytes(&x,
reinterpret_cast<const u8*>(encryptedBlock.constData()),
reinterpret_cast<u8*>(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;
}

View File

@ -46,9 +46,8 @@ public:
static void generateNewIV(int index, const QByteArray& hash, QByteArray& ivTable, QVector<quint32>& ivCounter);
//static QByteArray decryptFastFile_BO2(const QByteArray& fastFileData);
static QByteArray decryptFastFile_BO2(const QByteArray& fastFileData);
static QByteArray decryptFastFile_BO3(const QByteArray& fastFileData);
static QByteArray DecryptFile(const QByteArray& fastFileData, const QString& aFileName, const QByteArray& aKey);
};
#endif // ENCRYPTION_H

View File

@ -59,7 +59,7 @@ void ECRYPT_encrypt_bytes(ECRYPT_ctx *x,const u8 *m,u8 *c,u32 bytes)
u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
u8 *ctarget;
u8 tmp[64];
u32 i;
int i;
if (!bytes) return;
@ -82,10 +82,7 @@ void ECRYPT_encrypt_bytes(ECRYPT_ctx *x,const u8 *m,u8 *c,u32 bytes)
for (;;) {
if (bytes < 64) {
for (i = 0; i < bytes; ++i)
{
tmp[i] = m[i];
}
for (i = 0;i < bytes;++i) tmp[i] = m[i];
m = tmp;
ctarget = c;
c = tmp;

View File

@ -94,6 +94,7 @@ void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]);
/* blk0() and blk() perform the initial expand. */
/* I got the idea of expanding during the round function from SSLeay */
/* FIXME: can we do this in an endian-proof way? */
#ifdef WORDS_BIGENDIAN
#define blk0(i) block->l[i]
#else

View File

@ -69,9 +69,15 @@ bool FastFile_COD10_360::Load(const QString aFilePath) {
bool FastFile_COD10_360::Load(const QByteArray aData) {
QByteArray decompressedData;
// Create a XDataStream on the input data.
XDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::LittleEndian);
// 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);
@ -90,7 +96,7 @@ bool FastFile_COD10_360::Load(const QByteArray aData) {
QByteArray rsaSignature(256, Qt::Uninitialized);
fastFileStream.readRawData(rsaSignature.data(), 256);
decompressedData = Encryption::DecryptFile(aData, fileName, "0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3");
decompressedData = Encryption::decryptFastFile_BO2(aData);
// For COD9, write out the complete decompressed zone for testing.
QFile testFile("exports/" + GetBaseStem() + ".zone");
@ -98,7 +104,6 @@ bool FastFile_COD10_360::Load(const QByteArray aData) {
testFile.write(decompressedData);
testFile.close();
}
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
// Load the zone file with the decompressed data (using an Xbox platform flag).
ZoneFile_COD10_360* zoneFile = new ZoneFile_COD10_360();

View File

@ -68,74 +68,29 @@ bool FastFile_COD11_360::Load(const QString aFilePath) {
return true;
}
enum DB_CompressorType : qint32
{
DB_COMPRESSOR_INVALID = 0x0,
DB_COMPRESSOR_ZLIB = 0x1,
DB_COMPRESSOR_LZX = 0x2,
DB_COMPRESSOR_PASSTHROUGH = 0x3,
};
bool FastFile_COD11_360::Load(const QByteArray aData) {
QByteArray decompressedData;
// Prepare data stream for parsing
XDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::BigEndian);
QDataStream fastFileStream(aData);
fastFileStream.setByteOrder(QDataStream::LittleEndian);
// Verify magic header
QByteArray fileMagic(8, Qt::Uninitialized);
fastFileStream.readRawData(fileMagic.data(), 8);
quint32 version = fastFileStream.ParseUInt32();
fastFileStream.skipRawData(1);
DB_CompressorType compressorType = (DB_CompressorType)fastFileStream.ParseInt8();
fastFileStream.skipRawData(10);
qint32 blockCount = fastFileStream.ParseInt32();
if (version != 1838)
{
qWarning() << "Invalid fast file version:" << version << "!";
if (fileMagic != "TAff0000") {
qWarning() << "Invalid fast file magic for COD12!";
return false;
}
if (blockCount > 17280)
{
qWarning() << "Fast file has too many blocks:" << blockCount << "> 17280!";
return false;
}
fastFileStream.skipRawData(12 * blockCount);
// 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.
qint32 startPos = fastFileStream.ParseInt32();
Q_UNUSED(startPos);
// Correctly positioned at 0x138
QByteArray encryptedData = aData.mid(0x138);
decompressedData = Encryption::decryptFastFile_BO3(encryptedData);
qint32 endPos = fastFileStream.ParseInt32();
Q_UNUSED(endPos);
if (fileMagic == "S1ffu100")
{
QByteArray compressedData = aData.mid(fastFileStream.device()->pos());
if (compressorType == DB_COMPRESSOR_ZLIB)
{
decompressedData = Compression::DecompressZLIB(compressedData);
}
else if (compressorType == DB_COMPRESSOR_LZX)
{
decompressedData = Compression::DecompressXMem(compressedData, 0, 0x80000, 0);
}
}
else if (fileMagic == "S1ff0100")
{
}
else
{
qWarning() << "Invalid fast file magic:" << fileMagic << "!";
return false;
}
// Output for verification/testing
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
// Load the zone file with decompressed data

View File

@ -72,69 +72,24 @@ bool FastFile_COD12_360::Load(const QByteArray aData) {
QByteArray decompressedData;
// Prepare data stream for parsing
XDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::LittleEndian);
QDataStream fastFileStream(aData);
fastFileStream.setByteOrder(QDataStream::LittleEndian);
// 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 != 4) {
qDebug() << "Invalid platform: " << platformFlag;
return false;
} else if (encryptionFlag != 0) {
qDebug() << "Decryption not supported yet!";
// 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;
}
fastFileStream.skipRawData(128);
// 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.
quint64 size;
fastFileStream >> size;
// Correctly positioned at 0x138
QByteArray encryptedData = aData.mid(0x138);
decompressedData = Encryption::decryptFastFile_BO3(encryptedData);
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);
}
// Output for verification/testing
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);

View File

@ -68,9 +68,9 @@ bool FastFile_COD2_360::Load(const QString aFilePath) {
}
bool FastFile_COD2_360::Load(const QByteArray aData) {
// Create a XDataStream on the input data.
XDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::LittleEndian);
// 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());

View File

@ -80,9 +80,9 @@ bool FastFile_COD4_360::Load(const QByteArray aData) {
// For COD5, simply decompress from offset 12.
decompressedData = Compression::DecompressZLIB(aData.mid(12));
} else if (header == "IWff0100") {
// Create a XDataStream on the input data.
XDataStream fastFileStream(aData.mid(12));
fastFileStream.setByteOrder(XDataStream::LittleEndian);
// Create a QDataStream on the input data.
QDataStream fastFileStream(aData.mid(12));
fastFileStream.setByteOrder(QDataStream::LittleEndian);
QByteArray magic(8, Qt::Uninitialized);
fastFileStream.readRawData(magic.data(), 8);

View File

@ -70,47 +70,30 @@ bool FastFile_COD6_360::Load(const QString aFilePath) {
}
bool FastFile_COD6_360::Load(const QByteArray aData) {
XDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::BigEndian);
QByteArray magic(8, Qt::Uninitialized);
fastFileStream.readRawData(magic.data(), 8);
quint32 version = fastFileStream.ParseUInt32();
if (version != 269)
const qint64 zlibOffset = Compression::FindZlibOffset(aData);
if (zlibOffset == -1)
{
qDebug() << QString("Invalid version: %1!").arg(version);
qWarning() << "Z-Lib stream not found";
return false;
}
QByteArray compressed = aData.mid(zlibOffset);
QByteArray decompressedData = Compression::DecompressZLIB(compressed);
if (decompressedData.isEmpty() || decompressedData.size() < 1024)
{
QByteArray stripped = Compression::StripHashBlocks(compressed);
QByteArray retry = Compression::DecompressZLIB(stripped);
if (!retry.isEmpty())
decompressedData.swap(retry);
}
if (decompressedData.isEmpty())
{
qWarning() << "Unable to decompress fast-file";
return false;
}
bool localPatch = fastFileStream.ParseBool();
Q_UNUSED(localPatch);
quint8 compressor = fastFileStream.ParseUInt8();
Q_UNUSED(compressor);
// Skip fastfile date/time
fastFileStream.skipRawData(11);
quint32 hashCount = fastFileStream.ParseUInt32();
fastFileStream.skipRawData(12 * hashCount);
fastFileStream.skipRawData(8);
QByteArray decompressedData;
if (magic == "IWff0100")
{
}
else if (magic == "IWffu100")
{
quint32 zlibSize = aData.size() - fastFileStream.device()->pos();
QByteArray zlibData(zlibSize, Qt::Uninitialized);
fastFileStream.readRawData(zlibData.data(), zlibSize);
decompressedData = Compression::DecompressZLIB(zlibData);
}
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
ZoneFile_COD6_360* zoneFile = new ZoneFile_COD6_360();

View File

@ -71,11 +71,16 @@ bool FastFile_COD7_360::Load(const QString aFilePath) {
bool FastFile_COD7_360::Load(const QByteArray aData) {
QByteArray decompressedData;
// Create a XDataStream on the input data.
XDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::BigEndian);
// Create a QDataStream on the input data.
QDataStream fastFileStream(aData);
fastFileStream.skipRawData(12);
fastFileStream.skipRawData(16);
// 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);
@ -97,8 +102,6 @@ bool FastFile_COD7_360::Load(const QByteArray aData) {
QByteArray rsaSignature(256, Qt::Uninitialized);
fastFileStream.readRawData(rsaSignature.data(), 256);
QByteArray key = QByteArray::fromHex("1ac1d12d527c59b40eca619120ff8217ccff09cd16896f81b829c7f52793405d");
// Now the stream should be positioned at 0x13C, where sections begin.
int sectionIndex = 0;
while (true) {

View File

@ -1,148 +0,0 @@
#include "fastfile_cod7_5_360.h"
#include "zonefile_cod7_360.h"
#include "compression.h"
#include "encryption.h"
#include <QFile>
#include <QDebug>
FastFile_COD7_5_360::FastFile_COD7_5_360()
: FastFile() {
SetCompany(COMPANY_INFINITY_WARD);
SetType(FILETYPE_FAST_FILE);
SetSignage(SIGNAGE_UNSIGNED);
SetMagic(0);
SetVersion(0);
SetPlatform("360");
SetGame("COD7.5");
}
FastFile_COD7_5_360::FastFile_COD7_5_360(const QByteArray& aData)
: FastFile_COD7_5_360() {
if (!aData.isEmpty()) {
Load(aData);
}
}
FastFile_COD7_5_360::FastFile_COD7_5_360(const QString aFilePath)
: FastFile_COD7_5_360() {
if (!aFilePath.isEmpty()) {
Load(aFilePath);
}
}
FastFile_COD7_5_360::~FastFile_COD7_5_360() {
}
QByteArray FastFile_COD7_5_360::GetBinaryData() const {
return QByteArray();
}
bool FastFile_COD7_5_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;
}
enum NX_Language : qint32
{
LANGUAGE_ENGLISH = 0x0,
LANGUAGE_FRENCH = 0x1,
LANGUAGE_GERMAN = 0x2,
LANGUAGE_ITALIAN = 0x3,
LANGUAGE_SPANISH = 0x4,
LANGUAGE_BRITISH = 0x5,
LANGUAGE_RUSSIAN = 0x6,
LANGUAGE_POLISH = 0x7,
LANGUAGE_KOREAN = 0x8,
LANGUAGE_TAIWANESE = 0x9,
LANGUAGE_JAPANESE = 0xA,
LANGUAGE_CHINESE = 0xB,
LANGUAGE_THAI = 0xC,
LANGUAGE_LEET = 0xD,
LANGUAGE_CZECH = 0xE,
MAX_LANGUAGES = 0xF,
};
bool FastFile_COD7_5_360::Load(const QByteArray aData) {
// Create a XDataStream on the input data.
XDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::BigEndian);
QByteArray magic(8, Qt::Uninitialized);
fastFileStream.readRawData(magic.data(), 8);
quint32 version = fastFileStream.ParseUInt32();
if (version != 357)
{
qDebug() << QString("Invalid version: %1!").arg(version);
return false;
}
bool localPatch = fastFileStream.ParseBool();
Q_UNUSED(localPatch);
quint8 compressor = fastFileStream.ParseUInt8();
Q_UNUSED(compressor);
// Skip fastfile date/time
fastFileStream.skipRawData(8);
NX_Language language = (NX_Language)fastFileStream.ParseInt32();
Q_UNUSED(language);
quint32 hashCount = fastFileStream.ParseUInt32();
fastFileStream.skipRawData(12 * hashCount);
fastFileStream.skipRawData(8);
QByteArray decompressedData;
if (magic == "NXff0100")
{
}
else if (magic == "NXffu100")
{
quint32 zlibSize = aData.size() - fastFileStream.device()->pos();
QByteArray zlibData(zlibSize, Qt::Uninitialized);
fastFileStream.readRawData(zlibData.data(), zlibSize);
decompressedData = Compression::DecompressZLIB(zlibData);
}
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
ZoneFile_COD7_360* zoneFile = new ZoneFile_COD7_360();
zoneFile->SetStem(GetBaseStem() + ".zone");
if (!zoneFile->Load(decompressedData)) {
qWarning() << "Failed to load ZoneFile!";
return false;
}
SetZoneFile(zoneFile);
return true;
}

View File

@ -1,20 +0,0 @@
#ifndef FASTFILE_COD7_5_360_H
#define FASTFILE_COD7_5_360_H
#include "fastfile.h"
class FastFile_COD7_5_360 : public FastFile
{
public:
FastFile_COD7_5_360();
FastFile_COD7_5_360(const QByteArray& aData);
FastFile_COD7_5_360(const QString aFilePath);
~FastFile_COD7_5_360();
QByteArray GetBinaryData() const override;
bool Load(const QString aFilePath) override;
bool Load(const QByteArray aData) override;
};
#endif // FASTFILE_COD7_5_360_H

View File

@ -69,12 +69,15 @@ bool FastFile_COD8_360::Load(const QString aFilePath) {
bool FastFile_COD8_360::Load(const QByteArray aData) {
QByteArray decompressedData;
// Create a XDataStream on the input data.
XDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::LittleEndian);
// Create a QDataStream on the input data.
QDataStream fastFileStream(aData);
fastFileStream.setByteOrder(QDataStream::LittleEndian);
// For COD7/COD9, use BigEndian.
fastFileStream.setByteOrder(XDataStream::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);
@ -89,7 +92,11 @@ bool FastFile_COD8_360::Load(const QByteArray aData) {
QByteArray fileName(32, Qt::Uninitialized);
fastFileStream.readRawData(fileName.data(), 32);
decompressedData = Encryption::DecryptFile(aData, fileName, "0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3");
// 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/" + GetBaseStem() + ".zone");

View File

@ -69,12 +69,15 @@ bool FastFile_COD9_360::Load(const QString aFilePath) {
bool FastFile_COD9_360::Load(const QByteArray aData) {
QByteArray decompressedData;
// Create a XDataStream on the input data.
XDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::LittleEndian);
// Create a QDataStream on the input data.
QDataStream fastFileStream(aData);
fastFileStream.setByteOrder(QDataStream::LittleEndian);
// For COD7/COD9, use BigEndian.
fastFileStream.setByteOrder(XDataStream::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);
@ -93,7 +96,7 @@ bool FastFile_COD9_360::Load(const QByteArray aData) {
QByteArray rsaSignature(256, Qt::Uninitialized);
fastFileStream.readRawData(rsaSignature.data(), 256);
decompressedData = Encryption::DecryptFile(aData, fileName, "0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3");
decompressedData = Encryption::decryptFastFile_BO2(aData);
// For COD9, write out the complete decompressed zone for testing.
QFile testFile("exports/" + GetBaseStem() + ".zone");

View File

@ -69,9 +69,9 @@ bool FastFile_COD10_PC::Load(const QString aFilePath) {
bool FastFile_COD10_PC::Load(const QByteArray aData) {
QByteArray decompressedData;
// Create a XDataStream on the input data.
XDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::LittleEndian);
// Create a QDataStream on the input data.
QDataStream fastFileStream(aData);
fastFileStream.setByteOrder(QDataStream::LittleEndian);
// Parse header values.
SetCompany(pParseFFCompany(&fastFileStream));
@ -84,13 +84,18 @@ bool FastFile_COD10_PC::Load(const QByteArray aData) {
SetGame("COD9");
// For COD7/COD9, use BigEndian.
fastFileStream.setByteOrder(XDataStream::BigEndian);
fastFileStream.setByteOrder(QDataStream::BigEndian);
if (GetPlatform() == "PC") {
fastFileStream.setByteOrder(XDataStream::LittleEndian);
fastFileStream.setByteOrder(QDataStream::LittleEndian);
}
// Select key based on game.
QByteArray key = QByteArray::fromHex("641D8A2FE31D3AA63622BBC9CE8587229D42B0F8ED9B924130BF88B65EDC50BE");
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);
@ -109,7 +114,11 @@ bool FastFile_COD10_PC::Load(const QByteArray aData) {
QByteArray rsaSignature(256, Qt::Uninitialized);
fastFileStream.readRawData(rsaSignature.data(), 256);
//decompressedData = Encryption::decryptFastFile_BO2(aData);
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/" + GetBaseStem() + ".zone");
@ -117,7 +126,6 @@ bool FastFile_COD10_PC::Load(const QByteArray aData) {
testFile.write(decompressedData);
testFile.close();
}
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
// Load the zone file with the decompressed data (using an Xbox platform flag).
ZoneFile_COD10_PC* zoneFile = new ZoneFile_COD10_PC();

View File

@ -69,9 +69,9 @@ bool FastFile_COD11_PC::Load(const QString aFilePath) {
bool FastFile_COD11_PC::Load(const QByteArray aData) {
QByteArray decompressedData;
// Create a XDataStream on the input data.
XDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::LittleEndian);
// Create a QDataStream on the input data.
QDataStream fastFileStream(aData);
fastFileStream.setByteOrder(QDataStream::LittleEndian);
// Parse header values.
SetCompany(pParseFFCompany(&fastFileStream));
@ -80,11 +80,22 @@ bool FastFile_COD11_PC::Load(const QByteArray aData) {
SetMagic(pParseFFMagic(&fastFileStream));
quint32 version = pParseFFVersion(&fastFileStream);
SetVersion(version);
SetPlatform(pCalculateFFPlatform(version));
SetGame("COD9");
fastFileStream.setByteOrder(XDataStream::LittleEndian);
// For COD7/COD9, use BigEndian.
fastFileStream.setByteOrder(QDataStream::BigEndian);
if (GetPlatform() == "PC") {
fastFileStream.setByteOrder(QDataStream::LittleEndian);
}
// Select key based on game.
QByteArray key = QByteArray::fromHex("641D8A2FE31D3AA63622BBC9CE8587229D42B0F8ED9B924130BF88B65EDC50BE");
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);
@ -103,7 +114,11 @@ bool FastFile_COD11_PC::Load(const QByteArray aData) {
QByteArray rsaSignature(256, Qt::Uninitialized);
fastFileStream.readRawData(rsaSignature.data(), 256);
//decompressedData = Encryption::decryptFastFile_BO2(aData);
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/" + GetBaseStem() + ".zone");
@ -111,7 +126,6 @@ bool FastFile_COD11_PC::Load(const QByteArray aData) {
testFile.write(decompressedData);
testFile.close();
}
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
// Load the zone file with the decompressed data (using an Xbox platform flag).
ZoneFile_COD11_PC* zoneFile = new ZoneFile_COD11_PC();

View File

@ -72,9 +72,9 @@ bool FastFile_COD12_PC::Load(const QString aFilePath) {
bool FastFile_COD12_PC::Load(const QByteArray aData) {
QByteArray decompressedData;
// Create a XDataStream on the input data.
XDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::LittleEndian);
// Create a QDataStream on the input data.
QDataStream fastFileStream(aData);
fastFileStream.setByteOrder(QDataStream::LittleEndian);
// Skip header magic
fastFileStream.skipRawData(8);
@ -136,6 +136,7 @@ bool FastFile_COD12_PC::Load(const QByteArray aData) {
// Sinze Fast Files are aligns, we must skip the full block
fastFileStream.device()->seek(blockPosition + 16 + blockSize);
}
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
// Load the zone file with the decompressed data (using an Xbox platform flag).

View File

@ -75,9 +75,9 @@ bool FastFile_COD4_PC::Load(const QByteArray aData) {
StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/data", 1000);
QByteArray decompressedData;
// Create a XDataStream on the input data.
XDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::LittleEndian);
// 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));

View File

@ -75,9 +75,9 @@ bool FastFile_COD5_PC::Load(const QByteArray aData) {
StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/data", 1000);
QByteArray decompressedData;
// Create a XDataStream on the input data.
XDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::LittleEndian);
// 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));

View File

@ -72,30 +72,12 @@ bool FastFile_COD6_PC::Load(const QString aFilePath) {
}
bool FastFile_COD6_PC::Load(const QByteArray aData) {
const qint64 zlibOffset = Compression::FindZlibOffset(aData);
qDebug() << "ZLib Offset: " << zlibOffset;
if (zlibOffset == -1)
{
qWarning() << "Z-Lib stream not found";
return false;
}
QByteArray compressed = aData.mid(zlibOffset);
StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/data", 1000);
QByteArray decompressedData;
QByteArray decompressedData = Compression::DecompressZLIB(compressed);
if (decompressedData.isEmpty() || decompressedData.size() < 1024)
{
QByteArray stripped = Compression::StripHashBlocks(compressed);
QByteArray retry = Compression::DecompressZLIB(stripped);
if (!retry.isEmpty())
decompressedData.swap(retry);
}
if (decompressedData.isEmpty())
{
qWarning() << "Unable to decompress fast-file";
return false;
}
// Assume the first 12 bytes are a header; the rest is zlib-compressed zone data.
const QByteArray compressedData = aData.mid(21);
decompressedData = Compression::DecompressZLIB(compressedData);
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);

View File

@ -72,9 +72,9 @@ bool FastFile_COD7_PC::Load(const QString aFilePath) {
bool FastFile_COD7_PC::Load(const QByteArray aData) {
QByteArray decompressedData;
// Create a XDataStream on the input data.
XDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::LittleEndian);
// Create a QDataStream on the input data.
QDataStream fastFileStream(aData);
fastFileStream.setByteOrder(QDataStream::LittleEndian);
// Parse header values.
SetCompany(pParseFFCompany(&fastFileStream));

View File

@ -72,19 +72,91 @@ bool FastFile_COD8_PC::Load(const QString aFilePath) {
bool FastFile_COD8_PC::Load(const QByteArray aData) {
QByteArray decompressedData;
// Create a XDataStream on the input data.
XDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::LittleEndian);
// 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));
quint32 version = pParseFFVersion(&fastFileStream);
SetVersion(version);
SetPlatform(pCalculateFFPlatform(version));
SetGame("COD7");
decompressedData = Compression::DecompressZLIB(aData.mid(21));
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
// 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_COD8_PC* zoneFile = new ZoneFile_COD8_PC();
zoneFile->SetStem(GetBaseStem() + ".zone");

View File

@ -67,18 +67,37 @@ bool FastFile_COD9_PC::Load(const QString aFilePath) {
}
bool FastFile_COD9_PC::Load(const QByteArray aData) {
// Create a XDataStream on the input data.
XDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::LittleEndian);
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));
quint32 version = pParseFFVersion(&fastFileStream);
SetVersion(version);
SetPlatform(pCalculateFFPlatform(version));
SetGame("COD9");
// Validate the fastfile magic.
// 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") {
@ -87,100 +106,35 @@ bool FastFile_COD9_PC::Load(const QByteArray aData) {
}
fastFileStream.skipRawData(4);
// Read IV seed name (32 bytes).
QByteArray nameKey(32, Qt::Uninitialized);
fastFileStream.readRawData(nameKey.data(), 32);
// Read IV table name (32 bytes).
QByteArray fileName(32, Qt::Uninitialized);
fastFileStream.readRawData(fileName.data(), 32);
// --- Salsa20 + IV setup ---
static QVector<quint32> ivCounter(4, 1);
QByteArray ivTable = Encryption::InitIVTable(nameKey);
ivCounter.fill(1); // reset global counters
// Skip the RSA signature (256 bytes).
QByteArray rsaSignature(256, Qt::Uninitialized);
fastFileStream.readRawData(rsaSignature.data(), 256);
// Skip RSA signature (0x100)
fastFileStream.skipRawData(0x100);
// Decrypt + decompress loop
QByteArray finalZone;
int chunkIndex = 0;
while (!fastFileStream.atEnd()) {
quint32 dataLength = 0;
fastFileStream >> dataLength;
if (dataLength == 0)
break;
QByteArray encryptedBlock(dataLength, Qt::Uninitialized);
if (fastFileStream.readRawData(encryptedBlock.data(), dataLength) != dataLength) {
qWarning() << "Unexpected EOF while reading block";
break;
if (GetPlatform() == "360") {
//decompressedData = Compressor::cod9_decryptFastFile(aData);
} else if (GetPlatform() == "PC") {
decompressedData = Encryption::decryptFastFile_BO2(aData);
}
// Derive IV for this chunk
QByteArray iv = Encryption::GetIV(ivTable, chunkIndex % 4);
// Salsa20 decryption
QByteArray decryptedBlock = Encryption::salsa20DecryptSection(
encryptedBlock,
QByteArray::fromHex("641D8A2FE31D3AA63622BBC9CE8587229D42B0F8ED9B924130BF88B65EDC50BE"),
iv,
64
);
// SHA1 hash of decrypted block
QCryptographicHash sha1(QCryptographicHash::Sha1);
sha1.addData(decryptedBlock);
QByteArray sha1Hash = sha1.result();
// Inflate into buffer
z_stream strm{};
strm.avail_in = static_cast<uInt>(decryptedBlock.size());
strm.next_in = reinterpret_cast<Bytef*>(decryptedBlock.data());
QByteArray decompressedData;
QByteArray buffer(0x10000, Qt::Uninitialized);
inflateInit2(&strm, -15);
int ret;
do {
strm.avail_out = buffer.size();
strm.next_out = reinterpret_cast<Bytef*>(buffer.data());
ret = inflate(&strm, Z_NO_FLUSH);
if (ret != Z_OK && ret != Z_STREAM_END && ret != Z_BUF_ERROR) {
qWarning() << "inflate failed with code" << ret;
break;
// For COD9, write out the complete decompressed zone for testing.
QFile testFile("exports/" + GetBaseStem() + ".zone");
if(testFile.open(QIODevice::WriteOnly)) {
testFile.write(decompressedData);
testFile.close();
}
int have = buffer.size() - strm.avail_out;
if (have > 0)
decompressedData.append(buffer.constData(), have);
} while (ret != Z_STREAM_END);
inflateEnd(&strm);
finalZone.append(decompressedData);
// Update IV table for next block
Encryption::UpdateIVTable(ivTable, chunkIndex % 4, sha1Hash);
chunkIndex++;
}
// Export decompressed zone
Utils::ExportData(GetBaseStem() + ".zone", finalZone);
// Load zone file
// Load the zone file with the decompressed data (using an Xbox platform flag).
ZoneFile_COD9_PC* zoneFile = new ZoneFile_COD9_PC();
zoneFile->SetStem(GetBaseStem() + ".zone");
if (!zoneFile->Load(finalZone)) {
if (!zoneFile->Load(decompressedData)) {
qWarning() << "Failed to load ZoneFile!";
return false;
}
SetZoneFile(zoneFile);
return true;
return true;
}

View File

@ -69,9 +69,9 @@ bool FastFile_COD10_PS3::Load(const QString aFilePath) {
bool FastFile_COD10_PS3::Load(const QByteArray aData) {
QByteArray decompressedData;
// Create a XDataStream on the input data.
XDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::LittleEndian);
// Create a QDataStream on the input data.
QDataStream fastFileStream(aData);
fastFileStream.setByteOrder(QDataStream::LittleEndian);
// Parse header values.
SetCompany(pParseFFCompany(&fastFileStream));
@ -84,9 +84,9 @@ bool FastFile_COD10_PS3::Load(const QByteArray aData) {
SetGame("COD9");
// For COD7/COD9, use BigEndian.
fastFileStream.setByteOrder(XDataStream::BigEndian);
fastFileStream.setByteOrder(QDataStream::BigEndian);
if (GetPlatform() == "PC") {
fastFileStream.setByteOrder(XDataStream::LittleEndian);
fastFileStream.setByteOrder(QDataStream::LittleEndian);
}
// Select key based on game.
@ -110,7 +110,15 @@ bool FastFile_COD10_PS3::Load(const QByteArray aData) {
QByteArray fileName(32, Qt::Uninitialized);
fastFileStream.readRawData(fileName.data(), 32);
//decompressedData = Encryption::decryptFastFile_BO2(aData);
// 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/" + GetBaseStem() + ".zone");

View File

@ -1,7 +1,6 @@
#include "fastfile_cod11_ps3.h"
#include "zonefile_cod11_ps3.h"
#include "encryption.h"
#include "compression.h"
#include <QFile>
#include <QDebug>
@ -67,77 +66,68 @@ bool FastFile_COD11_PS3::Load(const QString aFilePath) {
return true;
}
enum DB_CompressorType : qint32
{
DB_COMPRESSOR_INVALID = 0x0,
DB_COMPRESSOR_ZLIB = 0x1,
DB_COMPRESSOR_LZX = 0x2,
DB_COMPRESSOR_PASSTHROUGH = 0x3,
};
bool FastFile_COD11_PS3::Load(const QByteArray aData) {
QByteArray decompressedData;
// Prepare data stream for parsing
XDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::BigEndian);
// Create a QDataStream on the input data.
QDataStream fastFileStream(aData);
fastFileStream.setByteOrder(QDataStream::LittleEndian);
// Verify magic header
// 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);
quint32 version = fastFileStream.ParseUInt32();
fastFileStream.skipRawData(1);
DB_CompressorType compressorType = (DB_CompressorType)fastFileStream.ParseInt8();
fastFileStream.skipRawData(10);
qint32 blockCount = fastFileStream.ParseInt32();
if (version != 1838)
{
qWarning() << "Invalid fast file version:" << version << "!";
if (fileMagic != "PHEEBs71") {
qWarning() << "Invalid fast file magic!";
return false;
}
fastFileStream.skipRawData(4);
if (blockCount > 17280)
{
qWarning() << "Fast file has too many blocks:" << blockCount << "> 17280!";
return false;
}
fastFileStream.skipRawData(12 * blockCount);
// Read IV table name (32 bytes).
QByteArray fileName(32, Qt::Uninitialized);
fastFileStream.readRawData(fileName.data(), 32);
qint32 startPos = fastFileStream.ParseInt32();
Q_UNUSED(startPos);
// Skip the RSA signature (256 bytes).
QByteArray rsaSignature(256, Qt::Uninitialized);
fastFileStream.readRawData(rsaSignature.data(), 256);
qint32 endPos = fastFileStream.ParseInt32();
Q_UNUSED(endPos);
if (GetPlatform() == "360") {
//decompressedData = Compressor::cod9_decryptFastFile(aData);
} else if (GetPlatform() == "PC") {
decompressedData = Encryption::decryptFastFile_BO2(aData);
}
if (fileMagic == "S1ffu100")
{
QByteArray compressedData = aData.mid(fastFileStream.device()->pos());
if (compressorType == DB_COMPRESSOR_ZLIB)
{
decompressedData = Compression::DecompressZLIB(compressedData);
// For COD9, write out the complete decompressed zone for testing.
QFile testFile("exports/" + GetBaseStem() + ".zone");
if(testFile.open(QIODevice::WriteOnly)) {
testFile.write(decompressedData);
testFile.close();
}
else if (compressorType == DB_COMPRESSOR_LZX)
{
decompressedData = Compression::DecompressXMem(compressedData, 0, 0x80000, 0);
}
}
else if (fileMagic == "S1ff0100")
{
}
else
{
qWarning() << "Invalid fast file magic:" << fileMagic << "!";
return false;
}
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
// Load the zone file with decompressed data
// Load the zone file with the decompressed data (using an Xbox platform flag).
ZoneFile_COD11_PS3* zoneFile = new ZoneFile_COD11_PS3();
zoneFile->SetStem(GetBaseStem() + ".zone");
if (!zoneFile->Load(decompressedData)) {

View File

@ -69,9 +69,9 @@ bool FastFile_COD12_PS3::Load(const QString aFilePath) {
bool FastFile_COD12_PS3::Load(const QByteArray aData) {
QByteArray decompressedData;
// Create a XDataStream on the input data.
XDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::LittleEndian);
// Create a QDataStream on the input data.
QDataStream fastFileStream(aData);
fastFileStream.setByteOrder(QDataStream::LittleEndian);
// Parse header values.
SetCompany(pParseFFCompany(&fastFileStream));
@ -84,9 +84,9 @@ bool FastFile_COD12_PS3::Load(const QByteArray aData) {
SetGame("COD9");
// For COD7/COD9, use BigEndian.
fastFileStream.setByteOrder(XDataStream::BigEndian);
fastFileStream.setByteOrder(QDataStream::BigEndian);
if (GetPlatform() == "PC") {
fastFileStream.setByteOrder(XDataStream::LittleEndian);
fastFileStream.setByteOrder(QDataStream::LittleEndian);
}
// Select key based on game.
@ -110,7 +110,15 @@ bool FastFile_COD12_PS3::Load(const QByteArray aData) {
QByteArray fileName(32, Qt::Uninitialized);
fastFileStream.readRawData(fileName.data(), 32);
decompressedData = Encryption::decryptFastFile_BO3(aData);
// 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/" + GetBaseStem() + ".zone");

View File

@ -75,9 +75,9 @@ bool FastFile_COD4_PS3::Load(const QByteArray aData) {
StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/data", 1000);
QByteArray decompressedData;
// Create a XDataStream on the input data.
XDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::LittleEndian);
// Create a QDataStream on the input data.
QDataStream fastFileStream(aData);
fastFileStream.setByteOrder(QDataStream::LittleEndian);
// Parse header values.
SetCompany(pParseFFCompany(&fastFileStream));
@ -86,24 +86,29 @@ bool FastFile_COD4_PS3::Load(const QByteArray aData) {
SetMagic(pParseFFMagic(&fastFileStream));
SetVersion(pParseFFVersion(&fastFileStream));
int pos = 12;
// Loop until EOF or invalid chunk
fastFileStream.setByteOrder(XDataStream::BigEndian);
while (!fastFileStream.atEnd()) {
while (pos <= aData.size()) {
// Read 2-byte BIG-ENDIAN chunk size
quint16 chunkSize;
fastFileStream >> chunkSize;
quint32 chunkSize;
QDataStream chunkStream(aData.mid(pos, 2));
chunkStream.setByteOrder(QDataStream::BigEndian);
chunkStream >> chunkSize;
if (chunkSize == 0 || fastFileStream.device()->pos() + chunkSize > aData.size()) {
pos += 2;
if (chunkSize == 0 || pos + chunkSize > aData.size()) {
qWarning() << "Invalid or incomplete chunk detected, stopping.";
break;
}
QByteArray compressedChunk(chunkSize, Qt::Uninitialized);
fastFileStream.readRawData(compressedChunk.data(), chunkSize);
const QByteArray compressedChunk = aData.mid(pos, chunkSize);
QByteArray decompressedChunk = Compression::DecompressDeflate(compressedChunk);
decompressedData.append(decompressedChunk);
decompressedData.append(Compression::DecompressDeflate(compressedChunk));
pos += chunkSize;
}
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
ZoneFile_COD4_PS3* zoneFile = new ZoneFile_COD4_PS3();

View File

@ -75,9 +75,9 @@ bool FastFile_COD5_PS3::Load(const QByteArray aData) {
StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/data", 1000);
QByteArray decompressedData;
// Create a XDataStream on the input data.
XDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::LittleEndian);
// Create a QDataStream on the input data.
QDataStream fastFileStream(aData);
fastFileStream.setByteOrder(QDataStream::LittleEndian);
// Parse header values.
SetCompany(pParseFFCompany(&fastFileStream));
@ -86,24 +86,29 @@ bool FastFile_COD5_PS3::Load(const QByteArray aData) {
SetMagic(pParseFFMagic(&fastFileStream));
SetVersion(pParseFFVersion(&fastFileStream));
int pos = 12;
// Loop until EOF or invalid chunk
fastFileStream.setByteOrder(XDataStream::BigEndian);
while (!fastFileStream.atEnd()) {
while (pos <= aData.size()) {
// Read 2-byte BIG-ENDIAN chunk size
quint16 chunkSize;
fastFileStream >> chunkSize;
quint32 chunkSize;
QDataStream chunkStream(aData.mid(pos, 2));
chunkStream.setByteOrder(QDataStream::BigEndian);
chunkStream >> chunkSize;
if (chunkSize == 0 || fastFileStream.device()->pos() + chunkSize > aData.size()) {
pos += 2;
if (chunkSize == 0 || pos + chunkSize > aData.size()) {
qWarning() << "Invalid or incomplete chunk detected, stopping.";
break;
}
QByteArray compressedChunk(chunkSize, Qt::Uninitialized);
fastFileStream.readRawData(compressedChunk.data(), chunkSize);
const QByteArray compressedChunk = aData.mid(pos, chunkSize);
QByteArray decompressedChunk = Compression::DecompressDeflate(compressedChunk);
decompressedData.append(decompressedChunk);
decompressedData.append(Compression::DecompressDeflate(compressedChunk));
pos += chunkSize;
}
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
ZoneFile_COD5_PS3* zoneFile = new ZoneFile_COD5_PS3();

View File

@ -72,30 +72,26 @@ bool FastFile_COD6_PS3::Load(const QString aFilePath) {
}
bool FastFile_COD6_PS3::Load(const QByteArray aData) {
const qint64 zlibOffset = Compression::FindZlibOffset(aData);
qDebug() << "ZLib Offset: " << zlibOffset;
if (zlibOffset == -1)
{
qWarning() << "Z-Lib stream not found";
return false;
}
QByteArray compressed = aData.mid(zlibOffset);
StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/data", 1000);
QByteArray decompressedData;
QByteArray decompressedData = Compression::DecompressZLIB(compressed);
// Create a QDataStream on the input data.
QDataStream fastFileStream(aData);
fastFileStream.setByteOrder(QDataStream::LittleEndian);
if (decompressedData.isEmpty() || decompressedData.size() < 1024)
{
QByteArray stripped = Compression::StripHashBlocks(compressed);
QByteArray retry = Compression::DecompressZLIB(stripped);
if (!retry.isEmpty())
decompressedData.swap(retry);
}
// 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");
if (decompressedData.isEmpty())
{
qWarning() << "Unable to decompress fast-file";
return false;
}
// For COD5, simply decompress from offset 12.
decompressedData = Compression::DecompressZLIB(aData.mid(12));
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);

View File

@ -62,35 +62,49 @@ bool FastFile_COD7_PS3::Load(const QString aFilePath) {
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 XDataStream on the input data.
XDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::LittleEndian);
// 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));
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 = new ZoneFile_COD7_PS3();
zoneFile->SetStem(GetBaseStem() + ".zone");
// For COD7/COD9, use BigEndian.
fastFileStream.setByteOrder(XDataStream::BigEndian);
fastFileStream.setByteOrder(QDataStream::BigEndian);
if (GetPlatform() == "PC") {
fastFileStream.setByteOrder(QDataStream::LittleEndian);
// Select key based on game.
QByteArray key = "46D3F997F29C9ACE175B0DAE3AB8C0C1B8E423E2E3BF7E3C311EA35245BF193A";
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);
@ -149,12 +163,12 @@ bool FastFile_COD7_PS3::Load(const QByteArray aData) {
sectionIndex++;
}
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
if (!zoneFile->Load(decompressedData)) {
qWarning() << "Failed to load ZoneFile!";
return false;
}
}
SetZoneFile(zoneFile);
return true;

View File

@ -72,9 +72,9 @@ bool FastFile_COD8_PS3::Load(const QString aFilePath) {
bool FastFile_COD8_PS3::Load(const QByteArray aData) {
QByteArray decompressedData;
// Create a XDataStream on the input data.
XDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::LittleEndian);
// Create a QDataStream on the input data.
QDataStream fastFileStream(aData);
fastFileStream.setByteOrder(QDataStream::LittleEndian);
// Parse header values.
SetCompany(pParseFFCompany(&fastFileStream));
@ -90,9 +90,9 @@ bool FastFile_COD8_PS3::Load(const QByteArray aData) {
zoneFile->SetStem(GetBaseStem() + ".zone");
// For COD7/COD9, use BigEndian.
fastFileStream.setByteOrder(XDataStream::BigEndian);
fastFileStream.setByteOrder(QDataStream::BigEndian);
if (GetPlatform() == "PC") {
fastFileStream.setByteOrder(XDataStream::LittleEndian);
fastFileStream.setByteOrder(QDataStream::LittleEndian);
// Select key based on game.
QByteArray key;
@ -118,6 +118,51 @@ bool FastFile_COD8_PS3::Load(const QByteArray aData) {
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++;
}
if (!zoneFile->Load(decompressedData)) {
qWarning() << "Failed to load ZoneFile!";
return false;

View File

@ -69,9 +69,9 @@ bool FastFile_COD9_PS3::Load(const QString aFilePath) {
bool FastFile_COD9_PS3::Load(const QByteArray aData) {
QByteArray decompressedData;
// Create a XDataStream on the input data.
XDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::LittleEndian);
// Create a QDataStream on the input data.
QDataStream fastFileStream(aData);
fastFileStream.setByteOrder(QDataStream::LittleEndian);
// Parse header values.
SetCompany(pParseFFCompany(&fastFileStream));
@ -84,9 +84,9 @@ bool FastFile_COD9_PS3::Load(const QByteArray aData) {
SetGame("COD9");
// For COD7/COD9, use BigEndian.
fastFileStream.setByteOrder(XDataStream::BigEndian);
fastFileStream.setByteOrder(QDataStream::BigEndian);
if (GetPlatform() == "PC") {
fastFileStream.setByteOrder(XDataStream::LittleEndian);
fastFileStream.setByteOrder(QDataStream::LittleEndian);
}
// Select key based on game.
@ -117,7 +117,7 @@ bool FastFile_COD9_PS3::Load(const QByteArray aData) {
if (GetPlatform() == "360") {
//decompressedData = Compressor::cod9_decryptFastFile(aData);
} else if (GetPlatform() == "PC") {
//decompressedData = Encryption::decryptFastFile_BO2(aData);
decompressedData = Encryption::decryptFastFile_BO2(aData);
}
// For COD9, write out the complete decompressed zone for testing.

View File

@ -69,9 +69,9 @@ bool FastFile_COD7_Wii::Load(const QString aFilePath) {
bool FastFile_COD7_Wii::Load(const QByteArray aData) {
QByteArray decompressedData;
// Create a XDataStream on the input data.
XDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::LittleEndian);
// Create a QDataStream on the input data.
QDataStream fastFileStream(aData);
fastFileStream.setByteOrder(QDataStream::LittleEndian);
// Parse header values.
SetCompany(pParseFFCompany(&fastFileStream));
@ -84,7 +84,7 @@ bool FastFile_COD7_Wii::Load(const QByteArray aData) {
SetGame("COD7");
// For COD7/COD9, use BigEndian.
fastFileStream.setByteOrder(XDataStream::BigEndian);
fastFileStream.setByteOrder(QDataStream::BigEndian);
// For COD7, simply decompress from offset 12.
decompressedData = Compression::DecompressZLIB(aData.mid(12));

View File

@ -69,9 +69,9 @@ bool FastFile_COD8_Wii::Load(const QString aFilePath) {
bool FastFile_COD8_Wii::Load(const QByteArray aData) {
QByteArray decompressedData;
// Create a XDataStream on the input data.
XDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::LittleEndian);
// Create a QDataStream on the input data.
QDataStream fastFileStream(aData);
fastFileStream.setByteOrder(QDataStream::LittleEndian);
// Parse header values.
SetCompany(pParseFFCompany(&fastFileStream));
@ -81,7 +81,7 @@ bool FastFile_COD8_Wii::Load(const QByteArray aData) {
SetVersion(pParseFFVersion(&fastFileStream));
// For COD7/COD9, use BigEndian.
fastFileStream.setByteOrder(XDataStream::BigEndian);
fastFileStream.setByteOrder(QDataStream::BigEndian);
// For COD7, simply decompress from offset 12.
decompressedData = Compression::DecompressZLIB(aData.mid(25));

View File

@ -67,9 +67,9 @@ bool FastFile_COD10_WiiU::Load(const QString aFilePath) {
bool FastFile_COD10_WiiU::Load(const QByteArray aData) {
QByteArray decompressedData;
// Create a XDataStream on the input data.
XDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::LittleEndian);
// Create a QDataStream on the input data.
QDataStream fastFileStream(aData);
fastFileStream.setByteOrder(QDataStream::LittleEndian);
// Parse header values.
SetCompany(pParseFFCompany(&fastFileStream));
@ -82,9 +82,9 @@ bool FastFile_COD10_WiiU::Load(const QByteArray aData) {
SetGame("COD9");
// For COD7/COD9, use BigEndian.
fastFileStream.setByteOrder(XDataStream::BigEndian);
fastFileStream.setByteOrder(QDataStream::BigEndian);
if (GetPlatform() == "PC") {
fastFileStream.setByteOrder(XDataStream::LittleEndian);
fastFileStream.setByteOrder(QDataStream::LittleEndian);
}
// Select key based on game.
@ -115,7 +115,7 @@ bool FastFile_COD10_WiiU::Load(const QByteArray aData) {
if (GetPlatform() == "360") {
//decompressedData = Compressor::cod9_decryptFastFile(aData);
} else if (GetPlatform() == "PC") {
//decompressedData = Encryption::decryptFastFile_BO2(aData);
decompressedData = Encryption::decryptFastFile_BO2(aData);
}
// For COD9, write out the complete decompressed zone for testing.

View File

@ -67,9 +67,9 @@ bool FastFile_COD9_WiiU::Load(const QString aFilePath) {
bool FastFile_COD9_WiiU::Load(const QByteArray aData) {
QByteArray decompressedData;
// Create a XDataStream on the input data.
XDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::LittleEndian);
// Create a QDataStream on the input data.
QDataStream fastFileStream(aData);
fastFileStream.setByteOrder(QDataStream::LittleEndian);
// Parse header values.
SetCompany(pParseFFCompany(&fastFileStream));
@ -82,9 +82,9 @@ bool FastFile_COD9_WiiU::Load(const QByteArray aData) {
SetGame("COD9");
// For COD7/COD9, use BigEndian.
fastFileStream.setByteOrder(XDataStream::BigEndian);
fastFileStream.setByteOrder(QDataStream::BigEndian);
if (GetPlatform() == "PC") {
fastFileStream.setByteOrder(XDataStream::LittleEndian);
fastFileStream.setByteOrder(QDataStream::LittleEndian);
}
// Select key based on game.
@ -115,7 +115,7 @@ bool FastFile_COD9_WiiU::Load(const QByteArray aData) {
if (GetPlatform() == "360") {
//decompressedData = Compressor::cod9_decryptFastFile(aData);
} else if (GetPlatform() == "PC") {
//decompressedData = Encryption::decryptFastFile_BO2(aData);
decompressedData = Encryption::decryptFastFile_BO2(aData);
}
// For COD9, write out the complete decompressed zone for testing.

View File

@ -115,7 +115,7 @@ void FastFile::SetPlatform(const QString aPlatform) {
mPlatform = aPlatform;
}
FF_COMPANY FastFile::pParseFFCompany(XDataStream *afastFileStream, quint32 &aCompanyInt) {
FF_COMPANY FastFile::pParseFFCompany(QDataStream *afastFileStream, quint32 &aCompanyInt) {
LogManager::instance().addEntry("Parsing company into reference...");
// Check for null datastream ptr
if (!afastFileStream) { return COMPANY_NONE; }
@ -137,7 +137,7 @@ FF_COMPANY FastFile::pParseFFCompany(XDataStream *afastFileStream, quint32 &aCom
return COMPANY_NONE;
}
FF_COMPANY FastFile::pParseFFCompany(XDataStream *afastFileStream) {
FF_COMPANY FastFile::pParseFFCompany(QDataStream *afastFileStream) {
LogManager::instance().addEntry("Parsing company...");
// Check for null datastream ptr
if (!afastFileStream) { return COMPANY_NONE; }
@ -157,7 +157,7 @@ FF_COMPANY FastFile::pParseFFCompany(XDataStream *afastFileStream) {
return COMPANY_NONE;
}
FF_FILETYPE FastFile::pParseFFFileType(XDataStream *afastFileStream) {
FF_FILETYPE FastFile::pParseFFFileType(QDataStream *afastFileStream) {
// Parse filetype
QByteArray fileTypeData(2, Qt::Uninitialized);
afastFileStream->readRawData(fileTypeData.data(), 2);
@ -168,7 +168,7 @@ FF_FILETYPE FastFile::pParseFFFileType(XDataStream *afastFileStream) {
return FILETYPE_NONE;
}
FF_SIGNAGE FastFile::pParseFFSignage(XDataStream *afastFileStream) {
FF_SIGNAGE FastFile::pParseFFSignage(QDataStream *afastFileStream) {
// Parse filetype
QByteArray signedData(1, Qt::Uninitialized);
afastFileStream->readRawData(signedData.data(), 1);
@ -181,7 +181,7 @@ FF_SIGNAGE FastFile::pParseFFSignage(XDataStream *afastFileStream) {
return SIGNAGE_NONE;
}
QString FastFile::pParseFFMagic(XDataStream *afastFileStream) {
QString FastFile::pParseFFMagic(QDataStream *afastFileStream) {
// Parse magic
QByteArray magicData(3, Qt::Uninitialized);
afastFileStream->readRawData(magicData.data(), 3);
@ -192,7 +192,7 @@ QString FastFile::pParseFFMagic(XDataStream *afastFileStream) {
return "";
}
quint32 FastFile::pParseFFVersion(XDataStream *afastFileStream) {
quint32 FastFile::pParseFFVersion(QDataStream *afastFileStream) {
// Parse version
quint32 version;
*afastFileStream >> version;
@ -267,7 +267,7 @@ FastFile* FastFile::Open(const QString &aFilePath) {
const QString fastFileStem = aFilePath.section("/", -1, -1);
LogManager::instance().addEntry(QString("Stem: %1").arg(fastFileStem));
FastFile* fastFile = FastFileFactory::Create(data, fastFileStem);
FastFile* fastFile = FastFileFactory::Create(data);
fastFile->SetStem(fastFileStem);
return fastFile;

View File

@ -46,12 +46,12 @@ public:
virtual void SetGame(const QString aGame);
virtual void SetPlatform(const QString aPlatform);
static FF_COMPANY pParseFFCompany(XDataStream *afastFileStream, quint32 &aCompanyInt);
static FF_COMPANY pParseFFCompany(XDataStream *afastFileStream);
static FF_FILETYPE pParseFFFileType(XDataStream *afastFileStream);
static FF_SIGNAGE pParseFFSignage(XDataStream *afastFileStream);
static QString pParseFFMagic(XDataStream *afastFileStream);
static quint32 pParseFFVersion(XDataStream *afastFileStream);
static FF_COMPANY pParseFFCompany(QDataStream *afastFileStream, quint32 &aCompanyInt);
static FF_COMPANY pParseFFCompany(QDataStream *afastFileStream);
static FF_FILETYPE pParseFFFileType(QDataStream *afastFileStream);
static FF_SIGNAGE pParseFFSignage(QDataStream *afastFileStream);
static QString pParseFFMagic(QDataStream *afastFileStream);
static quint32 pParseFFVersion(QDataStream *afastFileStream);
static QString pCalculateFFPlatform(quint32 aVersion);
static QString pCalculateFFGame(quint32 aVersion);

View File

@ -7,7 +7,6 @@
#include "360/fastfile_cod5_360.h"
#include "360/fastfile_cod6_360.h"
#include "360/fastfile_cod7_360.h"
#include "360/fastfile_cod7_5_360.h"
#include "360/fastfile_cod8_360.h"
#include "360/fastfile_cod9_360.h"
#include "360/fastfile_cod10_360.h"
@ -67,12 +66,11 @@ enum FastFile_Game {
GAME_COD5 = 0x03,
GAME_COD6 = 0x04,
GAME_COD7 = 0x05,
GAME_COD7_5 = 0x06,
GAME_COD8 = 0x07,
GAME_COD9 = 0x08,
GAME_COD10 = 0x09,
GAME_COD11 = 0x10,
GAME_COD12 = 0x11
GAME_COD8 = 0x06,
GAME_COD9 = 0x07,
GAME_COD10 = 0x08,
GAME_COD11 = 0x09,
GAME_COD12 = 0x010
};
class FastFileFactory {
@ -187,86 +185,83 @@ public:
if (aPlatform == PLATFORM_360) {
if (aGame == GAME_COD2) {
resultFF = new FastFile_COD2_360();
resultFF = new FastFile_COD2_360(aData);
} else if (aGame == GAME_COD4) {
resultFF = new FastFile_COD4_360();
resultFF = new FastFile_COD4_360(aData);
} else if (aGame == GAME_COD5) {
resultFF = new FastFile_COD5_360();
resultFF = new FastFile_COD5_360(aData);
} else if (aGame == GAME_COD6) {
resultFF = new FastFile_COD6_360();
resultFF = new FastFile_COD6_360(aData);
} else if (aGame == GAME_COD7) {
resultFF = new FastFile_COD7_360();
} else if (aGame == GAME_COD7_5) {
resultFF = new FastFile_COD7_5_360();
resultFF = new FastFile_COD7_360(aData);
} else if (aGame == GAME_COD8) {
resultFF = new FastFile_COD8_360();
resultFF = new FastFile_COD8_360(aData);
} else if (aGame == GAME_COD9) {
resultFF = new FastFile_COD9_360();
resultFF = new FastFile_COD9_360(aData);
} else if (aGame == GAME_COD10) {
resultFF = new FastFile_COD10_360();
resultFF = new FastFile_COD10_360(aData);
} else if (aGame == GAME_COD11) {
resultFF = new FastFile_COD11_360();
resultFF = new FastFile_COD11_360(aData);
} else if (aGame == GAME_COD12) {
resultFF = new FastFile_COD12_360();
resultFF = new FastFile_COD12_360(aData);
}
} else if (aPlatform == PLATFORM_PC) {
if (aGame == GAME_COD4) {
resultFF = new FastFile_COD4_PC();
resultFF = new FastFile_COD4_PC(aData);
} else if (aGame == GAME_COD5) {
resultFF = new FastFile_COD5_PC();
resultFF = new FastFile_COD5_PC(aData);
} else if (aGame == GAME_COD6) {
resultFF = new FastFile_COD6_PC();
resultFF = new FastFile_COD6_PC(aData);
} else if (aGame == GAME_COD7) {
resultFF = new FastFile_COD7_PC();
resultFF = new FastFile_COD7_PC(aData);
} else if (aGame == GAME_COD8) {
resultFF = new FastFile_COD8_PC();
resultFF = new FastFile_COD8_PC(aData);
} else if (aGame == GAME_COD9) {
resultFF = new FastFile_COD9_PC();
resultFF = new FastFile_COD9_PC(aData);
} else if (aGame == GAME_COD10) {
resultFF = new FastFile_COD10_PC();
resultFF = new FastFile_COD10_PC(aData);
} else if (aGame == GAME_COD11) {
resultFF = new FastFile_COD11_PC();
resultFF = new FastFile_COD11_PC(aData);
} else if (aGame == GAME_COD12) {
resultFF = new FastFile_COD12_PC();
resultFF = new FastFile_COD12_PC(aData);
}
} else if (aPlatform == PLATFORM_PS3) {
if (aGame == GAME_COD4) {
resultFF = new FastFile_COD4_PS3();
resultFF = new FastFile_COD4_PS3(aData);
} else if (aGame == GAME_COD5) {
resultFF = new FastFile_COD5_PS3();
resultFF = new FastFile_COD5_PS3(aData);
} else if (aGame == GAME_COD6) {
resultFF = new FastFile_COD6_PS3();
resultFF = new FastFile_COD6_PS3(aData);
} else if (aGame == GAME_COD7) {
resultFF = new FastFile_COD7_PS3();
resultFF = new FastFile_COD7_PS3(aData);
} else if (aGame == GAME_COD8) {
resultFF = new FastFile_COD8_PS3();
resultFF = new FastFile_COD8_PS3(aData);
} else if (aGame == GAME_COD9) {
resultFF = new FastFile_COD9_PS3();
resultFF = new FastFile_COD9_PS3(aData);
} else if (aGame == GAME_COD10) {
resultFF = new FastFile_COD10_PS3();
resultFF = new FastFile_COD10_PS3(aData);
} else if (aGame == GAME_COD11) {
resultFF = new FastFile_COD11_PS3();
resultFF = new FastFile_COD11_PS3(aData);
} else if (aGame == GAME_COD12) {
resultFF = new FastFile_COD12_PS3();
resultFF = new FastFile_COD12_PS3(aData);
}
} else if (aPlatform == PLATFORM_WII) {
if (aGame == GAME_COD4) {
resultFF = new FastFile_COD4_Wii();
resultFF = new FastFile_COD4_Wii(aData);
} else if (aGame == GAME_COD7) {
resultFF = new FastFile_COD7_Wii();
resultFF = new FastFile_COD7_Wii(aData);
} else if (aGame == GAME_COD8) {
resultFF = new FastFile_COD8_Wii();
resultFF = new FastFile_COD8_Wii(aData);
}
} else if (aPlatform == PLATFORM_WIIU) {
if (aGame == GAME_COD9) {
resultFF = new FastFile_COD9_WiiU();
resultFF = new FastFile_COD9_WiiU(aData);
} else if (aGame == GAME_COD10) {
resultFF = new FastFile_COD10_WiiU();
resultFF = new FastFile_COD10_WiiU(aData);
}
}
if (resultFF) {
resultFF->SetStem(aStem);
resultFF->Load(aData);
}
return resultFF;
}
@ -288,7 +283,7 @@ private:
static FastFile_Platform pGetPlatform(const QByteArray& aData) {
const QStringList sections = pGetDataSections(aData);
if (sections[0] == "0000" || sections[0] == "4E58") {
if (sections[0] == "0000") {
return PLATFORM_360;
} else if (sections[4] == "0000") {
if (sections[5] == "0001" && sections[6] == "78DA") {
@ -297,8 +292,6 @@ private:
return PLATFORM_360;
} else if (sections[5] == "0183" && sections[6] == "7801") {
return PLATFORM_360;
} else if (sections[5] == "01D9" && sections[6] == "0000") {
return PLATFORM_360;
} else if (sections[6] == "0101" && sections[7] == "CA3E") {
return PLATFORM_360;
} else if (sections[6] == "0000" && sections[7] == "0001") {
@ -340,8 +333,6 @@ private:
return GAME_COD6;
} else if (sections[4] == "D901" || sections[5] == "01DD" || sections[5] == "01D9") {
return GAME_COD7;
} else if (sections[0] == "4E58") {
return GAME_COD7_5;
} else if (sections[4] == "0100" || sections[5] == "006B" || sections[5] == "0070") {
return GAME_COD8;
} else if (sections[4] == "9300" || sections[5] == "0092"

View File

@ -6,6 +6,6 @@ SUBDIRS += core \
fastfile \
xassets \
zonefile \
#ddsfile \
#iwifile \
#ipakfile
ddsfile \
iwifile \
ipakfile

View File

@ -5,10 +5,14 @@ XAnimDeltaPart::XAnimDeltaPart()
, mTrans()
, mQuat()
{
SetName("Animation Delta Part");
}
void XAnimDeltaPart::ParseData(XDataStream *aStream) {
XAnimDeltaPart::~XAnimDeltaPart()
{
}
void XAnimDeltaPart::ParseData(QDataStream *aStream) {
if (GetPtr() == -1) {
mTrans.ParsePtr(aStream);
mQuat.ParsePtr(aStream);

View File

@ -9,9 +9,9 @@ class XAnimDeltaPart : public XAsset
{
public:
explicit XAnimDeltaPart();
~XAnimDeltaPart() = default;
~XAnimDeltaPart();
void ParseData(XDataStream *aStream) override;
void ParseData(QDataStream *aStream) override;
void Clear() override;
const XAnimPartTrans& GetTrans() const;

View File

@ -1,14 +1,12 @@
#include "xanimdeltapartquat.h"
XAnimDeltaPartQuat::XAnimDeltaPartQuat()
: XAsset()
{
SetName("Animation Delta Part Quat");
: XAsset() {
}
void XAnimDeltaPartQuat::ParseData(XDataStream *aStream) {
void XAnimDeltaPartQuat::ParseData(QDataStream *aStream) {
if (GetPtr() == -1) {
mSize = aStream->ParseUInt32(QString("%1 size").arg(GetName()));
*aStream >> mSize;
// Parse data
mData.ParseData(aStream);

View File

@ -1,3 +1,9 @@
#ifndef XANIMDELTAPARTQUAT_H
#define XANIMDELTAPARTQUAT_H
@ -8,9 +14,8 @@ class XAnimDeltaPartQuat : public XAsset
{
public:
explicit XAnimDeltaPartQuat();
~XAnimDeltaPartQuat() = default;
void ParseData(XDataStream *aStream) override;
void ParseData(QDataStream *aStream) override;
quint32 GetSize() const;
void SetSize(quint32 size);
@ -24,3 +29,8 @@ private:
};
#endif // XANIMDELTAPARTQUAT_H

View File

@ -1,12 +1,10 @@
#include "xanimdeltapartquatdata.h"
XAnimDeltaPartQuatData::XAnimDeltaPartQuatData()
: XAsset()
{
SetName("Animation Delta Part Quat Data");
: XAsset() {
}
void XAnimDeltaPartQuatData::ParseData(XDataStream *aStream) {
void XAnimDeltaPartQuatData::ParseData(QDataStream *aStream) {
if (GetPtr() == -1) {
// Parse frames
mFrames.ParseData(aStream);

View File

@ -1,3 +1,9 @@
#ifndef XANIMDELTAPARTQUATDATA_H
#define XANIMDELTAPARTQUATDATA_H
@ -8,9 +14,8 @@ class XAnimDeltaPartQuatData : public XAsset
{
public:
explicit XAnimDeltaPartQuatData();
~XAnimDeltaPartQuatData() = default;
void ParseData(XDataStream *aStream) override;
void ParseData(QDataStream *aStream) override;
const XAnimDeltaPartQuatDataFrames& GetFrames() const;
void SetFrames(const XAnimDeltaPartQuatDataFrames& frames);
@ -24,3 +29,8 @@ private:
};
#endif // XANIMDELTAPARTQUATDATA_H

View File

@ -1,9 +1,7 @@
#include "xanimdeltapartquatdataframes.h"
XAnimDeltaPartQuatDataFrames::XAnimDeltaPartQuatDataFrames()
: XAsset()
{
SetName("Animation Delta Part Quat Data Frame");
: XAsset() {
}
quint32 XAnimDeltaPartQuatDataFrames::GetFramesPtr() const {
@ -36,12 +34,12 @@ void XAnimDeltaPartQuatDataFrames::SetIndices(const XAnimDynamicIndices& indices
mIndices = indices;
}
void XAnimDeltaPartQuatDataFrames::ParseData(XDataStream *aStream) {
void XAnimDeltaPartQuatDataFrames::ParseData(QDataStream *aStream) {
if (GetPtr() == -1) {
mFramesPtr = aStream->ParseInt32(QString("%1 frames ptr").arg(GetName()));
mFrames[0] = aStream->ParseInt16(QString("%1 frame %2").arg(GetName()).arg(0));
mFrames[1] = aStream->ParseInt16(QString("%1 frame %2").arg(GetName()).arg(1));
*aStream
>> mFramesPtr
>> mFrames[0]
>> mFrames[1];
// Parse indices
mIndices.ParseData(aStream);

View File

@ -8,7 +8,6 @@ class XAnimDeltaPartQuatDataFrames : public XAsset
{
public:
explicit XAnimDeltaPartQuatDataFrames();
~XAnimDeltaPartQuatDataFrames() = default;
quint32 GetFramesPtr() const;
void SetFramesPtr(quint32 ptr);
@ -20,11 +19,11 @@ public:
const XAnimDynamicIndices& GetIndices() const;
void SetIndices(const XAnimDynamicIndices& indices);
void ParseData(XDataStream *aStream) override;
void ParseData(QDataStream *aStream) override;
void Clear() override;
private:
qint32 mFramesPtr = 0;
quint32 mFramesPtr = 0;
qint16 mFrames[2] = {0};
XAnimDynamicIndices mIndices;
};

View File

@ -4,17 +4,24 @@ XAnimDynamicFrames::XAnimDynamicFrames()
: XAsset()
, mFrames(3)
{
SetName("Animation Dynamic Frames");
}
void XAnimDynamicFrames::ParseData(XDataStream *aStream) {
XAnimDynamicFrames::~XAnimDynamicFrames()
{
}
void XAnimDynamicFrames::ParseData(QDataStream *aStream) {
if (GetPtr() == -1) {
qint32 framePtr = aStream->ParseInt32(QString("%1 frames ptr").arg(GetName()));
qint32 framePtr;
*aStream >> framePtr;
if (framePtr == -1)
{
mFrames[0] = aStream->ParseUInt8(QString("%1 frame %2").arg(GetName()).arg(0));
mFrames[1] = aStream->ParseUInt8(QString("%1 frame %2").arg(GetName()).arg(1));
mFrames[2] = aStream->ParseUInt8(QString("%1 frame %2").arg(GetName()).arg(2));
*aStream
>> mFrames[0]
>> mFrames[1]
>> mFrames[2];
}
}
}

View File

@ -1,3 +1,4 @@
#ifndef XANIMDYNAMICFRAMES_H
#define XANIMDYNAMICFRAMES_H
@ -9,9 +10,9 @@ class XAnimDynamicFrames : public XAsset
{
public:
explicit XAnimDynamicFrames();
~XAnimDynamicFrames() = default;
~XAnimDynamicFrames();
void ParseData(XDataStream *aStream) override;
void ParseData(QDataStream *aStream) override;
void Clear() override;
QVector<quint8> GetFrames() const;

View File

@ -4,12 +4,16 @@ XAnimDynamicIndices::XAnimDynamicIndices()
: XAsset()
, mIndices(1)
{
SetName("Animation Dynamic Indices");
}
void XAnimDynamicIndices::ParseData(XDataStream *aStream) {
XAnimDynamicIndices::~XAnimDynamicIndices()
{
}
void XAnimDynamicIndices::ParseData(QDataStream *aStream) {
if (GetPtr() == -1) {
mIndices[0] = aStream->ParseUInt8(QString("%1 index").arg(GetName()));
*aStream >> mIndices[0];
}
}

View File

@ -9,9 +9,9 @@ class XAnimDynamicIndices : public XAsset
{
public:
explicit XAnimDynamicIndices();
~XAnimDynamicIndices() = default;
~XAnimDynamicIndices();
void ParseData(XDataStream *aStream) override;
void ParseData(QDataStream *aStream) override;
void Clear() override;
QVector<quint8> GetIndices() const;

View File

@ -4,15 +4,21 @@ XAnimIndices::XAnimIndices()
: XAsset()
, mIndex(0)
{
SetName("Animation Indices");
}
void XAnimIndices::ParseData(XDataStream *aStream) {
XAnimIndices::~XAnimIndices()
{
}
void XAnimIndices::ParseData(QDataStream *aStream) {
if (GetPtr() == -1) {
qint32 indexPtr = aStream->ParseInt32(QString("%1 index ptr").arg(GetName()));
qint32 indexPtr;
*aStream >> indexPtr;
if (indexPtr == -1)
{
mIndex = aStream->ParseUInt32(QString("%1 index").arg(GetName()));
*aStream >> mIndex;
}
}
}

View File

@ -7,9 +7,9 @@ class XAnimIndices : public XAsset
{
public:
explicit XAnimIndices();
~XAnimIndices() = default;
~XAnimIndices();
void ParseData(XDataStream *aStream) override;
void ParseData(QDataStream *aStream) override;
void Clear() override;
quint32 GetIndex() const;

View File

@ -5,14 +5,19 @@ XAnimNotifyInfo::XAnimNotifyInfo()
, mName(0)
, mTime(0.0f)
{
SetName("Animation Notify Info");
}
void XAnimNotifyInfo::ParseData(XDataStream *aStream) {
if (GetPtr() == -1) {
XAnimNotifyInfo::~XAnimNotifyInfo()
{
mName = aStream->ParseUInt32(QString("%1 name").arg(GetName()));
mTime = aStream->ParseSingle(QString("%1 time").arg(GetName()));
}
void XAnimNotifyInfo::ParseData(QDataStream *aStream) {
if (GetPtr() == -1) {
*aStream
>> mName
>> mTime;
}
}
@ -21,3 +26,19 @@ void XAnimNotifyInfo::Clear()
mName = 0;
mTime = 0.0f;
}
quint32 XAnimNotifyInfo::GetName() const {
return mName;
}
void XAnimNotifyInfo::SetName(quint32 name) {
mName = name;
}
float XAnimNotifyInfo::GetTime() const {
return mTime;
}
void XAnimNotifyInfo::SetTime(float time) {
mTime = time;
}

View File

@ -7,11 +7,17 @@ class XAnimNotifyInfo : public XAsset
{
public:
explicit XAnimNotifyInfo();
~XAnimNotifyInfo() = default;
~XAnimNotifyInfo();
void ParseData(XDataStream *aStream) override;
void ParseData(QDataStream *aStream) override;
void Clear() override;
quint32 GetName() const;
void SetName(quint32 name);
float GetTime() const;
void SetTime(float time);
private:
quint32 mName;
float mTime;

View File

@ -31,49 +31,68 @@ XAnimParts::XAnimParts()
, mDeltaPart()
{
SetType(ASSET_TYPE_XANIMPARTS);
SetName("Animation Parts");
SetName("XAnimParts");
}
void XAnimParts::ParseData(XDataStream *aStream) {
XAnimParts::~XAnimParts()
{
}
void XAnimParts::ParseData(QDataStream *aStream) {
if (GetPtr() == -1) {
mName.ParsePtr(aStream, false);
// Parse all fields
mDataByteCount = aStream->ParseUInt32(QString("%1 data byte count").arg(GetName()));
mDataShortCount = aStream->ParseUInt32(QString("%1 data short count").arg(GetName()));
mDataIntCount = aStream->ParseUInt32(QString("%1 data int count").arg(GetName()));
mRandomDataByteCount = aStream->ParseUInt32(QString("%1 random date byte count").arg(GetName()));
mRandomDataIntCount = aStream->ParseUInt32(QString("%1 random data int count").arg(GetName()));
mNumFrames = aStream->ParseUInt32(QString("%1 # frames").arg(GetName()));
*aStream
>> mDataByteCount
>> mDataShortCount
>> mDataIntCount
>> mRandomDataByteCount
>> mRandomDataIntCount
>> mNumFrames;
quint8 loopDelta = aStream->ParseUInt8(QString("%1 loop delta").arg(GetName()));
quint8 loopDelta;
*aStream >> loopDelta;
mIsLoop = (loopDelta & 0x1) != 0;
mIsDelta = (loopDelta & 0x2) != 0;
for (int i = 0; i < 12; i++)
{
mBoneCount[i] = aStream->ParseUInt8(QString("%1 bone count %2").arg(GetName()).arg(i));
*aStream >> mBoneCount[i];
}
mNotifyCount = aStream->ParseUInt8(QString("%1 notify count").arg(GetName()));
mAssetType = aStream->ParseUInt8(QString("%1 asset type").arg(GetName()));
mPad = aStream->ParseUInt32(QString("%1 pad").arg(GetName())) != 0;
*aStream
>> mNotifyCount
>> mAssetType;
quint32 pad;
*aStream >> pad;
mPad = (pad != 0);
qint32 namesPtr, dataBytePtr, dataShortPtr, dataIntPtr,
randomDataShortPtr, randomDataBytePtr, randomDataIntPtr;
mRandomDataShortCount = aStream->ParseUInt32(QString("%1 random data short count").arg(GetName()));
mIndexCount = aStream->ParseUInt32(QString("%1 index count").arg(GetName()));
mFramerate = aStream->ParseSingle(QString("%1 frame rate").arg(GetName()));
mFrequency = aStream->ParseSingle(QString("%1 frequency").arg(GetName()));
namesPtr = aStream->ParseInt32(QString("%1 names ptr").arg(GetName()));
dataBytePtr = aStream->ParseInt32(QString("%1 data byte ptr").arg(GetName()));
dataShortPtr = aStream->ParseInt32(QString("%1 data short ptr").arg(GetName()));
dataIntPtr = aStream->ParseInt32(QString("%1 data int ptr").arg(GetName()));
randomDataShortPtr = aStream->ParseInt32(QString("%1 random data short ptr").arg(GetName()));
randomDataBytePtr = aStream->ParseInt32(QString("%1 random data byte ptr").arg(GetName()));
randomDataIntPtr = aStream->ParseInt32(QString("%1 random data int ptr").arg(GetName()));
*aStream
>> mRandomDataShortCount
>> mIndexCount
>> mFramerate
>> mFrequency
>> namesPtr
>> mNames
>> dataBytePtr
>> mDataByte
>> dataShortPtr
>> mDataShort
>> dataIntPtr
>> mDataInt
>> randomDataShortPtr
>> mRandomDataShort
>> randomDataBytePtr
>> mRandomDataByte
>> randomDataIntPtr
>> mRandomDataInt;
// Parse indices
mIndices.ParseData(aStream);
@ -83,33 +102,33 @@ void XAnimParts::ParseData(XDataStream *aStream) {
mName.ParseData(aStream);
if (namesPtr)
{
mNames = aStream->ParseInt32(QString("%1 names").arg(GetName()));
}
mNotify.ParseData(aStream);
mDeltaPart.ParseData(aStream);
if (dataBytePtr)
{
mDataByte = aStream->ParseUInt8(QString("%1 data byte").arg(GetName()));
*aStream >> mDataByte;
}
if (dataShortPtr)
{
mDataShort = aStream->ParseInt16(QString("%1 data short").arg(GetName()));
*aStream >> mDataShort;
}
if (dataIntPtr)
{
mDataInt = aStream->ParseInt32(QString("%1 data int").arg(GetName()));
*aStream >> mDataInt;
}
if (randomDataShortPtr)
{
mRandomDataShort = aStream->ParseInt16(QString("%1 random data short").arg(GetName()));
*aStream >> mDataInt;
}
if (randomDataBytePtr)
{
mRandomDataByte = aStream->ParseUInt8(QString("%1 random data byte").arg(GetName()));
*aStream >> mRandomDataByte;
}
if (randomDataIntPtr)
{
mRandomDataInt = aStream->ParseInt32(QString("%1 random data int").arg(GetName()));
*aStream >> mRandomDataInt;
}
mIndices.ParseData(aStream);
}

View File

@ -13,9 +13,9 @@ class XAnimParts : public XAsset
{
public:
explicit XAnimParts();
~XAnimParts() = default;
~XAnimParts();
void ParseData(XDataStream *aStream) override;
void ParseData(QDataStream *aStream) override;
void Clear() override;
private:
@ -43,13 +43,13 @@ private:
float mFramerate = 0.0f;
float mFrequency = 0.0f;
quint16 mNames = 0;
quint32 mNames = 0;
quint8 mDataByte = 0;
qint16 mDataShort = 0;
qint32 mDataInt = 0;
int mDataInt = 0;
qint16 mRandomDataShort = 0;
quint8 mRandomDataByte = 0;
qint32 mRandomDataInt = 0;
int mRandomDataInt = 0;
XAnimIndices mIndices;
XAnimNotifyInfo mNotify;
XAnimDeltaPart mDeltaPart;

View File

@ -6,7 +6,6 @@ XAnimPartTrans::XAnimPartTrans()
, mIsSmallTrans(false)
, mData()
{
SetName("Animation Part Trans");
}
XAnimPartTrans::XAnimPartTrans(const XAnimPartTrans &aSrc)
@ -18,10 +17,18 @@ XAnimPartTrans::XAnimPartTrans(const XAnimPartTrans &aSrc)
}
void XAnimPartTrans::ParseData(XDataStream *aStream) {
XAnimPartTrans::~XAnimPartTrans()
{
}
void XAnimPartTrans::ParseData(QDataStream *aStream) {
if (GetPtr() == -1) {
mSize = aStream->ParseUInt32(QString("%1 size").arg(GetName()));
mIsSmallTrans = aStream->ParseUInt8(QString("%1 is small trans").arg(GetName())) != 0;
quint8 smallTransByte;
*aStream
>> mSize
>> smallTransByte;
mIsSmallTrans = (smallTransByte != 0);
// Parse data
mData.ParseData(aStream);

View File

@ -9,9 +9,9 @@ class XAnimPartTrans : public XAsset
public:
explicit XAnimPartTrans();
XAnimPartTrans(const XAnimPartTrans& aSrc);
~XAnimPartTrans() = default;
~XAnimPartTrans();
void ParseData(XDataStream* aStream) override;
void ParseData(QDataStream* aStream) override;
void Clear() override;
private:

View File

@ -5,7 +5,6 @@ XAnimPartTransData::XAnimPartTransData()
, mFrames()
, mFrame()
{
SetName("Animation Part Trans Data");
}
XAnimPartTransData::XAnimPartTransData(const XAnimPartTransData &aSrc)
@ -16,7 +15,12 @@ XAnimPartTransData::XAnimPartTransData(const XAnimPartTransData &aSrc)
}
void XAnimPartTransData::ParseData(XDataStream *aStream) {
XAnimPartTransData::~XAnimPartTransData()
{
}
void XAnimPartTransData::ParseData(QDataStream *aStream) {
if (GetPtr() == -1) {
// We need to determine which part of the union to parse
// For simplicity, we'll assume it's always frames for now

View File

@ -9,9 +9,9 @@ class XAnimPartTransData : public XAsset
public:
explicit XAnimPartTransData();
XAnimPartTransData(const XAnimPartTransData &aSrc);
~XAnimPartTransData() = default;
~XAnimPartTransData();
void ParseData(XDataStream *aStream) override;
void ParseData(QDataStream *aStream) override;
void Clear() override;
private:

View File

@ -7,17 +7,22 @@ XAnimPartTransFrames::XAnimPartTransFrames()
, mFrames()
, mIndices()
{
SetName("Animation Parts Trans Frames");
}
void XAnimPartTransFrames::ParseData(XDataStream *aStream) {
XAnimPartTransFrames::~XAnimPartTransFrames()
{
}
void XAnimPartTransFrames::ParseData(QDataStream *aStream) {
if (GetPtr() == -1) {
mMins[0] = aStream->ParseSingle(QString("%1 min %2").arg(GetName()).arg(0));
mMins[1] = aStream->ParseSingle(QString("%1 min %2").arg(GetName()).arg(1));
mMins[2] = aStream->ParseSingle(QString("%1 min %2").arg(GetName()).arg(2));
mMaxs[0] = aStream->ParseSingle(QString("%1 max %2").arg(GetName()).arg(0));
mMaxs[1] = aStream->ParseSingle(QString("%1 max %2").arg(GetName()).arg(1));
mMaxs[2] = aStream->ParseSingle(QString("%1 max %2").arg(GetName()).arg(2));
*aStream
>> mMins[0]
>> mMins[1]
>> mMins[2]
>> mMaxs[0]
>> mMaxs[1]
>> mMaxs[2];
// Parse frames
mFrames.ParseData(aStream);

View File

@ -11,9 +11,9 @@ class XAnimPartTransFrames : public XAsset
{
public:
explicit XAnimPartTransFrames();
~XAnimPartTransFrames() = default;
~XAnimPartTransFrames();
void ParseData(XDataStream *aStream) override;
void ParseData(QDataStream *aStream) override;
void Clear() override;
private:

View File

@ -19,6 +19,8 @@
#include "xstringtable.h"
#include "xweapondef.h"
XAsset::
XAsset::XAsset()
: mPtr(0)
, mType(ASSET_TYPE_NONE)
@ -27,6 +29,11 @@ XAsset::XAsset()
}
XAsset::~XAsset()
{
}
void XAsset::SetPtr(qint32 aPtr) {
mPtr = aPtr;
}
@ -76,9 +83,20 @@ void XAsset::Clear()
mType = ASSET_TYPE_NONE;
}
void XAsset::ParsePtr(XDataStream *aStream, bool aDataFlag) {
void XAsset::ParsePtr(QDataStream *aStream, bool aDataFlag) {
*aStream >> mPtr;
if (mDebug)
{
// Always treat as unsigned when displaying in hex
quint64 raw = static_cast<quint64>(static_cast<quint32>(mPtr));
QString hexPtr = QString("0x%1")
.arg(raw, 8, 16, QLatin1Char('0'))
.toUpper();
qDebug() << QString("[%1] Parsed %2 ptr %3 (%4)").arg(aStream->device()->pos(), 10, 10, QChar('0')).arg(GetName()).arg(mPtr).arg(hexPtr);
}
mPtr = aStream->ParseInt32(QString("%1 ptr").arg(GetName()));
if (aDataFlag && mPtr == -1)
{
ParseData(aStream);
@ -87,6 +105,10 @@ void XAsset::ParsePtr(XDataStream *aStream, bool aDataFlag) {
XAsset* XAsset::Create(XAssetType aAssetType)
{
if (mDebug)
{
qDebug() << QString("Creating XAsset with type %1").arg(XAssetTypeToString(aAssetType));
}
switch (aAssetType)
{
case ASSET_TYPE_XANIMPARTS:

View File

@ -3,7 +3,7 @@
#include "xassettype.h"
#include "xdatastream.h"
#include <QDataStream>
#include <QString>
#include <QDebug>
#include <QIODevice>
@ -12,7 +12,7 @@ class XAsset
{
public:
XAsset();
virtual ~XAsset() = default;
virtual ~XAsset();
void SetPtr(qint32 aPtr);
qint32 GetPtr() const;
@ -27,8 +27,8 @@ public:
bool IsDebug() const;
virtual void Clear();
virtual void ParsePtr(XDataStream *aStream, bool aDataFlag = true);
virtual void ParseData(XDataStream *aStream) = 0;
virtual void ParsePtr(QDataStream *aStream, bool aDataFlag = true);
virtual void ParseData(QDataStream *aStream) = 0;
static XAsset* Create(XAssetType aAssetType);
static QString XAssetTypeToString(XAssetType type);

View File

@ -3,39 +3,41 @@
XAssetHeader::XAssetHeader()
: XAsset()
, mRawType(0)
, mAssetType()
, mAssetPtr(0)
, mZoneFile(nullptr)
{
SetName("Asset Header");
}
XAssetHeader::XAssetHeader(ZoneFile *aZoneFile)
: XAsset()
, mRawType(0)
, mAssetType()
, mAssetPtr(0)
, mZoneFile(aZoneFile)
{
SetName("Asset Header");
}
void XAssetHeader::ParseData(XDataStream *aStream)
XAssetHeader::~XAssetHeader()
{
mRawType = aStream->ParseUInt32(QString("%1 raw type").arg(GetName()));
mAssetPtr = aStream->ParseInt32(QString("%1 asset ptr").arg(GetName()));
mAssetType = mZoneFile->GetType(mRawType);
}
qDebug() << "Found asset:" << XAssetTypeToString(mAssetType) << QString::number(mRawType, 16);
void XAssetHeader::ParseData(QDataStream *aStream)
{
quint32 rawAssetType;
*aStream
>> rawAssetType
>> mAssetPtr;
mAssetType = mZoneFile->GetType(rawAssetType);
}
void XAssetHeader::Clear()
{
mAssetType = ASSET_TYPE_NONE;
mAssetPtr = 0;
mRawType = 0;
}
XAssetType XAssetHeader::GetAssetType() const
@ -43,11 +45,6 @@ XAssetType XAssetHeader::GetAssetType() const
return mAssetType;
}
quint32 XAssetHeader::GetRawAssetType() const
{
return mRawType;
}
qint32 XAssetHeader::GetAssetPtr() const
{
return mAssetPtr;

View File

@ -10,17 +10,15 @@ class XAssetHeader: public XAsset
public:
explicit XAssetHeader();
XAssetHeader(ZoneFile* aZoneFile);
~XAssetHeader() = default;
~XAssetHeader();
void ParseData(XDataStream *aStream) override;
void ParseData(QDataStream *aStream) override;
void Clear() override;
XAssetType GetAssetType() const;
quint32 GetRawAssetType() const;
qint32 GetAssetPtr() const;
private:
quint32 mRawType;
XAssetType mAssetType;
qint32 mAssetPtr;
ZoneFile *mZoneFile;

View File

@ -10,8 +10,6 @@ XAssetList::XAssetList()
, mAssetHeaders()
, mZoneFile(nullptr)
{
SetType(ASSET_TYPE_ASSETLIST);
SetName("Asset List");
}
XAssetList::XAssetList(ZoneFile* aZoneFile)
@ -31,23 +29,30 @@ XAssetList::~XAssetList()
}
void XAssetList::ParseData(XDataStream *aStream) {
void XAssetList::ParseData(QDataStream *aStream) {
// Parse string list
if (IsDebug())
{
qDebug() << QString("[%1] Parsing data for %2").arg(aStream->device()->pos(), 10, 10, QChar('0')).arg(GetName());
}
mStringList.ParsePtr(aStream, false);
mStringList.ParsePtr(aStream);
// Parse asset count and assets
mAssetCount = aStream->ParseUInt32(QString("%1 asset count").arg(GetName()));
qint32 assetsPtr = aStream->ParseInt32(QString("%1 assets ptr").arg(GetName()));
qint32 assetsPtr;
*aStream
>> mAssetCount
>> assetsPtr;
if (IsDebug())
{
qDebug() << QString("[%1] mAssetCount = %2").arg(aStream->device()->pos(), 10, 10, QChar('0')).arg(mAssetCount);
qDebug() << QString("[%1] assetsPtr = %2").arg(aStream->device()->pos(), 10, 10, QChar('0')).arg(assetsPtr);
}
mStringList.ParseData(aStream);
if (assetsPtr)
{
for (quint32 i = 0; i < mAssetCount; i++)
for (int i = 0; i < mAssetCount; i++)
{
XAssetHeader assetHeader(mZoneFile);
assetHeader.ParseData(aStream);
@ -57,21 +62,13 @@ void XAssetList::ParseData(XDataStream *aStream) {
for (int i = 0; i < mAssetHeaders.size(); i++)
{
if (aStream->device()->pos() > 98000)
{
qDebug() << "test";
}
XAssetHeader assetHeader = mAssetHeaders[i];
XAsset* asset = XAsset::Create(assetHeader.GetAssetType());
if (asset)
{
asset->SetPtr(assetHeader.GetAssetPtr());
asset->ParseData(aStream);
mAssets.append(asset);
}
}
}
}
void XAssetList::Clear()

View File

@ -14,9 +14,9 @@ class XAssetList : public XAsset
public:
explicit XAssetList();
XAssetList(ZoneFile* aZoneFile);
~XAssetList() override;
~XAssetList();
void ParseData(XDataStream *aStream) override;
void ParseData(QDataStream *aStream) override;
void Clear() override;
XScriptStringList GetStringList() const;

View File

@ -5,7 +5,7 @@ XAudioChannelMap::XAudioChannelMap()
, mEntryCount(0)
, mEntries(QVector<XAudioChannelMapEntry*>())
{
SetName("Audio Channel Map");
}
XAudioChannelMap::~XAudioChannelMap()
@ -32,13 +32,15 @@ void XAudioChannelMap::SetMapEntry(int aIndex, XAudioChannelMapEntry *aEntry)
mEntries[aIndex] = aEntry;
}
void XAudioChannelMap::ParseData(XDataStream *aStream)
void XAudioChannelMap::ParseData(QDataStream *aStream)
{
mEntryCount = aStream->ParseUInt8(QString("%1 entry count").arg(GetName()));
*aStream >> mEntryCount;
aStream->skipRawData(3);
quint32 entriesPtr = aStream->ParseInt32(QString("%1 entries ptr").arg(GetName()));
quint32 entriesPtr;
*aStream >> entriesPtr;
if (entriesPtr)
{
mEntries.resize(mEntryCount);

View File

@ -17,7 +17,7 @@ public:
XAudioChannelMapEntry* GetMapEntry(int aIndex) const;
void SetMapEntry(int aIndex, XAudioChannelMapEntry* aEntry);
virtual void ParseData(XDataStream* aStream) override;
virtual void ParseData(QDataStream* aStream) override;
virtual void Clear() override;
private:

View File

@ -6,7 +6,7 @@ XAudioChannelMapEntry::XAudioChannelMapEntry()
, mOutputChannel(0)
, mVolume(0.0)
{
SetName("Audio Channel Map Entry");
}
XAudioChannelMapEntry::~XAudioChannelMapEntry()
@ -44,15 +44,16 @@ void XAudioChannelMapEntry::SetVolume(float aVolume)
mVolume = aVolume;
}
void XAudioChannelMapEntry::ParseData(XDataStream *aStream)
void XAudioChannelMapEntry::ParseData(QDataStream *aStream)
{
mInputChannel = aStream->ParseUInt8(QString("%1 input channel").arg(GetName()));
mOutputChannel = aStream->ParseUInt8(QString("%1 output channel").arg(GetName()));
*aStream
>> mInputChannel
>> mOutputChannel;
// Skip padding bytes in struct
aStream->skipRawData(2);
mVolume = aStream->ParseSingle(QString("%1 volume").arg(GetName()));
*aStream >> mVolume;
}
void XAudioChannelMapEntry::Clear()

View File

@ -18,7 +18,7 @@ public:
float GetVolume() const;
void SetVolume(float aVolume);
virtual void ParseData(XDataStream* aStream) override;
virtual void ParseData(QDataStream* aStream) override;
virtual void Clear() override;
private:

View File

@ -1,10 +1,8 @@
#include "xaudioformatinfo.h"
XAudioFormatInfo::XAudioFormatInfo()
: XAsset()
, mStream()
{
SetName("Audio Format Info");
}
XAudioFormatInfo::~XAudioFormatInfo()
@ -12,14 +10,12 @@ XAudioFormatInfo::~XAudioFormatInfo()
}
void XAudioFormatInfo::ParseData(XDataStream *aStream)
void XAudioFormatInfo::ParseData(QDataStream *aStream)
{
Q_UNUSED(aStream);
// TODO: Implement ParseData(...) for XAudioFormatInfo
}
void XAudioFormatInfo::Clear()
{
mStream.clear();
}

View File

@ -2,21 +2,22 @@
#define XAUDIOFORMATINFO_H
#include "xasset.h"
#include "xaudioxmaformat.h"
#include <QVector>
class XAudioXmaFormat;
class XAudioFormatInfo : public XAsset
{
public:
explicit XAudioFormatInfo();
XAudioFormatInfo();
~XAudioFormatInfo();
virtual void ParseData(XDataStream* aStream) override;
virtual void ParseData(QDataStream* aStream) override;
virtual void Clear() override;
private:
QVector<XAudioXmaFormat> mStream;
QVector<XAudioXmaFormat*> mStream;
};
#endif // XAUDIOFORMATINFO_H

View File

@ -8,7 +8,7 @@ XAudioPacketAligned::XAudioPacketAligned()
, aXmaLoop()
, mContext()
{
SetName("Audio Packet Aligned");
}
XAudioPacketAligned::~XAudioPacketAligned()
@ -16,11 +16,14 @@ XAudioPacketAligned::~XAudioPacketAligned()
}
void XAudioPacketAligned::ParseData(XDataStream *aStream)
void XAudioPacketAligned::ParseData(QDataStream *aStream)
{
qint32 bufferPtr = aStream->ParseInt32(QString("%1 buffer ptr").arg(GetName()));
mBufferSize = aStream->ParseUInt32(QString("%1 buffer size").arg(GetName()));
mLoopCount = aStream->ParseUInt32(QString("%1 loop count").arg(GetName()));
qint32 bufferPtr, contextPtr;
*aStream
>> bufferPtr
>> mBufferSize
>> mLoopCount;
for (int i = 0; i < 6; i++)
{
@ -28,16 +31,15 @@ void XAudioPacketAligned::ParseData(XDataStream *aStream)
loop.ParseData(aStream);
}
qint32 contextPtr = aStream->ParseInt32(QString("%1 context ptr").arg(GetName()));
*aStream >> contextPtr;
if (bufferPtr)
{
aStream->readRawData(mBuffer.data(), mBufferSize);
}
if (contextPtr)
{
mContext = aStream->ParseInt8(QString("%1 context").arg(GetName()));
*aStream >> mContext;
}
}

View File

@ -12,7 +12,7 @@ public:
XAudioPacketAligned();
~XAudioPacketAligned();
virtual void ParseData(XDataStream* aStream) override;
virtual void ParseData(QDataStream* aStream) override;
virtual void Clear() override;
private:

View File

@ -5,7 +5,7 @@ XAudioReverbSettings::XAudioReverbSettings()
, mPresetOverridden(0)
, mReverbSettings(new XReverbSettings())
{
SetName("Audio Reverb Settings");
}
void XAudioReverbSettings::Clear()
@ -24,11 +24,12 @@ XReverbSettings* XAudioReverbSettings::GetReverbSettings() const
return mReverbSettings;
}
void XAudioReverbSettings::ParseData(XDataStream *aStream)
void XAudioReverbSettings::ParseData(QDataStream *aStream)
{
if (GetPtr())
{
mPresetOverridden = aStream->ParseInt32(QString("%1 preset overidden").arg(GetName()));
*aStream
>> mPresetOverridden;
if (mReverbSettings != nullptr)
{

Some files were not shown because too many files have changed in this diff Show More