Compare commits
No commits in common. "main" and "feature/test" have entirely different histories.
main
...
feature/te
3
.gitignore
vendored
3
.gitignore
vendored
@ -3,9 +3,6 @@
|
|||||||
/data/fastfiles/
|
/data/fastfiles/
|
||||||
/releases/
|
/releases/
|
||||||
|
|
||||||
.vscode/*
|
|
||||||
.qmake.stash
|
|
||||||
|
|
||||||
# Ignore Qt Creator user files
|
# Ignore Qt Creator user files
|
||||||
*.pro.user
|
*.pro.user
|
||||||
*.pro.user.*
|
*.pro.user.*
|
||||||
|
|||||||
23
.qmake.stash
Normal file
23
.qmake.stash
Normal 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
4
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"workbench.colorTheme": "Default Dark Modern",
|
||||||
|
"workbench.startupEditor": "none"
|
||||||
|
}
|
||||||
@ -2,9 +2,9 @@ TEMPLATE = subdirs
|
|||||||
|
|
||||||
SUBDIRS += libs \
|
SUBDIRS += libs \
|
||||||
app \
|
app \
|
||||||
#tools \
|
tools \
|
||||||
#tests
|
tests
|
||||||
|
|
||||||
#tests.depends = libs
|
tests.depends = libs
|
||||||
app.depends = libs
|
app.depends = libs
|
||||||
#tools.depends = libs
|
tools.depends = libs
|
||||||
|
|||||||
36
ai-commit.sh
36
ai-commit.sh
@ -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
|
|
||||||
18
app/app.pro
18
app/app.pro
@ -13,9 +13,9 @@ FORMS += $$files($$PWD/*.ui)
|
|||||||
RESOURCES += ../data/data.qrc
|
RESOURCES += ../data/data.qrc
|
||||||
|
|
||||||
LIBS += \
|
LIBS += \
|
||||||
-L$$PWD/../third_party/devil_sdk/lib/ -lDevIL -lILU -lILUT \
|
#-L$$PWD/../third_party/devil_sdk/lib/ -lDevIL -lILU -lILUT \
|
||||||
-L$$PWD/../third_party/zlib/lib/ -lzlib \
|
#-L$$PWD/../third_party/zlib/lib/ -lzlib \
|
||||||
-L$$PWD/../third_party/xbox_sdk/lib -lxcompress64 \
|
#-L$$PWD/../third_party/xbox_sdk/lib -lxcompress64 \
|
||||||
-L$$OUT_PWD/../libs/ -lcore \
|
-L$$OUT_PWD/../libs/ -lcore \
|
||||||
-L$$OUT_PWD/../libs/ -lxassets\
|
-L$$OUT_PWD/../libs/ -lxassets\
|
||||||
-L$$OUT_PWD/../libs/ -lcompression \
|
-L$$OUT_PWD/../libs/ -lcompression \
|
||||||
@ -27,9 +27,9 @@ LIBS += \
|
|||||||
-L$$OUT_PWD/../libs/ -lzonefile
|
-L$$OUT_PWD/../libs/ -lzonefile
|
||||||
|
|
||||||
INCLUDEPATH += \
|
INCLUDEPATH += \
|
||||||
$$PWD/../third_party/devil_sdk/include/ \
|
#$$PWD/../third_party/devil_sdk/include/ \
|
||||||
$$PWD/../third_party/zlib/include \
|
#$$PWD/../third_party/zlib/include \
|
||||||
$$PWD/../third_party/xbox_sdk/include \
|
#$$PWD/../third_party/xbox_sdk/include \
|
||||||
$$PWD/../libs/core \
|
$$PWD/../libs/core \
|
||||||
$$PWD/../libs/compression \
|
$$PWD/../libs/compression \
|
||||||
$$PWD/../libs/encryption \
|
$$PWD/../libs/encryption \
|
||||||
@ -41,9 +41,9 @@ INCLUDEPATH += \
|
|||||||
$$PWD/../libs/zonefile
|
$$PWD/../libs/zonefile
|
||||||
|
|
||||||
DEPENDPATH += \
|
DEPENDPATH += \
|
||||||
$$PWD/../third_party/devil_sdk/include/ \
|
#$$PWD/../third_party/devil_sdk/include/ \
|
||||||
$$PWD/../third_party/zlib/include \
|
#$$PWD/../third_party/zlib/include \
|
||||||
$$PWD/../third_party/xbox_sdk/include \
|
#$$PWD/../third_party/xbox_sdk/include \
|
||||||
$$PWD/../libs/core \
|
$$PWD/../libs/core \
|
||||||
$$PWD/../libs/compression \
|
$$PWD/../libs/compression \
|
||||||
$$PWD/../libs/encryption \
|
$$PWD/../libs/encryption \
|
||||||
|
|||||||
@ -533,7 +533,7 @@ bool MainWindow::OpenFastFile(const QString aFastFilePath) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
FastFile* fastFile = FastFile::Open(aFastFilePath);
|
FastFile* fastFile = FastFileFactory::Create(aFastFilePath);
|
||||||
fastFile->SetStem(fastFileStem);
|
fastFile->SetStem(fastFileStem);
|
||||||
mTreeWidget->AddFastFile(fastFile);
|
mTreeWidget->AddFastFile(fastFile);
|
||||||
|
|
||||||
@ -548,7 +548,7 @@ bool MainWindow::OpenFastFile(const QByteArray& aFastFileData, const QString aFa
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
FastFile* fastFile = FastFile::Open(aFastFileData);
|
FastFile* fastFile = FastFileFactory::Create(aFastFileData);
|
||||||
fastFile->SetStem(fastFileStem);
|
fastFile->SetStem(fastFileStem);
|
||||||
mTreeWidget->AddFastFile(fastFile);
|
mTreeWidget->AddFastFile(fastFile);
|
||||||
|
|
||||||
@ -789,7 +789,7 @@ int MainWindow::LoadFile_IPAK(const QString aFilePath) {
|
|||||||
|
|
||||||
QVector<IPAKIndexEntry> entries = QVector<IPAKIndexEntry>();
|
QVector<IPAKIndexEntry> entries = QVector<IPAKIndexEntry>();
|
||||||
QVector<IPAKSection> sections = QVector<IPAKSection>(header.sectionCount);
|
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;
|
IPAKSection currentSection;
|
||||||
stream >> currentSection;
|
stream >> currentSection;
|
||||||
sections << currentSection;
|
sections << currentSection;
|
||||||
@ -811,7 +811,7 @@ int MainWindow::LoadFile_IPAK(const QString aFilePath) {
|
|||||||
<< " - Count: " << chunkHeader.count << "\n"
|
<< " - Count: " << chunkHeader.count << "\n"
|
||||||
<< " - Offset: " << chunkHeader.offset;
|
<< " - Offset: " << chunkHeader.offset;
|
||||||
|
|
||||||
for (quint32 j = 0; j < 31; j++) {
|
for (uint j = 0; j < 31; j++) {
|
||||||
IPAKDataChunkCommand command;
|
IPAKDataChunkCommand command;
|
||||||
stream >> command;
|
stream >> command;
|
||||||
if (!command.size) { continue; }
|
if (!command.size) { continue; }
|
||||||
@ -821,7 +821,7 @@ int MainWindow::LoadFile_IPAK(const QString aFilePath) {
|
|||||||
<< " - Compressed: " << command.compressed;
|
<< " - Compressed: " << command.compressed;
|
||||||
|
|
||||||
}
|
}
|
||||||
for (quint32 j = 0; j < chunkHeader.count; j++) {
|
for (uint j = 0; j < chunkHeader.count; j++) {
|
||||||
auto command = chunkHeader.commands[j];
|
auto command = chunkHeader.commands[j];
|
||||||
|
|
||||||
qDebug() << "Reading from " << stream.device()->pos();
|
qDebug() << "Reading from " << stream.device()->pos();
|
||||||
@ -846,7 +846,7 @@ int MainWindow::LoadFile_IPAK(const QString aFilePath) {
|
|||||||
stream.skipRawData(sizeof(quint32) * (31 - chunkHeader.count));
|
stream.skipRawData(sizeof(quint32) * (31 - chunkHeader.count));
|
||||||
qDebug() << stream.device()->pos();
|
qDebug() << stream.device()->pos();
|
||||||
} else if (sectionType == "Index") {
|
} else if (sectionType == "Index") {
|
||||||
for (quint32 j = 0; j < currentSection.itemCount; j++) {
|
for (uint j = 0; j < currentSection.itemCount; j++) {
|
||||||
IPAKIndexEntry entry;
|
IPAKIndexEntry entry;
|
||||||
stream >> entry;
|
stream >> entry;
|
||||||
|
|
||||||
|
|||||||
@ -3,27 +3,19 @@
|
|||||||
|
|
||||||
MaterialViewer::MaterialViewer(QWidget *parent)
|
MaterialViewer::MaterialViewer(QWidget *parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
, ui(new Ui::MaterialViewer)
|
, ui(new Ui::MaterialViewer) {
|
||||||
{
|
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
MaterialViewer::~MaterialViewer()
|
MaterialViewer::~MaterialViewer() {
|
||||||
{
|
|
||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ToHexStr(quint32 in)
|
QString ToHexStr(quint32 in) {
|
||||||
{
|
|
||||||
return QString("%1").arg(in, 8, 16, QChar('0')).toUpper();
|
return QString("%1").arg(in, 8, 16, QChar('0')).toUpper();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaterialViewer::SetMaterial(const XMaterial* aMaterial)
|
void MaterialViewer::SetMaterial(const XMaterial* aMaterial) {
|
||||||
{
|
|
||||||
Q_UNUSED(aMaterial);
|
|
||||||
|
|
||||||
// TODO: Fill in MaterialViewer::SetMaterial
|
|
||||||
|
|
||||||
// ui->lineEdit_NamePtr->setText(ToHexStr(aMaterial->namePtr));
|
// ui->lineEdit_NamePtr->setText(ToHexStr(aMaterial->namePtr));
|
||||||
// ui->lineEdit_Name->setText(aMaterial->name);
|
// ui->lineEdit_Name->setText(aMaterial->name);
|
||||||
// ui->lineEdit_RefPtr->setText(ToHexStr(aMaterial->refNamePtr));
|
// ui->lineEdit_RefPtr->setText(ToHexStr(aMaterial->refNamePtr));
|
||||||
|
|||||||
@ -22,7 +22,7 @@ RumbleGraphViewer::~RumbleGraphViewer() {
|
|||||||
void RumbleGraphViewer::SetRumbleGraphFile(const XRawFile* aRawFile) {
|
void RumbleGraphViewer::SetRumbleGraphFile(const XRawFile* aRawFile) {
|
||||||
mRumbleGraphFile = aRawFile;
|
mRumbleGraphFile = aRawFile;
|
||||||
|
|
||||||
XDataStream rawFileStream;//(mRumbleGraphFile->contents.toLatin1());
|
QDataStream rawFileStream;//(mRumbleGraphFile->contents.toLatin1());
|
||||||
|
|
||||||
QByteArray magic(15, Qt::Uninitialized);
|
QByteArray magic(15, Qt::Uninitialized);
|
||||||
rawFileStream.readRawData(magic.data(), 15);
|
rawFileStream.readRawData(magic.data(), 15);
|
||||||
|
|||||||
@ -490,12 +490,12 @@ void XTreeWidget::PrepareContextMenu(const QPoint &pos) {
|
|||||||
});
|
});
|
||||||
QAction *exportZoneFileAction = new QAction("Export Zone File");
|
QAction *exportZoneFileAction = new QAction("Export Zone File");
|
||||||
exportSubmenu->addAction(exportZoneFileAction);
|
exportSubmenu->addAction(exportZoneFileAction);
|
||||||
connect(exportZoneFileAction, &QAction::triggered, this, [](bool checked) {
|
connect(exportZoneFileAction, &QAction::triggered, this, [fastFile](bool checked) {
|
||||||
Q_UNUSED(checked);
|
Q_UNUSED(checked);
|
||||||
|
|
||||||
// const QString zoneFilePath = QFileDialog::getSaveFileName(
|
const QString zoneFilePath = QFileDialog::getSaveFileName(
|
||||||
// nullptr, "Export Zone File...", QDir::currentPath(),
|
nullptr, "Export Zone File...", QDir::currentPath(),
|
||||||
// "Zone File (*.zone);;All Files(*.*)");
|
"Zone File (*.zone);;All Files(*.*)");
|
||||||
//fastFile->GetZoneFile()->SaveZoneFile(zoneFilePath);
|
//fastFile->GetZoneFile()->SaveZoneFile(zoneFilePath);
|
||||||
});
|
});
|
||||||
} else if (activeText.contains(".zone")) {
|
} else if (activeText.contains(".zone")) {
|
||||||
@ -508,7 +508,7 @@ void XTreeWidget::PrepareContextMenu(const QPoint &pos) {
|
|||||||
QMenu *exportSubmenu = new QMenu("Export...", this);
|
QMenu *exportSubmenu = new QMenu("Export...", this);
|
||||||
contextMenu->addMenu(exportSubmenu);
|
contextMenu->addMenu(exportSubmenu);
|
||||||
|
|
||||||
//const ZoneFile* zoneFile = mZoneFiles[fileStem];
|
const ZoneFile* zoneFile = mZoneFiles[fileStem];
|
||||||
|
|
||||||
QAction *exportZoneFileAction = new QAction("Export Zone File");
|
QAction *exportZoneFileAction = new QAction("Export Zone File");
|
||||||
exportSubmenu->addAction(exportZoneFileAction);
|
exportSubmenu->addAction(exportZoneFileAction);
|
||||||
@ -530,7 +530,7 @@ void XTreeWidget::PrepareContextMenu(const QPoint &pos) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (parentItem && parentItem != invisibleRootItem() && parentItem->text(0).contains(".zone")) {
|
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;
|
// QVector<LoadedSound> LoadedSounds = mZoneFiles[fileStem]->GetAssetMap().sounds;
|
||||||
// for (LoadedSound LoadedSound : LoadedSounds) {
|
// for (LoadedSound LoadedSound : LoadedSounds) {
|
||||||
// for (Sound sound : LoadedSound.sounds) {
|
// for (Sound sound : LoadedSound.sounds) {
|
||||||
@ -577,14 +577,14 @@ void XTreeWidget::PrepareContextMenu(const QPoint &pos) {
|
|||||||
}
|
}
|
||||||
if (parentItem && parentItem != invisibleRootItem() && parentItem->text(0).contains(".zone")) {
|
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);
|
||||||
//auto zoneFile = mZoneFiles[fileStem];
|
auto zoneFile = mZoneFiles[fileStem];
|
||||||
|
|
||||||
QMenu *exportSubmenu = new QMenu("Export...", this);
|
QMenu *exportSubmenu = new QMenu("Export...", this);
|
||||||
contextMenu->addMenu(exportSubmenu);
|
contextMenu->addMenu(exportSubmenu);
|
||||||
|
|
||||||
QAction *exportAllWAVAction = new QAction("Export ALL as WAV Files");
|
QAction *exportAllWAVAction = new QAction("Export ALL as WAV Files");
|
||||||
exportSubmenu->addAction(exportAllWAVAction);
|
exportSubmenu->addAction(exportAllWAVAction);
|
||||||
connect(exportAllWAVAction, &QAction::triggered, this, [](bool checked) {
|
connect(exportAllWAVAction, &QAction::triggered, this, [zoneFile](bool checked) {
|
||||||
Q_UNUSED(checked);
|
Q_UNUSED(checked);
|
||||||
|
|
||||||
// for (LoadedSound LoadedSound : zoneFile->GetAssetMap().sounds) {
|
// for (LoadedSound LoadedSound : zoneFile->GetAssetMap().sounds) {
|
||||||
|
|||||||
@ -1,91 +1,73 @@
|
|||||||
#include "compression.h"
|
#include "compression.h"
|
||||||
#include "minilzo.h"
|
//#include "minilzo.h"
|
||||||
#include "xcompress.h"
|
|
||||||
|
//#define XBOXAPI __declspec(dllimport)
|
||||||
|
//#include "xcompress.h"
|
||||||
|
|
||||||
#include <QLibrary>
|
#include <QLibrary>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
|
#include <QDataStream>
|
||||||
|
|
||||||
QByteArray Compression::CompressXMem(const QByteArray &data)
|
QByteArray Compression::CompressXMem(const QByteArray &data)
|
||||||
{
|
{
|
||||||
XMEMCODEC_PARAMETERS_LZX lzxParams = {};
|
// XMEMCODEC_PARAMETERS_LZX lzxParams = {};
|
||||||
lzxParams.Flags = 0;
|
// lzxParams.Flags = 0;
|
||||||
lzxParams.WindowSize = 0x20000;
|
// lzxParams.WindowSize = 0x20000;
|
||||||
lzxParams.CompressionPartitionSize = 0x80000;
|
// lzxParams.CompressionPartitionSize = 0x80000;
|
||||||
|
|
||||||
XMEMCOMPRESSION_CONTEXT ctx = nullptr;
|
// XMEMCOMPRESSION_CONTEXT ctx = nullptr;
|
||||||
if (FAILED(XMemCreateCompressionContext(XMEMCODEC_LZX, &lzxParams, 0, &ctx)) || !ctx)
|
// if (FAILED(XMemCreateCompressionContext(XMEMCODEC_LZX, &lzxParams, 0, &ctx)) || !ctx)
|
||||||
return QByteArray();
|
// return QByteArray();
|
||||||
|
|
||||||
SIZE_T estimatedSize = data.size() + XCOMPRESS_LZX_BLOCK_GROWTH_SIZE_MAX;
|
// SIZE_T estimatedSize = data.size() + XCOMPRESS_LZX_BLOCK_GROWTH_SIZE_MAX;
|
||||||
QByteArray output(static_cast<int>(estimatedSize), 0);
|
// QByteArray output(static_cast<int>(estimatedSize), 0);
|
||||||
SIZE_T actualSize = estimatedSize;
|
// SIZE_T actualSize = estimatedSize;
|
||||||
|
|
||||||
HRESULT hr = XMemCompress(ctx, output.data(), &actualSize, data.constData(), data.size());
|
// HRESULT hr = XMemCompress(ctx, output.data(), &actualSize, data.constData(), data.size());
|
||||||
XMemDestroyCompressionContext(ctx);
|
// XMemDestroyCompressionContext(ctx);
|
||||||
|
|
||||||
if (FAILED(hr))
|
// if (FAILED(hr))
|
||||||
return QByteArray();
|
// return QByteArray();
|
||||||
|
|
||||||
output.resize(static_cast<int>(actualSize));
|
// output.resize(static_cast<int>(actualSize));
|
||||||
return output;
|
// return output;
|
||||||
|
return QByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray Compression::DecompressXMem(const QByteArray &data,
|
QByteArray Compression::DecompressXMem(const QByteArray &data, int flags, int windowSize, int partSize)
|
||||||
int flags, int windowSize, int partSize)
|
|
||||||
{
|
{
|
||||||
if (data.isEmpty())
|
// if (data.isEmpty())
|
||||||
return {};
|
// return {};
|
||||||
|
|
||||||
XMEMCODEC_PARAMETERS_LZX lzxParams = {};
|
// XMEMCODEC_PARAMETERS_LZX lzxParams = {};
|
||||||
lzxParams.Flags = flags;
|
// lzxParams.Flags = flags;
|
||||||
lzxParams.WindowSize = windowSize;
|
// lzxParams.WindowSize = windowSize;
|
||||||
lzxParams.CompressionPartitionSize = partSize;
|
// 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(
|
// // Allocate large enough buffer for decompression (16 MB is a safe upper bound)
|
||||||
XMEMCODEC_LZX, &lzxParams, 1,
|
// const SIZE_T kMaxOutSize = 16 * 1024 * 1024;
|
||||||
internalState.data(), internalState.size());
|
// QByteArray output(static_cast<int>(kMaxOutSize), Qt::Uninitialized);
|
||||||
|
// SIZE_T actualSize = kMaxOutSize;
|
||||||
|
|
||||||
if (!ctx || XMemResetDecompressionContext(ctx)) {
|
// HRESULT hr = XMemDecompress(ctx,
|
||||||
qWarning() << "Failed to init LZX context";
|
// output.data(), &actualSize,
|
||||||
return {};
|
// data.constData(), data.size() + 16);
|
||||||
}
|
|
||||||
|
|
||||||
QByteArray output;
|
// XMemDestroyDecompressionContext(ctx);
|
||||||
output.reserve(16 * 1024 * 1024); // rough guess
|
|
||||||
|
|
||||||
const quint8 *nextIn = reinterpret_cast<const quint8*>(data.constData());
|
// if (FAILED(hr)) {
|
||||||
SIZE_T availIn = data.size();
|
// qWarning() << "XMemDecompress failed with HRESULT:" << hr;
|
||||||
|
// return {};
|
||||||
|
// }
|
||||||
|
|
||||||
QByteArray scratch(0x10000, Qt::Uninitialized); // 64 KB chunks
|
// output.resize(static_cast<int>(actualSize));
|
||||||
|
// return output;
|
||||||
while (availIn > 0) {
|
return QByteArray();
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
quint32 Compression::CalculateAdler32Checksum(const QByteArray &data) {
|
quint32 Compression::CalculateAdler32Checksum(const QByteArray &data) {
|
||||||
@ -100,18 +82,19 @@ quint32 Compression::CalculateAdler32Checksum(const QByteArray &data) {
|
|||||||
|
|
||||||
qint64 Compression::FindZlibOffset(const QByteArray &bytes)
|
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();
|
QByteArray window = bytes.mid(pos, 0x20);
|
||||||
if (testSegment == "7801" ||
|
if (!window.contains(QByteArray::fromHex("000000")) &&
|
||||||
testSegment == "785E" ||
|
!window.contains(QByteArray::fromHex("FFFFFF")))
|
||||||
testSegment == "789C" ||
|
return pos;
|
||||||
testSegment == "78DA") {
|
|
||||||
return stream.device()->pos();
|
|
||||||
}
|
|
||||||
stream.skipRawData(1);
|
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -315,22 +298,22 @@ QByteArray Compression::CompressDeflateWithSettings(const QByteArray &aData, int
|
|||||||
|
|
||||||
QByteArray Compression::DecompressLZO(const QByteArray &aCompressedData, quint32 aDestSize) {
|
QByteArray Compression::DecompressLZO(const QByteArray &aCompressedData, quint32 aDestSize) {
|
||||||
QByteArray dst;
|
QByteArray dst;
|
||||||
static bool ok = (lzo_init() == LZO_E_OK);
|
// static bool ok = (lzo_init() == LZO_E_OK);
|
||||||
if (!ok)
|
// if (!ok)
|
||||||
throw std::runtime_error("lzo_init failed");
|
// throw std::runtime_error("lzo_init failed");
|
||||||
|
|
||||||
dst = QByteArray(aDestSize, Qt::Uninitialized);
|
// dst = QByteArray(aDestSize, Qt::Uninitialized);
|
||||||
lzo_uint out = aDestSize;
|
// lzo_uint out = aDestSize;
|
||||||
|
|
||||||
int rc = lzo1x_decompress_safe(
|
// int rc = lzo1x_decompress_safe(
|
||||||
reinterpret_cast<const lzo_bytep>(aCompressedData.constData()),
|
// reinterpret_cast<const lzo_bytep>(aCompressedData.constData()),
|
||||||
static_cast<lzo_uint>(aCompressedData.size()),
|
// static_cast<lzo_uint>(aCompressedData.size()),
|
||||||
reinterpret_cast<lzo_bytep>(dst.data()),
|
// reinterpret_cast<lzo_bytep>(dst.data()),
|
||||||
&out,
|
// &out,
|
||||||
nullptr);
|
// nullptr);
|
||||||
|
|
||||||
if (rc != LZO_E_OK || out != aDestSize)
|
// if (rc != LZO_E_OK || out != aDestSize)
|
||||||
throw std::runtime_error("LZO decompression error");
|
// throw std::runtime_error("LZO decompression error");
|
||||||
|
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,14 +3,13 @@ TEMPLATE = lib
|
|||||||
CONFIG += staticlib c++17
|
CONFIG += staticlib c++17
|
||||||
DEFINES += MINILZO_USE_STATIC
|
DEFINES += MINILZO_USE_STATIC
|
||||||
|
|
||||||
SOURCES += $$files($$PWD/*.cpp, true) \
|
SOURCES += $$files($$PWD/*.cpp, true)
|
||||||
$$files($$PWD/*.c, true)
|
|
||||||
HEADERS += $$files($$PWD/*.h, true)
|
HEADERS += $$files($$PWD/*.h, true)
|
||||||
|
|
||||||
LIBS += \
|
LIBS += \
|
||||||
-L$$PWD/../../third_party/xbox_sdk/lib -lxcompress64 \
|
-L$$PWD/../../third_party/xbox_sdk/lib -lxcompress64 \
|
||||||
-L$$OUT_PWD/../libs/core -lcore \
|
-L$$OUT_PWD/../libs/core -lcore \
|
||||||
-L$$OUT_PWD/../libs/encryption -lencryption
|
-L$$OUT_PWD/../libs/encryption -lencryption
|
||||||
|
|
||||||
INCLUDEPATH += \
|
INCLUDEPATH += \
|
||||||
$$PWD/../../third_party/xbox_sdk/include \
|
$$PWD/../../third_party/xbox_sdk/include \
|
||||||
|
|||||||
@ -57,7 +57,7 @@
|
|||||||
|
|
||||||
/* get OS and architecture defines */
|
/* get OS and architecture defines */
|
||||||
#ifndef __LZODEFS_H_INCLUDED
|
#ifndef __LZODEFS_H_INCLUDED
|
||||||
#include <lzodefs.h>
|
#include <lzo/lzodefs.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -25,6 +25,12 @@
|
|||||||
http://www.oberhumer.com/opensource/lzo/
|
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
|
#define __LZO_IN_MINILZO 1
|
||||||
|
|
||||||
#if defined(LZO_CFG_FREESTANDING)
|
#if defined(LZO_CFG_FREESTANDING)
|
||||||
|
|||||||
@ -25,6 +25,13 @@
|
|||||||
http://www.oberhumer.com/opensource/lzo/
|
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
|
#ifndef __MINILZO_H_INCLUDED
|
||||||
#define __MINILZO_H_INCLUDED 1
|
#define __MINILZO_H_INCLUDED 1
|
||||||
|
|
||||||
|
|||||||
@ -2,10 +2,8 @@ QT += core widgets
|
|||||||
TEMPLATE = lib
|
TEMPLATE = lib
|
||||||
CONFIG += staticlib c++17
|
CONFIG += staticlib c++17
|
||||||
|
|
||||||
SOURCES += $$files($$PWD/*.cpp, true) \
|
SOURCES += $$files($$PWD/*.cpp, true)
|
||||||
xdatastream.cpp
|
HEADERS += $$files($$PWD/*.h, true)
|
||||||
HEADERS += $$files($$PWD/*.h, true) \
|
|
||||||
xdatastream.h
|
|
||||||
|
|
||||||
LIBS += -L$$OUT_PWD/../libs/xassets -lxassets
|
LIBS += -L$$OUT_PWD/../libs/xassets -lxassets
|
||||||
|
|
||||||
|
|||||||
@ -4,9 +4,9 @@
|
|||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
enum IWI_VERSION {
|
enum IWI_VERSION {
|
||||||
IWI_VERSION_COD2 = 0x05, // 05 CoD2
|
IWI_VERSION_COD2 = 0x05, // 05 CoD2
|
||||||
IWI_VERSION_COD4 = 0x06, // 06 CoD4
|
IWI_VERSION_COD4 = 0x06, // 06 CoD4
|
||||||
IWI_VERSION_COD5 = 0x06, // 06 CoD5
|
IWI_VERSION_COD5 = 0x06, // 06 CoD5
|
||||||
IWI_VERSION_CODMW2 = 0x08, // 08 CoDMW2
|
IWI_VERSION_CODMW2 = 0x08, // 08 CoDMW2
|
||||||
IWI_VERSION_CODMW3 = 0x08, // 08 CoDMW3
|
IWI_VERSION_CODMW3 = 0x08, // 08 CoDMW3
|
||||||
IWI_VERSION_CODBO1 = 0x0D, // 13 CoDBO1
|
IWI_VERSION_CODBO1 = 0x0D, // 13 CoDBO1
|
||||||
@ -16,37 +16,37 @@ enum IWI_VERSION {
|
|||||||
enum IWI_FORMAT {
|
enum IWI_FORMAT {
|
||||||
// IWI Format
|
// IWI Format
|
||||||
IWI_FORMAT_ARGB32 = 0x01, // 01 ARGB32
|
IWI_FORMAT_ARGB32 = 0x01, // 01 ARGB32
|
||||||
IWI_FORMAT_RGB24 = 0x02, // 02 RGB24
|
IWI_FORMAT_RGB24 = 0x02, // 02 RGB24
|
||||||
IWI_FORMAT_GA16 = 0x03, // 03 GA16
|
IWI_FORMAT_GA16 = 0x03, // 03 GA16
|
||||||
IWI_FORMAT_A8 = 0x04, // 04 A8
|
IWI_FORMAT_A8 = 0x04, // 04 A8
|
||||||
IWI_FORMAT_DXT1 = 0x0B, // 11 DXT1
|
IWI_FORMAT_DXT1 = 0x0B, // 11 DXT1
|
||||||
IWI_FORMAT_DXT3 = 0x0C, // 12 DXT3
|
IWI_FORMAT_DXT3 = 0x0C, // 12 DXT3
|
||||||
IWI_FORMAT_DXT5 = 0x0D // 13 DXT5
|
IWI_FORMAT_DXT5 = 0x0D // 13 DXT5
|
||||||
};
|
};
|
||||||
|
|
||||||
enum DDS_FLAGS {
|
enum DDS_FLAGS {
|
||||||
DDSD_CAPS = 0x1,
|
DDSD_CAPS = 0x1,
|
||||||
DDSD_HEIGHT = 0x2,
|
DDSD_HEIGHT = 0x2,
|
||||||
DDSD_WIDTH = 0x4,
|
DDSD_WIDTH = 0x4,
|
||||||
DDSD_PITCH = 0x8,
|
DDSD_PITCH = 0x8,
|
||||||
DDSD_PIXELFORMAT = 0x1000,
|
DDSD_PIXELFORMAT = 0x1000,
|
||||||
DDSD_MIPMAPCOUNT = 0x20000,
|
DDSD_MIPMAPCOUNT = 0x20000,
|
||||||
DDSD_LINEARSIZE = 0x80000,
|
DDSD_LINEARSIZE = 0x80000,
|
||||||
DDSD_DEPTH = 0x800000
|
DDSD_DEPTH = 0x800000
|
||||||
};
|
};
|
||||||
|
|
||||||
enum DDS_PIXELFORMAT_FLAGS {
|
enum DDS_PIXELFORMAT_FLAGS {
|
||||||
DDPF_ALPHAPIXELS = 0x1,
|
DDPF_ALPHAPIXELS = 0x1,
|
||||||
DDPF_ALPHA = 0x2,
|
DDPF_ALPHA = 0x2,
|
||||||
DDPF_FOURCC = 0x4,
|
DDPF_FOURCC = 0x4,
|
||||||
DDPF_RGB = 0x40,
|
DDPF_RGB = 0x40,
|
||||||
DDPF_YUV = 0x200,
|
DDPF_YUV = 0x200,
|
||||||
DDPF_LUMINANCE = 0x20000
|
DDPF_LUMINANCE = 0x20000
|
||||||
};
|
};
|
||||||
|
|
||||||
enum DDS_CAPS_FLAGS {
|
enum DDS_CAPS_FLAGS {
|
||||||
DDSCAPS_COMPLEX = 0x8,
|
DDSCAPS_COMPLEX = 0x8,
|
||||||
DDSCAPS_MIPMAP = 0x400000,
|
DDSCAPS_MIPMAP = 0x400000,
|
||||||
DDSCAPS_TEXTURE = 0x1000
|
DDSCAPS_TEXTURE = 0x1000
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -189,15 +189,15 @@ enum MENU_ITEM_TYPE {
|
|||||||
ITEM_TYPE_RADIOBUTTON = 2, // toggle button, may be grouped
|
ITEM_TYPE_RADIOBUTTON = 2, // toggle button, may be grouped
|
||||||
ITEM_TYPE_CHECKBOX = 3, // check box
|
ITEM_TYPE_CHECKBOX = 3, // check box
|
||||||
ITEM_TYPE_EDITFIELD = 4, // editable text, associated with a dvar
|
ITEM_TYPE_EDITFIELD = 4, // editable text, associated with a dvar
|
||||||
ITEM_TYPE_COMBO = 5, // drop down list
|
ITEM_TYPE_COMBO = 5, // drop down list
|
||||||
ITEM_TYPE_LISTBOX = 6, // scrollable list
|
ITEM_TYPE_LISTBOX = 6, // scrollable list
|
||||||
ITEM_TYPE_MODEL = 7, // model
|
ITEM_TYPE_MODEL = 7, // model
|
||||||
ITEM_TYPE_OWNERDRAW = 8, // owner draw, name specs what it is
|
ITEM_TYPE_OWNERDRAW = 8, // owner draw, name specs what it is
|
||||||
ITEM_TYPE_NUMERICFIELD = 9, // editable text, associated with a dvar
|
ITEM_TYPE_NUMERICFIELD = 9, // editable text, associated with a dvar
|
||||||
ITEM_TYPE_SLIDER = 10, // mouse speed, volume, etc.
|
ITEM_TYPE_SLIDER = 10, // mouse speed, volume, etc.
|
||||||
ITEM_TYPE_YESNO = 11, // yes no dvar setting
|
ITEM_TYPE_YESNO = 11, // yes no dvar setting
|
||||||
ITEM_TYPE_MULTI = 12, // multiple list setting, enumerated
|
ITEM_TYPE_MULTI = 12, // multiple list setting, enumerated
|
||||||
ITEM_TYPE_DVARENUM = 13, // multiple list setting, enumerated from a dvar
|
ITEM_TYPE_DVARENUM = 13, // multiple list setting, enumerated from a dvar
|
||||||
ITEM_TYPE_BIND = 14, // bind
|
ITEM_TYPE_BIND = 14, // bind
|
||||||
ITEM_TYPE_MENUMODEL = 15, // special menu model
|
ITEM_TYPE_MENUMODEL = 15, // special menu model
|
||||||
ITEM_TYPE_VALIDFILEFIELD = 16, // text must be valid for use in a dos filename
|
ITEM_TYPE_VALIDFILEFIELD = 16, // text must be valid for use in a dos filename
|
||||||
|
|||||||
@ -223,7 +223,7 @@ public:
|
|||||||
|
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
static bool ReadUntilString(XDataStream* stream, const QString& targetString) {
|
static bool ReadUntilString(QDataStream* stream, const QString& targetString) {
|
||||||
if (!stream || targetString.isEmpty()) {
|
if (!stream || targetString.isEmpty()) {
|
||||||
return false; // Invalid input
|
return false; // Invalid input
|
||||||
}
|
}
|
||||||
@ -257,7 +257,7 @@ public:
|
|||||||
return false;
|
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) {
|
if (!stream || hexString.isEmpty() || hexString.size() % 2 != 0) {
|
||||||
return false; // Invalid input
|
return false; // Invalid input
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
|
||||||
}
|
|
||||||
@ -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
|
|
||||||
@ -24,9 +24,9 @@ enum FF_GAME {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum IWI_VERSION {
|
enum IWI_VERSION {
|
||||||
IWI_VERSION_COD2 = 0x05, // 05 CoD2
|
IWI_VERSION_COD2 = 0x05, // 05 CoD2
|
||||||
IWI_VERSION_COD4 = 0x06, // 06 CoD4
|
IWI_VERSION_COD4 = 0x06, // 06 CoD4
|
||||||
IWI_VERSION_COD5 = 0x06, // 06 CoD5
|
IWI_VERSION_COD5 = 0x06, // 06 CoD5
|
||||||
IWI_VERSION_CODMW2 = 0x08, // 08 CoDMW2
|
IWI_VERSION_CODMW2 = 0x08, // 08 CoDMW2
|
||||||
IWI_VERSION_CODMW3 = 0x08, // 08 CoDMW3
|
IWI_VERSION_CODMW3 = 0x08, // 08 CoDMW3
|
||||||
IWI_VERSION_CODBO1 = 0x0D, // 13 CoDBO1
|
IWI_VERSION_CODBO1 = 0x0D, // 13 CoDBO1
|
||||||
@ -36,37 +36,37 @@ enum IWI_VERSION {
|
|||||||
enum IWI_FORMAT {
|
enum IWI_FORMAT {
|
||||||
// IWI Format
|
// IWI Format
|
||||||
IWI_FORMAT_ARGB32 = 0x01, // 01 ARGB32
|
IWI_FORMAT_ARGB32 = 0x01, // 01 ARGB32
|
||||||
IWI_FORMAT_RGB24 = 0x02, // 02 RGB24
|
IWI_FORMAT_RGB24 = 0x02, // 02 RGB24
|
||||||
IWI_FORMAT_GA16 = 0x03, // 03 GA16
|
IWI_FORMAT_GA16 = 0x03, // 03 GA16
|
||||||
IWI_FORMAT_A8 = 0x04, // 04 A8
|
IWI_FORMAT_A8 = 0x04, // 04 A8
|
||||||
IWI_FORMAT_DXT1 = 0x0B, // 11 DXT1
|
IWI_FORMAT_DXT1 = 0x0B, // 11 DXT1
|
||||||
IWI_FORMAT_DXT3 = 0x0C, // 12 DXT3
|
IWI_FORMAT_DXT3 = 0x0C, // 12 DXT3
|
||||||
IWI_FORMAT_DXT5 = 0x0D // 13 DXT5
|
IWI_FORMAT_DXT5 = 0x0D // 13 DXT5
|
||||||
};
|
};
|
||||||
|
|
||||||
enum DDS_FLAGS {
|
enum DDS_FLAGS {
|
||||||
DDSD_CAPS = 0x1,
|
DDSD_CAPS = 0x1,
|
||||||
DDSD_HEIGHT = 0x2,
|
DDSD_HEIGHT = 0x2,
|
||||||
DDSD_WIDTH = 0x4,
|
DDSD_WIDTH = 0x4,
|
||||||
DDSD_PITCH = 0x8,
|
DDSD_PITCH = 0x8,
|
||||||
DDSD_PIXELFORMAT = 0x1000,
|
DDSD_PIXELFORMAT = 0x1000,
|
||||||
DDSD_MIPMAPCOUNT = 0x20000,
|
DDSD_MIPMAPCOUNT = 0x20000,
|
||||||
DDSD_LINEARSIZE = 0x80000,
|
DDSD_LINEARSIZE = 0x80000,
|
||||||
DDSD_DEPTH = 0x800000
|
DDSD_DEPTH = 0x800000
|
||||||
};
|
};
|
||||||
|
|
||||||
enum DDS_PIXELFORMAT_FLAGS {
|
enum DDS_PIXELFORMAT_FLAGS {
|
||||||
DDPF_ALPHAPIXELS = 0x1,
|
DDPF_ALPHAPIXELS = 0x1,
|
||||||
DDPF_ALPHA = 0x2,
|
DDPF_ALPHA = 0x2,
|
||||||
DDPF_FOURCC = 0x4,
|
DDPF_FOURCC = 0x4,
|
||||||
DDPF_RGB = 0x40,
|
DDPF_RGB = 0x40,
|
||||||
DDPF_YUV = 0x200,
|
DDPF_YUV = 0x200,
|
||||||
DDPF_LUMINANCE = 0x20000
|
DDPF_LUMINANCE = 0x20000
|
||||||
};
|
};
|
||||||
|
|
||||||
enum DDS_CAPS_FLAGS {
|
enum DDS_CAPS_FLAGS {
|
||||||
DDSCAPS_COMPLEX = 0x8,
|
DDSCAPS_COMPLEX = 0x8,
|
||||||
DDSCAPS_MIPMAP = 0x400000,
|
DDSCAPS_MIPMAP = 0x400000,
|
||||||
DDSCAPS_TEXTURE = 0x1000
|
DDSCAPS_TEXTURE = 0x1000
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -209,15 +209,15 @@ enum MENU_ITEM_TYPE {
|
|||||||
ITEM_TYPE_RADIOBUTTON = 2, // toggle button, may be grouped
|
ITEM_TYPE_RADIOBUTTON = 2, // toggle button, may be grouped
|
||||||
ITEM_TYPE_CHECKBOX = 3, // check box
|
ITEM_TYPE_CHECKBOX = 3, // check box
|
||||||
ITEM_TYPE_EDITFIELD = 4, // editable text, associated with a dvar
|
ITEM_TYPE_EDITFIELD = 4, // editable text, associated with a dvar
|
||||||
ITEM_TYPE_COMBO = 5, // drop down list
|
ITEM_TYPE_COMBO = 5, // drop down list
|
||||||
ITEM_TYPE_LISTBOX = 6, // scrollable list
|
ITEM_TYPE_LISTBOX = 6, // scrollable list
|
||||||
ITEM_TYPE_MODEL = 7, // model
|
ITEM_TYPE_MODEL = 7, // model
|
||||||
ITEM_TYPE_OWNERDRAW = 8, // owner draw, name specs what it is
|
ITEM_TYPE_OWNERDRAW = 8, // owner draw, name specs what it is
|
||||||
ITEM_TYPE_NUMERICFIELD = 9, // editable text, associated with a dvar
|
ITEM_TYPE_NUMERICFIELD = 9, // editable text, associated with a dvar
|
||||||
ITEM_TYPE_SLIDER = 10, // mouse speed, volume, etc.
|
ITEM_TYPE_SLIDER = 10, // mouse speed, volume, etc.
|
||||||
ITEM_TYPE_YESNO = 11, // yes no dvar setting
|
ITEM_TYPE_YESNO = 11, // yes no dvar setting
|
||||||
ITEM_TYPE_MULTI = 12, // multiple list setting, enumerated
|
ITEM_TYPE_MULTI = 12, // multiple list setting, enumerated
|
||||||
ITEM_TYPE_DVARENUM = 13, // multiple list setting, enumerated from a dvar
|
ITEM_TYPE_DVARENUM = 13, // multiple list setting, enumerated from a dvar
|
||||||
ITEM_TYPE_BIND = 14, // bind
|
ITEM_TYPE_BIND = 14, // bind
|
||||||
ITEM_TYPE_MENUMODEL = 15, // special menu model
|
ITEM_TYPE_MENUMODEL = 15, // special menu model
|
||||||
ITEM_TYPE_VALIDFILEFIELD = 16, // text must be valid for use in a dos filename
|
ITEM_TYPE_VALIDFILEFIELD = 16, // text must be valid for use in a dos filename
|
||||||
|
|||||||
@ -1,5 +1,15 @@
|
|||||||
/* ecrypt-portable.h */
|
/* 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. ***
|
* *** Please do not edit this file. ***
|
||||||
*
|
*
|
||||||
|
|||||||
@ -1,35 +1,27 @@
|
|||||||
#include <QtCore>
|
#include "encryption.h"
|
||||||
#include "QtZlib/zlib.h"
|
#include "QtZlib/zlib.h"
|
||||||
#include "ecrypt-sync.h"
|
#include "ecrypt-sync.h"
|
||||||
#include "sha1.h"
|
|
||||||
#include "encryption.h"
|
|
||||||
#include "compression.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[0] = static_cast<quint8>(value >> 0);
|
||||||
array[1] = static_cast<quint8>(value >> 8);
|
array[1] = static_cast<quint8>(value >> 8);
|
||||||
array[2] = static_cast<quint8>(value >> 16);
|
array[2] = static_cast<quint8>(value >> 16);
|
||||||
array[3] = static_cast<quint8>(value >> 24);
|
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) |
|
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[1])) << 8) |
|
||||||
(static_cast<quint32>(static_cast<uchar>(array[2])) << 16) |
|
(static_cast<quint32>(static_cast<uchar>(array[2])) << 16) |
|
||||||
(static_cast<quint32>(static_cast<uchar>(array[3])) << 24));
|
(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));
|
return (value << numBits) | (value >> (32 - numBits));
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray Encryption::InitIVTable(const QByteArray &feed)
|
QByteArray Encryption::InitIVTable(const QByteArray &feed) {
|
||||||
{
|
|
||||||
const int tableSize = 0xFB0;
|
const int tableSize = 0xFB0;
|
||||||
QByteArray table;
|
QByteArray table;
|
||||||
table.resize(tableSize);
|
table.resize(tableSize);
|
||||||
@ -39,7 +31,7 @@ QByteArray Encryption::InitIVTable(const QByteArray &feed)
|
|||||||
if (static_cast<uchar>(feed.at(ptr)) == 0x00)
|
if (static_cast<uchar>(feed.at(ptr)) == 0x00)
|
||||||
ptr = 0;
|
ptr = 0;
|
||||||
int base = i * 20 + x * 4;
|
int base = i * 20 + x * 4;
|
||||||
table[base] = feed.at(ptr);
|
table[base] = feed.at(ptr);
|
||||||
table[base + 1] = feed.at(ptr);
|
table[base + 1] = feed.at(ptr);
|
||||||
table[base + 2] = feed.at(ptr);
|
table[base + 2] = feed.at(ptr);
|
||||||
table[base + 3] = feed.at(ptr);
|
table[base + 3] = feed.at(ptr);
|
||||||
@ -56,23 +48,22 @@ QByteArray Encryption::InitIVTable(const QByteArray &feed)
|
|||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Encryption::unk(quint64 arg1, quint8 arg2)
|
int Encryption::unk(quint64 arg1, quint8 arg2) {
|
||||||
{
|
|
||||||
if (arg2 >= 0x40)
|
if (arg2 >= 0x40)
|
||||||
return 0;
|
return 0;
|
||||||
return static_cast<int>(arg1 >> arg2);
|
return static_cast<int>(arg1 >> arg2);
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray Encryption::GetIV(const QByteArray &table, int index)
|
QByteArray Encryption::GetIV(const QByteArray &table, int index) {
|
||||||
{
|
int num1 = 0xFA0 + index;
|
||||||
int num1 = (4 * index % 4 + 0xFA0) + index % 4 + (index - (index % 4));
|
|
||||||
int num2 = unk(0x51EB851FLL * num1, 0x20);
|
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);
|
return table.mid(startIndex, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Encryption::UpdateIVTable(QByteArray &table, int index, const QByteArray §ionHash)
|
void Encryption::UpdateIVTable(QByteArray &table, int index, const QByteArray §ionHash) {
|
||||||
{
|
|
||||||
int blockNumIndex = index % 4;
|
int blockNumIndex = index % 4;
|
||||||
int baseOffset = 0xFA0 + blockNumIndex * 4;
|
int baseOffset = 0xFA0 + blockNumIndex * 4;
|
||||||
quint32 blockNumVal = (static_cast<uchar>(table.at(baseOffset)) ) |
|
quint32 blockNumVal = (static_cast<uchar>(table.at(baseOffset)) ) |
|
||||||
@ -86,7 +77,7 @@ void Encryption::UpdateIVTable(QByteArray &table, int index, const QByteArray &s
|
|||||||
int hashIndex = 0;
|
int hashIndex = 0;
|
||||||
for (int x = 0; x < 4; ++x) {
|
for (int x = 0; x < 4; ++x) {
|
||||||
table[startIndex - 1] = table.at(startIndex - 1) ^ sectionHash.at(hashIndex);
|
table[startIndex - 1] = table.at(startIndex - 1) ^ sectionHash.at(hashIndex);
|
||||||
table[startIndex] = table.at(startIndex) ^ sectionHash.at(hashIndex + 1);
|
table[startIndex] = table.at(startIndex) ^ sectionHash.at(hashIndex + 1);
|
||||||
table[startIndex + 1] = table.at(startIndex + 1) ^ sectionHash.at(hashIndex + 2);
|
table[startIndex + 1] = table.at(startIndex + 1) ^ sectionHash.at(hashIndex + 2);
|
||||||
table[startIndex + 2] = table.at(startIndex + 2) ^ sectionHash.at(hashIndex + 3);
|
table[startIndex + 2] = table.at(startIndex + 2) ^ sectionHash.at(hashIndex + 3);
|
||||||
table[startIndex + 3] = table.at(startIndex + 3) ^ sectionHash.at(hashIndex + 4);
|
table[startIndex + 3] = table.at(startIndex + 3) ^ sectionHash.at(hashIndex + 4);
|
||||||
@ -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)
|
// Converts 4 bytes (starting at offset) from data into a 32-bit quint32eger (little-endian)
|
||||||
return ((static_cast<quint32>(static_cast<uchar>(data[offset])) ) |
|
return ((static_cast<quint32>(static_cast<uchar>(data[offset])) ) |
|
||||||
(static_cast<quint32>(static_cast<uchar>(data[offset+1])) << 8 ) |
|
(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]++;
|
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");
|
const QByteArray salsaKey = QByteArray::fromHex("0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3");
|
||||||
|
|
||||||
QByteArray ivTable(0xFB0, 0);
|
QByteArray ivTable(0xFB0, 0);
|
||||||
@ -426,71 +504,3 @@ QByteArray Encryption::decryptFastFile_BO3(const QByteArray &fastFileData)
|
|||||||
|
|
||||||
return finalFastFile;
|
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;
|
|
||||||
}
|
|
||||||
|
|||||||
@ -46,9 +46,8 @@ public:
|
|||||||
|
|
||||||
static void generateNewIV(int index, const QByteArray& hash, QByteArray& ivTable, QVector<quint32>& ivCounter);
|
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 decryptFastFile_BO3(const QByteArray& fastFileData);
|
||||||
static QByteArray DecryptFile(const QByteArray& fastFileData, const QString& aFileName, const QByteArray& aKey);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ENCRYPTION_H
|
#endif // ENCRYPTION_H
|
||||||
|
|||||||
@ -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;
|
u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
|
||||||
u8 *ctarget;
|
u8 *ctarget;
|
||||||
u8 tmp[64];
|
u8 tmp[64];
|
||||||
u32 i;
|
int i;
|
||||||
|
|
||||||
if (!bytes) return;
|
if (!bytes) return;
|
||||||
|
|
||||||
@ -82,10 +82,7 @@ void ECRYPT_encrypt_bytes(ECRYPT_ctx *x,const u8 *m,u8 *c,u32 bytes)
|
|||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (bytes < 64) {
|
if (bytes < 64) {
|
||||||
for (i = 0; i < bytes; ++i)
|
for (i = 0;i < bytes;++i) tmp[i] = m[i];
|
||||||
{
|
|
||||||
tmp[i] = m[i];
|
|
||||||
}
|
|
||||||
m = tmp;
|
m = tmp;
|
||||||
ctarget = c;
|
ctarget = c;
|
||||||
c = tmp;
|
c = tmp;
|
||||||
|
|||||||
@ -94,6 +94,7 @@ void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]);
|
|||||||
|
|
||||||
/* blk0() and blk() perform the initial expand. */
|
/* blk0() and blk() perform the initial expand. */
|
||||||
/* I got the idea of expanding during the round function from SSLeay */
|
/* 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
|
#ifdef WORDS_BIGENDIAN
|
||||||
#define blk0(i) block->l[i]
|
#define blk0(i) block->l[i]
|
||||||
#else
|
#else
|
||||||
|
|||||||
@ -69,9 +69,15 @@ bool FastFile_COD10_360::Load(const QString aFilePath) {
|
|||||||
bool FastFile_COD10_360::Load(const QByteArray aData) {
|
bool FastFile_COD10_360::Load(const QByteArray aData) {
|
||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Create a XDataStream on the input data.
|
// Create a QDataStream on the input data.
|
||||||
XDataStream fastFileStream(aData);
|
QDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
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.
|
// Read the 8-byte magic.
|
||||||
QByteArray fileMagic(8, Qt::Uninitialized);
|
QByteArray fileMagic(8, Qt::Uninitialized);
|
||||||
@ -90,7 +96,7 @@ bool FastFile_COD10_360::Load(const QByteArray aData) {
|
|||||||
QByteArray rsaSignature(256, Qt::Uninitialized);
|
QByteArray rsaSignature(256, Qt::Uninitialized);
|
||||||
fastFileStream.readRawData(rsaSignature.data(), 256);
|
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.
|
// For COD9, write out the complete decompressed zone for testing.
|
||||||
QFile testFile("exports/" + GetBaseStem() + ".zone");
|
QFile testFile("exports/" + GetBaseStem() + ".zone");
|
||||||
@ -98,7 +104,6 @@ bool FastFile_COD10_360::Load(const QByteArray aData) {
|
|||||||
testFile.write(decompressedData);
|
testFile.write(decompressedData);
|
||||||
testFile.close();
|
testFile.close();
|
||||||
}
|
}
|
||||||
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
|
||||||
|
|
||||||
// Load the zone file with the decompressed data (using an Xbox platform flag).
|
// Load the zone file with the decompressed data (using an Xbox platform flag).
|
||||||
ZoneFile_COD10_360* zoneFile = new ZoneFile_COD10_360();
|
ZoneFile_COD10_360* zoneFile = new ZoneFile_COD10_360();
|
||||||
|
|||||||
@ -68,74 +68,29 @@ bool FastFile_COD11_360::Load(const QString aFilePath) {
|
|||||||
return true;
|
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) {
|
bool FastFile_COD11_360::Load(const QByteArray aData) {
|
||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Prepare data stream for parsing
|
// Prepare data stream for parsing
|
||||||
XDataStream fastFileStream(aData);
|
QDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
|
||||||
// Verify magic header
|
// Verify magic header
|
||||||
QByteArray fileMagic(8, Qt::Uninitialized);
|
QByteArray fileMagic(8, Qt::Uninitialized);
|
||||||
fastFileStream.readRawData(fileMagic.data(), 8);
|
fastFileStream.readRawData(fileMagic.data(), 8);
|
||||||
quint32 version = fastFileStream.ParseUInt32();
|
if (fileMagic != "TAff0000") {
|
||||||
|
qWarning() << "Invalid fast file magic for COD12!";
|
||||||
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 << "!";
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (blockCount > 17280)
|
// 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.
|
||||||
qWarning() << "Fast file has too many blocks:" << blockCount << "> 17280!";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
fastFileStream.skipRawData(12 * blockCount);
|
|
||||||
|
|
||||||
qint32 startPos = fastFileStream.ParseInt32();
|
// Correctly positioned at 0x138
|
||||||
Q_UNUSED(startPos);
|
QByteArray encryptedData = aData.mid(0x138);
|
||||||
|
decompressedData = Encryption::decryptFastFile_BO3(encryptedData);
|
||||||
|
|
||||||
qint32 endPos = fastFileStream.ParseInt32();
|
// Output for verification/testing
|
||||||
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;
|
|
||||||
}
|
|
||||||
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
||||||
|
|
||||||
// Load the zone file with decompressed data
|
// Load the zone file with decompressed data
|
||||||
|
|||||||
@ -72,69 +72,24 @@ bool FastFile_COD12_360::Load(const QByteArray aData) {
|
|||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Prepare data stream for parsing
|
// Prepare data stream for parsing
|
||||||
XDataStream fastFileStream(aData);
|
QDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
|
||||||
// Skip header magic
|
// Verify magic header
|
||||||
fastFileStream.skipRawData(8);
|
QByteArray fileMagic(8, Qt::Uninitialized);
|
||||||
|
fastFileStream.readRawData(fileMagic.data(), 8);
|
||||||
quint32 version;
|
if (fileMagic != "TAff0000") {
|
||||||
fastFileStream >> version;
|
qWarning() << "Invalid fast file magic for COD12!";
|
||||||
|
|
||||||
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!";
|
|
||||||
return false;
|
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;
|
// Correctly positioned at 0x138
|
||||||
fastFileStream >> size;
|
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
|
// Output for verification/testing
|
||||||
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
||||||
|
|
||||||
|
|||||||
@ -68,9 +68,9 @@ bool FastFile_COD2_360::Load(const QString aFilePath) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool FastFile_COD2_360::Load(const QByteArray aData) {
|
bool FastFile_COD2_360::Load(const QByteArray aData) {
|
||||||
// Create a XDataStream on the input data.
|
// Create a QDataStream on the input data.
|
||||||
XDataStream fastFileStream(aData);
|
QDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
|
||||||
Utils::ReadUntilHex(&fastFileStream, "78");
|
Utils::ReadUntilHex(&fastFileStream, "78");
|
||||||
QByteArray compressedData = aData.mid(fastFileStream.device()->pos());
|
QByteArray compressedData = aData.mid(fastFileStream.device()->pos());
|
||||||
|
|||||||
@ -80,9 +80,9 @@ bool FastFile_COD4_360::Load(const QByteArray aData) {
|
|||||||
// For COD5, simply decompress from offset 12.
|
// For COD5, simply decompress from offset 12.
|
||||||
decompressedData = Compression::DecompressZLIB(aData.mid(12));
|
decompressedData = Compression::DecompressZLIB(aData.mid(12));
|
||||||
} else if (header == "IWff0100") {
|
} else if (header == "IWff0100") {
|
||||||
// Create a XDataStream on the input data.
|
// Create a QDataStream on the input data.
|
||||||
XDataStream fastFileStream(aData.mid(12));
|
QDataStream fastFileStream(aData.mid(12));
|
||||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
|
||||||
QByteArray magic(8, Qt::Uninitialized);
|
QByteArray magic(8, Qt::Uninitialized);
|
||||||
fastFileStream.readRawData(magic.data(), 8);
|
fastFileStream.readRawData(magic.data(), 8);
|
||||||
|
|||||||
@ -70,47 +70,30 @@ bool FastFile_COD6_360::Load(const QString aFilePath) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool FastFile_COD6_360::Load(const QByteArray aData) {
|
bool FastFile_COD6_360::Load(const QByteArray aData) {
|
||||||
XDataStream fastFileStream(aData);
|
const qint64 zlibOffset = Compression::FindZlibOffset(aData);
|
||||||
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
if (zlibOffset == -1)
|
||||||
|
|
||||||
QByteArray magic(8, Qt::Uninitialized);
|
|
||||||
fastFileStream.readRawData(magic.data(), 8);
|
|
||||||
|
|
||||||
quint32 version = fastFileStream.ParseUInt32();
|
|
||||||
|
|
||||||
if (version != 269)
|
|
||||||
{
|
{
|
||||||
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;
|
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);
|
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
||||||
|
|
||||||
ZoneFile_COD6_360* zoneFile = new ZoneFile_COD6_360();
|
ZoneFile_COD6_360* zoneFile = new ZoneFile_COD6_360();
|
||||||
|
|||||||
@ -71,11 +71,16 @@ bool FastFile_COD7_360::Load(const QString aFilePath) {
|
|||||||
bool FastFile_COD7_360::Load(const QByteArray aData) {
|
bool FastFile_COD7_360::Load(const QByteArray aData) {
|
||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Create a XDataStream on the input data.
|
// Create a QDataStream on the input data.
|
||||||
XDataStream fastFileStream(aData);
|
QDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
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.
|
// Read the 8-byte magic.
|
||||||
QByteArray fileMagic(8, Qt::Uninitialized);
|
QByteArray fileMagic(8, Qt::Uninitialized);
|
||||||
@ -97,8 +102,6 @@ bool FastFile_COD7_360::Load(const QByteArray aData) {
|
|||||||
QByteArray rsaSignature(256, Qt::Uninitialized);
|
QByteArray rsaSignature(256, Qt::Uninitialized);
|
||||||
fastFileStream.readRawData(rsaSignature.data(), 256);
|
fastFileStream.readRawData(rsaSignature.data(), 256);
|
||||||
|
|
||||||
QByteArray key = QByteArray::fromHex("1ac1d12d527c59b40eca619120ff8217ccff09cd16896f81b829c7f52793405d");
|
|
||||||
|
|
||||||
// Now the stream should be positioned at 0x13C, where sections begin.
|
// Now the stream should be positioned at 0x13C, where sections begin.
|
||||||
int sectionIndex = 0;
|
int sectionIndex = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|||||||
@ -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;
|
|
||||||
}
|
|
||||||
@ -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
|
|
||||||
@ -69,12 +69,15 @@ bool FastFile_COD8_360::Load(const QString aFilePath) {
|
|||||||
bool FastFile_COD8_360::Load(const QByteArray aData) {
|
bool FastFile_COD8_360::Load(const QByteArray aData) {
|
||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Create a XDataStream on the input data.
|
// Create a QDataStream on the input data.
|
||||||
XDataStream fastFileStream(aData);
|
QDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
|
||||||
// For COD7/COD9, use BigEndian.
|
// 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.
|
// Read the 8-byte magic.
|
||||||
QByteArray fileMagic(8, Qt::Uninitialized);
|
QByteArray fileMagic(8, Qt::Uninitialized);
|
||||||
@ -89,7 +92,11 @@ bool FastFile_COD8_360::Load(const QByteArray aData) {
|
|||||||
QByteArray fileName(32, Qt::Uninitialized);
|
QByteArray fileName(32, Qt::Uninitialized);
|
||||||
fastFileStream.readRawData(fileName.data(), 32);
|
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.
|
// For COD9, write out the complete decompressed zone for testing.
|
||||||
QFile testFile("exports/" + GetBaseStem() + ".zone");
|
QFile testFile("exports/" + GetBaseStem() + ".zone");
|
||||||
|
|||||||
@ -69,12 +69,15 @@ bool FastFile_COD9_360::Load(const QString aFilePath) {
|
|||||||
bool FastFile_COD9_360::Load(const QByteArray aData) {
|
bool FastFile_COD9_360::Load(const QByteArray aData) {
|
||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Create a XDataStream on the input data.
|
// Create a QDataStream on the input data.
|
||||||
XDataStream fastFileStream(aData);
|
QDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
|
||||||
// For COD7/COD9, use BigEndian.
|
// 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.
|
// Read the 8-byte magic.
|
||||||
QByteArray fileMagic(8, Qt::Uninitialized);
|
QByteArray fileMagic(8, Qt::Uninitialized);
|
||||||
@ -93,7 +96,7 @@ bool FastFile_COD9_360::Load(const QByteArray aData) {
|
|||||||
QByteArray rsaSignature(256, Qt::Uninitialized);
|
QByteArray rsaSignature(256, Qt::Uninitialized);
|
||||||
fastFileStream.readRawData(rsaSignature.data(), 256);
|
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.
|
// For COD9, write out the complete decompressed zone for testing.
|
||||||
QFile testFile("exports/" + GetBaseStem() + ".zone");
|
QFile testFile("exports/" + GetBaseStem() + ".zone");
|
||||||
|
|||||||
@ -69,9 +69,9 @@ bool FastFile_COD10_PC::Load(const QString aFilePath) {
|
|||||||
bool FastFile_COD10_PC::Load(const QByteArray aData) {
|
bool FastFile_COD10_PC::Load(const QByteArray aData) {
|
||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Create a XDataStream on the input data.
|
// Create a QDataStream on the input data.
|
||||||
XDataStream fastFileStream(aData);
|
QDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
|
||||||
// Parse header values.
|
// Parse header values.
|
||||||
SetCompany(pParseFFCompany(&fastFileStream));
|
SetCompany(pParseFFCompany(&fastFileStream));
|
||||||
@ -84,13 +84,18 @@ bool FastFile_COD10_PC::Load(const QByteArray aData) {
|
|||||||
SetGame("COD9");
|
SetGame("COD9");
|
||||||
|
|
||||||
// For COD7/COD9, use BigEndian.
|
// For COD7/COD9, use BigEndian.
|
||||||
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
fastFileStream.setByteOrder(QDataStream::BigEndian);
|
||||||
if (GetPlatform() == "PC") {
|
if (GetPlatform() == "PC") {
|
||||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select key based on game.
|
// 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.
|
// Read the 8-byte magic.
|
||||||
QByteArray fileMagic(8, Qt::Uninitialized);
|
QByteArray fileMagic(8, Qt::Uninitialized);
|
||||||
@ -109,7 +114,11 @@ bool FastFile_COD10_PC::Load(const QByteArray aData) {
|
|||||||
QByteArray rsaSignature(256, Qt::Uninitialized);
|
QByteArray rsaSignature(256, Qt::Uninitialized);
|
||||||
fastFileStream.readRawData(rsaSignature.data(), 256);
|
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.
|
// For COD9, write out the complete decompressed zone for testing.
|
||||||
QFile testFile("exports/" + GetBaseStem() + ".zone");
|
QFile testFile("exports/" + GetBaseStem() + ".zone");
|
||||||
@ -117,7 +126,6 @@ bool FastFile_COD10_PC::Load(const QByteArray aData) {
|
|||||||
testFile.write(decompressedData);
|
testFile.write(decompressedData);
|
||||||
testFile.close();
|
testFile.close();
|
||||||
}
|
}
|
||||||
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
|
||||||
|
|
||||||
// Load the zone file with the decompressed data (using an Xbox platform flag).
|
// Load the zone file with the decompressed data (using an Xbox platform flag).
|
||||||
ZoneFile_COD10_PC* zoneFile = new ZoneFile_COD10_PC();
|
ZoneFile_COD10_PC* zoneFile = new ZoneFile_COD10_PC();
|
||||||
|
|||||||
@ -69,9 +69,9 @@ bool FastFile_COD11_PC::Load(const QString aFilePath) {
|
|||||||
bool FastFile_COD11_PC::Load(const QByteArray aData) {
|
bool FastFile_COD11_PC::Load(const QByteArray aData) {
|
||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Create a XDataStream on the input data.
|
// Create a QDataStream on the input data.
|
||||||
XDataStream fastFileStream(aData);
|
QDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
|
||||||
// Parse header values.
|
// Parse header values.
|
||||||
SetCompany(pParseFFCompany(&fastFileStream));
|
SetCompany(pParseFFCompany(&fastFileStream));
|
||||||
@ -80,11 +80,22 @@ bool FastFile_COD11_PC::Load(const QByteArray aData) {
|
|||||||
SetMagic(pParseFFMagic(&fastFileStream));
|
SetMagic(pParseFFMagic(&fastFileStream));
|
||||||
quint32 version = pParseFFVersion(&fastFileStream);
|
quint32 version = pParseFFVersion(&fastFileStream);
|
||||||
SetVersion(version);
|
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.
|
// 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.
|
// Read the 8-byte magic.
|
||||||
QByteArray fileMagic(8, Qt::Uninitialized);
|
QByteArray fileMagic(8, Qt::Uninitialized);
|
||||||
@ -103,7 +114,11 @@ bool FastFile_COD11_PC::Load(const QByteArray aData) {
|
|||||||
QByteArray rsaSignature(256, Qt::Uninitialized);
|
QByteArray rsaSignature(256, Qt::Uninitialized);
|
||||||
fastFileStream.readRawData(rsaSignature.data(), 256);
|
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.
|
// For COD9, write out the complete decompressed zone for testing.
|
||||||
QFile testFile("exports/" + GetBaseStem() + ".zone");
|
QFile testFile("exports/" + GetBaseStem() + ".zone");
|
||||||
@ -111,7 +126,6 @@ bool FastFile_COD11_PC::Load(const QByteArray aData) {
|
|||||||
testFile.write(decompressedData);
|
testFile.write(decompressedData);
|
||||||
testFile.close();
|
testFile.close();
|
||||||
}
|
}
|
||||||
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
|
||||||
|
|
||||||
// Load the zone file with the decompressed data (using an Xbox platform flag).
|
// Load the zone file with the decompressed data (using an Xbox platform flag).
|
||||||
ZoneFile_COD11_PC* zoneFile = new ZoneFile_COD11_PC();
|
ZoneFile_COD11_PC* zoneFile = new ZoneFile_COD11_PC();
|
||||||
|
|||||||
@ -72,9 +72,9 @@ bool FastFile_COD12_PC::Load(const QString aFilePath) {
|
|||||||
bool FastFile_COD12_PC::Load(const QByteArray aData) {
|
bool FastFile_COD12_PC::Load(const QByteArray aData) {
|
||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Create a XDataStream on the input data.
|
// Create a QDataStream on the input data.
|
||||||
XDataStream fastFileStream(aData);
|
QDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
|
||||||
// Skip header magic
|
// Skip header magic
|
||||||
fastFileStream.skipRawData(8);
|
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
|
// Sinze Fast Files are aligns, we must skip the full block
|
||||||
fastFileStream.device()->seek(blockPosition + 16 + blockSize);
|
fastFileStream.device()->seek(blockPosition + 16 + blockSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
||||||
|
|
||||||
// Load the zone file with the decompressed data (using an Xbox platform flag).
|
// Load the zone file with the decompressed data (using an Xbox platform flag).
|
||||||
|
|||||||
@ -75,9 +75,9 @@ bool FastFile_COD4_PC::Load(const QByteArray aData) {
|
|||||||
StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/data", 1000);
|
StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/data", 1000);
|
||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Create a XDataStream on the input data.
|
// Create a QDataStream on the input data.
|
||||||
XDataStream fastFileStream(aData);
|
QDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
|
||||||
// For COD5, simply decompress from offset 12.
|
// For COD5, simply decompress from offset 12.
|
||||||
decompressedData = Compression::DecompressZLIB(aData.mid(12));
|
decompressedData = Compression::DecompressZLIB(aData.mid(12));
|
||||||
|
|||||||
@ -75,9 +75,9 @@ bool FastFile_COD5_PC::Load(const QByteArray aData) {
|
|||||||
StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/data", 1000);
|
StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/data", 1000);
|
||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Create a XDataStream on the input data.
|
// Create a QDataStream on the input data.
|
||||||
XDataStream fastFileStream(aData);
|
QDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
|
||||||
// For COD5, simply decompress from offset 12.
|
// For COD5, simply decompress from offset 12.
|
||||||
decompressedData = Compression::DecompressZLIB(aData.mid(12));
|
decompressedData = Compression::DecompressZLIB(aData.mid(12));
|
||||||
|
|||||||
@ -72,30 +72,12 @@ bool FastFile_COD6_PC::Load(const QString aFilePath) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool FastFile_COD6_PC::Load(const QByteArray aData) {
|
bool FastFile_COD6_PC::Load(const QByteArray aData) {
|
||||||
const qint64 zlibOffset = Compression::FindZlibOffset(aData);
|
StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/data", 1000);
|
||||||
qDebug() << "ZLib Offset: " << zlibOffset;
|
QByteArray decompressedData;
|
||||||
if (zlibOffset == -1)
|
|
||||||
{
|
|
||||||
qWarning() << "Z-Lib stream not found";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
QByteArray compressed = aData.mid(zlibOffset);
|
|
||||||
|
|
||||||
QByteArray decompressedData = Compression::DecompressZLIB(compressed);
|
// Assume the first 12 bytes are a header; the rest is zlib-compressed zone data.
|
||||||
|
const QByteArray compressedData = aData.mid(21);
|
||||||
if (decompressedData.isEmpty() || decompressedData.size() < 1024)
|
decompressedData = Compression::DecompressZLIB(compressedData);
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
||||||
|
|
||||||
|
|||||||
@ -72,9 +72,9 @@ bool FastFile_COD7_PC::Load(const QString aFilePath) {
|
|||||||
bool FastFile_COD7_PC::Load(const QByteArray aData) {
|
bool FastFile_COD7_PC::Load(const QByteArray aData) {
|
||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Create a XDataStream on the input data.
|
// Create a QDataStream on the input data.
|
||||||
XDataStream fastFileStream(aData);
|
QDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
|
||||||
// Parse header values.
|
// Parse header values.
|
||||||
SetCompany(pParseFFCompany(&fastFileStream));
|
SetCompany(pParseFFCompany(&fastFileStream));
|
||||||
|
|||||||
@ -72,19 +72,91 @@ bool FastFile_COD8_PC::Load(const QString aFilePath) {
|
|||||||
bool FastFile_COD8_PC::Load(const QByteArray aData) {
|
bool FastFile_COD8_PC::Load(const QByteArray aData) {
|
||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Create a XDataStream on the input data.
|
// Create a QDataStream on the input data.
|
||||||
XDataStream fastFileStream(aData);
|
QDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
|
||||||
// Parse header values.
|
// Parse header values.
|
||||||
SetCompany(pParseFFCompany(&fastFileStream));
|
SetCompany(pParseFFCompany(&fastFileStream));
|
||||||
SetType(pParseFFFileType(&fastFileStream));
|
SetType(pParseFFFileType(&fastFileStream));
|
||||||
SetSignage(pParseFFSignage(&fastFileStream));
|
SetSignage(pParseFFSignage(&fastFileStream));
|
||||||
SetMagic(pParseFFMagic(&fastFileStream));
|
SetMagic(pParseFFMagic(&fastFileStream));
|
||||||
SetVersion(pParseFFVersion(&fastFileStream));
|
quint32 version = pParseFFVersion(&fastFileStream);
|
||||||
|
SetVersion(version);
|
||||||
|
SetPlatform(pCalculateFFPlatform(version));
|
||||||
|
SetGame("COD7");
|
||||||
|
|
||||||
decompressedData = Compression::DecompressZLIB(aData.mid(21));
|
// For COD7/COD9, use BigEndian.
|
||||||
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
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_COD8_PC* zoneFile = new ZoneFile_COD8_PC();
|
||||||
zoneFile->SetStem(GetBaseStem() + ".zone");
|
zoneFile->SetStem(GetBaseStem() + ".zone");
|
||||||
|
|||||||
@ -67,18 +67,37 @@ bool FastFile_COD9_PC::Load(const QString aFilePath) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool FastFile_COD9_PC::Load(const QByteArray aData) {
|
bool FastFile_COD9_PC::Load(const QByteArray aData) {
|
||||||
// Create a XDataStream on the input data.
|
QByteArray decompressedData;
|
||||||
XDataStream fastFileStream(aData);
|
|
||||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
// Create a QDataStream on the input data.
|
||||||
|
QDataStream fastFileStream(aData);
|
||||||
|
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
|
||||||
// Parse header values.
|
// Parse header values.
|
||||||
SetCompany(pParseFFCompany(&fastFileStream));
|
SetCompany(pParseFFCompany(&fastFileStream));
|
||||||
SetType(pParseFFFileType(&fastFileStream));
|
SetType(pParseFFFileType(&fastFileStream));
|
||||||
SetSignage(pParseFFSignage(&fastFileStream));
|
SetSignage(pParseFFSignage(&fastFileStream));
|
||||||
SetMagic(pParseFFMagic(&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);
|
QByteArray fileMagic(8, Qt::Uninitialized);
|
||||||
fastFileStream.readRawData(fileMagic.data(), 8);
|
fastFileStream.readRawData(fileMagic.data(), 8);
|
||||||
if (fileMagic != "PHEEBs71") {
|
if (fileMagic != "PHEEBs71") {
|
||||||
@ -87,100 +106,35 @@ bool FastFile_COD9_PC::Load(const QByteArray aData) {
|
|||||||
}
|
}
|
||||||
fastFileStream.skipRawData(4);
|
fastFileStream.skipRawData(4);
|
||||||
|
|
||||||
// Read IV seed name (32 bytes).
|
// Read IV table name (32 bytes).
|
||||||
QByteArray nameKey(32, Qt::Uninitialized);
|
QByteArray fileName(32, Qt::Uninitialized);
|
||||||
fastFileStream.readRawData(nameKey.data(), 32);
|
fastFileStream.readRawData(fileName.data(), 32);
|
||||||
|
|
||||||
// --- Salsa20 + IV setup ---
|
// Skip the RSA signature (256 bytes).
|
||||||
static QVector<quint32> ivCounter(4, 1);
|
QByteArray rsaSignature(256, Qt::Uninitialized);
|
||||||
QByteArray ivTable = Encryption::InitIVTable(nameKey);
|
fastFileStream.readRawData(rsaSignature.data(), 256);
|
||||||
ivCounter.fill(1); // reset global counters
|
|
||||||
|
|
||||||
// Skip RSA signature (0x100)
|
if (GetPlatform() == "360") {
|
||||||
fastFileStream.skipRawData(0x100);
|
//decompressedData = Compressor::cod9_decryptFastFile(aData);
|
||||||
|
} else if (GetPlatform() == "PC") {
|
||||||
// Decrypt + decompress loop
|
decompressedData = Encryption::decryptFastFile_BO2(aData);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
// For COD9, write out the complete decompressed zone for testing.
|
||||||
Utils::ExportData(GetBaseStem() + ".zone", finalZone);
|
QFile testFile("exports/" + GetBaseStem() + ".zone");
|
||||||
|
if(testFile.open(QIODevice::WriteOnly)) {
|
||||||
|
testFile.write(decompressedData);
|
||||||
|
testFile.close();
|
||||||
|
}
|
||||||
|
|
||||||
// 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_COD9_PC* zoneFile = new ZoneFile_COD9_PC();
|
||||||
zoneFile->SetStem(GetBaseStem() + ".zone");
|
zoneFile->SetStem(GetBaseStem() + ".zone");
|
||||||
if (!zoneFile->Load(finalZone)) {
|
if (!zoneFile->Load(decompressedData)) {
|
||||||
qWarning() << "Failed to load ZoneFile!";
|
qWarning() << "Failed to load ZoneFile!";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
SetZoneFile(zoneFile);
|
SetZoneFile(zoneFile);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -69,9 +69,9 @@ bool FastFile_COD10_PS3::Load(const QString aFilePath) {
|
|||||||
bool FastFile_COD10_PS3::Load(const QByteArray aData) {
|
bool FastFile_COD10_PS3::Load(const QByteArray aData) {
|
||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Create a XDataStream on the input data.
|
// Create a QDataStream on the input data.
|
||||||
XDataStream fastFileStream(aData);
|
QDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
|
||||||
// Parse header values.
|
// Parse header values.
|
||||||
SetCompany(pParseFFCompany(&fastFileStream));
|
SetCompany(pParseFFCompany(&fastFileStream));
|
||||||
@ -84,9 +84,9 @@ bool FastFile_COD10_PS3::Load(const QByteArray aData) {
|
|||||||
SetGame("COD9");
|
SetGame("COD9");
|
||||||
|
|
||||||
// For COD7/COD9, use BigEndian.
|
// For COD7/COD9, use BigEndian.
|
||||||
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
fastFileStream.setByteOrder(QDataStream::BigEndian);
|
||||||
if (GetPlatform() == "PC") {
|
if (GetPlatform() == "PC") {
|
||||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select key based on game.
|
// Select key based on game.
|
||||||
@ -110,7 +110,15 @@ bool FastFile_COD10_PS3::Load(const QByteArray aData) {
|
|||||||
QByteArray fileName(32, Qt::Uninitialized);
|
QByteArray fileName(32, Qt::Uninitialized);
|
||||||
fastFileStream.readRawData(fileName.data(), 32);
|
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.
|
// For COD9, write out the complete decompressed zone for testing.
|
||||||
QFile testFile("exports/" + GetBaseStem() + ".zone");
|
QFile testFile("exports/" + GetBaseStem() + ".zone");
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
#include "fastfile_cod11_ps3.h"
|
#include "fastfile_cod11_ps3.h"
|
||||||
#include "zonefile_cod11_ps3.h"
|
#include "zonefile_cod11_ps3.h"
|
||||||
#include "encryption.h"
|
#include "encryption.h"
|
||||||
#include "compression.h"
|
|
||||||
|
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
@ -67,77 +66,68 @@ bool FastFile_COD11_PS3::Load(const QString aFilePath) {
|
|||||||
return true;
|
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) {
|
bool FastFile_COD11_PS3::Load(const QByteArray aData) {
|
||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Prepare data stream for parsing
|
// Create a QDataStream on the input data.
|
||||||
XDataStream fastFileStream(aData);
|
QDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
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);
|
QByteArray fileMagic(8, Qt::Uninitialized);
|
||||||
fastFileStream.readRawData(fileMagic.data(), 8);
|
fastFileStream.readRawData(fileMagic.data(), 8);
|
||||||
quint32 version = fastFileStream.ParseUInt32();
|
if (fileMagic != "PHEEBs71") {
|
||||||
|
qWarning() << "Invalid fast file magic!";
|
||||||
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 << "!";
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
fastFileStream.skipRawData(4);
|
||||||
|
|
||||||
if (blockCount > 17280)
|
// Read IV table name (32 bytes).
|
||||||
{
|
QByteArray fileName(32, Qt::Uninitialized);
|
||||||
qWarning() << "Fast file has too many blocks:" << blockCount << "> 17280!";
|
fastFileStream.readRawData(fileName.data(), 32);
|
||||||
return false;
|
|
||||||
|
// 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);
|
||||||
}
|
}
|
||||||
fastFileStream.skipRawData(12 * blockCount);
|
|
||||||
|
|
||||||
qint32 startPos = fastFileStream.ParseInt32();
|
// For COD9, write out the complete decompressed zone for testing.
|
||||||
Q_UNUSED(startPos);
|
QFile testFile("exports/" + GetBaseStem() + ".zone");
|
||||||
|
if(testFile.open(QIODevice::WriteOnly)) {
|
||||||
qint32 endPos = fastFileStream.ParseInt32();
|
testFile.write(decompressedData);
|
||||||
Q_UNUSED(endPos);
|
testFile.close();
|
||||||
|
|
||||||
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")
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
// Load the zone file with the decompressed data (using an Xbox platform flag).
|
||||||
else
|
|
||||||
{
|
|
||||||
qWarning() << "Invalid fast file magic:" << fileMagic << "!";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
|
||||||
|
|
||||||
// Load the zone file with decompressed data
|
|
||||||
ZoneFile_COD11_PS3* zoneFile = new ZoneFile_COD11_PS3();
|
ZoneFile_COD11_PS3* zoneFile = new ZoneFile_COD11_PS3();
|
||||||
zoneFile->SetStem(GetBaseStem() + ".zone");
|
zoneFile->SetStem(GetBaseStem() + ".zone");
|
||||||
if (!zoneFile->Load(decompressedData)) {
|
if (!zoneFile->Load(decompressedData)) {
|
||||||
|
|||||||
@ -69,9 +69,9 @@ bool FastFile_COD12_PS3::Load(const QString aFilePath) {
|
|||||||
bool FastFile_COD12_PS3::Load(const QByteArray aData) {
|
bool FastFile_COD12_PS3::Load(const QByteArray aData) {
|
||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Create a XDataStream on the input data.
|
// Create a QDataStream on the input data.
|
||||||
XDataStream fastFileStream(aData);
|
QDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
|
||||||
// Parse header values.
|
// Parse header values.
|
||||||
SetCompany(pParseFFCompany(&fastFileStream));
|
SetCompany(pParseFFCompany(&fastFileStream));
|
||||||
@ -84,9 +84,9 @@ bool FastFile_COD12_PS3::Load(const QByteArray aData) {
|
|||||||
SetGame("COD9");
|
SetGame("COD9");
|
||||||
|
|
||||||
// For COD7/COD9, use BigEndian.
|
// For COD7/COD9, use BigEndian.
|
||||||
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
fastFileStream.setByteOrder(QDataStream::BigEndian);
|
||||||
if (GetPlatform() == "PC") {
|
if (GetPlatform() == "PC") {
|
||||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select key based on game.
|
// Select key based on game.
|
||||||
@ -110,7 +110,15 @@ bool FastFile_COD12_PS3::Load(const QByteArray aData) {
|
|||||||
QByteArray fileName(32, Qt::Uninitialized);
|
QByteArray fileName(32, Qt::Uninitialized);
|
||||||
fastFileStream.readRawData(fileName.data(), 32);
|
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.
|
// For COD9, write out the complete decompressed zone for testing.
|
||||||
QFile testFile("exports/" + GetBaseStem() + ".zone");
|
QFile testFile("exports/" + GetBaseStem() + ".zone");
|
||||||
|
|||||||
@ -75,9 +75,9 @@ bool FastFile_COD4_PS3::Load(const QByteArray aData) {
|
|||||||
StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/data", 1000);
|
StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/data", 1000);
|
||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Create a XDataStream on the input data.
|
// Create a QDataStream on the input data.
|
||||||
XDataStream fastFileStream(aData);
|
QDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
|
||||||
// Parse header values.
|
// Parse header values.
|
||||||
SetCompany(pParseFFCompany(&fastFileStream));
|
SetCompany(pParseFFCompany(&fastFileStream));
|
||||||
@ -86,24 +86,29 @@ bool FastFile_COD4_PS3::Load(const QByteArray aData) {
|
|||||||
SetMagic(pParseFFMagic(&fastFileStream));
|
SetMagic(pParseFFMagic(&fastFileStream));
|
||||||
SetVersion(pParseFFVersion(&fastFileStream));
|
SetVersion(pParseFFVersion(&fastFileStream));
|
||||||
|
|
||||||
|
int pos = 12;
|
||||||
// Loop until EOF or invalid chunk
|
// Loop until EOF or invalid chunk
|
||||||
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
while (pos <= aData.size()) {
|
||||||
while (!fastFileStream.atEnd()) {
|
|
||||||
// Read 2-byte BIG-ENDIAN chunk size
|
// Read 2-byte BIG-ENDIAN chunk size
|
||||||
quint16 chunkSize;
|
quint32 chunkSize;
|
||||||
fastFileStream >> 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.";
|
qWarning() << "Invalid or incomplete chunk detected, stopping.";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray compressedChunk(chunkSize, Qt::Uninitialized);
|
const QByteArray compressedChunk = aData.mid(pos, chunkSize);
|
||||||
fastFileStream.readRawData(compressedChunk.data(), chunkSize);
|
|
||||||
|
|
||||||
QByteArray decompressedChunk = Compression::DecompressDeflate(compressedChunk);
|
decompressedData.append(Compression::DecompressDeflate(compressedChunk));
|
||||||
decompressedData.append(decompressedChunk);
|
|
||||||
|
pos += chunkSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
||||||
|
|
||||||
ZoneFile_COD4_PS3* zoneFile = new ZoneFile_COD4_PS3();
|
ZoneFile_COD4_PS3* zoneFile = new ZoneFile_COD4_PS3();
|
||||||
|
|||||||
@ -75,9 +75,9 @@ bool FastFile_COD5_PS3::Load(const QByteArray aData) {
|
|||||||
StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/data", 1000);
|
StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/data", 1000);
|
||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Create a XDataStream on the input data.
|
// Create a QDataStream on the input data.
|
||||||
XDataStream fastFileStream(aData);
|
QDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
|
||||||
// Parse header values.
|
// Parse header values.
|
||||||
SetCompany(pParseFFCompany(&fastFileStream));
|
SetCompany(pParseFFCompany(&fastFileStream));
|
||||||
@ -86,24 +86,29 @@ bool FastFile_COD5_PS3::Load(const QByteArray aData) {
|
|||||||
SetMagic(pParseFFMagic(&fastFileStream));
|
SetMagic(pParseFFMagic(&fastFileStream));
|
||||||
SetVersion(pParseFFVersion(&fastFileStream));
|
SetVersion(pParseFFVersion(&fastFileStream));
|
||||||
|
|
||||||
|
int pos = 12;
|
||||||
// Loop until EOF or invalid chunk
|
// Loop until EOF or invalid chunk
|
||||||
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
while (pos <= aData.size()) {
|
||||||
while (!fastFileStream.atEnd()) {
|
|
||||||
// Read 2-byte BIG-ENDIAN chunk size
|
// Read 2-byte BIG-ENDIAN chunk size
|
||||||
quint16 chunkSize;
|
quint32 chunkSize;
|
||||||
fastFileStream >> 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.";
|
qWarning() << "Invalid or incomplete chunk detected, stopping.";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray compressedChunk(chunkSize, Qt::Uninitialized);
|
const QByteArray compressedChunk = aData.mid(pos, chunkSize);
|
||||||
fastFileStream.readRawData(compressedChunk.data(), chunkSize);
|
|
||||||
|
|
||||||
QByteArray decompressedChunk = Compression::DecompressDeflate(compressedChunk);
|
decompressedData.append(Compression::DecompressDeflate(compressedChunk));
|
||||||
decompressedData.append(decompressedChunk);
|
|
||||||
|
pos += chunkSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
||||||
|
|
||||||
ZoneFile_COD5_PS3* zoneFile = new ZoneFile_COD5_PS3();
|
ZoneFile_COD5_PS3* zoneFile = new ZoneFile_COD5_PS3();
|
||||||
|
|||||||
@ -72,30 +72,26 @@ bool FastFile_COD6_PS3::Load(const QString aFilePath) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool FastFile_COD6_PS3::Load(const QByteArray aData) {
|
bool FastFile_COD6_PS3::Load(const QByteArray aData) {
|
||||||
const qint64 zlibOffset = Compression::FindZlibOffset(aData);
|
StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/data", 1000);
|
||||||
qDebug() << "ZLib Offset: " << zlibOffset;
|
QByteArray decompressedData;
|
||||||
if (zlibOffset == -1)
|
|
||||||
{
|
|
||||||
qWarning() << "Z-Lib stream not found";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
QByteArray compressed = aData.mid(zlibOffset);
|
|
||||||
|
|
||||||
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)
|
// Parse header values.
|
||||||
{
|
SetCompany(pParseFFCompany(&fastFileStream));
|
||||||
QByteArray stripped = Compression::StripHashBlocks(compressed);
|
SetType(pParseFFFileType(&fastFileStream));
|
||||||
QByteArray retry = Compression::DecompressZLIB(stripped);
|
SetSignage(pParseFFSignage(&fastFileStream));
|
||||||
if (!retry.isEmpty())
|
SetMagic(pParseFFMagic(&fastFileStream));
|
||||||
decompressedData.swap(retry);
|
quint32 version = pParseFFVersion(&fastFileStream);
|
||||||
}
|
SetVersion(version);
|
||||||
|
const QString platformStr = pCalculateFFPlatform(version);
|
||||||
|
SetPlatform(platformStr);
|
||||||
|
SetGame("COD5");
|
||||||
|
|
||||||
if (decompressedData.isEmpty())
|
// For COD5, simply decompress from offset 12.
|
||||||
{
|
decompressedData = Compression::DecompressZLIB(aData.mid(12));
|
||||||
qWarning() << "Unable to decompress fast-file";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
||||||
|
|
||||||
|
|||||||
@ -62,98 +62,112 @@ bool FastFile_COD7_PS3::Load(const QString aFilePath) {
|
|||||||
qDebug() << "Error: Failed to load fastfile: " << fastFileStem;
|
qDebug() << "Error: Failed to load fastfile: " << fastFileStem;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
file->close();
|
file->close();
|
||||||
|
|
||||||
|
// Open zone file after decompressing ff and writing
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FastFile_COD7_PS3::Load(const QByteArray aData) {
|
bool FastFile_COD7_PS3::Load(const QByteArray aData) {
|
||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Create a XDataStream on the input data.
|
// Create a QDataStream on the input data.
|
||||||
XDataStream fastFileStream(aData);
|
QDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
|
||||||
// Parse header values.
|
// Parse header values.
|
||||||
SetCompany(pParseFFCompany(&fastFileStream));
|
SetCompany(pParseFFCompany(&fastFileStream));
|
||||||
SetType(pParseFFFileType(&fastFileStream));
|
SetType(pParseFFFileType(&fastFileStream));
|
||||||
SetSignage(pParseFFSignage(&fastFileStream));
|
SetSignage(pParseFFSignage(&fastFileStream));
|
||||||
SetMagic(pParseFFMagic(&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).
|
// Load the zone file with the decompressed data (using an Xbox platform flag).
|
||||||
ZoneFile_COD7_PS3* zoneFile = new ZoneFile_COD7_PS3();
|
ZoneFile_COD7_PS3* zoneFile = new ZoneFile_COD7_PS3();
|
||||||
zoneFile->SetStem(GetBaseStem() + ".zone");
|
zoneFile->SetStem(GetBaseStem() + ".zone");
|
||||||
|
|
||||||
// For COD7/COD9, use BigEndian.
|
// 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.
|
// Select key based on game.
|
||||||
QByteArray key = "46D3F997F29C9ACE175B0DAE3AB8C0C1B8E423E2E3BF7E3C311EA35245BF193A";
|
QByteArray key;
|
||||||
fastFileStream.skipRawData(4);
|
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.
|
// Read the 8-byte magic.
|
||||||
QByteArray fileMagic(8, Qt::Uninitialized);
|
QByteArray fileMagic(8, Qt::Uninitialized);
|
||||||
fastFileStream.readRawData(fileMagic.data(), 8);
|
fastFileStream.readRawData(fileMagic.data(), 8);
|
||||||
if (fileMagic != "PHEEBs71") {
|
if (fileMagic != "PHEEBs71") {
|
||||||
qWarning() << "Invalid fast file magic!";
|
qWarning() << "Invalid fast file magic!";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
fastFileStream.skipRawData(4);
|
fastFileStream.skipRawData(4);
|
||||||
|
|
||||||
// Read IV table name (32 bytes).
|
// Read IV table name (32 bytes).
|
||||||
QByteArray fileName(32, Qt::Uninitialized);
|
QByteArray fileName(32, Qt::Uninitialized);
|
||||||
fastFileStream.readRawData(fileName.data(), 32);
|
fastFileStream.readRawData(fileName.data(), 32);
|
||||||
|
|
||||||
// Build the IV table from the fileName.
|
// Build the IV table from the fileName.
|
||||||
QByteArray ivTable = Encryption::InitIVTable(fileName);
|
QByteArray ivTable = Encryption::InitIVTable(fileName);
|
||||||
|
|
||||||
// Skip the RSA signature (256 bytes).
|
// Skip the RSA signature (256 bytes).
|
||||||
QByteArray rsaSignature(256, Qt::Uninitialized);
|
QByteArray rsaSignature(256, Qt::Uninitialized);
|
||||||
fastFileStream.readRawData(rsaSignature.data(), 256);
|
fastFileStream.readRawData(rsaSignature.data(), 256);
|
||||||
|
|
||||||
// Now the stream should be positioned at 0x13C, where sections begin.
|
// Now the stream should be positioned at 0x13C, where sections begin.
|
||||||
int sectionIndex = 0;
|
int sectionIndex = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
qint32 sectionSize = 0;
|
qint32 sectionSize = 0;
|
||||||
fastFileStream >> sectionSize;
|
fastFileStream >> sectionSize;
|
||||||
qDebug() << "Section index:" << sectionIndex << "Size:" << sectionSize
|
qDebug() << "Section index:" << sectionIndex << "Size:" << sectionSize
|
||||||
<< "Pos:" << fastFileStream.device()->pos();
|
<< "Pos:" << fastFileStream.device()->pos();
|
||||||
if (sectionSize == 0)
|
if (sectionSize == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Read the section data.
|
// Read the section data.
|
||||||
QByteArray sectionData;
|
QByteArray sectionData;
|
||||||
sectionData.resize(sectionSize);
|
sectionData.resize(sectionSize);
|
||||||
fastFileStream.readRawData(sectionData.data(), sectionSize);
|
fastFileStream.readRawData(sectionData.data(), sectionSize);
|
||||||
|
|
||||||
// Compute the IV for this section.
|
// Compute the IV for this section.
|
||||||
QByteArray iv = Encryption::GetIV(ivTable, sectionIndex);
|
QByteArray iv = Encryption::GetIV(ivTable, sectionIndex);
|
||||||
|
|
||||||
// Decrypt the section using Salsa20.
|
// Decrypt the section using Salsa20.
|
||||||
QByteArray decData = Encryption::salsa20DecryptSection(sectionData, key, iv);
|
QByteArray decData = Encryption::salsa20DecryptSection(sectionData, key, iv);
|
||||||
|
|
||||||
// Compute SHA1 hash of the decrypted data.
|
// Compute SHA1 hash of the decrypted data.
|
||||||
QByteArray sectionHash = QCryptographicHash::hash(decData, QCryptographicHash::Sha1);
|
QByteArray sectionHash = QCryptographicHash::hash(decData, QCryptographicHash::Sha1);
|
||||||
|
|
||||||
// Update the IV table based on the section hash.
|
// Update the IV table based on the section hash.
|
||||||
Encryption::UpdateIVTable(ivTable, sectionIndex, sectionHash);
|
Encryption::UpdateIVTable(ivTable, sectionIndex, sectionHash);
|
||||||
|
|
||||||
// Build a compressed data buffer by prepending the two-byte zlib header.
|
// Build a compressed data buffer by prepending the two-byte zlib header.
|
||||||
QByteArray compressedData;
|
QByteArray compressedData;
|
||||||
compressedData.append(char(0x78));
|
compressedData.append(char(0x78));
|
||||||
compressedData.append(char(0x01));
|
compressedData.append(char(0x01));
|
||||||
compressedData.append(decData);
|
compressedData.append(decData);
|
||||||
|
|
||||||
decompressedData.append(Compression::DecompressZLIB(compressedData));
|
decompressedData.append(Compression::DecompressZLIB(compressedData));
|
||||||
|
|
||||||
sectionIndex++;
|
sectionIndex++;
|
||||||
}
|
}
|
||||||
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
|
||||||
|
|
||||||
if (!zoneFile->Load(decompressedData)) {
|
if (!zoneFile->Load(decompressedData)) {
|
||||||
qWarning() << "Failed to load ZoneFile!";
|
qWarning() << "Failed to load ZoneFile!";
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
SetZoneFile(zoneFile);
|
SetZoneFile(zoneFile);
|
||||||
|
|
||||||
|
|||||||
@ -72,9 +72,9 @@ bool FastFile_COD8_PS3::Load(const QString aFilePath) {
|
|||||||
bool FastFile_COD8_PS3::Load(const QByteArray aData) {
|
bool FastFile_COD8_PS3::Load(const QByteArray aData) {
|
||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Create a XDataStream on the input data.
|
// Create a QDataStream on the input data.
|
||||||
XDataStream fastFileStream(aData);
|
QDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
|
||||||
// Parse header values.
|
// Parse header values.
|
||||||
SetCompany(pParseFFCompany(&fastFileStream));
|
SetCompany(pParseFFCompany(&fastFileStream));
|
||||||
@ -90,9 +90,9 @@ bool FastFile_COD8_PS3::Load(const QByteArray aData) {
|
|||||||
zoneFile->SetStem(GetBaseStem() + ".zone");
|
zoneFile->SetStem(GetBaseStem() + ".zone");
|
||||||
|
|
||||||
// For COD7/COD9, use BigEndian.
|
// For COD7/COD9, use BigEndian.
|
||||||
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
fastFileStream.setByteOrder(QDataStream::BigEndian);
|
||||||
if (GetPlatform() == "PC") {
|
if (GetPlatform() == "PC") {
|
||||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
|
||||||
// Select key based on game.
|
// Select key based on game.
|
||||||
QByteArray key;
|
QByteArray key;
|
||||||
@ -118,6 +118,51 @@ bool FastFile_COD8_PS3::Load(const QByteArray aData) {
|
|||||||
QByteArray fileName(32, Qt::Uninitialized);
|
QByteArray fileName(32, Qt::Uninitialized);
|
||||||
fastFileStream.readRawData(fileName.data(), 32);
|
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)) {
|
if (!zoneFile->Load(decompressedData)) {
|
||||||
qWarning() << "Failed to load ZoneFile!";
|
qWarning() << "Failed to load ZoneFile!";
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -69,9 +69,9 @@ bool FastFile_COD9_PS3::Load(const QString aFilePath) {
|
|||||||
bool FastFile_COD9_PS3::Load(const QByteArray aData) {
|
bool FastFile_COD9_PS3::Load(const QByteArray aData) {
|
||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Create a XDataStream on the input data.
|
// Create a QDataStream on the input data.
|
||||||
XDataStream fastFileStream(aData);
|
QDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
|
||||||
// Parse header values.
|
// Parse header values.
|
||||||
SetCompany(pParseFFCompany(&fastFileStream));
|
SetCompany(pParseFFCompany(&fastFileStream));
|
||||||
@ -84,9 +84,9 @@ bool FastFile_COD9_PS3::Load(const QByteArray aData) {
|
|||||||
SetGame("COD9");
|
SetGame("COD9");
|
||||||
|
|
||||||
// For COD7/COD9, use BigEndian.
|
// For COD7/COD9, use BigEndian.
|
||||||
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
fastFileStream.setByteOrder(QDataStream::BigEndian);
|
||||||
if (GetPlatform() == "PC") {
|
if (GetPlatform() == "PC") {
|
||||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select key based on game.
|
// Select key based on game.
|
||||||
@ -117,7 +117,7 @@ bool FastFile_COD9_PS3::Load(const QByteArray aData) {
|
|||||||
if (GetPlatform() == "360") {
|
if (GetPlatform() == "360") {
|
||||||
//decompressedData = Compressor::cod9_decryptFastFile(aData);
|
//decompressedData = Compressor::cod9_decryptFastFile(aData);
|
||||||
} else if (GetPlatform() == "PC") {
|
} else if (GetPlatform() == "PC") {
|
||||||
//decompressedData = Encryption::decryptFastFile_BO2(aData);
|
decompressedData = Encryption::decryptFastFile_BO2(aData);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For COD9, write out the complete decompressed zone for testing.
|
// For COD9, write out the complete decompressed zone for testing.
|
||||||
|
|||||||
@ -69,9 +69,9 @@ bool FastFile_COD7_Wii::Load(const QString aFilePath) {
|
|||||||
bool FastFile_COD7_Wii::Load(const QByteArray aData) {
|
bool FastFile_COD7_Wii::Load(const QByteArray aData) {
|
||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Create a XDataStream on the input data.
|
// Create a QDataStream on the input data.
|
||||||
XDataStream fastFileStream(aData);
|
QDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
|
||||||
// Parse header values.
|
// Parse header values.
|
||||||
SetCompany(pParseFFCompany(&fastFileStream));
|
SetCompany(pParseFFCompany(&fastFileStream));
|
||||||
@ -84,7 +84,7 @@ bool FastFile_COD7_Wii::Load(const QByteArray aData) {
|
|||||||
SetGame("COD7");
|
SetGame("COD7");
|
||||||
|
|
||||||
// For COD7/COD9, use BigEndian.
|
// For COD7/COD9, use BigEndian.
|
||||||
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
fastFileStream.setByteOrder(QDataStream::BigEndian);
|
||||||
|
|
||||||
// For COD7, simply decompress from offset 12.
|
// For COD7, simply decompress from offset 12.
|
||||||
decompressedData = Compression::DecompressZLIB(aData.mid(12));
|
decompressedData = Compression::DecompressZLIB(aData.mid(12));
|
||||||
|
|||||||
@ -69,9 +69,9 @@ bool FastFile_COD8_Wii::Load(const QString aFilePath) {
|
|||||||
bool FastFile_COD8_Wii::Load(const QByteArray aData) {
|
bool FastFile_COD8_Wii::Load(const QByteArray aData) {
|
||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Create a XDataStream on the input data.
|
// Create a QDataStream on the input data.
|
||||||
XDataStream fastFileStream(aData);
|
QDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
|
||||||
// Parse header values.
|
// Parse header values.
|
||||||
SetCompany(pParseFFCompany(&fastFileStream));
|
SetCompany(pParseFFCompany(&fastFileStream));
|
||||||
@ -81,7 +81,7 @@ bool FastFile_COD8_Wii::Load(const QByteArray aData) {
|
|||||||
SetVersion(pParseFFVersion(&fastFileStream));
|
SetVersion(pParseFFVersion(&fastFileStream));
|
||||||
|
|
||||||
// For COD7/COD9, use BigEndian.
|
// For COD7/COD9, use BigEndian.
|
||||||
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
fastFileStream.setByteOrder(QDataStream::BigEndian);
|
||||||
|
|
||||||
// For COD7, simply decompress from offset 12.
|
// For COD7, simply decompress from offset 12.
|
||||||
decompressedData = Compression::DecompressZLIB(aData.mid(25));
|
decompressedData = Compression::DecompressZLIB(aData.mid(25));
|
||||||
|
|||||||
@ -67,9 +67,9 @@ bool FastFile_COD10_WiiU::Load(const QString aFilePath) {
|
|||||||
bool FastFile_COD10_WiiU::Load(const QByteArray aData) {
|
bool FastFile_COD10_WiiU::Load(const QByteArray aData) {
|
||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Create a XDataStream on the input data.
|
// Create a QDataStream on the input data.
|
||||||
XDataStream fastFileStream(aData);
|
QDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
|
||||||
// Parse header values.
|
// Parse header values.
|
||||||
SetCompany(pParseFFCompany(&fastFileStream));
|
SetCompany(pParseFFCompany(&fastFileStream));
|
||||||
@ -82,9 +82,9 @@ bool FastFile_COD10_WiiU::Load(const QByteArray aData) {
|
|||||||
SetGame("COD9");
|
SetGame("COD9");
|
||||||
|
|
||||||
// For COD7/COD9, use BigEndian.
|
// For COD7/COD9, use BigEndian.
|
||||||
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
fastFileStream.setByteOrder(QDataStream::BigEndian);
|
||||||
if (GetPlatform() == "PC") {
|
if (GetPlatform() == "PC") {
|
||||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select key based on game.
|
// Select key based on game.
|
||||||
@ -115,7 +115,7 @@ bool FastFile_COD10_WiiU::Load(const QByteArray aData) {
|
|||||||
if (GetPlatform() == "360") {
|
if (GetPlatform() == "360") {
|
||||||
//decompressedData = Compressor::cod9_decryptFastFile(aData);
|
//decompressedData = Compressor::cod9_decryptFastFile(aData);
|
||||||
} else if (GetPlatform() == "PC") {
|
} else if (GetPlatform() == "PC") {
|
||||||
//decompressedData = Encryption::decryptFastFile_BO2(aData);
|
decompressedData = Encryption::decryptFastFile_BO2(aData);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For COD9, write out the complete decompressed zone for testing.
|
// For COD9, write out the complete decompressed zone for testing.
|
||||||
|
|||||||
@ -67,9 +67,9 @@ bool FastFile_COD9_WiiU::Load(const QString aFilePath) {
|
|||||||
bool FastFile_COD9_WiiU::Load(const QByteArray aData) {
|
bool FastFile_COD9_WiiU::Load(const QByteArray aData) {
|
||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Create a XDataStream on the input data.
|
// Create a QDataStream on the input data.
|
||||||
XDataStream fastFileStream(aData);
|
QDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
|
||||||
// Parse header values.
|
// Parse header values.
|
||||||
SetCompany(pParseFFCompany(&fastFileStream));
|
SetCompany(pParseFFCompany(&fastFileStream));
|
||||||
@ -82,9 +82,9 @@ bool FastFile_COD9_WiiU::Load(const QByteArray aData) {
|
|||||||
SetGame("COD9");
|
SetGame("COD9");
|
||||||
|
|
||||||
// For COD7/COD9, use BigEndian.
|
// For COD7/COD9, use BigEndian.
|
||||||
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
fastFileStream.setByteOrder(QDataStream::BigEndian);
|
||||||
if (GetPlatform() == "PC") {
|
if (GetPlatform() == "PC") {
|
||||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select key based on game.
|
// Select key based on game.
|
||||||
@ -115,7 +115,7 @@ bool FastFile_COD9_WiiU::Load(const QByteArray aData) {
|
|||||||
if (GetPlatform() == "360") {
|
if (GetPlatform() == "360") {
|
||||||
//decompressedData = Compressor::cod9_decryptFastFile(aData);
|
//decompressedData = Compressor::cod9_decryptFastFile(aData);
|
||||||
} else if (GetPlatform() == "PC") {
|
} else if (GetPlatform() == "PC") {
|
||||||
//decompressedData = Encryption::decryptFastFile_BO2(aData);
|
decompressedData = Encryption::decryptFastFile_BO2(aData);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For COD9, write out the complete decompressed zone for testing.
|
// For COD9, write out the complete decompressed zone for testing.
|
||||||
|
|||||||
@ -115,7 +115,7 @@ void FastFile::SetPlatform(const QString aPlatform) {
|
|||||||
mPlatform = 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...");
|
LogManager::instance().addEntry("Parsing company into reference...");
|
||||||
// Check for null datastream ptr
|
// Check for null datastream ptr
|
||||||
if (!afastFileStream) { return COMPANY_NONE; }
|
if (!afastFileStream) { return COMPANY_NONE; }
|
||||||
@ -137,7 +137,7 @@ FF_COMPANY FastFile::pParseFFCompany(XDataStream *afastFileStream, quint32 &aCom
|
|||||||
return COMPANY_NONE;
|
return COMPANY_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
FF_COMPANY FastFile::pParseFFCompany(XDataStream *afastFileStream) {
|
FF_COMPANY FastFile::pParseFFCompany(QDataStream *afastFileStream) {
|
||||||
LogManager::instance().addEntry("Parsing company...");
|
LogManager::instance().addEntry("Parsing company...");
|
||||||
// Check for null datastream ptr
|
// Check for null datastream ptr
|
||||||
if (!afastFileStream) { return COMPANY_NONE; }
|
if (!afastFileStream) { return COMPANY_NONE; }
|
||||||
@ -157,7 +157,7 @@ FF_COMPANY FastFile::pParseFFCompany(XDataStream *afastFileStream) {
|
|||||||
return COMPANY_NONE;
|
return COMPANY_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
FF_FILETYPE FastFile::pParseFFFileType(XDataStream *afastFileStream) {
|
FF_FILETYPE FastFile::pParseFFFileType(QDataStream *afastFileStream) {
|
||||||
// Parse filetype
|
// Parse filetype
|
||||||
QByteArray fileTypeData(2, Qt::Uninitialized);
|
QByteArray fileTypeData(2, Qt::Uninitialized);
|
||||||
afastFileStream->readRawData(fileTypeData.data(), 2);
|
afastFileStream->readRawData(fileTypeData.data(), 2);
|
||||||
@ -168,7 +168,7 @@ FF_FILETYPE FastFile::pParseFFFileType(XDataStream *afastFileStream) {
|
|||||||
return FILETYPE_NONE;
|
return FILETYPE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
FF_SIGNAGE FastFile::pParseFFSignage(XDataStream *afastFileStream) {
|
FF_SIGNAGE FastFile::pParseFFSignage(QDataStream *afastFileStream) {
|
||||||
// Parse filetype
|
// Parse filetype
|
||||||
QByteArray signedData(1, Qt::Uninitialized);
|
QByteArray signedData(1, Qt::Uninitialized);
|
||||||
afastFileStream->readRawData(signedData.data(), 1);
|
afastFileStream->readRawData(signedData.data(), 1);
|
||||||
@ -181,7 +181,7 @@ FF_SIGNAGE FastFile::pParseFFSignage(XDataStream *afastFileStream) {
|
|||||||
return SIGNAGE_NONE;
|
return SIGNAGE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString FastFile::pParseFFMagic(XDataStream *afastFileStream) {
|
QString FastFile::pParseFFMagic(QDataStream *afastFileStream) {
|
||||||
// Parse magic
|
// Parse magic
|
||||||
QByteArray magicData(3, Qt::Uninitialized);
|
QByteArray magicData(3, Qt::Uninitialized);
|
||||||
afastFileStream->readRawData(magicData.data(), 3);
|
afastFileStream->readRawData(magicData.data(), 3);
|
||||||
@ -192,7 +192,7 @@ QString FastFile::pParseFFMagic(XDataStream *afastFileStream) {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
quint32 FastFile::pParseFFVersion(XDataStream *afastFileStream) {
|
quint32 FastFile::pParseFFVersion(QDataStream *afastFileStream) {
|
||||||
// Parse version
|
// Parse version
|
||||||
quint32 version;
|
quint32 version;
|
||||||
*afastFileStream >> version;
|
*afastFileStream >> version;
|
||||||
@ -267,7 +267,7 @@ FastFile* FastFile::Open(const QString &aFilePath) {
|
|||||||
const QString fastFileStem = aFilePath.section("/", -1, -1);
|
const QString fastFileStem = aFilePath.section("/", -1, -1);
|
||||||
LogManager::instance().addEntry(QString("Stem: %1").arg(fastFileStem));
|
LogManager::instance().addEntry(QString("Stem: %1").arg(fastFileStem));
|
||||||
|
|
||||||
FastFile* fastFile = FastFileFactory::Create(data, fastFileStem);
|
FastFile* fastFile = FastFileFactory::Create(data);
|
||||||
fastFile->SetStem(fastFileStem);
|
fastFile->SetStem(fastFileStem);
|
||||||
|
|
||||||
return fastFile;
|
return fastFile;
|
||||||
|
|||||||
@ -46,12 +46,12 @@ public:
|
|||||||
virtual void SetGame(const QString aGame);
|
virtual void SetGame(const QString aGame);
|
||||||
virtual void SetPlatform(const QString aPlatform);
|
virtual void SetPlatform(const QString aPlatform);
|
||||||
|
|
||||||
static FF_COMPANY pParseFFCompany(XDataStream *afastFileStream, quint32 &aCompanyInt);
|
static FF_COMPANY pParseFFCompany(QDataStream *afastFileStream, quint32 &aCompanyInt);
|
||||||
static FF_COMPANY pParseFFCompany(XDataStream *afastFileStream);
|
static FF_COMPANY pParseFFCompany(QDataStream *afastFileStream);
|
||||||
static FF_FILETYPE pParseFFFileType(XDataStream *afastFileStream);
|
static FF_FILETYPE pParseFFFileType(QDataStream *afastFileStream);
|
||||||
static FF_SIGNAGE pParseFFSignage(XDataStream *afastFileStream);
|
static FF_SIGNAGE pParseFFSignage(QDataStream *afastFileStream);
|
||||||
static QString pParseFFMagic(XDataStream *afastFileStream);
|
static QString pParseFFMagic(QDataStream *afastFileStream);
|
||||||
static quint32 pParseFFVersion(XDataStream *afastFileStream);
|
static quint32 pParseFFVersion(QDataStream *afastFileStream);
|
||||||
static QString pCalculateFFPlatform(quint32 aVersion);
|
static QString pCalculateFFPlatform(quint32 aVersion);
|
||||||
static QString pCalculateFFGame(quint32 aVersion);
|
static QString pCalculateFFGame(quint32 aVersion);
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,6 @@
|
|||||||
#include "360/fastfile_cod5_360.h"
|
#include "360/fastfile_cod5_360.h"
|
||||||
#include "360/fastfile_cod6_360.h"
|
#include "360/fastfile_cod6_360.h"
|
||||||
#include "360/fastfile_cod7_360.h"
|
#include "360/fastfile_cod7_360.h"
|
||||||
#include "360/fastfile_cod7_5_360.h"
|
|
||||||
#include "360/fastfile_cod8_360.h"
|
#include "360/fastfile_cod8_360.h"
|
||||||
#include "360/fastfile_cod9_360.h"
|
#include "360/fastfile_cod9_360.h"
|
||||||
#include "360/fastfile_cod10_360.h"
|
#include "360/fastfile_cod10_360.h"
|
||||||
@ -53,26 +52,25 @@ class FastFile;
|
|||||||
|
|
||||||
enum FastFile_Platform {
|
enum FastFile_Platform {
|
||||||
PLATFORM_NONE = 0x00,
|
PLATFORM_NONE = 0x00,
|
||||||
PLATFORM_PC = 0x01,
|
PLATFORM_PC = 0x01,
|
||||||
PLATFORM_360 = 0x02,
|
PLATFORM_360 = 0x02,
|
||||||
PLATFORM_PS3 = 0x03,
|
PLATFORM_PS3 = 0x03,
|
||||||
PLATFORM_WII = 0x04,
|
PLATFORM_WII = 0x04,
|
||||||
PLATFORM_WIIU = 0x05
|
PLATFORM_WIIU = 0x05
|
||||||
};
|
};
|
||||||
|
|
||||||
enum FastFile_Game {
|
enum FastFile_Game {
|
||||||
GAME_NONE = 0x00,
|
GAME_NONE = 0x00,
|
||||||
GAME_COD2 = 0x01,
|
GAME_COD2 = 0x01,
|
||||||
GAME_COD4 = 0x02,
|
GAME_COD4 = 0x02,
|
||||||
GAME_COD5 = 0x03,
|
GAME_COD5 = 0x03,
|
||||||
GAME_COD6 = 0x04,
|
GAME_COD6 = 0x04,
|
||||||
GAME_COD7 = 0x05,
|
GAME_COD7 = 0x05,
|
||||||
GAME_COD7_5 = 0x06,
|
GAME_COD8 = 0x06,
|
||||||
GAME_COD8 = 0x07,
|
GAME_COD9 = 0x07,
|
||||||
GAME_COD9 = 0x08,
|
GAME_COD10 = 0x08,
|
||||||
GAME_COD10 = 0x09,
|
GAME_COD11 = 0x09,
|
||||||
GAME_COD11 = 0x10,
|
GAME_COD12 = 0x010
|
||||||
GAME_COD12 = 0x11
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class FastFileFactory {
|
class FastFileFactory {
|
||||||
@ -187,86 +185,83 @@ public:
|
|||||||
|
|
||||||
if (aPlatform == PLATFORM_360) {
|
if (aPlatform == PLATFORM_360) {
|
||||||
if (aGame == GAME_COD2) {
|
if (aGame == GAME_COD2) {
|
||||||
resultFF = new FastFile_COD2_360();
|
resultFF = new FastFile_COD2_360(aData);
|
||||||
} else if (aGame == GAME_COD4) {
|
} else if (aGame == GAME_COD4) {
|
||||||
resultFF = new FastFile_COD4_360();
|
resultFF = new FastFile_COD4_360(aData);
|
||||||
} else if (aGame == GAME_COD5) {
|
} else if (aGame == GAME_COD5) {
|
||||||
resultFF = new FastFile_COD5_360();
|
resultFF = new FastFile_COD5_360(aData);
|
||||||
} else if (aGame == GAME_COD6) {
|
} else if (aGame == GAME_COD6) {
|
||||||
resultFF = new FastFile_COD6_360();
|
resultFF = new FastFile_COD6_360(aData);
|
||||||
} else if (aGame == GAME_COD7) {
|
} else if (aGame == GAME_COD7) {
|
||||||
resultFF = new FastFile_COD7_360();
|
resultFF = new FastFile_COD7_360(aData);
|
||||||
} else if (aGame == GAME_COD7_5) {
|
|
||||||
resultFF = new FastFile_COD7_5_360();
|
|
||||||
} else if (aGame == GAME_COD8) {
|
} else if (aGame == GAME_COD8) {
|
||||||
resultFF = new FastFile_COD8_360();
|
resultFF = new FastFile_COD8_360(aData);
|
||||||
} else if (aGame == GAME_COD9) {
|
} else if (aGame == GAME_COD9) {
|
||||||
resultFF = new FastFile_COD9_360();
|
resultFF = new FastFile_COD9_360(aData);
|
||||||
} else if (aGame == GAME_COD10) {
|
} else if (aGame == GAME_COD10) {
|
||||||
resultFF = new FastFile_COD10_360();
|
resultFF = new FastFile_COD10_360(aData);
|
||||||
} else if (aGame == GAME_COD11) {
|
} else if (aGame == GAME_COD11) {
|
||||||
resultFF = new FastFile_COD11_360();
|
resultFF = new FastFile_COD11_360(aData);
|
||||||
} else if (aGame == GAME_COD12) {
|
} else if (aGame == GAME_COD12) {
|
||||||
resultFF = new FastFile_COD12_360();
|
resultFF = new FastFile_COD12_360(aData);
|
||||||
}
|
}
|
||||||
} else if (aPlatform == PLATFORM_PC) {
|
} else if (aPlatform == PLATFORM_PC) {
|
||||||
if (aGame == GAME_COD4) {
|
if (aGame == GAME_COD4) {
|
||||||
resultFF = new FastFile_COD4_PC();
|
resultFF = new FastFile_COD4_PC(aData);
|
||||||
} else if (aGame == GAME_COD5) {
|
} else if (aGame == GAME_COD5) {
|
||||||
resultFF = new FastFile_COD5_PC();
|
resultFF = new FastFile_COD5_PC(aData);
|
||||||
} else if (aGame == GAME_COD6) {
|
} else if (aGame == GAME_COD6) {
|
||||||
resultFF = new FastFile_COD6_PC();
|
resultFF = new FastFile_COD6_PC(aData);
|
||||||
} else if (aGame == GAME_COD7) {
|
} else if (aGame == GAME_COD7) {
|
||||||
resultFF = new FastFile_COD7_PC();
|
resultFF = new FastFile_COD7_PC(aData);
|
||||||
} else if (aGame == GAME_COD8) {
|
} else if (aGame == GAME_COD8) {
|
||||||
resultFF = new FastFile_COD8_PC();
|
resultFF = new FastFile_COD8_PC(aData);
|
||||||
} else if (aGame == GAME_COD9) {
|
} else if (aGame == GAME_COD9) {
|
||||||
resultFF = new FastFile_COD9_PC();
|
resultFF = new FastFile_COD9_PC(aData);
|
||||||
} else if (aGame == GAME_COD10) {
|
} else if (aGame == GAME_COD10) {
|
||||||
resultFF = new FastFile_COD10_PC();
|
resultFF = new FastFile_COD10_PC(aData);
|
||||||
} else if (aGame == GAME_COD11) {
|
} else if (aGame == GAME_COD11) {
|
||||||
resultFF = new FastFile_COD11_PC();
|
resultFF = new FastFile_COD11_PC(aData);
|
||||||
} else if (aGame == GAME_COD12) {
|
} else if (aGame == GAME_COD12) {
|
||||||
resultFF = new FastFile_COD12_PC();
|
resultFF = new FastFile_COD12_PC(aData);
|
||||||
}
|
}
|
||||||
} else if (aPlatform == PLATFORM_PS3) {
|
} else if (aPlatform == PLATFORM_PS3) {
|
||||||
if (aGame == GAME_COD4) {
|
if (aGame == GAME_COD4) {
|
||||||
resultFF = new FastFile_COD4_PS3();
|
resultFF = new FastFile_COD4_PS3(aData);
|
||||||
} else if (aGame == GAME_COD5) {
|
} else if (aGame == GAME_COD5) {
|
||||||
resultFF = new FastFile_COD5_PS3();
|
resultFF = new FastFile_COD5_PS3(aData);
|
||||||
} else if (aGame == GAME_COD6) {
|
} else if (aGame == GAME_COD6) {
|
||||||
resultFF = new FastFile_COD6_PS3();
|
resultFF = new FastFile_COD6_PS3(aData);
|
||||||
} else if (aGame == GAME_COD7) {
|
} else if (aGame == GAME_COD7) {
|
||||||
resultFF = new FastFile_COD7_PS3();
|
resultFF = new FastFile_COD7_PS3(aData);
|
||||||
} else if (aGame == GAME_COD8) {
|
} else if (aGame == GAME_COD8) {
|
||||||
resultFF = new FastFile_COD8_PS3();
|
resultFF = new FastFile_COD8_PS3(aData);
|
||||||
} else if (aGame == GAME_COD9) {
|
} else if (aGame == GAME_COD9) {
|
||||||
resultFF = new FastFile_COD9_PS3();
|
resultFF = new FastFile_COD9_PS3(aData);
|
||||||
} else if (aGame == GAME_COD10) {
|
} else if (aGame == GAME_COD10) {
|
||||||
resultFF = new FastFile_COD10_PS3();
|
resultFF = new FastFile_COD10_PS3(aData);
|
||||||
} else if (aGame == GAME_COD11) {
|
} else if (aGame == GAME_COD11) {
|
||||||
resultFF = new FastFile_COD11_PS3();
|
resultFF = new FastFile_COD11_PS3(aData);
|
||||||
} else if (aGame == GAME_COD12) {
|
} else if (aGame == GAME_COD12) {
|
||||||
resultFF = new FastFile_COD12_PS3();
|
resultFF = new FastFile_COD12_PS3(aData);
|
||||||
}
|
}
|
||||||
} else if (aPlatform == PLATFORM_WII) {
|
} else if (aPlatform == PLATFORM_WII) {
|
||||||
if (aGame == GAME_COD4) {
|
if (aGame == GAME_COD4) {
|
||||||
resultFF = new FastFile_COD4_Wii();
|
resultFF = new FastFile_COD4_Wii(aData);
|
||||||
} else if (aGame == GAME_COD7) {
|
} else if (aGame == GAME_COD7) {
|
||||||
resultFF = new FastFile_COD7_Wii();
|
resultFF = new FastFile_COD7_Wii(aData);
|
||||||
} else if (aGame == GAME_COD8) {
|
} else if (aGame == GAME_COD8) {
|
||||||
resultFF = new FastFile_COD8_Wii();
|
resultFF = new FastFile_COD8_Wii(aData);
|
||||||
}
|
}
|
||||||
} else if (aPlatform == PLATFORM_WIIU) {
|
} else if (aPlatform == PLATFORM_WIIU) {
|
||||||
if (aGame == GAME_COD9) {
|
if (aGame == GAME_COD9) {
|
||||||
resultFF = new FastFile_COD9_WiiU();
|
resultFF = new FastFile_COD9_WiiU(aData);
|
||||||
} else if (aGame == GAME_COD10) {
|
} else if (aGame == GAME_COD10) {
|
||||||
resultFF = new FastFile_COD10_WiiU();
|
resultFF = new FastFile_COD10_WiiU(aData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (resultFF) {
|
if (resultFF) {
|
||||||
resultFF->SetStem(aStem);
|
resultFF->SetStem(aStem);
|
||||||
resultFF->Load(aData);
|
|
||||||
}
|
}
|
||||||
return resultFF;
|
return resultFF;
|
||||||
}
|
}
|
||||||
@ -288,7 +283,7 @@ private:
|
|||||||
|
|
||||||
static FastFile_Platform pGetPlatform(const QByteArray& aData) {
|
static FastFile_Platform pGetPlatform(const QByteArray& aData) {
|
||||||
const QStringList sections = pGetDataSections(aData);
|
const QStringList sections = pGetDataSections(aData);
|
||||||
if (sections[0] == "0000" || sections[0] == "4E58") {
|
if (sections[0] == "0000") {
|
||||||
return PLATFORM_360;
|
return PLATFORM_360;
|
||||||
} else if (sections[4] == "0000") {
|
} else if (sections[4] == "0000") {
|
||||||
if (sections[5] == "0001" && sections[6] == "78DA") {
|
if (sections[5] == "0001" && sections[6] == "78DA") {
|
||||||
@ -297,8 +292,6 @@ private:
|
|||||||
return PLATFORM_360;
|
return PLATFORM_360;
|
||||||
} else if (sections[5] == "0183" && sections[6] == "7801") {
|
} else if (sections[5] == "0183" && sections[6] == "7801") {
|
||||||
return PLATFORM_360;
|
return PLATFORM_360;
|
||||||
} else if (sections[5] == "01D9" && sections[6] == "0000") {
|
|
||||||
return PLATFORM_360;
|
|
||||||
} else if (sections[6] == "0101" && sections[7] == "CA3E") {
|
} else if (sections[6] == "0101" && sections[7] == "CA3E") {
|
||||||
return PLATFORM_360;
|
return PLATFORM_360;
|
||||||
} else if (sections[6] == "0000" && sections[7] == "0001") {
|
} else if (sections[6] == "0000" && sections[7] == "0001") {
|
||||||
@ -340,8 +333,6 @@ private:
|
|||||||
return GAME_COD6;
|
return GAME_COD6;
|
||||||
} else if (sections[4] == "D901" || sections[5] == "01DD" || sections[5] == "01D9") {
|
} else if (sections[4] == "D901" || sections[5] == "01DD" || sections[5] == "01D9") {
|
||||||
return GAME_COD7;
|
return GAME_COD7;
|
||||||
} else if (sections[0] == "4E58") {
|
|
||||||
return GAME_COD7_5;
|
|
||||||
} else if (sections[4] == "0100" || sections[5] == "006B" || sections[5] == "0070") {
|
} else if (sections[4] == "0100" || sections[5] == "006B" || sections[5] == "0070") {
|
||||||
return GAME_COD8;
|
return GAME_COD8;
|
||||||
} else if (sections[4] == "9300" || sections[5] == "0092"
|
} else if (sections[4] == "9300" || sections[5] == "0092"
|
||||||
|
|||||||
@ -6,6 +6,6 @@ SUBDIRS += core \
|
|||||||
fastfile \
|
fastfile \
|
||||||
xassets \
|
xassets \
|
||||||
zonefile \
|
zonefile \
|
||||||
#ddsfile \
|
ddsfile \
|
||||||
#iwifile \
|
iwifile \
|
||||||
#ipakfile
|
ipakfile
|
||||||
|
|||||||
@ -5,10 +5,14 @@ XAnimDeltaPart::XAnimDeltaPart()
|
|||||||
, mTrans()
|
, mTrans()
|
||||||
, mQuat()
|
, mQuat()
|
||||||
{
|
{
|
||||||
SetName("Animation Delta Part");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void XAnimDeltaPart::ParseData(XDataStream *aStream) {
|
XAnimDeltaPart::~XAnimDeltaPart()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void XAnimDeltaPart::ParseData(QDataStream *aStream) {
|
||||||
if (GetPtr() == -1) {
|
if (GetPtr() == -1) {
|
||||||
mTrans.ParsePtr(aStream);
|
mTrans.ParsePtr(aStream);
|
||||||
mQuat.ParsePtr(aStream);
|
mQuat.ParsePtr(aStream);
|
||||||
|
|||||||
@ -9,9 +9,9 @@ class XAnimDeltaPart : public XAsset
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit XAnimDeltaPart();
|
explicit XAnimDeltaPart();
|
||||||
~XAnimDeltaPart() = default;
|
~XAnimDeltaPart();
|
||||||
|
|
||||||
void ParseData(XDataStream *aStream) override;
|
void ParseData(QDataStream *aStream) override;
|
||||||
void Clear() override;
|
void Clear() override;
|
||||||
|
|
||||||
const XAnimPartTrans& GetTrans() const;
|
const XAnimPartTrans& GetTrans() const;
|
||||||
|
|||||||
@ -1,14 +1,12 @@
|
|||||||
#include "xanimdeltapartquat.h"
|
#include "xanimdeltapartquat.h"
|
||||||
|
|
||||||
XAnimDeltaPartQuat::XAnimDeltaPartQuat()
|
XAnimDeltaPartQuat::XAnimDeltaPartQuat()
|
||||||
: XAsset()
|
: XAsset() {
|
||||||
{
|
|
||||||
SetName("Animation Delta Part Quat");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void XAnimDeltaPartQuat::ParseData(XDataStream *aStream) {
|
void XAnimDeltaPartQuat::ParseData(QDataStream *aStream) {
|
||||||
if (GetPtr() == -1) {
|
if (GetPtr() == -1) {
|
||||||
mSize = aStream->ParseUInt32(QString("%1 size").arg(GetName()));
|
*aStream >> mSize;
|
||||||
|
|
||||||
// Parse data
|
// Parse data
|
||||||
mData.ParseData(aStream);
|
mData.ParseData(aStream);
|
||||||
|
|||||||
@ -1,3 +1,9 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef XANIMDELTAPARTQUAT_H
|
#ifndef XANIMDELTAPARTQUAT_H
|
||||||
#define XANIMDELTAPARTQUAT_H
|
#define XANIMDELTAPARTQUAT_H
|
||||||
|
|
||||||
@ -8,9 +14,8 @@ class XAnimDeltaPartQuat : public XAsset
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit XAnimDeltaPartQuat();
|
explicit XAnimDeltaPartQuat();
|
||||||
~XAnimDeltaPartQuat() = default;
|
|
||||||
|
|
||||||
void ParseData(XDataStream *aStream) override;
|
void ParseData(QDataStream *aStream) override;
|
||||||
|
|
||||||
quint32 GetSize() const;
|
quint32 GetSize() const;
|
||||||
void SetSize(quint32 size);
|
void SetSize(quint32 size);
|
||||||
@ -24,3 +29,8 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
#endif // XANIMDELTAPARTQUAT_H
|
#endif // XANIMDELTAPARTQUAT_H
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,10 @@
|
|||||||
#include "xanimdeltapartquatdata.h"
|
#include "xanimdeltapartquatdata.h"
|
||||||
|
|
||||||
XAnimDeltaPartQuatData::XAnimDeltaPartQuatData()
|
XAnimDeltaPartQuatData::XAnimDeltaPartQuatData()
|
||||||
: XAsset()
|
: XAsset() {
|
||||||
{
|
|
||||||
SetName("Animation Delta Part Quat Data");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void XAnimDeltaPartQuatData::ParseData(XDataStream *aStream) {
|
void XAnimDeltaPartQuatData::ParseData(QDataStream *aStream) {
|
||||||
if (GetPtr() == -1) {
|
if (GetPtr() == -1) {
|
||||||
// Parse frames
|
// Parse frames
|
||||||
mFrames.ParseData(aStream);
|
mFrames.ParseData(aStream);
|
||||||
|
|||||||
@ -1,3 +1,9 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef XANIMDELTAPARTQUATDATA_H
|
#ifndef XANIMDELTAPARTQUATDATA_H
|
||||||
#define XANIMDELTAPARTQUATDATA_H
|
#define XANIMDELTAPARTQUATDATA_H
|
||||||
|
|
||||||
@ -8,9 +14,8 @@ class XAnimDeltaPartQuatData : public XAsset
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit XAnimDeltaPartQuatData();
|
explicit XAnimDeltaPartQuatData();
|
||||||
~XAnimDeltaPartQuatData() = default;
|
|
||||||
|
|
||||||
void ParseData(XDataStream *aStream) override;
|
void ParseData(QDataStream *aStream) override;
|
||||||
|
|
||||||
const XAnimDeltaPartQuatDataFrames& GetFrames() const;
|
const XAnimDeltaPartQuatDataFrames& GetFrames() const;
|
||||||
void SetFrames(const XAnimDeltaPartQuatDataFrames& frames);
|
void SetFrames(const XAnimDeltaPartQuatDataFrames& frames);
|
||||||
@ -24,3 +29,8 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
#endif // XANIMDELTAPARTQUATDATA_H
|
#endif // XANIMDELTAPARTQUATDATA_H
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,7 @@
|
|||||||
#include "xanimdeltapartquatdataframes.h"
|
#include "xanimdeltapartquatdataframes.h"
|
||||||
|
|
||||||
XAnimDeltaPartQuatDataFrames::XAnimDeltaPartQuatDataFrames()
|
XAnimDeltaPartQuatDataFrames::XAnimDeltaPartQuatDataFrames()
|
||||||
: XAsset()
|
: XAsset() {
|
||||||
{
|
|
||||||
SetName("Animation Delta Part Quat Data Frame");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
quint32 XAnimDeltaPartQuatDataFrames::GetFramesPtr() const {
|
quint32 XAnimDeltaPartQuatDataFrames::GetFramesPtr() const {
|
||||||
@ -36,12 +34,12 @@ void XAnimDeltaPartQuatDataFrames::SetIndices(const XAnimDynamicIndices& indices
|
|||||||
mIndices = indices;
|
mIndices = indices;
|
||||||
}
|
}
|
||||||
|
|
||||||
void XAnimDeltaPartQuatDataFrames::ParseData(XDataStream *aStream) {
|
void XAnimDeltaPartQuatDataFrames::ParseData(QDataStream *aStream) {
|
||||||
if (GetPtr() == -1) {
|
if (GetPtr() == -1) {
|
||||||
mFramesPtr = aStream->ParseInt32(QString("%1 frames ptr").arg(GetName()));
|
*aStream
|
||||||
|
>> mFramesPtr
|
||||||
mFrames[0] = aStream->ParseInt16(QString("%1 frame %2").arg(GetName()).arg(0));
|
>> mFrames[0]
|
||||||
mFrames[1] = aStream->ParseInt16(QString("%1 frame %2").arg(GetName()).arg(1));
|
>> mFrames[1];
|
||||||
|
|
||||||
// Parse indices
|
// Parse indices
|
||||||
mIndices.ParseData(aStream);
|
mIndices.ParseData(aStream);
|
||||||
|
|||||||
@ -8,7 +8,6 @@ class XAnimDeltaPartQuatDataFrames : public XAsset
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit XAnimDeltaPartQuatDataFrames();
|
explicit XAnimDeltaPartQuatDataFrames();
|
||||||
~XAnimDeltaPartQuatDataFrames() = default;
|
|
||||||
|
|
||||||
quint32 GetFramesPtr() const;
|
quint32 GetFramesPtr() const;
|
||||||
void SetFramesPtr(quint32 ptr);
|
void SetFramesPtr(quint32 ptr);
|
||||||
@ -20,11 +19,11 @@ public:
|
|||||||
const XAnimDynamicIndices& GetIndices() const;
|
const XAnimDynamicIndices& GetIndices() const;
|
||||||
void SetIndices(const XAnimDynamicIndices& indices);
|
void SetIndices(const XAnimDynamicIndices& indices);
|
||||||
|
|
||||||
void ParseData(XDataStream *aStream) override;
|
void ParseData(QDataStream *aStream) override;
|
||||||
void Clear() override;
|
void Clear() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
qint32 mFramesPtr = 0;
|
quint32 mFramesPtr = 0;
|
||||||
qint16 mFrames[2] = {0};
|
qint16 mFrames[2] = {0};
|
||||||
XAnimDynamicIndices mIndices;
|
XAnimDynamicIndices mIndices;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -4,17 +4,24 @@ XAnimDynamicFrames::XAnimDynamicFrames()
|
|||||||
: XAsset()
|
: XAsset()
|
||||||
, mFrames(3)
|
, mFrames(3)
|
||||||
{
|
{
|
||||||
SetName("Animation Dynamic Frames");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void XAnimDynamicFrames::ParseData(XDataStream *aStream) {
|
XAnimDynamicFrames::~XAnimDynamicFrames()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void XAnimDynamicFrames::ParseData(QDataStream *aStream) {
|
||||||
if (GetPtr() == -1) {
|
if (GetPtr() == -1) {
|
||||||
qint32 framePtr = aStream->ParseInt32(QString("%1 frames ptr").arg(GetName()));
|
qint32 framePtr;
|
||||||
|
*aStream >> framePtr;
|
||||||
|
|
||||||
if (framePtr == -1)
|
if (framePtr == -1)
|
||||||
{
|
{
|
||||||
mFrames[0] = aStream->ParseUInt8(QString("%1 frame %2").arg(GetName()).arg(0));
|
*aStream
|
||||||
mFrames[1] = aStream->ParseUInt8(QString("%1 frame %2").arg(GetName()).arg(1));
|
>> mFrames[0]
|
||||||
mFrames[2] = aStream->ParseUInt8(QString("%1 frame %2").arg(GetName()).arg(2));
|
>> mFrames[1]
|
||||||
|
>> mFrames[2];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
#ifndef XANIMDYNAMICFRAMES_H
|
#ifndef XANIMDYNAMICFRAMES_H
|
||||||
#define XANIMDYNAMICFRAMES_H
|
#define XANIMDYNAMICFRAMES_H
|
||||||
|
|
||||||
@ -9,9 +10,9 @@ class XAnimDynamicFrames : public XAsset
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit XAnimDynamicFrames();
|
explicit XAnimDynamicFrames();
|
||||||
~XAnimDynamicFrames() = default;
|
~XAnimDynamicFrames();
|
||||||
|
|
||||||
void ParseData(XDataStream *aStream) override;
|
void ParseData(QDataStream *aStream) override;
|
||||||
void Clear() override;
|
void Clear() override;
|
||||||
|
|
||||||
QVector<quint8> GetFrames() const;
|
QVector<quint8> GetFrames() const;
|
||||||
|
|||||||
@ -4,12 +4,16 @@ XAnimDynamicIndices::XAnimDynamicIndices()
|
|||||||
: XAsset()
|
: XAsset()
|
||||||
, mIndices(1)
|
, mIndices(1)
|
||||||
{
|
{
|
||||||
SetName("Animation Dynamic Indices");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void XAnimDynamicIndices::ParseData(XDataStream *aStream) {
|
XAnimDynamicIndices::~XAnimDynamicIndices()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void XAnimDynamicIndices::ParseData(QDataStream *aStream) {
|
||||||
if (GetPtr() == -1) {
|
if (GetPtr() == -1) {
|
||||||
mIndices[0] = aStream->ParseUInt8(QString("%1 index").arg(GetName()));
|
*aStream >> mIndices[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,9 +9,9 @@ class XAnimDynamicIndices : public XAsset
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit XAnimDynamicIndices();
|
explicit XAnimDynamicIndices();
|
||||||
~XAnimDynamicIndices() = default;
|
~XAnimDynamicIndices();
|
||||||
|
|
||||||
void ParseData(XDataStream *aStream) override;
|
void ParseData(QDataStream *aStream) override;
|
||||||
void Clear() override;
|
void Clear() override;
|
||||||
|
|
||||||
QVector<quint8> GetIndices() const;
|
QVector<quint8> GetIndices() const;
|
||||||
|
|||||||
@ -4,15 +4,21 @@ XAnimIndices::XAnimIndices()
|
|||||||
: XAsset()
|
: XAsset()
|
||||||
, mIndex(0)
|
, mIndex(0)
|
||||||
{
|
{
|
||||||
SetName("Animation Indices");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void XAnimIndices::ParseData(XDataStream *aStream) {
|
XAnimIndices::~XAnimIndices()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void XAnimIndices::ParseData(QDataStream *aStream) {
|
||||||
if (GetPtr() == -1) {
|
if (GetPtr() == -1) {
|
||||||
qint32 indexPtr = aStream->ParseInt32(QString("%1 index ptr").arg(GetName()));
|
qint32 indexPtr;
|
||||||
|
*aStream >> indexPtr;
|
||||||
if (indexPtr == -1)
|
if (indexPtr == -1)
|
||||||
{
|
{
|
||||||
mIndex = aStream->ParseUInt32(QString("%1 index").arg(GetName()));
|
*aStream >> mIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,9 +7,9 @@ class XAnimIndices : public XAsset
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit XAnimIndices();
|
explicit XAnimIndices();
|
||||||
~XAnimIndices() = default;
|
~XAnimIndices();
|
||||||
|
|
||||||
void ParseData(XDataStream *aStream) override;
|
void ParseData(QDataStream *aStream) override;
|
||||||
void Clear() override;
|
void Clear() override;
|
||||||
|
|
||||||
quint32 GetIndex() const;
|
quint32 GetIndex() const;
|
||||||
|
|||||||
@ -5,14 +5,19 @@ XAnimNotifyInfo::XAnimNotifyInfo()
|
|||||||
, mName(0)
|
, mName(0)
|
||||||
, mTime(0.0f)
|
, mTime(0.0f)
|
||||||
{
|
{
|
||||||
SetName("Animation Notify Info");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void XAnimNotifyInfo::ParseData(XDataStream *aStream) {
|
XAnimNotifyInfo::~XAnimNotifyInfo()
|
||||||
if (GetPtr() == -1) {
|
{
|
||||||
|
|
||||||
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;
|
mName = 0;
|
||||||
mTime = 0.0f;
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@ -7,11 +7,17 @@ class XAnimNotifyInfo : public XAsset
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit XAnimNotifyInfo();
|
explicit XAnimNotifyInfo();
|
||||||
~XAnimNotifyInfo() = default;
|
~XAnimNotifyInfo();
|
||||||
|
|
||||||
void ParseData(XDataStream *aStream) override;
|
void ParseData(QDataStream *aStream) override;
|
||||||
void Clear() override;
|
void Clear() override;
|
||||||
|
|
||||||
|
quint32 GetName() const;
|
||||||
|
void SetName(quint32 name);
|
||||||
|
|
||||||
|
float GetTime() const;
|
||||||
|
void SetTime(float time);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
quint32 mName;
|
quint32 mName;
|
||||||
float mTime;
|
float mTime;
|
||||||
|
|||||||
@ -31,49 +31,68 @@ XAnimParts::XAnimParts()
|
|||||||
, mDeltaPart()
|
, mDeltaPart()
|
||||||
{
|
{
|
||||||
SetType(ASSET_TYPE_XANIMPARTS);
|
SetType(ASSET_TYPE_XANIMPARTS);
|
||||||
SetName("Animation Parts");
|
SetName("XAnimParts");
|
||||||
}
|
}
|
||||||
|
|
||||||
void XAnimParts::ParseData(XDataStream *aStream) {
|
XAnimParts::~XAnimParts()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void XAnimParts::ParseData(QDataStream *aStream) {
|
||||||
if (GetPtr() == -1) {
|
if (GetPtr() == -1) {
|
||||||
|
|
||||||
mName.ParsePtr(aStream, false);
|
mName.ParsePtr(aStream, false);
|
||||||
|
|
||||||
// Parse all fields
|
// Parse all fields
|
||||||
mDataByteCount = aStream->ParseUInt32(QString("%1 data byte count").arg(GetName()));
|
*aStream
|
||||||
mDataShortCount = aStream->ParseUInt32(QString("%1 data short count").arg(GetName()));
|
>> mDataByteCount
|
||||||
mDataIntCount = aStream->ParseUInt32(QString("%1 data int count").arg(GetName()));
|
>> mDataShortCount
|
||||||
mRandomDataByteCount = aStream->ParseUInt32(QString("%1 random date byte count").arg(GetName()));
|
>> mDataIntCount
|
||||||
mRandomDataIntCount = aStream->ParseUInt32(QString("%1 random data int count").arg(GetName()));
|
>> mRandomDataByteCount
|
||||||
mNumFrames = aStream->ParseUInt32(QString("%1 # frames").arg(GetName()));
|
>> mRandomDataIntCount
|
||||||
|
>> mNumFrames;
|
||||||
|
|
||||||
quint8 loopDelta = aStream->ParseUInt8(QString("%1 loop delta").arg(GetName()));
|
quint8 loopDelta;
|
||||||
|
*aStream >> loopDelta;
|
||||||
mIsLoop = (loopDelta & 0x1) != 0;
|
mIsLoop = (loopDelta & 0x1) != 0;
|
||||||
mIsDelta = (loopDelta & 0x2) != 0;
|
mIsDelta = (loopDelta & 0x2) != 0;
|
||||||
|
|
||||||
for (int i = 0; i < 12; i++)
|
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()));
|
*aStream
|
||||||
mAssetType = aStream->ParseUInt8(QString("%1 asset type").arg(GetName()));
|
>> mNotifyCount
|
||||||
mPad = aStream->ParseUInt32(QString("%1 pad").arg(GetName())) != 0;
|
>> mAssetType;
|
||||||
|
|
||||||
|
quint32 pad;
|
||||||
|
*aStream >> pad;
|
||||||
|
mPad = (pad != 0);
|
||||||
|
|
||||||
qint32 namesPtr, dataBytePtr, dataShortPtr, dataIntPtr,
|
qint32 namesPtr, dataBytePtr, dataShortPtr, dataIntPtr,
|
||||||
randomDataShortPtr, randomDataBytePtr, randomDataIntPtr;
|
randomDataShortPtr, randomDataBytePtr, randomDataIntPtr;
|
||||||
|
|
||||||
mRandomDataShortCount = aStream->ParseUInt32(QString("%1 random data short count").arg(GetName()));
|
*aStream
|
||||||
mIndexCount = aStream->ParseUInt32(QString("%1 index count").arg(GetName()));
|
>> mRandomDataShortCount
|
||||||
mFramerate = aStream->ParseSingle(QString("%1 frame rate").arg(GetName()));
|
>> mIndexCount
|
||||||
mFrequency = aStream->ParseSingle(QString("%1 frequency").arg(GetName()));
|
>> mFramerate
|
||||||
namesPtr = aStream->ParseInt32(QString("%1 names ptr").arg(GetName()));
|
>> mFrequency
|
||||||
dataBytePtr = aStream->ParseInt32(QString("%1 data byte ptr").arg(GetName()));
|
>> namesPtr
|
||||||
dataShortPtr = aStream->ParseInt32(QString("%1 data short ptr").arg(GetName()));
|
>> mNames
|
||||||
dataIntPtr = aStream->ParseInt32(QString("%1 data int ptr").arg(GetName()));
|
>> dataBytePtr
|
||||||
randomDataShortPtr = aStream->ParseInt32(QString("%1 random data short ptr").arg(GetName()));
|
>> mDataByte
|
||||||
randomDataBytePtr = aStream->ParseInt32(QString("%1 random data byte ptr").arg(GetName()));
|
>> dataShortPtr
|
||||||
randomDataIntPtr = aStream->ParseInt32(QString("%1 random data int ptr").arg(GetName()));
|
>> mDataShort
|
||||||
|
>> dataIntPtr
|
||||||
|
>> mDataInt
|
||||||
|
>> randomDataShortPtr
|
||||||
|
>> mRandomDataShort
|
||||||
|
>> randomDataBytePtr
|
||||||
|
>> mRandomDataByte
|
||||||
|
>> randomDataIntPtr
|
||||||
|
>> mRandomDataInt;
|
||||||
|
|
||||||
// Parse indices
|
// Parse indices
|
||||||
mIndices.ParseData(aStream);
|
mIndices.ParseData(aStream);
|
||||||
@ -83,33 +102,33 @@ void XAnimParts::ParseData(XDataStream *aStream) {
|
|||||||
mName.ParseData(aStream);
|
mName.ParseData(aStream);
|
||||||
if (namesPtr)
|
if (namesPtr)
|
||||||
{
|
{
|
||||||
mNames = aStream->ParseInt32(QString("%1 names").arg(GetName()));
|
|
||||||
}
|
}
|
||||||
mNotify.ParseData(aStream);
|
mNotify.ParseData(aStream);
|
||||||
mDeltaPart.ParseData(aStream);
|
mDeltaPart.ParseData(aStream);
|
||||||
if (dataBytePtr)
|
if (dataBytePtr)
|
||||||
{
|
{
|
||||||
mDataByte = aStream->ParseUInt8(QString("%1 data byte").arg(GetName()));
|
*aStream >> mDataByte;
|
||||||
}
|
}
|
||||||
if (dataShortPtr)
|
if (dataShortPtr)
|
||||||
{
|
{
|
||||||
mDataShort = aStream->ParseInt16(QString("%1 data short").arg(GetName()));
|
*aStream >> mDataShort;
|
||||||
}
|
}
|
||||||
if (dataIntPtr)
|
if (dataIntPtr)
|
||||||
{
|
{
|
||||||
mDataInt = aStream->ParseInt32(QString("%1 data int").arg(GetName()));
|
*aStream >> mDataInt;
|
||||||
}
|
}
|
||||||
if (randomDataShortPtr)
|
if (randomDataShortPtr)
|
||||||
{
|
{
|
||||||
mRandomDataShort = aStream->ParseInt16(QString("%1 random data short").arg(GetName()));
|
*aStream >> mDataInt;
|
||||||
}
|
}
|
||||||
if (randomDataBytePtr)
|
if (randomDataBytePtr)
|
||||||
{
|
{
|
||||||
mRandomDataByte = aStream->ParseUInt8(QString("%1 random data byte").arg(GetName()));
|
*aStream >> mRandomDataByte;
|
||||||
}
|
}
|
||||||
if (randomDataIntPtr)
|
if (randomDataIntPtr)
|
||||||
{
|
{
|
||||||
mRandomDataInt = aStream->ParseInt32(QString("%1 random data int").arg(GetName()));
|
*aStream >> mRandomDataInt;
|
||||||
}
|
}
|
||||||
mIndices.ParseData(aStream);
|
mIndices.ParseData(aStream);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,9 +13,9 @@ class XAnimParts : public XAsset
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit XAnimParts();
|
explicit XAnimParts();
|
||||||
~XAnimParts() = default;
|
~XAnimParts();
|
||||||
|
|
||||||
void ParseData(XDataStream *aStream) override;
|
void ParseData(QDataStream *aStream) override;
|
||||||
void Clear() override;
|
void Clear() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -43,13 +43,13 @@ private:
|
|||||||
float mFramerate = 0.0f;
|
float mFramerate = 0.0f;
|
||||||
float mFrequency = 0.0f;
|
float mFrequency = 0.0f;
|
||||||
|
|
||||||
quint16 mNames = 0;
|
quint32 mNames = 0;
|
||||||
quint8 mDataByte = 0;
|
quint8 mDataByte = 0;
|
||||||
qint16 mDataShort = 0;
|
qint16 mDataShort = 0;
|
||||||
qint32 mDataInt = 0;
|
int mDataInt = 0;
|
||||||
qint16 mRandomDataShort = 0;
|
qint16 mRandomDataShort = 0;
|
||||||
quint8 mRandomDataByte = 0;
|
quint8 mRandomDataByte = 0;
|
||||||
qint32 mRandomDataInt = 0;
|
int mRandomDataInt = 0;
|
||||||
XAnimIndices mIndices;
|
XAnimIndices mIndices;
|
||||||
XAnimNotifyInfo mNotify;
|
XAnimNotifyInfo mNotify;
|
||||||
XAnimDeltaPart mDeltaPart;
|
XAnimDeltaPart mDeltaPart;
|
||||||
|
|||||||
@ -6,7 +6,6 @@ XAnimPartTrans::XAnimPartTrans()
|
|||||||
, mIsSmallTrans(false)
|
, mIsSmallTrans(false)
|
||||||
, mData()
|
, mData()
|
||||||
{
|
{
|
||||||
SetName("Animation Part Trans");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
XAnimPartTrans::XAnimPartTrans(const XAnimPartTrans &aSrc)
|
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) {
|
if (GetPtr() == -1) {
|
||||||
mSize = aStream->ParseUInt32(QString("%1 size").arg(GetName()));
|
quint8 smallTransByte;
|
||||||
mIsSmallTrans = aStream->ParseUInt8(QString("%1 is small trans").arg(GetName())) != 0;
|
*aStream
|
||||||
|
>> mSize
|
||||||
|
>> smallTransByte;
|
||||||
|
mIsSmallTrans = (smallTransByte != 0);
|
||||||
|
|
||||||
// Parse data
|
// Parse data
|
||||||
mData.ParseData(aStream);
|
mData.ParseData(aStream);
|
||||||
|
|||||||
@ -9,9 +9,9 @@ class XAnimPartTrans : public XAsset
|
|||||||
public:
|
public:
|
||||||
explicit XAnimPartTrans();
|
explicit XAnimPartTrans();
|
||||||
XAnimPartTrans(const XAnimPartTrans& aSrc);
|
XAnimPartTrans(const XAnimPartTrans& aSrc);
|
||||||
~XAnimPartTrans() = default;
|
~XAnimPartTrans();
|
||||||
|
|
||||||
void ParseData(XDataStream* aStream) override;
|
void ParseData(QDataStream* aStream) override;
|
||||||
void Clear() override;
|
void Clear() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@ -5,7 +5,6 @@ XAnimPartTransData::XAnimPartTransData()
|
|||||||
, mFrames()
|
, mFrames()
|
||||||
, mFrame()
|
, mFrame()
|
||||||
{
|
{
|
||||||
SetName("Animation Part Trans Data");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
XAnimPartTransData::XAnimPartTransData(const XAnimPartTransData &aSrc)
|
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) {
|
if (GetPtr() == -1) {
|
||||||
// We need to determine which part of the union to parse
|
// We need to determine which part of the union to parse
|
||||||
// For simplicity, we'll assume it's always frames for now
|
// For simplicity, we'll assume it's always frames for now
|
||||||
|
|||||||
@ -9,9 +9,9 @@ class XAnimPartTransData : public XAsset
|
|||||||
public:
|
public:
|
||||||
explicit XAnimPartTransData();
|
explicit XAnimPartTransData();
|
||||||
XAnimPartTransData(const XAnimPartTransData &aSrc);
|
XAnimPartTransData(const XAnimPartTransData &aSrc);
|
||||||
~XAnimPartTransData() = default;
|
~XAnimPartTransData();
|
||||||
|
|
||||||
void ParseData(XDataStream *aStream) override;
|
void ParseData(QDataStream *aStream) override;
|
||||||
void Clear() override;
|
void Clear() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@ -7,17 +7,22 @@ XAnimPartTransFrames::XAnimPartTransFrames()
|
|||||||
, mFrames()
|
, mFrames()
|
||||||
, mIndices()
|
, mIndices()
|
||||||
{
|
{
|
||||||
SetName("Animation Parts Trans Frames");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void XAnimPartTransFrames::ParseData(XDataStream *aStream) {
|
XAnimPartTransFrames::~XAnimPartTransFrames()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void XAnimPartTransFrames::ParseData(QDataStream *aStream) {
|
||||||
if (GetPtr() == -1) {
|
if (GetPtr() == -1) {
|
||||||
mMins[0] = aStream->ParseSingle(QString("%1 min %2").arg(GetName()).arg(0));
|
*aStream
|
||||||
mMins[1] = aStream->ParseSingle(QString("%1 min %2").arg(GetName()).arg(1));
|
>> mMins[0]
|
||||||
mMins[2] = aStream->ParseSingle(QString("%1 min %2").arg(GetName()).arg(2));
|
>> mMins[1]
|
||||||
mMaxs[0] = aStream->ParseSingle(QString("%1 max %2").arg(GetName()).arg(0));
|
>> mMins[2]
|
||||||
mMaxs[1] = aStream->ParseSingle(QString("%1 max %2").arg(GetName()).arg(1));
|
>> mMaxs[0]
|
||||||
mMaxs[2] = aStream->ParseSingle(QString("%1 max %2").arg(GetName()).arg(2));
|
>> mMaxs[1]
|
||||||
|
>> mMaxs[2];
|
||||||
|
|
||||||
// Parse frames
|
// Parse frames
|
||||||
mFrames.ParseData(aStream);
|
mFrames.ParseData(aStream);
|
||||||
|
|||||||
@ -11,9 +11,9 @@ class XAnimPartTransFrames : public XAsset
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit XAnimPartTransFrames();
|
explicit XAnimPartTransFrames();
|
||||||
~XAnimPartTransFrames() = default;
|
~XAnimPartTransFrames();
|
||||||
|
|
||||||
void ParseData(XDataStream *aStream) override;
|
void ParseData(QDataStream *aStream) override;
|
||||||
void Clear() override;
|
void Clear() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@ -19,6 +19,8 @@
|
|||||||
#include "xstringtable.h"
|
#include "xstringtable.h"
|
||||||
#include "xweapondef.h"
|
#include "xweapondef.h"
|
||||||
|
|
||||||
|
XAsset::
|
||||||
|
|
||||||
XAsset::XAsset()
|
XAsset::XAsset()
|
||||||
: mPtr(0)
|
: mPtr(0)
|
||||||
, mType(ASSET_TYPE_NONE)
|
, mType(ASSET_TYPE_NONE)
|
||||||
@ -27,6 +29,11 @@ XAsset::XAsset()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
XAsset::~XAsset()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void XAsset::SetPtr(qint32 aPtr) {
|
void XAsset::SetPtr(qint32 aPtr) {
|
||||||
mPtr = aPtr;
|
mPtr = aPtr;
|
||||||
}
|
}
|
||||||
@ -76,9 +83,20 @@ void XAsset::Clear()
|
|||||||
mType = ASSET_TYPE_NONE;
|
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)
|
if (aDataFlag && mPtr == -1)
|
||||||
{
|
{
|
||||||
ParseData(aStream);
|
ParseData(aStream);
|
||||||
@ -87,6 +105,10 @@ void XAsset::ParsePtr(XDataStream *aStream, bool aDataFlag) {
|
|||||||
|
|
||||||
XAsset* XAsset::Create(XAssetType aAssetType)
|
XAsset* XAsset::Create(XAssetType aAssetType)
|
||||||
{
|
{
|
||||||
|
if (mDebug)
|
||||||
|
{
|
||||||
|
qDebug() << QString("Creating XAsset with type %1").arg(XAssetTypeToString(aAssetType));
|
||||||
|
}
|
||||||
switch (aAssetType)
|
switch (aAssetType)
|
||||||
{
|
{
|
||||||
case ASSET_TYPE_XANIMPARTS:
|
case ASSET_TYPE_XANIMPARTS:
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include "xassettype.h"
|
#include "xassettype.h"
|
||||||
|
|
||||||
#include "xdatastream.h"
|
#include <QDataStream>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QIODevice>
|
#include <QIODevice>
|
||||||
@ -12,7 +12,7 @@ class XAsset
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
XAsset();
|
XAsset();
|
||||||
virtual ~XAsset() = default;
|
virtual ~XAsset();
|
||||||
|
|
||||||
void SetPtr(qint32 aPtr);
|
void SetPtr(qint32 aPtr);
|
||||||
qint32 GetPtr() const;
|
qint32 GetPtr() const;
|
||||||
@ -27,8 +27,8 @@ public:
|
|||||||
bool IsDebug() const;
|
bool IsDebug() const;
|
||||||
|
|
||||||
virtual void Clear();
|
virtual void Clear();
|
||||||
virtual void ParsePtr(XDataStream *aStream, bool aDataFlag = true);
|
virtual void ParsePtr(QDataStream *aStream, bool aDataFlag = true);
|
||||||
virtual void ParseData(XDataStream *aStream) = 0;
|
virtual void ParseData(QDataStream *aStream) = 0;
|
||||||
|
|
||||||
static XAsset* Create(XAssetType aAssetType);
|
static XAsset* Create(XAssetType aAssetType);
|
||||||
static QString XAssetTypeToString(XAssetType type);
|
static QString XAssetTypeToString(XAssetType type);
|
||||||
|
|||||||
@ -3,39 +3,41 @@
|
|||||||
|
|
||||||
XAssetHeader::XAssetHeader()
|
XAssetHeader::XAssetHeader()
|
||||||
: XAsset()
|
: XAsset()
|
||||||
, mRawType(0)
|
|
||||||
, mAssetType()
|
, mAssetType()
|
||||||
, mAssetPtr(0)
|
, mAssetPtr(0)
|
||||||
, mZoneFile(nullptr)
|
, mZoneFile(nullptr)
|
||||||
{
|
{
|
||||||
SetName("Asset Header");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
XAssetHeader::XAssetHeader(ZoneFile *aZoneFile)
|
XAssetHeader::XAssetHeader(ZoneFile *aZoneFile)
|
||||||
: XAsset()
|
: XAsset()
|
||||||
, mRawType(0)
|
|
||||||
, mAssetType()
|
, mAssetType()
|
||||||
, mAssetPtr(0)
|
, mAssetPtr(0)
|
||||||
, mZoneFile(aZoneFile)
|
, 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()
|
void XAssetHeader::Clear()
|
||||||
{
|
{
|
||||||
mAssetType = ASSET_TYPE_NONE;
|
mAssetType = ASSET_TYPE_NONE;
|
||||||
mAssetPtr = 0;
|
mAssetPtr = 0;
|
||||||
mRawType = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
XAssetType XAssetHeader::GetAssetType() const
|
XAssetType XAssetHeader::GetAssetType() const
|
||||||
@ -43,11 +45,6 @@ XAssetType XAssetHeader::GetAssetType() const
|
|||||||
return mAssetType;
|
return mAssetType;
|
||||||
}
|
}
|
||||||
|
|
||||||
quint32 XAssetHeader::GetRawAssetType() const
|
|
||||||
{
|
|
||||||
return mRawType;
|
|
||||||
}
|
|
||||||
|
|
||||||
qint32 XAssetHeader::GetAssetPtr() const
|
qint32 XAssetHeader::GetAssetPtr() const
|
||||||
{
|
{
|
||||||
return mAssetPtr;
|
return mAssetPtr;
|
||||||
|
|||||||
@ -10,17 +10,15 @@ class XAssetHeader: public XAsset
|
|||||||
public:
|
public:
|
||||||
explicit XAssetHeader();
|
explicit XAssetHeader();
|
||||||
XAssetHeader(ZoneFile* aZoneFile);
|
XAssetHeader(ZoneFile* aZoneFile);
|
||||||
~XAssetHeader() = default;
|
~XAssetHeader();
|
||||||
|
|
||||||
void ParseData(XDataStream *aStream) override;
|
void ParseData(QDataStream *aStream) override;
|
||||||
void Clear() override;
|
void Clear() override;
|
||||||
|
|
||||||
XAssetType GetAssetType() const;
|
XAssetType GetAssetType() const;
|
||||||
quint32 GetRawAssetType() const;
|
|
||||||
qint32 GetAssetPtr() const;
|
qint32 GetAssetPtr() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
quint32 mRawType;
|
|
||||||
XAssetType mAssetType;
|
XAssetType mAssetType;
|
||||||
qint32 mAssetPtr;
|
qint32 mAssetPtr;
|
||||||
ZoneFile *mZoneFile;
|
ZoneFile *mZoneFile;
|
||||||
|
|||||||
@ -10,8 +10,6 @@ XAssetList::XAssetList()
|
|||||||
, mAssetHeaders()
|
, mAssetHeaders()
|
||||||
, mZoneFile(nullptr)
|
, mZoneFile(nullptr)
|
||||||
{
|
{
|
||||||
SetType(ASSET_TYPE_ASSETLIST);
|
|
||||||
SetName("Asset List");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
XAssetList::XAssetList(ZoneFile* aZoneFile)
|
XAssetList::XAssetList(ZoneFile* aZoneFile)
|
||||||
@ -31,23 +29,30 @@ XAssetList::~XAssetList()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void XAssetList::ParseData(XDataStream *aStream) {
|
void XAssetList::ParseData(QDataStream *aStream) {
|
||||||
// Parse string list
|
// Parse string list
|
||||||
if (IsDebug())
|
if (IsDebug())
|
||||||
{
|
{
|
||||||
qDebug() << QString("[%1] Parsing data for %2").arg(aStream->device()->pos(), 10, 10, QChar('0')).arg(GetName());
|
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
|
// Parse asset count and assets
|
||||||
mAssetCount = aStream->ParseUInt32(QString("%1 asset count").arg(GetName()));
|
qint32 assetsPtr;
|
||||||
qint32 assetsPtr = aStream->ParseInt32(QString("%1 assets ptr").arg(GetName()));
|
*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);
|
mStringList.ParseData(aStream);
|
||||||
|
|
||||||
if (assetsPtr)
|
if (assetsPtr)
|
||||||
{
|
{
|
||||||
for (quint32 i = 0; i < mAssetCount; i++)
|
for (int i = 0; i < mAssetCount; i++)
|
||||||
{
|
{
|
||||||
XAssetHeader assetHeader(mZoneFile);
|
XAssetHeader assetHeader(mZoneFile);
|
||||||
assetHeader.ParseData(aStream);
|
assetHeader.ParseData(aStream);
|
||||||
@ -57,19 +62,11 @@ void XAssetList::ParseData(XDataStream *aStream) {
|
|||||||
|
|
||||||
for (int i = 0; i < mAssetHeaders.size(); i++)
|
for (int i = 0; i < mAssetHeaders.size(); i++)
|
||||||
{
|
{
|
||||||
if (aStream->device()->pos() > 98000)
|
|
||||||
{
|
|
||||||
qDebug() << "test";
|
|
||||||
}
|
|
||||||
XAssetHeader assetHeader = mAssetHeaders[i];
|
XAssetHeader assetHeader = mAssetHeaders[i];
|
||||||
XAsset* asset = XAsset::Create(assetHeader.GetAssetType());
|
XAsset* asset = XAsset::Create(assetHeader.GetAssetType());
|
||||||
if (asset)
|
asset->ParseData(aStream);
|
||||||
{
|
|
||||||
asset->SetPtr(assetHeader.GetAssetPtr());
|
|
||||||
asset->ParseData(aStream);
|
|
||||||
|
|
||||||
mAssets.append(asset);
|
mAssets.append(asset);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,9 +14,9 @@ class XAssetList : public XAsset
|
|||||||
public:
|
public:
|
||||||
explicit XAssetList();
|
explicit XAssetList();
|
||||||
XAssetList(ZoneFile* aZoneFile);
|
XAssetList(ZoneFile* aZoneFile);
|
||||||
~XAssetList() override;
|
~XAssetList();
|
||||||
|
|
||||||
void ParseData(XDataStream *aStream) override;
|
void ParseData(QDataStream *aStream) override;
|
||||||
void Clear() override;
|
void Clear() override;
|
||||||
|
|
||||||
XScriptStringList GetStringList() const;
|
XScriptStringList GetStringList() const;
|
||||||
|
|||||||
@ -5,7 +5,7 @@ XAudioChannelMap::XAudioChannelMap()
|
|||||||
, mEntryCount(0)
|
, mEntryCount(0)
|
||||||
, mEntries(QVector<XAudioChannelMapEntry*>())
|
, mEntries(QVector<XAudioChannelMapEntry*>())
|
||||||
{
|
{
|
||||||
SetName("Audio Channel Map");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
XAudioChannelMap::~XAudioChannelMap()
|
XAudioChannelMap::~XAudioChannelMap()
|
||||||
@ -32,13 +32,15 @@ void XAudioChannelMap::SetMapEntry(int aIndex, XAudioChannelMapEntry *aEntry)
|
|||||||
mEntries[aIndex] = 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);
|
aStream->skipRawData(3);
|
||||||
|
|
||||||
quint32 entriesPtr = aStream->ParseInt32(QString("%1 entries ptr").arg(GetName()));
|
quint32 entriesPtr;
|
||||||
|
*aStream >> entriesPtr;
|
||||||
|
|
||||||
if (entriesPtr)
|
if (entriesPtr)
|
||||||
{
|
{
|
||||||
mEntries.resize(mEntryCount);
|
mEntries.resize(mEntryCount);
|
||||||
|
|||||||
@ -17,7 +17,7 @@ public:
|
|||||||
XAudioChannelMapEntry* GetMapEntry(int aIndex) const;
|
XAudioChannelMapEntry* GetMapEntry(int aIndex) const;
|
||||||
void SetMapEntry(int aIndex, XAudioChannelMapEntry* aEntry);
|
void SetMapEntry(int aIndex, XAudioChannelMapEntry* aEntry);
|
||||||
|
|
||||||
virtual void ParseData(XDataStream* aStream) override;
|
virtual void ParseData(QDataStream* aStream) override;
|
||||||
virtual void Clear() override;
|
virtual void Clear() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@ -6,7 +6,7 @@ XAudioChannelMapEntry::XAudioChannelMapEntry()
|
|||||||
, mOutputChannel(0)
|
, mOutputChannel(0)
|
||||||
, mVolume(0.0)
|
, mVolume(0.0)
|
||||||
{
|
{
|
||||||
SetName("Audio Channel Map Entry");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
XAudioChannelMapEntry::~XAudioChannelMapEntry()
|
XAudioChannelMapEntry::~XAudioChannelMapEntry()
|
||||||
@ -44,15 +44,16 @@ void XAudioChannelMapEntry::SetVolume(float aVolume)
|
|||||||
mVolume = aVolume;
|
mVolume = aVolume;
|
||||||
}
|
}
|
||||||
|
|
||||||
void XAudioChannelMapEntry::ParseData(XDataStream *aStream)
|
void XAudioChannelMapEntry::ParseData(QDataStream *aStream)
|
||||||
{
|
{
|
||||||
mInputChannel = aStream->ParseUInt8(QString("%1 input channel").arg(GetName()));
|
*aStream
|
||||||
mOutputChannel = aStream->ParseUInt8(QString("%1 output channel").arg(GetName()));
|
>> mInputChannel
|
||||||
|
>> mOutputChannel;
|
||||||
|
|
||||||
// Skip padding bytes in struct
|
// Skip padding bytes in struct
|
||||||
aStream->skipRawData(2);
|
aStream->skipRawData(2);
|
||||||
|
|
||||||
mVolume = aStream->ParseSingle(QString("%1 volume").arg(GetName()));
|
*aStream >> mVolume;
|
||||||
}
|
}
|
||||||
|
|
||||||
void XAudioChannelMapEntry::Clear()
|
void XAudioChannelMapEntry::Clear()
|
||||||
|
|||||||
@ -18,7 +18,7 @@ public:
|
|||||||
float GetVolume() const;
|
float GetVolume() const;
|
||||||
void SetVolume(float aVolume);
|
void SetVolume(float aVolume);
|
||||||
|
|
||||||
virtual void ParseData(XDataStream* aStream) override;
|
virtual void ParseData(QDataStream* aStream) override;
|
||||||
virtual void Clear() override;
|
virtual void Clear() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
#include "xaudioformatinfo.h"
|
#include "xaudioformatinfo.h"
|
||||||
|
|
||||||
XAudioFormatInfo::XAudioFormatInfo()
|
XAudioFormatInfo::XAudioFormatInfo()
|
||||||
: XAsset()
|
|
||||||
, mStream()
|
|
||||||
{
|
{
|
||||||
SetName("Audio Format Info");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
XAudioFormatInfo::~XAudioFormatInfo()
|
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()
|
void XAudioFormatInfo::Clear()
|
||||||
{
|
{
|
||||||
mStream.clear();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,21 +2,22 @@
|
|||||||
#define XAUDIOFORMATINFO_H
|
#define XAUDIOFORMATINFO_H
|
||||||
|
|
||||||
#include "xasset.h"
|
#include "xasset.h"
|
||||||
#include "xaudioxmaformat.h"
|
|
||||||
|
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
|
|
||||||
|
class XAudioXmaFormat;
|
||||||
|
|
||||||
class XAudioFormatInfo : public XAsset
|
class XAudioFormatInfo : public XAsset
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit XAudioFormatInfo();
|
XAudioFormatInfo();
|
||||||
~XAudioFormatInfo();
|
~XAudioFormatInfo();
|
||||||
|
|
||||||
virtual void ParseData(XDataStream* aStream) override;
|
virtual void ParseData(QDataStream* aStream) override;
|
||||||
virtual void Clear() override;
|
virtual void Clear() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QVector<XAudioXmaFormat> mStream;
|
QVector<XAudioXmaFormat*> mStream;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // XAUDIOFORMATINFO_H
|
#endif // XAUDIOFORMATINFO_H
|
||||||
|
|||||||
@ -8,7 +8,7 @@ XAudioPacketAligned::XAudioPacketAligned()
|
|||||||
, aXmaLoop()
|
, aXmaLoop()
|
||||||
, mContext()
|
, mContext()
|
||||||
{
|
{
|
||||||
SetName("Audio Packet Aligned");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
XAudioPacketAligned::~XAudioPacketAligned()
|
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()));
|
qint32 bufferPtr, contextPtr;
|
||||||
mBufferSize = aStream->ParseUInt32(QString("%1 buffer size").arg(GetName()));
|
|
||||||
mLoopCount = aStream->ParseUInt32(QString("%1 loop count").arg(GetName()));
|
*aStream
|
||||||
|
>> bufferPtr
|
||||||
|
>> mBufferSize
|
||||||
|
>> mLoopCount;
|
||||||
|
|
||||||
for (int i = 0; i < 6; i++)
|
for (int i = 0; i < 6; i++)
|
||||||
{
|
{
|
||||||
@ -28,16 +31,15 @@ void XAudioPacketAligned::ParseData(XDataStream *aStream)
|
|||||||
loop.ParseData(aStream);
|
loop.ParseData(aStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
qint32 contextPtr = aStream->ParseInt32(QString("%1 context ptr").arg(GetName()));
|
*aStream >> contextPtr;
|
||||||
|
|
||||||
if (bufferPtr)
|
if (bufferPtr)
|
||||||
{
|
{
|
||||||
aStream->readRawData(mBuffer.data(), mBufferSize);
|
aStream->readRawData(mBuffer.data(), mBufferSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (contextPtr)
|
if (contextPtr)
|
||||||
{
|
{
|
||||||
mContext = aStream->ParseInt8(QString("%1 context").arg(GetName()));
|
*aStream >> mContext;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user