Compare commits
218 Commits
feature/te
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
91a79f78cc | ||
|
|
8d5e5812ec | ||
|
|
622323117a | ||
|
|
2fdbe74a4a | ||
|
|
13af32ed2d | ||
|
|
dd00cee809 | ||
|
|
34cafac121 | ||
|
|
4bf4c12159 | ||
|
|
754c563515 | ||
|
|
ea1a829957 | ||
|
|
ccb956a834 | ||
|
|
ba83aa5247 | ||
|
|
324e84eafc | ||
|
|
e290f2aca9 | ||
|
|
b13001ac90 | ||
|
|
1e24a2cc81 | ||
|
|
631dbdfa53 | ||
|
|
fbf295f2a8 | ||
|
|
00c84fd622 | ||
|
|
a8cee21ae8 | ||
|
|
48d7c3e692 | ||
|
|
c7291b567f | ||
|
|
ecb0e528c2 | ||
|
|
2de65b22ec | ||
|
|
a01d07ce41 | ||
|
|
348bf2a299 | ||
|
|
37c81d78ce | ||
|
|
33052d2e11 | ||
|
|
4603ebd7cf | ||
|
|
00f0a8a828 | ||
|
|
367e4e012e | ||
|
|
3bf4e8b0e5 | ||
|
|
39a5a75333 | ||
|
|
20f4dcd798 | ||
|
|
8398156122 | ||
|
|
8136ba1d34 | ||
|
|
2c18b939e7 | ||
|
|
01d2b95417 | ||
|
|
8cfb82e03d | ||
|
|
2d8d34bab8 | ||
|
|
6e772cb6b7 | ||
|
|
32ce8e350f | ||
|
|
73ab1a368a | ||
|
|
d9aa25c4af | ||
|
|
d18cfb6968 | ||
|
|
924e448270 | ||
|
|
4dc402fd16 | ||
|
|
8b802028e9 | ||
|
|
f6a20c873a | ||
|
|
4e4422466c | ||
|
|
3bf032d2e0 | ||
|
|
3d378b28c9 | ||
|
|
1f7ca563bf | ||
|
|
f6a0ff580c | ||
|
|
b9e858a6d5 | ||
|
|
f88eeec7ee | ||
|
|
9c6c55fe75 | ||
|
|
e6f2932ef1 | ||
|
|
8c1f9539c7 | ||
|
|
21379d133d | ||
|
|
6e58c8fc2f | ||
|
|
10db1eec7d | ||
|
|
d267ad19f5 | ||
|
|
99d2885f9c | ||
|
|
0545bfe642 | ||
|
|
7e408d2c2e | ||
|
|
512b9bae61 | ||
|
|
0f10bf9375 | ||
|
|
63468fa91e | ||
|
|
d9f6e13bdf | ||
|
|
e512636ad6 | ||
|
|
f2769e689f | ||
|
|
9898a03417 | ||
|
|
7174f1fe22 | ||
|
|
4480eb83d7 | ||
|
|
5ee673175c | ||
|
|
86885f999c | ||
|
|
2e4e0a6b99 | ||
|
|
338b50c694 | ||
|
|
20b57db193 | ||
|
|
7b61cff46d | ||
|
|
25728f9486 | ||
|
|
8e215f13af | ||
|
|
a71607aae3 | ||
|
|
2ae9bf95a4 | ||
|
|
08cf71cb02 | ||
|
|
8f3fa82f64 | ||
|
|
e40bee38af | ||
|
|
2799108c7d | ||
|
|
e1be487b6b | ||
|
|
383d6e2439 | ||
|
|
3452b73eb0 | ||
|
|
9dc45d3024 | ||
|
|
dc0a8a1e3d | ||
|
|
cf2102e182 | ||
|
|
6db6760a0a | ||
|
|
cdd0142759 | ||
|
|
4fbf77e661 | ||
|
|
8d31623138 | ||
|
|
acd14a2179 | ||
|
|
f09124f611 | ||
|
|
ead2e4eaf7 | ||
|
|
63ccc50de3 | ||
|
|
a753c24d9d | ||
|
|
d4bf2e0796 | ||
|
|
2472cd5d1b | ||
|
|
7bfe92eb9c | ||
|
|
990d413673 | ||
|
|
b4f677f81b | ||
|
|
59dfc3f05e | ||
|
|
3d409fc1d4 | ||
|
|
ab437b460f | ||
|
|
ff46687106 | ||
|
|
d7f099dc05 | ||
|
|
415156256a | ||
|
|
c799f53687 | ||
|
|
15ff5e65b1 | ||
|
|
a3769f0bad | ||
|
|
8a668620de | ||
|
|
935634c9e2 | ||
|
|
d13e227eb9 | ||
|
|
b977dbd183 | ||
|
|
15399a2969 | ||
|
|
bc3cc77a0a | ||
|
|
dcd6d9bf7b | ||
|
|
ddcb00676a | ||
|
|
73f9207839 | ||
|
|
bccbca87fa | ||
|
|
a24fec5558 | ||
|
|
c26ba7dcab | ||
|
|
cadcd2d53c | ||
|
|
7eca939c06 | ||
|
|
975567cdd4 | ||
|
|
2df2d491ae | ||
|
|
9b4852f393 | ||
|
|
f3d0abb65e | ||
|
|
9a5ae3bf51 | ||
|
|
d11783ebfc | ||
|
|
f5eebe6743 | ||
|
|
b8c7bdb1ba | ||
|
|
87bbe47e7e | ||
|
|
1ff6475fdb | ||
|
|
2f044a8d94 | ||
|
|
a1a54665d9 | ||
|
|
6e73c2d50c | ||
|
|
53f690c554 | ||
|
|
eebd333e11 | ||
|
|
3b65f1bdf2 | ||
|
|
a9444c05bf | ||
|
|
9a957138b5 | ||
|
|
a94e3bd012 | ||
|
|
b80cfab4fb | ||
|
|
da6233c10d | ||
|
|
43e925ae23 | ||
|
|
cd7c65ef4a | ||
|
|
fd7f466578 | ||
|
|
3a84ccd30f | ||
|
|
7fdd451cd1 | ||
|
|
59d5b12e80 | ||
|
|
d81513a95f | ||
|
|
23d577336f | ||
|
|
b9646c1140 | ||
|
|
7d103dfcea | ||
|
|
df1bad5380 | ||
|
|
6a41e543ee | ||
|
|
06e94e9648 | ||
|
|
096da843d1 | ||
|
|
ba6da187f3 | ||
|
|
11cc55dd71 | ||
|
|
e82dbce63c | ||
|
|
4677ab9637 | ||
|
|
b77e6e8077 | ||
|
|
3416060d4b | ||
|
|
ce7ed928c4 | ||
|
|
b7c7eff1b5 | ||
|
|
64b5471ea4 | ||
|
|
ef2d880039 | ||
|
|
a577d329ec | ||
|
|
80fc72e8b0 | ||
|
|
0a3fbfe39a | ||
|
|
4f430055f3 | ||
|
|
67832954e4 | ||
|
|
333de659ed | ||
|
|
0374410315 | ||
|
|
296a25d26f | ||
|
|
0e141ae95c | ||
|
|
fc1c89c710 | ||
|
|
422ceb9a25 | ||
|
|
14a494cc24 | ||
|
|
0da6a4aee7 | ||
|
|
00618f8081 | ||
|
|
d525f9bee3 | ||
|
|
ab7d2bb3b8 | ||
|
|
e2f35a0314 | ||
|
|
e4c409ab19 | ||
|
|
48c28e046d | ||
|
|
0f45fb5788 | ||
|
|
8d4303b166 | ||
|
|
857a55f133 | ||
|
|
b513834076 | ||
|
|
2131034ad9 | ||
|
|
4a53b0ff74 | ||
|
|
f7ff77b11d | ||
|
|
e06fe64311 | ||
|
|
e416d47df4 | ||
|
|
51a0d00b93 | ||
|
|
ae16506d87 | ||
|
|
75c128534e | ||
|
|
e0b7ff743c | ||
|
|
84314df7cb | ||
|
|
1545a92c27 | ||
|
|
b62c548193 | ||
|
|
d92098571e | ||
|
|
1eb340aaea | ||
|
|
6211ea3c77 | ||
|
|
3d91f1f3f4 | ||
| 365aac8cfa | |||
| b80a11093a |
3
.gitignore
vendored
3
.gitignore
vendored
@ -3,6 +3,9 @@
|
||||
/data/fastfiles/
|
||||
/releases/
|
||||
|
||||
.vscode/*
|
||||
.qmake.stash
|
||||
|
||||
# Ignore Qt Creator user files
|
||||
*.pro.user
|
||||
*.pro.user.*
|
||||
|
||||
23
.qmake.stash
23
.qmake.stash
@ -1,23 +0,0 @@
|
||||
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
4
.vscode/settings.json
vendored
@ -1,4 +0,0 @@
|
||||
{
|
||||
"workbench.colorTheme": "Default Dark Modern",
|
||||
"workbench.startupEditor": "none"
|
||||
}
|
||||
@ -2,9 +2,9 @@ TEMPLATE = subdirs
|
||||
|
||||
SUBDIRS += libs \
|
||||
app \
|
||||
tools \
|
||||
tests
|
||||
#tools \
|
||||
#tests
|
||||
|
||||
tests.depends = libs
|
||||
#tests.depends = libs
|
||||
app.depends = libs
|
||||
tools.depends = libs
|
||||
#tools.depends = libs
|
||||
|
||||
36
ai-commit.sh
Normal file
36
ai-commit.sh
Normal file
@ -0,0 +1,36 @@
|
||||
#!/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
|
||||
|
||||
LIBS += \
|
||||
#-L$$PWD/../third_party/devil_sdk/lib/ -lDevIL -lILU -lILUT \
|
||||
#-L$$PWD/../third_party/zlib/lib/ -lzlib \
|
||||
#-L$$PWD/../third_party/xbox_sdk/lib -lxcompress64 \
|
||||
-L$$PWD/../third_party/devil_sdk/lib/ -lDevIL -lILU -lILUT \
|
||||
-L$$PWD/../third_party/zlib/lib/ -lzlib \
|
||||
-L$$PWD/../third_party/xbox_sdk/lib -lxcompress64 \
|
||||
-L$$OUT_PWD/../libs/ -lcore \
|
||||
-L$$OUT_PWD/../libs/ -lxassets\
|
||||
-L$$OUT_PWD/../libs/ -lcompression \
|
||||
@ -27,9 +27,9 @@ LIBS += \
|
||||
-L$$OUT_PWD/../libs/ -lzonefile
|
||||
|
||||
INCLUDEPATH += \
|
||||
#$$PWD/../third_party/devil_sdk/include/ \
|
||||
#$$PWD/../third_party/zlib/include \
|
||||
#$$PWD/../third_party/xbox_sdk/include \
|
||||
$$PWD/../third_party/devil_sdk/include/ \
|
||||
$$PWD/../third_party/zlib/include \
|
||||
$$PWD/../third_party/xbox_sdk/include \
|
||||
$$PWD/../libs/core \
|
||||
$$PWD/../libs/compression \
|
||||
$$PWD/../libs/encryption \
|
||||
@ -41,9 +41,9 @@ INCLUDEPATH += \
|
||||
$$PWD/../libs/zonefile
|
||||
|
||||
DEPENDPATH += \
|
||||
#$$PWD/../third_party/devil_sdk/include/ \
|
||||
#$$PWD/../third_party/zlib/include \
|
||||
#$$PWD/../third_party/xbox_sdk/include \
|
||||
$$PWD/../third_party/devil_sdk/include/ \
|
||||
$$PWD/../third_party/zlib/include \
|
||||
$$PWD/../third_party/xbox_sdk/include \
|
||||
$$PWD/../libs/core \
|
||||
$$PWD/../libs/compression \
|
||||
$$PWD/../libs/encryption \
|
||||
|
||||
@ -533,7 +533,7 @@ bool MainWindow::OpenFastFile(const QString aFastFilePath) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FastFile* fastFile = FastFileFactory::Create(aFastFilePath);
|
||||
FastFile* fastFile = FastFile::Open(aFastFilePath);
|
||||
fastFile->SetStem(fastFileStem);
|
||||
mTreeWidget->AddFastFile(fastFile);
|
||||
|
||||
@ -548,7 +548,7 @@ bool MainWindow::OpenFastFile(const QByteArray& aFastFileData, const QString aFa
|
||||
return false;
|
||||
}
|
||||
|
||||
FastFile* fastFile = FastFileFactory::Create(aFastFileData);
|
||||
FastFile* fastFile = FastFile::Open(aFastFileData);
|
||||
fastFile->SetStem(fastFileStem);
|
||||
mTreeWidget->AddFastFile(fastFile);
|
||||
|
||||
@ -789,7 +789,7 @@ int MainWindow::LoadFile_IPAK(const QString aFilePath) {
|
||||
|
||||
QVector<IPAKIndexEntry> entries = QVector<IPAKIndexEntry>();
|
||||
QVector<IPAKSection> sections = QVector<IPAKSection>(header.sectionCount);
|
||||
for (uint i = 0; i < header.sectionCount; i++) {
|
||||
for (quint32 i = 0; i < header.sectionCount; i++) {
|
||||
IPAKSection currentSection;
|
||||
stream >> currentSection;
|
||||
sections << currentSection;
|
||||
@ -811,7 +811,7 @@ int MainWindow::LoadFile_IPAK(const QString aFilePath) {
|
||||
<< " - Count: " << chunkHeader.count << "\n"
|
||||
<< " - Offset: " << chunkHeader.offset;
|
||||
|
||||
for (uint j = 0; j < 31; j++) {
|
||||
for (quint32 j = 0; j < 31; j++) {
|
||||
IPAKDataChunkCommand command;
|
||||
stream >> command;
|
||||
if (!command.size) { continue; }
|
||||
@ -821,7 +821,7 @@ int MainWindow::LoadFile_IPAK(const QString aFilePath) {
|
||||
<< " - Compressed: " << command.compressed;
|
||||
|
||||
}
|
||||
for (uint j = 0; j < chunkHeader.count; j++) {
|
||||
for (quint32 j = 0; j < chunkHeader.count; j++) {
|
||||
auto command = chunkHeader.commands[j];
|
||||
|
||||
qDebug() << "Reading from " << stream.device()->pos();
|
||||
@ -846,7 +846,7 @@ int MainWindow::LoadFile_IPAK(const QString aFilePath) {
|
||||
stream.skipRawData(sizeof(quint32) * (31 - chunkHeader.count));
|
||||
qDebug() << stream.device()->pos();
|
||||
} else if (sectionType == "Index") {
|
||||
for (uint j = 0; j < currentSection.itemCount; j++) {
|
||||
for (quint32 j = 0; j < currentSection.itemCount; j++) {
|
||||
IPAKIndexEntry entry;
|
||||
stream >> entry;
|
||||
|
||||
|
||||
@ -3,19 +3,27 @@
|
||||
|
||||
MaterialViewer::MaterialViewer(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, ui(new Ui::MaterialViewer) {
|
||||
, ui(new Ui::MaterialViewer)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
MaterialViewer::~MaterialViewer() {
|
||||
MaterialViewer::~MaterialViewer()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
QString ToHexStr(quint32 in) {
|
||||
QString ToHexStr(quint32 in)
|
||||
{
|
||||
return QString("%1").arg(in, 8, 16, QChar('0')).toUpper();
|
||||
}
|
||||
|
||||
void MaterialViewer::SetMaterial(const XMaterial* aMaterial) {
|
||||
void MaterialViewer::SetMaterial(const XMaterial* aMaterial)
|
||||
{
|
||||
Q_UNUSED(aMaterial);
|
||||
|
||||
// TODO: Fill in MaterialViewer::SetMaterial
|
||||
|
||||
// ui->lineEdit_NamePtr->setText(ToHexStr(aMaterial->namePtr));
|
||||
// ui->lineEdit_Name->setText(aMaterial->name);
|
||||
// ui->lineEdit_RefPtr->setText(ToHexStr(aMaterial->refNamePtr));
|
||||
|
||||
@ -22,7 +22,7 @@ RumbleGraphViewer::~RumbleGraphViewer() {
|
||||
void RumbleGraphViewer::SetRumbleGraphFile(const XRawFile* aRawFile) {
|
||||
mRumbleGraphFile = aRawFile;
|
||||
|
||||
QDataStream rawFileStream;//(mRumbleGraphFile->contents.toLatin1());
|
||||
XDataStream rawFileStream;//(mRumbleGraphFile->contents.toLatin1());
|
||||
|
||||
QByteArray magic(15, Qt::Uninitialized);
|
||||
rawFileStream.readRawData(magic.data(), 15);
|
||||
|
||||
@ -490,12 +490,12 @@ void XTreeWidget::PrepareContextMenu(const QPoint &pos) {
|
||||
});
|
||||
QAction *exportZoneFileAction = new QAction("Export Zone File");
|
||||
exportSubmenu->addAction(exportZoneFileAction);
|
||||
connect(exportZoneFileAction, &QAction::triggered, this, [fastFile](bool checked) {
|
||||
connect(exportZoneFileAction, &QAction::triggered, this, [](bool checked) {
|
||||
Q_UNUSED(checked);
|
||||
|
||||
const QString zoneFilePath = QFileDialog::getSaveFileName(
|
||||
nullptr, "Export Zone File...", QDir::currentPath(),
|
||||
"Zone File (*.zone);;All Files(*.*)");
|
||||
// const QString zoneFilePath = QFileDialog::getSaveFileName(
|
||||
// nullptr, "Export Zone File...", QDir::currentPath(),
|
||||
// "Zone File (*.zone);;All Files(*.*)");
|
||||
//fastFile->GetZoneFile()->SaveZoneFile(zoneFilePath);
|
||||
});
|
||||
} else if (activeText.contains(".zone")) {
|
||||
@ -508,7 +508,7 @@ void XTreeWidget::PrepareContextMenu(const QPoint &pos) {
|
||||
QMenu *exportSubmenu = new QMenu("Export...", this);
|
||||
contextMenu->addMenu(exportSubmenu);
|
||||
|
||||
const ZoneFile* zoneFile = mZoneFiles[fileStem];
|
||||
//const ZoneFile* zoneFile = mZoneFiles[fileStem];
|
||||
|
||||
QAction *exportZoneFileAction = new QAction("Export Zone File");
|
||||
exportSubmenu->addAction(exportZoneFileAction);
|
||||
@ -530,7 +530,7 @@ void XTreeWidget::PrepareContextMenu(const QPoint &pos) {
|
||||
}
|
||||
}
|
||||
if (parentItem && parentItem != invisibleRootItem() && parentItem->text(0).contains(".zone")) {
|
||||
const QString fileStem = parentItem->text(0).section('.', 0, 0);
|
||||
//const QString fileStem = parentItem->text(0).section('.', 0, 0);
|
||||
// QVector<LoadedSound> LoadedSounds = mZoneFiles[fileStem]->GetAssetMap().sounds;
|
||||
// for (LoadedSound LoadedSound : LoadedSounds) {
|
||||
// for (Sound sound : LoadedSound.sounds) {
|
||||
@ -577,14 +577,14 @@ void XTreeWidget::PrepareContextMenu(const QPoint &pos) {
|
||||
}
|
||||
if (parentItem && parentItem != invisibleRootItem() && parentItem->text(0).contains(".zone")) {
|
||||
const QString fileStem = parentItem->text(0).section('.', 0, 0);
|
||||
auto zoneFile = mZoneFiles[fileStem];
|
||||
//auto zoneFile = mZoneFiles[fileStem];
|
||||
|
||||
QMenu *exportSubmenu = new QMenu("Export...", this);
|
||||
contextMenu->addMenu(exportSubmenu);
|
||||
|
||||
QAction *exportAllWAVAction = new QAction("Export ALL as WAV Files");
|
||||
exportSubmenu->addAction(exportAllWAVAction);
|
||||
connect(exportAllWAVAction, &QAction::triggered, this, [zoneFile](bool checked) {
|
||||
connect(exportAllWAVAction, &QAction::triggered, this, [](bool checked) {
|
||||
Q_UNUSED(checked);
|
||||
|
||||
// for (LoadedSound LoadedSound : zoneFile->GetAssetMap().sounds) {
|
||||
|
||||
@ -1,73 +1,91 @@
|
||||
#include "compression.h"
|
||||
//#include "minilzo.h"
|
||||
|
||||
//#define XBOXAPI __declspec(dllimport)
|
||||
//#include "xcompress.h"
|
||||
#include "minilzo.h"
|
||||
#include "xcompress.h"
|
||||
|
||||
#include <QLibrary>
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QDataStream>
|
||||
|
||||
QByteArray Compression::CompressXMem(const QByteArray &data)
|
||||
{
|
||||
// XMEMCODEC_PARAMETERS_LZX lzxParams = {};
|
||||
// lzxParams.Flags = 0;
|
||||
// lzxParams.WindowSize = 0x20000;
|
||||
// lzxParams.CompressionPartitionSize = 0x80000;
|
||||
XMEMCODEC_PARAMETERS_LZX lzxParams = {};
|
||||
lzxParams.Flags = 0;
|
||||
lzxParams.WindowSize = 0x20000;
|
||||
lzxParams.CompressionPartitionSize = 0x80000;
|
||||
|
||||
// XMEMCOMPRESSION_CONTEXT ctx = nullptr;
|
||||
// if (FAILED(XMemCreateCompressionContext(XMEMCODEC_LZX, &lzxParams, 0, &ctx)) || !ctx)
|
||||
// return QByteArray();
|
||||
XMEMCOMPRESSION_CONTEXT ctx = nullptr;
|
||||
if (FAILED(XMemCreateCompressionContext(XMEMCODEC_LZX, &lzxParams, 0, &ctx)) || !ctx)
|
||||
return QByteArray();
|
||||
|
||||
// SIZE_T estimatedSize = data.size() + XCOMPRESS_LZX_BLOCK_GROWTH_SIZE_MAX;
|
||||
// QByteArray output(static_cast<int>(estimatedSize), 0);
|
||||
// SIZE_T actualSize = estimatedSize;
|
||||
SIZE_T estimatedSize = data.size() + XCOMPRESS_LZX_BLOCK_GROWTH_SIZE_MAX;
|
||||
QByteArray output(static_cast<int>(estimatedSize), 0);
|
||||
SIZE_T actualSize = estimatedSize;
|
||||
|
||||
// HRESULT hr = XMemCompress(ctx, output.data(), &actualSize, data.constData(), data.size());
|
||||
// XMemDestroyCompressionContext(ctx);
|
||||
HRESULT hr = XMemCompress(ctx, output.data(), &actualSize, data.constData(), data.size());
|
||||
XMemDestroyCompressionContext(ctx);
|
||||
|
||||
// if (FAILED(hr))
|
||||
// return QByteArray();
|
||||
if (FAILED(hr))
|
||||
return QByteArray();
|
||||
|
||||
// output.resize(static_cast<int>(actualSize));
|
||||
// return output;
|
||||
return QByteArray();
|
||||
output.resize(static_cast<int>(actualSize));
|
||||
return output;
|
||||
}
|
||||
|
||||
QByteArray Compression::DecompressXMem(const QByteArray &data, int flags, int windowSize, int partSize)
|
||||
QByteArray Compression::DecompressXMem(const QByteArray &data,
|
||||
int flags, int windowSize, int partSize)
|
||||
{
|
||||
// if (data.isEmpty())
|
||||
// return {};
|
||||
if (data.isEmpty())
|
||||
return {};
|
||||
|
||||
// XMEMCODEC_PARAMETERS_LZX lzxParams = {};
|
||||
// lzxParams.Flags = flags;
|
||||
// lzxParams.WindowSize = windowSize;
|
||||
// lzxParams.CompressionPartitionSize = partSize;
|
||||
XMEMCODEC_PARAMETERS_LZX lzxParams = {};
|
||||
lzxParams.Flags = flags;
|
||||
lzxParams.WindowSize = windowSize;
|
||||
lzxParams.CompressionPartitionSize = partSize;
|
||||
|
||||
// XMEMDECOMPRESSION_CONTEXT ctx = nullptr;
|
||||
// if (FAILED(XMemCreateDecompressionContext(XMEMCODEC_LZX, &lzxParams, 0, &ctx)) || !ctx)
|
||||
// return {};
|
||||
QByteArray internalState(0x94933, Qt::Uninitialized);
|
||||
|
||||
// // Allocate large enough buffer for decompression (16 MB is a safe upper bound)
|
||||
// const SIZE_T kMaxOutSize = 16 * 1024 * 1024;
|
||||
// QByteArray output(static_cast<int>(kMaxOutSize), Qt::Uninitialized);
|
||||
// SIZE_T actualSize = kMaxOutSize;
|
||||
XMEMDECOMPRESSION_CONTEXT ctx = XMemInitializeDecompressionContext(
|
||||
XMEMCODEC_LZX, &lzxParams, 1,
|
||||
internalState.data(), internalState.size());
|
||||
|
||||
// HRESULT hr = XMemDecompress(ctx,
|
||||
// output.data(), &actualSize,
|
||||
// data.constData(), data.size() + 16);
|
||||
if (!ctx || XMemResetDecompressionContext(ctx)) {
|
||||
qWarning() << "Failed to init LZX context";
|
||||
return {};
|
||||
}
|
||||
|
||||
// XMemDestroyDecompressionContext(ctx);
|
||||
QByteArray output;
|
||||
output.reserve(16 * 1024 * 1024); // rough guess
|
||||
|
||||
// if (FAILED(hr)) {
|
||||
// qWarning() << "XMemDecompress failed with HRESULT:" << hr;
|
||||
// return {};
|
||||
// }
|
||||
const quint8 *nextIn = reinterpret_cast<const quint8*>(data.constData());
|
||||
SIZE_T availIn = data.size();
|
||||
|
||||
// output.resize(static_cast<int>(actualSize));
|
||||
// return output;
|
||||
return QByteArray();
|
||||
QByteArray scratch(0x10000, Qt::Uninitialized); // 64 KB chunks
|
||||
|
||||
while (availIn > 0) {
|
||||
SIZE_T inSize = availIn; // let XMem tell us how much it will consume
|
||||
SIZE_T outSize = scratch.size(); // max 64 KB per call
|
||||
|
||||
HRESULT hr = XMemDecompressStream(ctx,
|
||||
scratch.data(), &outSize,
|
||||
nextIn, &inSize);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
qWarning() << "XMemDecompressStream failed, hr=" << hr;
|
||||
XMemDestroyDecompressionContext(ctx);
|
||||
return {};
|
||||
}
|
||||
|
||||
if (inSize == 0 && outSize == 0)
|
||||
break; // no progress
|
||||
|
||||
output.append(scratch.constData(), static_cast<int>(outSize));
|
||||
|
||||
nextIn += inSize;
|
||||
availIn -= inSize;
|
||||
}
|
||||
|
||||
XMemDestroyDecompressionContext(ctx);
|
||||
return output;
|
||||
}
|
||||
|
||||
quint32 Compression::CalculateAdler32Checksum(const QByteArray &data) {
|
||||
@ -82,19 +100,18 @@ quint32 Compression::CalculateAdler32Checksum(const QByteArray &data) {
|
||||
|
||||
qint64 Compression::FindZlibOffset(const QByteArray &bytes)
|
||||
{
|
||||
static const QByteArray iwffs("IWffs");
|
||||
auto idx = bytes.indexOf(iwffs);
|
||||
if (idx != -1)
|
||||
return idx + 0x4000;
|
||||
QDataStream stream(bytes);
|
||||
|
||||
const char header = 0x78; // z-lib: 0x78 [FLG]
|
||||
int pos = -1;
|
||||
while ((pos = bytes.indexOf(header, pos + 1)) != -1)
|
||||
while (!stream.atEnd())
|
||||
{
|
||||
QByteArray window = bytes.mid(pos, 0x20);
|
||||
if (!window.contains(QByteArray::fromHex("000000")) &&
|
||||
!window.contains(QByteArray::fromHex("FFFFFF")))
|
||||
return pos;
|
||||
QByteArray testSegment = stream.device()->peek(2).toHex().toUpper();
|
||||
if (testSegment == "7801" ||
|
||||
testSegment == "785E" ||
|
||||
testSegment == "789C" ||
|
||||
testSegment == "78DA") {
|
||||
return stream.device()->pos();
|
||||
}
|
||||
stream.skipRawData(1);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@ -298,22 +315,22 @@ QByteArray Compression::CompressDeflateWithSettings(const QByteArray &aData, int
|
||||
|
||||
QByteArray Compression::DecompressLZO(const QByteArray &aCompressedData, quint32 aDestSize) {
|
||||
QByteArray dst;
|
||||
// static bool ok = (lzo_init() == LZO_E_OK);
|
||||
// if (!ok)
|
||||
// throw std::runtime_error("lzo_init failed");
|
||||
static bool ok = (lzo_init() == LZO_E_OK);
|
||||
if (!ok)
|
||||
throw std::runtime_error("lzo_init failed");
|
||||
|
||||
// dst = QByteArray(aDestSize, Qt::Uninitialized);
|
||||
// lzo_uint out = aDestSize;
|
||||
dst = QByteArray(aDestSize, Qt::Uninitialized);
|
||||
lzo_uint out = aDestSize;
|
||||
|
||||
// int rc = lzo1x_decompress_safe(
|
||||
// reinterpret_cast<const lzo_bytep>(aCompressedData.constData()),
|
||||
// static_cast<lzo_uint>(aCompressedData.size()),
|
||||
// reinterpret_cast<lzo_bytep>(dst.data()),
|
||||
// &out,
|
||||
// nullptr);
|
||||
int rc = lzo1x_decompress_safe(
|
||||
reinterpret_cast<const lzo_bytep>(aCompressedData.constData()),
|
||||
static_cast<lzo_uint>(aCompressedData.size()),
|
||||
reinterpret_cast<lzo_bytep>(dst.data()),
|
||||
&out,
|
||||
nullptr);
|
||||
|
||||
// if (rc != LZO_E_OK || out != aDestSize)
|
||||
// throw std::runtime_error("LZO decompression error");
|
||||
if (rc != LZO_E_OK || out != aDestSize)
|
||||
throw std::runtime_error("LZO decompression error");
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
@ -3,13 +3,14 @@ TEMPLATE = lib
|
||||
CONFIG += staticlib c++17
|
||||
DEFINES += MINILZO_USE_STATIC
|
||||
|
||||
SOURCES += $$files($$PWD/*.cpp, true)
|
||||
SOURCES += $$files($$PWD/*.cpp, true) \
|
||||
$$files($$PWD/*.c, true)
|
||||
HEADERS += $$files($$PWD/*.h, true)
|
||||
|
||||
LIBS += \
|
||||
-L$$PWD/../../third_party/xbox_sdk/lib -lxcompress64 \
|
||||
-L$$OUT_PWD/../libs/core -lcore \
|
||||
-L$$OUT_PWD/../libs/encryption -lencryption
|
||||
-L$$PWD/../../third_party/xbox_sdk/lib -lxcompress64 \
|
||||
-L$$OUT_PWD/../libs/core -lcore \
|
||||
-L$$OUT_PWD/../libs/encryption -lencryption
|
||||
|
||||
INCLUDEPATH += \
|
||||
$$PWD/../../third_party/xbox_sdk/include \
|
||||
|
||||
@ -57,7 +57,7 @@
|
||||
|
||||
/* get OS and architecture defines */
|
||||
#ifndef __LZODEFS_H_INCLUDED
|
||||
#include <lzo/lzodefs.h>
|
||||
#include <lzodefs.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@ -25,12 +25,6 @@
|
||||
http://www.oberhumer.com/opensource/lzo/
|
||||
*/
|
||||
|
||||
/*
|
||||
* NOTE:
|
||||
* the full LZO package can be found at
|
||||
* http://www.oberhumer.com/opensource/lzo/
|
||||
*/
|
||||
|
||||
#define __LZO_IN_MINILZO 1
|
||||
|
||||
#if defined(LZO_CFG_FREESTANDING)
|
||||
|
||||
@ -25,13 +25,6 @@
|
||||
http://www.oberhumer.com/opensource/lzo/
|
||||
*/
|
||||
|
||||
/*
|
||||
* NOTE:
|
||||
* the full LZO package can be found at
|
||||
* http://www.oberhumer.com/opensource/lzo/
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __MINILZO_H_INCLUDED
|
||||
#define __MINILZO_H_INCLUDED 1
|
||||
|
||||
|
||||
@ -2,8 +2,10 @@ QT += core widgets
|
||||
TEMPLATE = lib
|
||||
CONFIG += staticlib c++17
|
||||
|
||||
SOURCES += $$files($$PWD/*.cpp, true)
|
||||
HEADERS += $$files($$PWD/*.h, true)
|
||||
SOURCES += $$files($$PWD/*.cpp, true) \
|
||||
xdatastream.cpp
|
||||
HEADERS += $$files($$PWD/*.h, true) \
|
||||
xdatastream.h
|
||||
|
||||
LIBS += -L$$OUT_PWD/../libs/xassets -lxassets
|
||||
|
||||
|
||||
@ -4,9 +4,9 @@
|
||||
#include <QString>
|
||||
|
||||
enum IWI_VERSION {
|
||||
IWI_VERSION_COD2 = 0x05, // 05 CoD2
|
||||
IWI_VERSION_COD4 = 0x06, // 06 CoD4
|
||||
IWI_VERSION_COD5 = 0x06, // 06 CoD5
|
||||
IWI_VERSION_COD2 = 0x05, // 05 CoD2
|
||||
IWI_VERSION_COD4 = 0x06, // 06 CoD4
|
||||
IWI_VERSION_COD5 = 0x06, // 06 CoD5
|
||||
IWI_VERSION_CODMW2 = 0x08, // 08 CoDMW2
|
||||
IWI_VERSION_CODMW3 = 0x08, // 08 CoDMW3
|
||||
IWI_VERSION_CODBO1 = 0x0D, // 13 CoDBO1
|
||||
@ -16,37 +16,37 @@ enum IWI_VERSION {
|
||||
enum IWI_FORMAT {
|
||||
// IWI Format
|
||||
IWI_FORMAT_ARGB32 = 0x01, // 01 ARGB32
|
||||
IWI_FORMAT_RGB24 = 0x02, // 02 RGB24
|
||||
IWI_FORMAT_GA16 = 0x03, // 03 GA16
|
||||
IWI_FORMAT_A8 = 0x04, // 04 A8
|
||||
IWI_FORMAT_DXT1 = 0x0B, // 11 DXT1
|
||||
IWI_FORMAT_DXT3 = 0x0C, // 12 DXT3
|
||||
IWI_FORMAT_DXT5 = 0x0D // 13 DXT5
|
||||
IWI_FORMAT_RGB24 = 0x02, // 02 RGB24
|
||||
IWI_FORMAT_GA16 = 0x03, // 03 GA16
|
||||
IWI_FORMAT_A8 = 0x04, // 04 A8
|
||||
IWI_FORMAT_DXT1 = 0x0B, // 11 DXT1
|
||||
IWI_FORMAT_DXT3 = 0x0C, // 12 DXT3
|
||||
IWI_FORMAT_DXT5 = 0x0D // 13 DXT5
|
||||
};
|
||||
|
||||
enum DDS_FLAGS {
|
||||
DDSD_CAPS = 0x1,
|
||||
DDSD_HEIGHT = 0x2,
|
||||
DDSD_WIDTH = 0x4,
|
||||
DDSD_PITCH = 0x8,
|
||||
DDSD_CAPS = 0x1,
|
||||
DDSD_HEIGHT = 0x2,
|
||||
DDSD_WIDTH = 0x4,
|
||||
DDSD_PITCH = 0x8,
|
||||
DDSD_PIXELFORMAT = 0x1000,
|
||||
DDSD_MIPMAPCOUNT = 0x20000,
|
||||
DDSD_LINEARSIZE = 0x80000,
|
||||
DDSD_DEPTH = 0x800000
|
||||
DDSD_LINEARSIZE = 0x80000,
|
||||
DDSD_DEPTH = 0x800000
|
||||
};
|
||||
|
||||
enum DDS_PIXELFORMAT_FLAGS {
|
||||
DDPF_ALPHAPIXELS = 0x1,
|
||||
DDPF_ALPHA = 0x2,
|
||||
DDPF_FOURCC = 0x4,
|
||||
DDPF_RGB = 0x40,
|
||||
DDPF_YUV = 0x200,
|
||||
DDPF_LUMINANCE = 0x20000
|
||||
DDPF_ALPHA = 0x2,
|
||||
DDPF_FOURCC = 0x4,
|
||||
DDPF_RGB = 0x40,
|
||||
DDPF_YUV = 0x200,
|
||||
DDPF_LUMINANCE = 0x20000
|
||||
};
|
||||
|
||||
enum DDS_CAPS_FLAGS {
|
||||
DDSCAPS_COMPLEX = 0x8,
|
||||
DDSCAPS_MIPMAP = 0x400000,
|
||||
DDSCAPS_MIPMAP = 0x400000,
|
||||
DDSCAPS_TEXTURE = 0x1000
|
||||
};
|
||||
|
||||
@ -189,15 +189,15 @@ enum MENU_ITEM_TYPE {
|
||||
ITEM_TYPE_RADIOBUTTON = 2, // toggle button, may be grouped
|
||||
ITEM_TYPE_CHECKBOX = 3, // check box
|
||||
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_MODEL = 7, // model
|
||||
ITEM_TYPE_MODEL = 7, // model
|
||||
ITEM_TYPE_OWNERDRAW = 8, // owner draw, name specs what it is
|
||||
ITEM_TYPE_NUMERICFIELD = 9, // editable text, associated with a dvar
|
||||
ITEM_TYPE_SLIDER = 10, // mouse speed, volume, etc.
|
||||
ITEM_TYPE_YESNO = 11, // yes no dvar setting
|
||||
ITEM_TYPE_MULTI = 12, // multiple list setting, enumerated
|
||||
ITEM_TYPE_DVARENUM = 13, // multiple list setting, enumerated from a dvar
|
||||
ITEM_TYPE_YESNO = 11, // yes no dvar setting
|
||||
ITEM_TYPE_MULTI = 12, // multiple list setting, enumerated
|
||||
ITEM_TYPE_DVARENUM = 13, // multiple list setting, enumerated from a dvar
|
||||
ITEM_TYPE_BIND = 14, // bind
|
||||
ITEM_TYPE_MENUMODEL = 15, // special menu model
|
||||
ITEM_TYPE_VALIDFILEFIELD = 16, // text must be valid for use in a dos filename
|
||||
|
||||
@ -223,7 +223,7 @@ public:
|
||||
|
||||
return color;
|
||||
}
|
||||
static bool ReadUntilString(QDataStream* stream, const QString& targetString) {
|
||||
static bool ReadUntilString(XDataStream* stream, const QString& targetString) {
|
||||
if (!stream || targetString.isEmpty()) {
|
||||
return false; // Invalid input
|
||||
}
|
||||
@ -257,7 +257,7 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool ReadUntilHex(QDataStream* stream, const QString& hexString) {
|
||||
static bool ReadUntilHex(XDataStream* stream, const QString& hexString) {
|
||||
if (!stream || hexString.isEmpty() || hexString.size() % 2 != 0) {
|
||||
return false; // Invalid input
|
||||
}
|
||||
|
||||
243
libs/core/xdatastream.cpp
Normal file
243
libs/core/xdatastream.cpp
Normal file
@ -0,0 +1,243 @@
|
||||
#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;
|
||||
}
|
||||
34
libs/core/xdatastream.h
Normal file
34
libs/core/xdatastream.h
Normal file
@ -0,0 +1,34 @@
|
||||
#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 {
|
||||
IWI_VERSION_COD2 = 0x05, // 05 CoD2
|
||||
IWI_VERSION_COD4 = 0x06, // 06 CoD4
|
||||
IWI_VERSION_COD5 = 0x06, // 06 CoD5
|
||||
IWI_VERSION_COD2 = 0x05, // 05 CoD2
|
||||
IWI_VERSION_COD4 = 0x06, // 06 CoD4
|
||||
IWI_VERSION_COD5 = 0x06, // 06 CoD5
|
||||
IWI_VERSION_CODMW2 = 0x08, // 08 CoDMW2
|
||||
IWI_VERSION_CODMW3 = 0x08, // 08 CoDMW3
|
||||
IWI_VERSION_CODBO1 = 0x0D, // 13 CoDBO1
|
||||
@ -36,37 +36,37 @@ enum IWI_VERSION {
|
||||
enum IWI_FORMAT {
|
||||
// IWI Format
|
||||
IWI_FORMAT_ARGB32 = 0x01, // 01 ARGB32
|
||||
IWI_FORMAT_RGB24 = 0x02, // 02 RGB24
|
||||
IWI_FORMAT_GA16 = 0x03, // 03 GA16
|
||||
IWI_FORMAT_A8 = 0x04, // 04 A8
|
||||
IWI_FORMAT_DXT1 = 0x0B, // 11 DXT1
|
||||
IWI_FORMAT_DXT3 = 0x0C, // 12 DXT3
|
||||
IWI_FORMAT_DXT5 = 0x0D // 13 DXT5
|
||||
IWI_FORMAT_RGB24 = 0x02, // 02 RGB24
|
||||
IWI_FORMAT_GA16 = 0x03, // 03 GA16
|
||||
IWI_FORMAT_A8 = 0x04, // 04 A8
|
||||
IWI_FORMAT_DXT1 = 0x0B, // 11 DXT1
|
||||
IWI_FORMAT_DXT3 = 0x0C, // 12 DXT3
|
||||
IWI_FORMAT_DXT5 = 0x0D // 13 DXT5
|
||||
};
|
||||
|
||||
enum DDS_FLAGS {
|
||||
DDSD_CAPS = 0x1,
|
||||
DDSD_HEIGHT = 0x2,
|
||||
DDSD_WIDTH = 0x4,
|
||||
DDSD_PITCH = 0x8,
|
||||
DDSD_CAPS = 0x1,
|
||||
DDSD_HEIGHT = 0x2,
|
||||
DDSD_WIDTH = 0x4,
|
||||
DDSD_PITCH = 0x8,
|
||||
DDSD_PIXELFORMAT = 0x1000,
|
||||
DDSD_MIPMAPCOUNT = 0x20000,
|
||||
DDSD_LINEARSIZE = 0x80000,
|
||||
DDSD_DEPTH = 0x800000
|
||||
DDSD_LINEARSIZE = 0x80000,
|
||||
DDSD_DEPTH = 0x800000
|
||||
};
|
||||
|
||||
enum DDS_PIXELFORMAT_FLAGS {
|
||||
DDPF_ALPHAPIXELS = 0x1,
|
||||
DDPF_ALPHA = 0x2,
|
||||
DDPF_FOURCC = 0x4,
|
||||
DDPF_RGB = 0x40,
|
||||
DDPF_YUV = 0x200,
|
||||
DDPF_LUMINANCE = 0x20000
|
||||
DDPF_ALPHA = 0x2,
|
||||
DDPF_FOURCC = 0x4,
|
||||
DDPF_RGB = 0x40,
|
||||
DDPF_YUV = 0x200,
|
||||
DDPF_LUMINANCE = 0x20000
|
||||
};
|
||||
|
||||
enum DDS_CAPS_FLAGS {
|
||||
DDSCAPS_COMPLEX = 0x8,
|
||||
DDSCAPS_MIPMAP = 0x400000,
|
||||
DDSCAPS_MIPMAP = 0x400000,
|
||||
DDSCAPS_TEXTURE = 0x1000
|
||||
};
|
||||
|
||||
@ -209,15 +209,15 @@ enum MENU_ITEM_TYPE {
|
||||
ITEM_TYPE_RADIOBUTTON = 2, // toggle button, may be grouped
|
||||
ITEM_TYPE_CHECKBOX = 3, // check box
|
||||
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_MODEL = 7, // model
|
||||
ITEM_TYPE_MODEL = 7, // model
|
||||
ITEM_TYPE_OWNERDRAW = 8, // owner draw, name specs what it is
|
||||
ITEM_TYPE_NUMERICFIELD = 9, // editable text, associated with a dvar
|
||||
ITEM_TYPE_SLIDER = 10, // mouse speed, volume, etc.
|
||||
ITEM_TYPE_YESNO = 11, // yes no dvar setting
|
||||
ITEM_TYPE_MULTI = 12, // multiple list setting, enumerated
|
||||
ITEM_TYPE_DVARENUM = 13, // multiple list setting, enumerated from a dvar
|
||||
ITEM_TYPE_YESNO = 11, // yes no dvar setting
|
||||
ITEM_TYPE_MULTI = 12, // multiple list setting, enumerated
|
||||
ITEM_TYPE_DVARENUM = 13, // multiple list setting, enumerated from a dvar
|
||||
ITEM_TYPE_BIND = 14, // bind
|
||||
ITEM_TYPE_MENUMODEL = 15, // special menu model
|
||||
ITEM_TYPE_VALIDFILEFIELD = 16, // text must be valid for use in a dos filename
|
||||
|
||||
@ -1,15 +1,5 @@
|
||||
/* 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. ***
|
||||
*
|
||||
|
||||
@ -1,27 +1,35 @@
|
||||
#include "encryption.h"
|
||||
#include <QtCore>
|
||||
#include "QtZlib/zlib.h"
|
||||
#include "ecrypt-sync.h"
|
||||
#include "sha1.h"
|
||||
#include "encryption.h"
|
||||
#include "compression.h"
|
||||
|
||||
void Encryption::Convert32BitTo8Bit(quint32 value, quint8 *array) {
|
||||
static QVector<quint32> ivCounter(4, 1); // start all counters at 1
|
||||
|
||||
void Encryption::Convert32BitTo8Bit(quint32 value, quint8 *array)
|
||||
{
|
||||
array[0] = static_cast<quint8>(value >> 0);
|
||||
array[1] = static_cast<quint8>(value >> 8);
|
||||
array[2] = static_cast<quint8>(value >> 16);
|
||||
array[3] = static_cast<quint8>(value >> 24);
|
||||
}
|
||||
|
||||
quint32 Encryption::ConvertArrayTo32Bit(const QByteArray &array) {
|
||||
quint32 Encryption::ConvertArrayTo32Bit(const QByteArray &array)
|
||||
{
|
||||
return ((static_cast<quint32>(static_cast<uchar>(array[0])) << 0) |
|
||||
(static_cast<quint32>(static_cast<uchar>(array[1])) << 8) |
|
||||
(static_cast<quint32>(static_cast<uchar>(array[2])) << 16) |
|
||||
(static_cast<quint32>(static_cast<uchar>(array[3])) << 24));
|
||||
}
|
||||
|
||||
quint32 Encryption::Rotate(quint32 value, quint32 numBits) {
|
||||
quint32 Encryption::Rotate(quint32 value, quint32 numBits)
|
||||
{
|
||||
return (value << numBits) | (value >> (32 - numBits));
|
||||
}
|
||||
|
||||
QByteArray Encryption::InitIVTable(const QByteArray &feed) {
|
||||
QByteArray Encryption::InitIVTable(const QByteArray &feed)
|
||||
{
|
||||
const int tableSize = 0xFB0;
|
||||
QByteArray table;
|
||||
table.resize(tableSize);
|
||||
@ -31,7 +39,7 @@ QByteArray Encryption::InitIVTable(const QByteArray &feed) {
|
||||
if (static_cast<uchar>(feed.at(ptr)) == 0x00)
|
||||
ptr = 0;
|
||||
int base = i * 20 + x * 4;
|
||||
table[base] = feed.at(ptr);
|
||||
table[base] = feed.at(ptr);
|
||||
table[base + 1] = feed.at(ptr);
|
||||
table[base + 2] = feed.at(ptr);
|
||||
table[base + 3] = feed.at(ptr);
|
||||
@ -48,22 +56,23 @@ QByteArray Encryption::InitIVTable(const QByteArray &feed) {
|
||||
return table;
|
||||
}
|
||||
|
||||
int Encryption::unk(quint64 arg1, quint8 arg2) {
|
||||
int Encryption::unk(quint64 arg1, quint8 arg2)
|
||||
{
|
||||
if (arg2 >= 0x40)
|
||||
return 0;
|
||||
return static_cast<int>(arg1 >> arg2);
|
||||
}
|
||||
|
||||
QByteArray Encryption::GetIV(const QByteArray &table, int index) {
|
||||
int num1 = 0xFA0 + index;
|
||||
QByteArray Encryption::GetIV(const QByteArray &table, int index)
|
||||
{
|
||||
int num1 = (4 * index % 4 + 0xFA0) + index % 4 + (index - (index % 4));
|
||||
int num2 = unk(0x51EB851FLL * num1, 0x20);
|
||||
int adjust = ((num2 >> 6) + (num2 >> 31));
|
||||
int startIndex = 20 * (num1 - 200 * adjust);
|
||||
// Return 8 bytes from that location.
|
||||
int startIndex = 20 * (num1 - 200 * ((num2 >> 6) + (num2 >> 31)));
|
||||
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 baseOffset = 0xFA0 + blockNumIndex * 4;
|
||||
quint32 blockNumVal = (static_cast<uchar>(table.at(baseOffset)) ) |
|
||||
@ -77,7 +86,7 @@ void Encryption::UpdateIVTable(QByteArray &table, int index, const QByteArray &s
|
||||
int hashIndex = 0;
|
||||
for (int x = 0; x < 4; ++x) {
|
||||
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 + 2] = table.at(startIndex + 2) ^ sectionHash.at(hashIndex + 3);
|
||||
table[startIndex + 3] = table.at(startIndex + 3) ^ sectionHash.at(hashIndex + 4);
|
||||
@ -86,7 +95,8 @@ void Encryption::UpdateIVTable(QByteArray &table, int index, const QByteArray &s
|
||||
}
|
||||
}
|
||||
|
||||
quint32 Encryption::ToUInt32(const QByteArray &data, int offset) {
|
||||
quint32 Encryption::ToUInt32(const QByteArray &data, int offset)
|
||||
{
|
||||
// Converts 4 bytes (starting at offset) from data into a 32-bit quint32eger (little-endian)
|
||||
return ((static_cast<quint32>(static_cast<uchar>(data[offset])) ) |
|
||||
(static_cast<quint32>(static_cast<uchar>(data[offset+1])) << 8 ) |
|
||||
@ -351,96 +361,8 @@ void Encryption::generateNewIV(int index, const QByteArray &hash, QByteArray &iv
|
||||
ivCounter[index]++;
|
||||
}
|
||||
|
||||
QByteArray Encryption::decryptFastFile_BO2(const QByteArray &fastFileData)
|
||||
QByteArray Encryption::decryptFastFile_BO3(const QByteArray &fastFileData)
|
||||
{
|
||||
const QByteArray bo2_salsa20_key = QByteArray::fromHex("641D8A2FE31D3AA63622BBC9CE8587229D42B0F8ED9B924130BF88B65EDC50BE");
|
||||
|
||||
QByteArray fileData = fastFileData;
|
||||
QByteArray finalFastFile;
|
||||
|
||||
QByteArray ivTable(16000, 0);
|
||||
fillIVTable(fileData, ivTable, 16000 - 1);
|
||||
|
||||
QVector<quint32> ivCounter(4, 1);
|
||||
QDataStream stream(fileData);
|
||||
stream.setByteOrder(QDataStream::LittleEndian);
|
||||
stream.skipRawData(0x138);
|
||||
|
||||
QByteArray sha1Hash(20, 0);
|
||||
QByteArray ivPtr(8, 0);
|
||||
int chunkIndex = 0;
|
||||
|
||||
while (!stream.atEnd()) {
|
||||
quint32 dataLength;
|
||||
stream >> dataLength;
|
||||
|
||||
if (dataLength == 0 || dataLength > fileData.size() - stream.device()->pos()) {
|
||||
qWarning() << "Invalid data length at offset: " << stream.device()->pos();
|
||||
break;
|
||||
}
|
||||
|
||||
fillIV(chunkIndex % 4, ivPtr, ivTable, ivCounter);
|
||||
|
||||
ECRYPT_ctx x;
|
||||
ECRYPT_keysetup(&x, reinterpret_cast<const u8*>(bo2_salsa20_key.constData()), 256, 0);
|
||||
ECRYPT_ivsetup(&x, reinterpret_cast<const u8*>(ivPtr.constData()));
|
||||
|
||||
QByteArray encryptedBlock = fileData.mid(stream.device()->pos(), dataLength);
|
||||
QByteArray decryptedBlock;
|
||||
decryptedBlock.resize(dataLength);
|
||||
|
||||
ECRYPT_decrypt_bytes(&x, reinterpret_cast<const u8*>(encryptedBlock.constData()),
|
||||
reinterpret_cast<u8*>(decryptedBlock.data()), dataLength);
|
||||
|
||||
QCryptographicHash sha1(QCryptographicHash::Sha1);
|
||||
sha1.addData(decryptedBlock);
|
||||
sha1Hash = sha1.result();
|
||||
|
||||
z_stream strm = {};
|
||||
strm.zalloc = Z_NULL;
|
||||
strm.zfree = Z_NULL;
|
||||
strm.opaque = Z_NULL;
|
||||
strm.avail_in = static_cast<uInt>(decryptedBlock.size());
|
||||
strm.next_in = reinterpret_cast<Bytef*>(decryptedBlock.data());
|
||||
|
||||
QByteArray decompressedData;
|
||||
decompressedData.resize(fmax(dataLength * 2, 4096));
|
||||
strm.avail_out = decompressedData.size();
|
||||
strm.next_out = reinterpret_cast<Bytef*>(decompressedData.data());
|
||||
|
||||
int zReturn = inflateInit2(&strm, -15);
|
||||
if (zReturn != Z_OK) {
|
||||
qWarning() << "inflateInit2 failed with error code" << zReturn;
|
||||
break;
|
||||
}
|
||||
|
||||
zReturn = inflate(&strm, Z_FINISH);
|
||||
inflateEnd(&strm);
|
||||
|
||||
if (zReturn != Z_STREAM_END) {
|
||||
qDebug() << "Error decompressing at offset: " << stream.device()->pos() << " : " << zReturn;
|
||||
decompressedData.clear();
|
||||
} else {
|
||||
decompressedData.resize(strm.total_out);
|
||||
}
|
||||
|
||||
finalFastFile.append(decompressedData);
|
||||
|
||||
generateNewIV(chunkIndex % 4, sha1Hash, ivTable, ivCounter);
|
||||
|
||||
if (stream.device()->pos() + static_cast<qint64>(dataLength) > fileData.size()) {
|
||||
qWarning() << "Skipping past file size!";
|
||||
break;
|
||||
}
|
||||
|
||||
stream.skipRawData(dataLength);
|
||||
chunkIndex++;
|
||||
}
|
||||
|
||||
return finalFastFile;
|
||||
}
|
||||
|
||||
QByteArray Encryption::decryptFastFile_BO3(const QByteArray &fastFileData) {
|
||||
const QByteArray salsaKey = QByteArray::fromHex("0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3");
|
||||
|
||||
QByteArray ivTable(0xFB0, 0);
|
||||
@ -504,3 +426,71 @@ QByteArray Encryption::decryptFastFile_BO3(const QByteArray &fastFileData) {
|
||||
|
||||
return finalFastFile;
|
||||
}
|
||||
|
||||
QByteArray Encryption::DecryptFile(const QByteArray &fastFileData, const QString &aFileName, const QByteArray &aKey)
|
||||
{
|
||||
Q_UNUSED(aFileName);
|
||||
|
||||
const QByteArray salsaKey = QByteArray::fromHex(aKey);
|
||||
|
||||
QByteArray ivTable(0xFB0, 0);
|
||||
fillIVTable(fastFileData, ivTable, 0xFB0 - 1);
|
||||
|
||||
QVector<quint32> ivCounter(4, 1);
|
||||
QDataStream stream(fastFileData);
|
||||
stream.setByteOrder(QDataStream::LittleEndian);
|
||||
|
||||
QByteArray finalFastFile;
|
||||
QByteArray sha1Hash(20, 0);
|
||||
QByteArray ivPtr(8, 0);
|
||||
int chunkIndex = 0;
|
||||
|
||||
while (!stream.atEnd()) {
|
||||
if (stream.device()->bytesAvailable() < 4) {
|
||||
qWarning() << "No sufficient data for chunk size at offset:" << stream.device()->pos();
|
||||
break;
|
||||
}
|
||||
|
||||
quint32 dataLength;
|
||||
stream >> dataLength;
|
||||
|
||||
if (dataLength == 0 || dataLength > fastFileData.size() - stream.device()->pos()) {
|
||||
qWarning() << "Invalid data length at offset:" << stream.device()->pos();
|
||||
break;
|
||||
}
|
||||
|
||||
fillIV(chunkIndex % 4, ivPtr, ivTable, ivCounter);
|
||||
|
||||
ECRYPT_ctx x;
|
||||
ECRYPT_keysetup(&x, reinterpret_cast<const u8*>(salsaKey.constData()), 256, 0);
|
||||
ECRYPT_ivsetup(&x, reinterpret_cast<const u8*>(ivPtr.constData()));
|
||||
|
||||
QByteArray encryptedBlock = fastFileData.mid(stream.device()->pos(), dataLength);
|
||||
QByteArray decryptedBlock(dataLength, Qt::Uninitialized);
|
||||
|
||||
ECRYPT_decrypt_bytes(&x,
|
||||
reinterpret_cast<const u8*>(encryptedBlock.constData()),
|
||||
reinterpret_cast<u8*>(decryptedBlock.data()),
|
||||
dataLength);
|
||||
|
||||
// SHA1 hash update
|
||||
sha1Hash = QCryptographicHash::hash(decryptedBlock, QCryptographicHash::Sha1);
|
||||
|
||||
// Decompress (ZLIB raw DEFLATE)
|
||||
QByteArray decompressedData = Compression::DecompressDeflate(decryptedBlock);
|
||||
if (decompressedData.isEmpty()) {
|
||||
qWarning() << "Failed decompression at chunk index:" << chunkIndex;
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
finalFastFile.append(decompressedData);
|
||||
|
||||
// Update IV table using SHA1
|
||||
generateNewIV(chunkIndex % 4, sha1Hash, ivTable, ivCounter);
|
||||
|
||||
stream.skipRawData(dataLength);
|
||||
chunkIndex++;
|
||||
}
|
||||
|
||||
return finalFastFile;
|
||||
}
|
||||
|
||||
@ -46,8 +46,9 @@ public:
|
||||
|
||||
static void generateNewIV(int index, const QByteArray& hash, QByteArray& ivTable, QVector<quint32>& ivCounter);
|
||||
|
||||
static QByteArray decryptFastFile_BO2(const QByteArray& fastFileData);
|
||||
//static QByteArray decryptFastFile_BO2(const QByteArray& fastFileData);
|
||||
static QByteArray decryptFastFile_BO3(const QByteArray& fastFileData);
|
||||
static QByteArray DecryptFile(const QByteArray& fastFileData, const QString& aFileName, const QByteArray& aKey);
|
||||
};
|
||||
|
||||
#endif // ENCRYPTION_H
|
||||
|
||||
@ -59,7 +59,7 @@ void ECRYPT_encrypt_bytes(ECRYPT_ctx *x,const u8 *m,u8 *c,u32 bytes)
|
||||
u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
|
||||
u8 *ctarget;
|
||||
u8 tmp[64];
|
||||
int i;
|
||||
u32 i;
|
||||
|
||||
if (!bytes) return;
|
||||
|
||||
@ -82,7 +82,10 @@ void ECRYPT_encrypt_bytes(ECRYPT_ctx *x,const u8 *m,u8 *c,u32 bytes)
|
||||
|
||||
for (;;) {
|
||||
if (bytes < 64) {
|
||||
for (i = 0;i < bytes;++i) tmp[i] = m[i];
|
||||
for (i = 0; i < bytes; ++i)
|
||||
{
|
||||
tmp[i] = m[i];
|
||||
}
|
||||
m = tmp;
|
||||
ctarget = c;
|
||||
c = tmp;
|
||||
|
||||
@ -94,7 +94,6 @@ void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]);
|
||||
|
||||
/* blk0() and blk() perform the initial expand. */
|
||||
/* I got the idea of expanding during the round function from SSLeay */
|
||||
/* FIXME: can we do this in an endian-proof way? */
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
#define blk0(i) block->l[i]
|
||||
#else
|
||||
|
||||
@ -69,15 +69,9 @@ bool FastFile_COD10_360::Load(const QString aFilePath) {
|
||||
bool FastFile_COD10_360::Load(const QByteArray aData) {
|
||||
QByteArray decompressedData;
|
||||
|
||||
// Create a QDataStream on the input data.
|
||||
QDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||
|
||||
// For COD7/COD9, use BigEndian.
|
||||
fastFileStream.setByteOrder(QDataStream::BigEndian);
|
||||
|
||||
// Select key based on game.
|
||||
QByteArray key = QByteArray::fromHex("0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3");
|
||||
// Create a XDataStream on the input data.
|
||||
XDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||
|
||||
// Read the 8-byte magic.
|
||||
QByteArray fileMagic(8, Qt::Uninitialized);
|
||||
@ -96,7 +90,7 @@ bool FastFile_COD10_360::Load(const QByteArray aData) {
|
||||
QByteArray rsaSignature(256, Qt::Uninitialized);
|
||||
fastFileStream.readRawData(rsaSignature.data(), 256);
|
||||
|
||||
decompressedData = Encryption::decryptFastFile_BO2(aData);
|
||||
decompressedData = Encryption::DecryptFile(aData, fileName, "0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3");
|
||||
|
||||
// For COD9, write out the complete decompressed zone for testing.
|
||||
QFile testFile("exports/" + GetBaseStem() + ".zone");
|
||||
@ -104,6 +98,7 @@ bool FastFile_COD10_360::Load(const QByteArray aData) {
|
||||
testFile.write(decompressedData);
|
||||
testFile.close();
|
||||
}
|
||||
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
||||
|
||||
// Load the zone file with the decompressed data (using an Xbox platform flag).
|
||||
ZoneFile_COD10_360* zoneFile = new ZoneFile_COD10_360();
|
||||
|
||||
@ -68,29 +68,74 @@ bool FastFile_COD11_360::Load(const QString aFilePath) {
|
||||
return true;
|
||||
}
|
||||
|
||||
enum DB_CompressorType : qint32
|
||||
{
|
||||
DB_COMPRESSOR_INVALID = 0x0,
|
||||
DB_COMPRESSOR_ZLIB = 0x1,
|
||||
DB_COMPRESSOR_LZX = 0x2,
|
||||
DB_COMPRESSOR_PASSTHROUGH = 0x3,
|
||||
};
|
||||
|
||||
bool FastFile_COD11_360::Load(const QByteArray aData) {
|
||||
QByteArray decompressedData;
|
||||
|
||||
// Prepare data stream for parsing
|
||||
QDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||
XDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
||||
|
||||
// Verify magic header
|
||||
QByteArray fileMagic(8, Qt::Uninitialized);
|
||||
fastFileStream.readRawData(fileMagic.data(), 8);
|
||||
if (fileMagic != "TAff0000") {
|
||||
qWarning() << "Invalid fast file magic for COD12!";
|
||||
quint32 version = fastFileStream.ParseUInt32();
|
||||
|
||||
fastFileStream.skipRawData(1);
|
||||
|
||||
DB_CompressorType compressorType = (DB_CompressorType)fastFileStream.ParseInt8();
|
||||
|
||||
fastFileStream.skipRawData(10);
|
||||
|
||||
qint32 blockCount = fastFileStream.ParseInt32();
|
||||
|
||||
if (version != 1838)
|
||||
{
|
||||
qWarning() << "Invalid fast file version:" << version << "!";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Skip: File size (4 bytes), flags/version (4 bytes), unknown (8 bytes), build tag (32 bytes), RSA signature (256 bytes)
|
||||
fastFileStream.skipRawData(4 + 4 + 8 + 32 + 256); // total 304 bytes skipped so far + 8 bytes magic = 312 bytes at correct position.
|
||||
if (blockCount > 17280)
|
||||
{
|
||||
qWarning() << "Fast file has too many blocks:" << blockCount << "> 17280!";
|
||||
return false;
|
||||
}
|
||||
fastFileStream.skipRawData(12 * blockCount);
|
||||
|
||||
// Correctly positioned at 0x138
|
||||
QByteArray encryptedData = aData.mid(0x138);
|
||||
decompressedData = Encryption::decryptFastFile_BO3(encryptedData);
|
||||
qint32 startPos = fastFileStream.ParseInt32();
|
||||
Q_UNUSED(startPos);
|
||||
|
||||
// Output for verification/testing
|
||||
qint32 endPos = fastFileStream.ParseInt32();
|
||||
Q_UNUSED(endPos);
|
||||
|
||||
if (fileMagic == "S1ffu100")
|
||||
{
|
||||
QByteArray compressedData = aData.mid(fastFileStream.device()->pos());
|
||||
if (compressorType == DB_COMPRESSOR_ZLIB)
|
||||
{
|
||||
decompressedData = Compression::DecompressZLIB(compressedData);
|
||||
}
|
||||
else if (compressorType == DB_COMPRESSOR_LZX)
|
||||
{
|
||||
decompressedData = Compression::DecompressXMem(compressedData, 0, 0x80000, 0);
|
||||
}
|
||||
}
|
||||
else if (fileMagic == "S1ff0100")
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
qWarning() << "Invalid fast file magic:" << fileMagic << "!";
|
||||
return false;
|
||||
}
|
||||
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
||||
|
||||
// Load the zone file with decompressed data
|
||||
|
||||
@ -72,24 +72,69 @@ bool FastFile_COD12_360::Load(const QByteArray aData) {
|
||||
QByteArray decompressedData;
|
||||
|
||||
// Prepare data stream for parsing
|
||||
QDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||
XDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||
|
||||
// Verify magic header
|
||||
QByteArray fileMagic(8, Qt::Uninitialized);
|
||||
fastFileStream.readRawData(fileMagic.data(), 8);
|
||||
if (fileMagic != "TAff0000") {
|
||||
qWarning() << "Invalid fast file magic for COD12!";
|
||||
// Skip header magic
|
||||
fastFileStream.skipRawData(8);
|
||||
|
||||
quint32 version;
|
||||
fastFileStream >> version;
|
||||
|
||||
quint8 unknownFlag, compressionFlag, platformFlag, encryptionFlag;
|
||||
fastFileStream >> unknownFlag >> compressionFlag >> platformFlag >> encryptionFlag;
|
||||
|
||||
if (compressionFlag != 1) {
|
||||
qDebug() << "Invalid fastfile compression: " << compressionFlag;
|
||||
return false;
|
||||
} else if (platformFlag != 4) {
|
||||
qDebug() << "Invalid platform: " << platformFlag;
|
||||
return false;
|
||||
} else if (encryptionFlag != 0) {
|
||||
qDebug() << "Decryption not supported yet!";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Skip: File size (4 bytes), flags/version (4 bytes), unknown (8 bytes), build tag (32 bytes), RSA signature (256 bytes)
|
||||
fastFileStream.skipRawData(4 + 4 + 8 + 32 + 256); // total 304 bytes skipped so far + 8 bytes magic = 312 bytes at correct position.
|
||||
fastFileStream.skipRawData(128);
|
||||
|
||||
// Correctly positioned at 0x138
|
||||
QByteArray encryptedData = aData.mid(0x138);
|
||||
decompressedData = Encryption::decryptFastFile_BO3(encryptedData);
|
||||
quint64 size;
|
||||
fastFileStream >> size;
|
||||
|
||||
fastFileStream.skipRawData(432);
|
||||
|
||||
int consumed = 0;
|
||||
while(consumed < size)
|
||||
{
|
||||
// Read Block Header
|
||||
quint32 compressedSize, decompressedSize, blockSize, blockPosition;
|
||||
fastFileStream >> compressedSize >> decompressedSize >> blockSize >> blockPosition;
|
||||
|
||||
// Validate the block position, it should match
|
||||
if(blockPosition != fastFileStream.device()->pos() - 16)
|
||||
{
|
||||
qDebug() << "Block Position does not match Stream Position.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for padding blocks
|
||||
if(decompressedSize == 0)
|
||||
{
|
||||
fastFileStream.device()->read((((fastFileStream.device()->pos()) + ((0x800000) - 1)) & ~((0x800000) - 1)) - fastFileStream.device()->pos());
|
||||
continue;
|
||||
}
|
||||
|
||||
fastFileStream.device()->read(2);
|
||||
|
||||
QByteArray compressedData(compressedSize - 2, Qt::Uninitialized);
|
||||
qDebug() << "Data position: " << fastFileStream.device()->pos() << " - Size: " << compressedSize;
|
||||
fastFileStream.readRawData(compressedData.data(), compressedSize - 2);
|
||||
decompressedData.append(Compression::DecompressDeflate(compressedData));
|
||||
|
||||
consumed += decompressedSize;
|
||||
|
||||
// Sinze Fast Files are aligns, we must skip the full block
|
||||
fastFileStream.device()->seek(blockPosition + 16 + blockSize);
|
||||
}
|
||||
// Output for verification/testing
|
||||
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) {
|
||||
// Create a QDataStream on the input data.
|
||||
QDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||
// Create a XDataStream on the input data.
|
||||
XDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||
|
||||
Utils::ReadUntilHex(&fastFileStream, "78");
|
||||
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.
|
||||
decompressedData = Compression::DecompressZLIB(aData.mid(12));
|
||||
} else if (header == "IWff0100") {
|
||||
// Create a QDataStream on the input data.
|
||||
QDataStream fastFileStream(aData.mid(12));
|
||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||
// Create a XDataStream on the input data.
|
||||
XDataStream fastFileStream(aData.mid(12));
|
||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||
|
||||
QByteArray magic(8, Qt::Uninitialized);
|
||||
fastFileStream.readRawData(magic.data(), 8);
|
||||
|
||||
@ -70,30 +70,47 @@ bool FastFile_COD6_360::Load(const QString aFilePath) {
|
||||
}
|
||||
|
||||
bool FastFile_COD6_360::Load(const QByteArray aData) {
|
||||
const qint64 zlibOffset = Compression::FindZlibOffset(aData);
|
||||
if (zlibOffset == -1)
|
||||
{
|
||||
qWarning() << "Z-Lib stream not found";
|
||||
return false;
|
||||
}
|
||||
QByteArray compressed = aData.mid(zlibOffset);
|
||||
XDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
||||
|
||||
QByteArray decompressedData = Compression::DecompressZLIB(compressed);
|
||||
QByteArray magic(8, Qt::Uninitialized);
|
||||
fastFileStream.readRawData(magic.data(), 8);
|
||||
|
||||
if (decompressedData.isEmpty() || decompressedData.size() < 1024)
|
||||
{
|
||||
QByteArray stripped = Compression::StripHashBlocks(compressed);
|
||||
QByteArray retry = Compression::DecompressZLIB(stripped);
|
||||
if (!retry.isEmpty())
|
||||
decompressedData.swap(retry);
|
||||
}
|
||||
quint32 version = fastFileStream.ParseUInt32();
|
||||
|
||||
if (decompressedData.isEmpty())
|
||||
if (version != 269)
|
||||
{
|
||||
qWarning() << "Unable to decompress fast-file";
|
||||
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(11);
|
||||
|
||||
quint32 hashCount = fastFileStream.ParseUInt32();
|
||||
fastFileStream.skipRawData(12 * hashCount);
|
||||
|
||||
fastFileStream.skipRawData(8);
|
||||
|
||||
QByteArray decompressedData;
|
||||
if (magic == "IWff0100")
|
||||
{
|
||||
|
||||
}
|
||||
else if (magic == "IWffu100")
|
||||
{
|
||||
quint32 zlibSize = aData.size() - fastFileStream.device()->pos();
|
||||
QByteArray zlibData(zlibSize, Qt::Uninitialized);
|
||||
fastFileStream.readRawData(zlibData.data(), zlibSize);
|
||||
|
||||
decompressedData = Compression::DecompressZLIB(zlibData);
|
||||
}
|
||||
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
||||
|
||||
ZoneFile_COD6_360* zoneFile = new ZoneFile_COD6_360();
|
||||
|
||||
@ -71,16 +71,11 @@ bool FastFile_COD7_360::Load(const QString aFilePath) {
|
||||
bool FastFile_COD7_360::Load(const QByteArray aData) {
|
||||
QByteArray decompressedData;
|
||||
|
||||
// Create a QDataStream on the input data.
|
||||
QDataStream fastFileStream(aData);
|
||||
fastFileStream.skipRawData(12);
|
||||
// Create a XDataStream on the input data.
|
||||
XDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
||||
|
||||
// For COD7/COD9, use BigEndian.
|
||||
fastFileStream.setByteOrder(QDataStream::BigEndian);
|
||||
|
||||
// Select key based on game.
|
||||
QByteArray key = QByteArray::fromHex("1ac1d12d527c59b40eca619120ff8217ccff09cd16896f81b829c7f52793405d");
|
||||
fastFileStream.skipRawData(4);
|
||||
fastFileStream.skipRawData(16);
|
||||
|
||||
// Read the 8-byte magic.
|
||||
QByteArray fileMagic(8, Qt::Uninitialized);
|
||||
@ -102,6 +97,8 @@ bool FastFile_COD7_360::Load(const QByteArray aData) {
|
||||
QByteArray rsaSignature(256, Qt::Uninitialized);
|
||||
fastFileStream.readRawData(rsaSignature.data(), 256);
|
||||
|
||||
QByteArray key = QByteArray::fromHex("1ac1d12d527c59b40eca619120ff8217ccff09cd16896f81b829c7f52793405d");
|
||||
|
||||
// Now the stream should be positioned at 0x13C, where sections begin.
|
||||
int sectionIndex = 0;
|
||||
while (true) {
|
||||
|
||||
148
libs/fastfile/360/fastfile_cod7_5_360.cpp
Normal file
148
libs/fastfile/360/fastfile_cod7_5_360.cpp
Normal file
@ -0,0 +1,148 @@
|
||||
#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;
|
||||
}
|
||||
20
libs/fastfile/360/fastfile_cod7_5_360.h
Normal file
20
libs/fastfile/360/fastfile_cod7_5_360.h
Normal file
@ -0,0 +1,20 @@
|
||||
#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,15 +69,12 @@ bool FastFile_COD8_360::Load(const QString aFilePath) {
|
||||
bool FastFile_COD8_360::Load(const QByteArray aData) {
|
||||
QByteArray decompressedData;
|
||||
|
||||
// Create a QDataStream on the input data.
|
||||
QDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||
// Create a XDataStream on the input data.
|
||||
XDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||
|
||||
// For COD7/COD9, use BigEndian.
|
||||
fastFileStream.setByteOrder(QDataStream::BigEndian);
|
||||
|
||||
// Select key based on game.
|
||||
QByteArray key = QByteArray::fromHex("0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3");
|
||||
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
||||
|
||||
// Read the 8-byte magic.
|
||||
QByteArray fileMagic(8, Qt::Uninitialized);
|
||||
@ -92,11 +89,7 @@ bool FastFile_COD8_360::Load(const QByteArray aData) {
|
||||
QByteArray fileName(32, Qt::Uninitialized);
|
||||
fastFileStream.readRawData(fileName.data(), 32);
|
||||
|
||||
// Skip the RSA signature (256 bytes).
|
||||
QByteArray rsaSignature(256, Qt::Uninitialized);
|
||||
fastFileStream.readRawData(rsaSignature.data(), 256);
|
||||
|
||||
decompressedData = Encryption::decryptFastFile_BO2(aData);
|
||||
decompressedData = Encryption::DecryptFile(aData, fileName, "0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3");
|
||||
|
||||
// For COD9, write out the complete decompressed zone for testing.
|
||||
QFile testFile("exports/" + GetBaseStem() + ".zone");
|
||||
|
||||
@ -69,15 +69,12 @@ bool FastFile_COD9_360::Load(const QString aFilePath) {
|
||||
bool FastFile_COD9_360::Load(const QByteArray aData) {
|
||||
QByteArray decompressedData;
|
||||
|
||||
// Create a QDataStream on the input data.
|
||||
QDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||
// Create a XDataStream on the input data.
|
||||
XDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||
|
||||
// For COD7/COD9, use BigEndian.
|
||||
fastFileStream.setByteOrder(QDataStream::BigEndian);
|
||||
|
||||
// Select key based on game.
|
||||
QByteArray key = QByteArray::fromHex("0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3");
|
||||
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
||||
|
||||
// Read the 8-byte magic.
|
||||
QByteArray fileMagic(8, Qt::Uninitialized);
|
||||
@ -96,7 +93,7 @@ bool FastFile_COD9_360::Load(const QByteArray aData) {
|
||||
QByteArray rsaSignature(256, Qt::Uninitialized);
|
||||
fastFileStream.readRawData(rsaSignature.data(), 256);
|
||||
|
||||
decompressedData = Encryption::decryptFastFile_BO2(aData);
|
||||
decompressedData = Encryption::DecryptFile(aData, fileName, "0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3");
|
||||
|
||||
// For COD9, write out the complete decompressed zone for testing.
|
||||
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) {
|
||||
QByteArray decompressedData;
|
||||
|
||||
// Create a QDataStream on the input data.
|
||||
QDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||
// Create a XDataStream on the input data.
|
||||
XDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||
|
||||
// Parse header values.
|
||||
SetCompany(pParseFFCompany(&fastFileStream));
|
||||
@ -84,18 +84,13 @@ bool FastFile_COD10_PC::Load(const QByteArray aData) {
|
||||
SetGame("COD9");
|
||||
|
||||
// For COD7/COD9, use BigEndian.
|
||||
fastFileStream.setByteOrder(QDataStream::BigEndian);
|
||||
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
||||
if (GetPlatform() == "PC") {
|
||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||
}
|
||||
|
||||
// Select key based on game.
|
||||
QByteArray key;
|
||||
if (GetPlatform() == "360") {
|
||||
key = QByteArray::fromHex("0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3");
|
||||
} else if (GetPlatform() == "PC") {
|
||||
key = QByteArray::fromHex("641D8A2FE31D3AA63622BBC9CE8587229D42B0F8ED9B924130BF88B65EDC50BE");
|
||||
}
|
||||
QByteArray key = QByteArray::fromHex("641D8A2FE31D3AA63622BBC9CE8587229D42B0F8ED9B924130BF88B65EDC50BE");
|
||||
|
||||
// Read the 8-byte magic.
|
||||
QByteArray fileMagic(8, Qt::Uninitialized);
|
||||
@ -114,11 +109,7 @@ bool FastFile_COD10_PC::Load(const QByteArray aData) {
|
||||
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);
|
||||
}
|
||||
//decompressedData = Encryption::decryptFastFile_BO2(aData);
|
||||
|
||||
// For COD9, write out the complete decompressed zone for testing.
|
||||
QFile testFile("exports/" + GetBaseStem() + ".zone");
|
||||
@ -126,6 +117,7 @@ bool FastFile_COD10_PC::Load(const QByteArray aData) {
|
||||
testFile.write(decompressedData);
|
||||
testFile.close();
|
||||
}
|
||||
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
||||
|
||||
// Load the zone file with the decompressed data (using an Xbox platform flag).
|
||||
ZoneFile_COD10_PC* zoneFile = new ZoneFile_COD10_PC();
|
||||
|
||||
@ -69,9 +69,9 @@ bool FastFile_COD11_PC::Load(const QString aFilePath) {
|
||||
bool FastFile_COD11_PC::Load(const QByteArray aData) {
|
||||
QByteArray decompressedData;
|
||||
|
||||
// Create a QDataStream on the input data.
|
||||
QDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||
// Create a XDataStream on the input data.
|
||||
XDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||
|
||||
// Parse header values.
|
||||
SetCompany(pParseFFCompany(&fastFileStream));
|
||||
@ -80,22 +80,11 @@ bool FastFile_COD11_PC::Load(const QByteArray aData) {
|
||||
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);
|
||||
}
|
||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||
|
||||
// Select key based on game.
|
||||
QByteArray key;
|
||||
if (GetPlatform() == "360") {
|
||||
key = QByteArray::fromHex("0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3");
|
||||
} else if (GetPlatform() == "PC") {
|
||||
key = QByteArray::fromHex("641D8A2FE31D3AA63622BBC9CE8587229D42B0F8ED9B924130BF88B65EDC50BE");
|
||||
}
|
||||
QByteArray key = QByteArray::fromHex("641D8A2FE31D3AA63622BBC9CE8587229D42B0F8ED9B924130BF88B65EDC50BE");
|
||||
|
||||
// Read the 8-byte magic.
|
||||
QByteArray fileMagic(8, Qt::Uninitialized);
|
||||
@ -114,11 +103,7 @@ bool FastFile_COD11_PC::Load(const QByteArray aData) {
|
||||
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);
|
||||
}
|
||||
//decompressedData = Encryption::decryptFastFile_BO2(aData);
|
||||
|
||||
// For COD9, write out the complete decompressed zone for testing.
|
||||
QFile testFile("exports/" + GetBaseStem() + ".zone");
|
||||
@ -126,6 +111,7 @@ bool FastFile_COD11_PC::Load(const QByteArray aData) {
|
||||
testFile.write(decompressedData);
|
||||
testFile.close();
|
||||
}
|
||||
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
||||
|
||||
// Load the zone file with the decompressed data (using an Xbox platform flag).
|
||||
ZoneFile_COD11_PC* zoneFile = new ZoneFile_COD11_PC();
|
||||
|
||||
@ -72,9 +72,9 @@ bool FastFile_COD12_PC::Load(const QString aFilePath) {
|
||||
bool FastFile_COD12_PC::Load(const QByteArray aData) {
|
||||
QByteArray decompressedData;
|
||||
|
||||
// Create a QDataStream on the input data.
|
||||
QDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||
// Create a XDataStream on the input data.
|
||||
XDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||
|
||||
// Skip header magic
|
||||
fastFileStream.skipRawData(8);
|
||||
@ -136,7 +136,6 @@ bool FastFile_COD12_PC::Load(const QByteArray aData) {
|
||||
// Sinze Fast Files are aligns, we must skip the full block
|
||||
fastFileStream.device()->seek(blockPosition + 16 + blockSize);
|
||||
}
|
||||
|
||||
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
||||
|
||||
// Load the zone file with the decompressed data (using an Xbox platform flag).
|
||||
|
||||
@ -75,9 +75,9 @@ bool FastFile_COD4_PC::Load(const QByteArray aData) {
|
||||
StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/data", 1000);
|
||||
QByteArray decompressedData;
|
||||
|
||||
// Create a QDataStream on the input data.
|
||||
QDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||
// Create a XDataStream on the input data.
|
||||
XDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||
|
||||
// For COD5, simply decompress from offset 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);
|
||||
QByteArray decompressedData;
|
||||
|
||||
// Create a QDataStream on the input data.
|
||||
QDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||
// Create a XDataStream on the input data.
|
||||
XDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||
|
||||
// For COD5, simply decompress from offset 12.
|
||||
decompressedData = Compression::DecompressZLIB(aData.mid(12));
|
||||
|
||||
@ -72,12 +72,30 @@ bool FastFile_COD6_PC::Load(const QString aFilePath) {
|
||||
}
|
||||
|
||||
bool FastFile_COD6_PC::Load(const QByteArray aData) {
|
||||
StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/data", 1000);
|
||||
QByteArray decompressedData;
|
||||
const qint64 zlibOffset = Compression::FindZlibOffset(aData);
|
||||
qDebug() << "ZLib Offset: " << zlibOffset;
|
||||
if (zlibOffset == -1)
|
||||
{
|
||||
qWarning() << "Z-Lib stream not found";
|
||||
return false;
|
||||
}
|
||||
QByteArray compressed = aData.mid(zlibOffset);
|
||||
|
||||
// Assume the first 12 bytes are a header; the rest is zlib-compressed zone data.
|
||||
const QByteArray compressedData = aData.mid(21);
|
||||
decompressedData = Compression::DecompressZLIB(compressedData);
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
QByteArray decompressedData;
|
||||
|
||||
// Create a QDataStream on the input data.
|
||||
QDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||
// Create a XDataStream on the input data.
|
||||
XDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||
|
||||
// Parse header values.
|
||||
SetCompany(pParseFFCompany(&fastFileStream));
|
||||
|
||||
@ -72,91 +72,19 @@ bool FastFile_COD8_PC::Load(const QString aFilePath) {
|
||||
bool FastFile_COD8_PC::Load(const QByteArray aData) {
|
||||
QByteArray decompressedData;
|
||||
|
||||
// Create a QDataStream on the input data.
|
||||
QDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||
// Create a XDataStream on the input data.
|
||||
XDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||
|
||||
// Parse header values.
|
||||
SetCompany(pParseFFCompany(&fastFileStream));
|
||||
SetType(pParseFFFileType(&fastFileStream));
|
||||
SetSignage(pParseFFSignage(&fastFileStream));
|
||||
SetMagic(pParseFFMagic(&fastFileStream));
|
||||
quint32 version = pParseFFVersion(&fastFileStream);
|
||||
SetVersion(version);
|
||||
SetPlatform(pCalculateFFPlatform(version));
|
||||
SetGame("COD7");
|
||||
SetVersion(pParseFFVersion(&fastFileStream));
|
||||
|
||||
// For COD7/COD9, use BigEndian.
|
||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||
|
||||
// Select key based on game.
|
||||
QByteArray key;
|
||||
fastFileStream.skipRawData(4);
|
||||
if (GetPlatform() == "360") {
|
||||
key = QByteArray::fromHex("1ac1d12d527c59b40eca619120ff8217ccff09cd16896f81b829c7f52793405d");
|
||||
} else if (GetPlatform() == "PS3") {
|
||||
key = QByteArray::fromHex("46D3F997F29C9ACE175B0DAE3AB8C0C1B8E423E2E3BF7E3C311EA35245BF193A");
|
||||
// or
|
||||
// key = QByteArray::fromHex("0C99B3DDB8D6D0845D1147E470F28A8BF2AE69A8A9F534767B54E9180FF55370");
|
||||
}
|
||||
|
||||
// Read the 8-byte magic.
|
||||
QByteArray fileMagic(8, Qt::Uninitialized);
|
||||
fastFileStream.readRawData(fileMagic.data(), 8);
|
||||
if (fileMagic != "PHEEBs71") {
|
||||
qWarning() << "Invalid fast file magic!";
|
||||
return false;
|
||||
}
|
||||
fastFileStream.skipRawData(4);
|
||||
|
||||
// Read IV table name (32 bytes).
|
||||
QByteArray fileName(32, Qt::Uninitialized);
|
||||
fastFileStream.readRawData(fileName.data(), 32);
|
||||
|
||||
// Build the IV table from the fileName.
|
||||
QByteArray ivTable = Encryption::InitIVTable(fileName);
|
||||
|
||||
// Skip the RSA signature (256 bytes).
|
||||
QByteArray rsaSignature(256, Qt::Uninitialized);
|
||||
fastFileStream.readRawData(rsaSignature.data(), 256);
|
||||
|
||||
// Now the stream should be positioned at 0x13C, where sections begin.
|
||||
int sectionIndex = 0;
|
||||
while (true) {
|
||||
qint32 sectionSize = 0;
|
||||
fastFileStream >> sectionSize;
|
||||
qDebug() << "Section index:" << sectionIndex << "Size:" << sectionSize
|
||||
<< "Pos:" << fastFileStream.device()->pos();
|
||||
if (sectionSize == 0)
|
||||
break;
|
||||
|
||||
// Read the section data.
|
||||
QByteArray sectionData;
|
||||
sectionData.resize(sectionSize);
|
||||
fastFileStream.readRawData(sectionData.data(), sectionSize);
|
||||
|
||||
// Compute the IV for this section.
|
||||
QByteArray iv = Encryption::GetIV(ivTable, sectionIndex);
|
||||
|
||||
// Decrypt the section using Salsa20.
|
||||
QByteArray decData = Encryption::salsa20DecryptSection(sectionData, key, iv);
|
||||
|
||||
// Compute SHA1 hash of the decrypted data.
|
||||
QByteArray sectionHash = QCryptographicHash::hash(decData, QCryptographicHash::Sha1);
|
||||
|
||||
// Update the IV table based on the section hash.
|
||||
Encryption::UpdateIVTable(ivTable, sectionIndex, sectionHash);
|
||||
|
||||
// Build a compressed data buffer by prepending the two-byte zlib header.
|
||||
QByteArray compressedData;
|
||||
compressedData.append(char(0x78));
|
||||
compressedData.append(char(0x01));
|
||||
compressedData.append(decData);
|
||||
|
||||
decompressedData.append(Compression::DecompressZLIB(compressedData));
|
||||
|
||||
sectionIndex++;
|
||||
}
|
||||
decompressedData = Compression::DecompressZLIB(aData.mid(21));
|
||||
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
||||
|
||||
ZoneFile_COD8_PC* zoneFile = new ZoneFile_COD8_PC();
|
||||
zoneFile->SetStem(GetBaseStem() + ".zone");
|
||||
|
||||
@ -67,37 +67,18 @@ bool FastFile_COD9_PC::Load(const QString aFilePath) {
|
||||
}
|
||||
|
||||
bool FastFile_COD9_PC::Load(const QByteArray aData) {
|
||||
QByteArray decompressedData;
|
||||
|
||||
// Create a QDataStream on the input data.
|
||||
QDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||
// Create a XDataStream on the input data.
|
||||
XDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||
|
||||
// Parse header values.
|
||||
SetCompany(pParseFFCompany(&fastFileStream));
|
||||
SetType(pParseFFFileType(&fastFileStream));
|
||||
SetSignage(pParseFFSignage(&fastFileStream));
|
||||
SetMagic(pParseFFMagic(&fastFileStream));
|
||||
quint32 version = pParseFFVersion(&fastFileStream);
|
||||
SetVersion(version);
|
||||
SetPlatform(pCalculateFFPlatform(version));
|
||||
SetGame("COD9");
|
||||
SetVersion(pParseFFVersion(&fastFileStream));
|
||||
|
||||
// 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.
|
||||
// Validate the fastfile magic.
|
||||
QByteArray fileMagic(8, Qt::Uninitialized);
|
||||
fastFileStream.readRawData(fileMagic.data(), 8);
|
||||
if (fileMagic != "PHEEBs71") {
|
||||
@ -106,35 +87,100 @@ bool FastFile_COD9_PC::Load(const QByteArray aData) {
|
||||
}
|
||||
fastFileStream.skipRawData(4);
|
||||
|
||||
// Read IV table name (32 bytes).
|
||||
QByteArray fileName(32, Qt::Uninitialized);
|
||||
fastFileStream.readRawData(fileName.data(), 32);
|
||||
// Read IV seed name (32 bytes).
|
||||
QByteArray nameKey(32, Qt::Uninitialized);
|
||||
fastFileStream.readRawData(nameKey.data(), 32);
|
||||
|
||||
// Skip the RSA signature (256 bytes).
|
||||
QByteArray rsaSignature(256, Qt::Uninitialized);
|
||||
fastFileStream.readRawData(rsaSignature.data(), 256);
|
||||
// --- Salsa20 + IV setup ---
|
||||
static QVector<quint32> ivCounter(4, 1);
|
||||
QByteArray ivTable = Encryption::InitIVTable(nameKey);
|
||||
ivCounter.fill(1); // reset global counters
|
||||
|
||||
if (GetPlatform() == "360") {
|
||||
//decompressedData = Compressor::cod9_decryptFastFile(aData);
|
||||
} else if (GetPlatform() == "PC") {
|
||||
decompressedData = Encryption::decryptFastFile_BO2(aData);
|
||||
// Skip RSA signature (0x100)
|
||||
fastFileStream.skipRawData(0x100);
|
||||
|
||||
// Decrypt + decompress loop
|
||||
QByteArray finalZone;
|
||||
int chunkIndex = 0;
|
||||
|
||||
while (!fastFileStream.atEnd()) {
|
||||
quint32 dataLength = 0;
|
||||
fastFileStream >> dataLength;
|
||||
if (dataLength == 0)
|
||||
break;
|
||||
|
||||
QByteArray encryptedBlock(dataLength, Qt::Uninitialized);
|
||||
if (fastFileStream.readRawData(encryptedBlock.data(), dataLength) != dataLength) {
|
||||
qWarning() << "Unexpected EOF while reading block";
|
||||
break;
|
||||
}
|
||||
|
||||
// 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++;
|
||||
}
|
||||
|
||||
// For COD9, write out the complete decompressed zone for testing.
|
||||
QFile testFile("exports/" + GetBaseStem() + ".zone");
|
||||
if(testFile.open(QIODevice::WriteOnly)) {
|
||||
testFile.write(decompressedData);
|
||||
testFile.close();
|
||||
}
|
||||
// Export decompressed zone
|
||||
Utils::ExportData(GetBaseStem() + ".zone", finalZone);
|
||||
|
||||
// Load the zone file with the decompressed data (using an Xbox platform flag).
|
||||
// Load zone file
|
||||
ZoneFile_COD9_PC* zoneFile = new ZoneFile_COD9_PC();
|
||||
zoneFile->SetStem(GetBaseStem() + ".zone");
|
||||
if (!zoneFile->Load(decompressedData)) {
|
||||
if (!zoneFile->Load(finalZone)) {
|
||||
qWarning() << "Failed to load ZoneFile!";
|
||||
return false;
|
||||
}
|
||||
SetZoneFile(zoneFile);
|
||||
|
||||
return true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -69,9 +69,9 @@ bool FastFile_COD10_PS3::Load(const QString aFilePath) {
|
||||
bool FastFile_COD10_PS3::Load(const QByteArray aData) {
|
||||
QByteArray decompressedData;
|
||||
|
||||
// Create a QDataStream on the input data.
|
||||
QDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||
// Create a XDataStream on the input data.
|
||||
XDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||
|
||||
// Parse header values.
|
||||
SetCompany(pParseFFCompany(&fastFileStream));
|
||||
@ -84,9 +84,9 @@ bool FastFile_COD10_PS3::Load(const QByteArray aData) {
|
||||
SetGame("COD9");
|
||||
|
||||
// For COD7/COD9, use BigEndian.
|
||||
fastFileStream.setByteOrder(QDataStream::BigEndian);
|
||||
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
||||
if (GetPlatform() == "PC") {
|
||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||
}
|
||||
|
||||
// Select key based on game.
|
||||
@ -110,15 +110,7 @@ bool FastFile_COD10_PS3::Load(const QByteArray aData) {
|
||||
QByteArray fileName(32, Qt::Uninitialized);
|
||||
fastFileStream.readRawData(fileName.data(), 32);
|
||||
|
||||
// Skip the RSA signature (256 bytes).
|
||||
QByteArray rsaSignature(256, Qt::Uninitialized);
|
||||
fastFileStream.readRawData(rsaSignature.data(), 256);
|
||||
|
||||
if (GetPlatform() == "360") {
|
||||
//decompressedData = Compressor::cod9_decryptFastFile(aData);
|
||||
} else if (GetPlatform() == "PC") {
|
||||
decompressedData = Encryption::decryptFastFile_BO2(aData);
|
||||
}
|
||||
//decompressedData = Encryption::decryptFastFile_BO2(aData);
|
||||
|
||||
// For COD9, write out the complete decompressed zone for testing.
|
||||
QFile testFile("exports/" + GetBaseStem() + ".zone");
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#include "fastfile_cod11_ps3.h"
|
||||
#include "zonefile_cod11_ps3.h"
|
||||
#include "encryption.h"
|
||||
#include "compression.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QDebug>
|
||||
@ -66,68 +67,77 @@ bool FastFile_COD11_PS3::Load(const QString aFilePath) {
|
||||
return true;
|
||||
}
|
||||
|
||||
enum DB_CompressorType : qint32
|
||||
{
|
||||
DB_COMPRESSOR_INVALID = 0x0,
|
||||
DB_COMPRESSOR_ZLIB = 0x1,
|
||||
DB_COMPRESSOR_LZX = 0x2,
|
||||
DB_COMPRESSOR_PASSTHROUGH = 0x3,
|
||||
};
|
||||
|
||||
bool FastFile_COD11_PS3::Load(const QByteArray aData) {
|
||||
QByteArray decompressedData;
|
||||
|
||||
// Create a QDataStream on the input data.
|
||||
QDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||
// Prepare data stream for parsing
|
||||
XDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
||||
|
||||
// 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.
|
||||
// Verify magic header
|
||||
QByteArray fileMagic(8, Qt::Uninitialized);
|
||||
fastFileStream.readRawData(fileMagic.data(), 8);
|
||||
if (fileMagic != "PHEEBs71") {
|
||||
qWarning() << "Invalid fast file magic!";
|
||||
quint32 version = fastFileStream.ParseUInt32();
|
||||
|
||||
fastFileStream.skipRawData(1);
|
||||
|
||||
DB_CompressorType compressorType = (DB_CompressorType)fastFileStream.ParseInt8();
|
||||
|
||||
fastFileStream.skipRawData(10);
|
||||
|
||||
qint32 blockCount = fastFileStream.ParseInt32();
|
||||
|
||||
if (version != 1838)
|
||||
{
|
||||
qWarning() << "Invalid fast file version:" << version << "!";
|
||||
return false;
|
||||
}
|
||||
fastFileStream.skipRawData(4);
|
||||
|
||||
// Read IV table name (32 bytes).
|
||||
QByteArray fileName(32, Qt::Uninitialized);
|
||||
fastFileStream.readRawData(fileName.data(), 32);
|
||||
|
||||
// Skip the RSA signature (256 bytes).
|
||||
QByteArray rsaSignature(256, Qt::Uninitialized);
|
||||
fastFileStream.readRawData(rsaSignature.data(), 256);
|
||||
|
||||
if (GetPlatform() == "360") {
|
||||
//decompressedData = Compressor::cod9_decryptFastFile(aData);
|
||||
} else if (GetPlatform() == "PC") {
|
||||
decompressedData = Encryption::decryptFastFile_BO2(aData);
|
||||
if (blockCount > 17280)
|
||||
{
|
||||
qWarning() << "Fast file has too many blocks:" << blockCount << "> 17280!";
|
||||
return false;
|
||||
}
|
||||
fastFileStream.skipRawData(12 * blockCount);
|
||||
|
||||
// For COD9, write out the complete decompressed zone for testing.
|
||||
QFile testFile("exports/" + GetBaseStem() + ".zone");
|
||||
if(testFile.open(QIODevice::WriteOnly)) {
|
||||
testFile.write(decompressedData);
|
||||
testFile.close();
|
||||
qint32 startPos = fastFileStream.ParseInt32();
|
||||
Q_UNUSED(startPos);
|
||||
|
||||
qint32 endPos = fastFileStream.ParseInt32();
|
||||
Q_UNUSED(endPos);
|
||||
|
||||
if (fileMagic == "S1ffu100")
|
||||
{
|
||||
QByteArray compressedData = aData.mid(fastFileStream.device()->pos());
|
||||
if (compressorType == DB_COMPRESSOR_ZLIB)
|
||||
{
|
||||
decompressedData = Compression::DecompressZLIB(compressedData);
|
||||
}
|
||||
else if (compressorType == DB_COMPRESSOR_LZX)
|
||||
{
|
||||
decompressedData = Compression::DecompressXMem(compressedData, 0, 0x80000, 0);
|
||||
}
|
||||
}
|
||||
else if (fileMagic == "S1ff0100")
|
||||
{
|
||||
|
||||
// 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->SetStem(GetBaseStem() + ".zone");
|
||||
if (!zoneFile->Load(decompressedData)) {
|
||||
|
||||
@ -69,9 +69,9 @@ bool FastFile_COD12_PS3::Load(const QString aFilePath) {
|
||||
bool FastFile_COD12_PS3::Load(const QByteArray aData) {
|
||||
QByteArray decompressedData;
|
||||
|
||||
// Create a QDataStream on the input data.
|
||||
QDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||
// Create a XDataStream on the input data.
|
||||
XDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||
|
||||
// Parse header values.
|
||||
SetCompany(pParseFFCompany(&fastFileStream));
|
||||
@ -84,9 +84,9 @@ bool FastFile_COD12_PS3::Load(const QByteArray aData) {
|
||||
SetGame("COD9");
|
||||
|
||||
// For COD7/COD9, use BigEndian.
|
||||
fastFileStream.setByteOrder(QDataStream::BigEndian);
|
||||
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
||||
if (GetPlatform() == "PC") {
|
||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||
}
|
||||
|
||||
// Select key based on game.
|
||||
@ -110,15 +110,7 @@ bool FastFile_COD12_PS3::Load(const QByteArray aData) {
|
||||
QByteArray fileName(32, Qt::Uninitialized);
|
||||
fastFileStream.readRawData(fileName.data(), 32);
|
||||
|
||||
// Skip the RSA signature (256 bytes).
|
||||
QByteArray rsaSignature(256, Qt::Uninitialized);
|
||||
fastFileStream.readRawData(rsaSignature.data(), 256);
|
||||
|
||||
if (GetPlatform() == "360") {
|
||||
//decompressedData = Compressor::cod9_decryptFastFile(aData);
|
||||
} else if (GetPlatform() == "PC") {
|
||||
decompressedData = Encryption::decryptFastFile_BO2(aData);
|
||||
}
|
||||
decompressedData = Encryption::decryptFastFile_BO3(aData);
|
||||
|
||||
// For COD9, write out the complete decompressed zone for testing.
|
||||
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);
|
||||
QByteArray decompressedData;
|
||||
|
||||
// Create a QDataStream on the input data.
|
||||
QDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||
// Create a XDataStream on the input data.
|
||||
XDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||
|
||||
// Parse header values.
|
||||
SetCompany(pParseFFCompany(&fastFileStream));
|
||||
@ -86,29 +86,24 @@ bool FastFile_COD4_PS3::Load(const QByteArray aData) {
|
||||
SetMagic(pParseFFMagic(&fastFileStream));
|
||||
SetVersion(pParseFFVersion(&fastFileStream));
|
||||
|
||||
int pos = 12;
|
||||
// Loop until EOF or invalid chunk
|
||||
while (pos <= aData.size()) {
|
||||
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
||||
while (!fastFileStream.atEnd()) {
|
||||
// Read 2-byte BIG-ENDIAN chunk size
|
||||
quint32 chunkSize;
|
||||
QDataStream chunkStream(aData.mid(pos, 2));
|
||||
chunkStream.setByteOrder(QDataStream::BigEndian);
|
||||
chunkStream >> chunkSize;
|
||||
quint16 chunkSize;
|
||||
fastFileStream >> chunkSize;
|
||||
|
||||
pos += 2;
|
||||
|
||||
if (chunkSize == 0 || pos + chunkSize > aData.size()) {
|
||||
if (chunkSize == 0 || fastFileStream.device()->pos() + chunkSize > aData.size()) {
|
||||
qWarning() << "Invalid or incomplete chunk detected, stopping.";
|
||||
break;
|
||||
}
|
||||
|
||||
const QByteArray compressedChunk = aData.mid(pos, chunkSize);
|
||||
QByteArray compressedChunk(chunkSize, Qt::Uninitialized);
|
||||
fastFileStream.readRawData(compressedChunk.data(), chunkSize);
|
||||
|
||||
decompressedData.append(Compression::DecompressDeflate(compressedChunk));
|
||||
|
||||
pos += chunkSize;
|
||||
QByteArray decompressedChunk = Compression::DecompressDeflate(compressedChunk);
|
||||
decompressedData.append(decompressedChunk);
|
||||
}
|
||||
|
||||
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
||||
|
||||
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);
|
||||
QByteArray decompressedData;
|
||||
|
||||
// Create a QDataStream on the input data.
|
||||
QDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||
// Create a XDataStream on the input data.
|
||||
XDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||
|
||||
// Parse header values.
|
||||
SetCompany(pParseFFCompany(&fastFileStream));
|
||||
@ -86,29 +86,24 @@ bool FastFile_COD5_PS3::Load(const QByteArray aData) {
|
||||
SetMagic(pParseFFMagic(&fastFileStream));
|
||||
SetVersion(pParseFFVersion(&fastFileStream));
|
||||
|
||||
int pos = 12;
|
||||
// Loop until EOF or invalid chunk
|
||||
while (pos <= aData.size()) {
|
||||
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
||||
while (!fastFileStream.atEnd()) {
|
||||
// Read 2-byte BIG-ENDIAN chunk size
|
||||
quint32 chunkSize;
|
||||
QDataStream chunkStream(aData.mid(pos, 2));
|
||||
chunkStream.setByteOrder(QDataStream::BigEndian);
|
||||
chunkStream >> chunkSize;
|
||||
quint16 chunkSize;
|
||||
fastFileStream >> chunkSize;
|
||||
|
||||
pos += 2;
|
||||
|
||||
if (chunkSize == 0 || pos + chunkSize > aData.size()) {
|
||||
if (chunkSize == 0 || fastFileStream.device()->pos() + chunkSize > aData.size()) {
|
||||
qWarning() << "Invalid or incomplete chunk detected, stopping.";
|
||||
break;
|
||||
}
|
||||
|
||||
const QByteArray compressedChunk = aData.mid(pos, chunkSize);
|
||||
QByteArray compressedChunk(chunkSize, Qt::Uninitialized);
|
||||
fastFileStream.readRawData(compressedChunk.data(), chunkSize);
|
||||
|
||||
decompressedData.append(Compression::DecompressDeflate(compressedChunk));
|
||||
|
||||
pos += chunkSize;
|
||||
QByteArray decompressedChunk = Compression::DecompressDeflate(compressedChunk);
|
||||
decompressedData.append(decompressedChunk);
|
||||
}
|
||||
|
||||
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
||||
|
||||
ZoneFile_COD5_PS3* zoneFile = new ZoneFile_COD5_PS3();
|
||||
|
||||
@ -72,26 +72,30 @@ bool FastFile_COD6_PS3::Load(const QString aFilePath) {
|
||||
}
|
||||
|
||||
bool FastFile_COD6_PS3::Load(const QByteArray aData) {
|
||||
StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/data", 1000);
|
||||
QByteArray decompressedData;
|
||||
const qint64 zlibOffset = Compression::FindZlibOffset(aData);
|
||||
qDebug() << "ZLib Offset: " << zlibOffset;
|
||||
if (zlibOffset == -1)
|
||||
{
|
||||
qWarning() << "Z-Lib stream not found";
|
||||
return false;
|
||||
}
|
||||
QByteArray compressed = aData.mid(zlibOffset);
|
||||
|
||||
// Create a QDataStream on the input data.
|
||||
QDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||
QByteArray decompressedData = Compression::DecompressZLIB(compressed);
|
||||
|
||||
// Parse header values.
|
||||
SetCompany(pParseFFCompany(&fastFileStream));
|
||||
SetType(pParseFFFileType(&fastFileStream));
|
||||
SetSignage(pParseFFSignage(&fastFileStream));
|
||||
SetMagic(pParseFFMagic(&fastFileStream));
|
||||
quint32 version = pParseFFVersion(&fastFileStream);
|
||||
SetVersion(version);
|
||||
const QString platformStr = pCalculateFFPlatform(version);
|
||||
SetPlatform(platformStr);
|
||||
SetGame("COD5");
|
||||
if (decompressedData.isEmpty() || decompressedData.size() < 1024)
|
||||
{
|
||||
QByteArray stripped = Compression::StripHashBlocks(compressed);
|
||||
QByteArray retry = Compression::DecompressZLIB(stripped);
|
||||
if (!retry.isEmpty())
|
||||
decompressedData.swap(retry);
|
||||
}
|
||||
|
||||
// For COD5, simply decompress from offset 12.
|
||||
decompressedData = Compression::DecompressZLIB(aData.mid(12));
|
||||
if (decompressedData.isEmpty())
|
||||
{
|
||||
qWarning() << "Unable to decompress fast-file";
|
||||
return false;
|
||||
}
|
||||
|
||||
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
||||
|
||||
|
||||
@ -62,112 +62,98 @@ bool FastFile_COD7_PS3::Load(const QString aFilePath) {
|
||||
qDebug() << "Error: Failed to load fastfile: " << fastFileStem;
|
||||
return false;
|
||||
}
|
||||
|
||||
file->close();
|
||||
|
||||
// Open zone file after decompressing ff and writing
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FastFile_COD7_PS3::Load(const QByteArray aData) {
|
||||
QByteArray decompressedData;
|
||||
|
||||
// Create a QDataStream on the input data.
|
||||
QDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||
// Create a XDataStream on the input data.
|
||||
XDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||
|
||||
// Parse header values.
|
||||
SetCompany(pParseFFCompany(&fastFileStream));
|
||||
SetType(pParseFFFileType(&fastFileStream));
|
||||
SetSignage(pParseFFSignage(&fastFileStream));
|
||||
SetMagic(pParseFFMagic(&fastFileStream));
|
||||
quint32 version = pParseFFVersion(&fastFileStream);
|
||||
SetVersion(version);
|
||||
SetPlatform(pCalculateFFPlatform(version));
|
||||
SetGame("COD7");
|
||||
SetVersion(pParseFFVersion(&fastFileStream));
|
||||
|
||||
// Load the zone file with the decompressed data (using an Xbox platform flag).
|
||||
ZoneFile_COD7_PS3* zoneFile = new ZoneFile_COD7_PS3();
|
||||
zoneFile->SetStem(GetBaseStem() + ".zone");
|
||||
|
||||
// For COD7/COD9, use BigEndian.
|
||||
fastFileStream.setByteOrder(QDataStream::BigEndian);
|
||||
if (GetPlatform() == "PC") {
|
||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
||||
|
||||
// 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");
|
||||
}
|
||||
// Select key based on game.
|
||||
QByteArray key = "46D3F997F29C9ACE175B0DAE3AB8C0C1B8E423E2E3BF7E3C311EA35245BF193A";
|
||||
fastFileStream.skipRawData(4);
|
||||
|
||||
// Read the 8-byte magic.
|
||||
QByteArray fileMagic(8, Qt::Uninitialized);
|
||||
fastFileStream.readRawData(fileMagic.data(), 8);
|
||||
if (fileMagic != "PHEEBs71") {
|
||||
qWarning() << "Invalid fast file magic!";
|
||||
return false;
|
||||
}
|
||||
fastFileStream.skipRawData(4);
|
||||
// Read 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);
|
||||
// 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);
|
||||
// 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);
|
||||
// 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;
|
||||
// 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);
|
||||
// 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);
|
||||
// Compute the IV for this section.
|
||||
QByteArray iv = Encryption::GetIV(ivTable, sectionIndex);
|
||||
|
||||
// Decrypt the section using Salsa20.
|
||||
QByteArray decData = Encryption::salsa20DecryptSection(sectionData, key, iv);
|
||||
// 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);
|
||||
// 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);
|
||||
// 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);
|
||||
// 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));
|
||||
decompressedData.append(Compression::DecompressZLIB(compressedData));
|
||||
|
||||
sectionIndex++;
|
||||
}
|
||||
sectionIndex++;
|
||||
}
|
||||
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
||||
|
||||
if (!zoneFile->Load(decompressedData)) {
|
||||
qWarning() << "Failed to load ZoneFile!";
|
||||
return false;
|
||||
}
|
||||
if (!zoneFile->Load(decompressedData)) {
|
||||
qWarning() << "Failed to load ZoneFile!";
|
||||
return false;
|
||||
}
|
||||
SetZoneFile(zoneFile);
|
||||
|
||||
|
||||
@ -72,9 +72,9 @@ bool FastFile_COD8_PS3::Load(const QString aFilePath) {
|
||||
bool FastFile_COD8_PS3::Load(const QByteArray aData) {
|
||||
QByteArray decompressedData;
|
||||
|
||||
// Create a QDataStream on the input data.
|
||||
QDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||
// Create a XDataStream on the input data.
|
||||
XDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||
|
||||
// Parse header values.
|
||||
SetCompany(pParseFFCompany(&fastFileStream));
|
||||
@ -90,9 +90,9 @@ bool FastFile_COD8_PS3::Load(const QByteArray aData) {
|
||||
zoneFile->SetStem(GetBaseStem() + ".zone");
|
||||
|
||||
// For COD7/COD9, use BigEndian.
|
||||
fastFileStream.setByteOrder(QDataStream::BigEndian);
|
||||
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
||||
if (GetPlatform() == "PC") {
|
||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||
|
||||
// Select key based on game.
|
||||
QByteArray key;
|
||||
@ -118,51 +118,6 @@ bool FastFile_COD8_PS3::Load(const QByteArray aData) {
|
||||
QByteArray fileName(32, Qt::Uninitialized);
|
||||
fastFileStream.readRawData(fileName.data(), 32);
|
||||
|
||||
// Build the IV table from the fileName.
|
||||
QByteArray ivTable = Encryption::InitIVTable(fileName);
|
||||
|
||||
// Skip the RSA signature (256 bytes).
|
||||
QByteArray rsaSignature(256, Qt::Uninitialized);
|
||||
fastFileStream.readRawData(rsaSignature.data(), 256);
|
||||
|
||||
// Now the stream should be positioned at 0x13C, where sections begin.
|
||||
int sectionIndex = 0;
|
||||
while (true) {
|
||||
qint32 sectionSize = 0;
|
||||
fastFileStream >> sectionSize;
|
||||
qDebug() << "Section index:" << sectionIndex << "Size:" << sectionSize
|
||||
<< "Pos:" << fastFileStream.device()->pos();
|
||||
if (sectionSize == 0)
|
||||
break;
|
||||
|
||||
// Read the section data.
|
||||
QByteArray sectionData;
|
||||
sectionData.resize(sectionSize);
|
||||
fastFileStream.readRawData(sectionData.data(), sectionSize);
|
||||
|
||||
// Compute the IV for this section.
|
||||
QByteArray iv = Encryption::GetIV(ivTable, sectionIndex);
|
||||
|
||||
// Decrypt the section using Salsa20.
|
||||
QByteArray decData = Encryption::salsa20DecryptSection(sectionData, key, iv);
|
||||
|
||||
// Compute SHA1 hash of the decrypted data.
|
||||
QByteArray sectionHash = QCryptographicHash::hash(decData, QCryptographicHash::Sha1);
|
||||
|
||||
// Update the IV table based on the section hash.
|
||||
Encryption::UpdateIVTable(ivTable, sectionIndex, sectionHash);
|
||||
|
||||
// Build a compressed data buffer by prepending the two-byte zlib header.
|
||||
QByteArray compressedData;
|
||||
compressedData.append(char(0x78));
|
||||
compressedData.append(char(0x01));
|
||||
compressedData.append(decData);
|
||||
|
||||
decompressedData.append(Compression::DecompressZLIB(compressedData));
|
||||
|
||||
sectionIndex++;
|
||||
}
|
||||
|
||||
if (!zoneFile->Load(decompressedData)) {
|
||||
qWarning() << "Failed to load ZoneFile!";
|
||||
return false;
|
||||
|
||||
@ -69,9 +69,9 @@ bool FastFile_COD9_PS3::Load(const QString aFilePath) {
|
||||
bool FastFile_COD9_PS3::Load(const QByteArray aData) {
|
||||
QByteArray decompressedData;
|
||||
|
||||
// Create a QDataStream on the input data.
|
||||
QDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||
// Create a XDataStream on the input data.
|
||||
XDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||
|
||||
// Parse header values.
|
||||
SetCompany(pParseFFCompany(&fastFileStream));
|
||||
@ -84,9 +84,9 @@ bool FastFile_COD9_PS3::Load(const QByteArray aData) {
|
||||
SetGame("COD9");
|
||||
|
||||
// For COD7/COD9, use BigEndian.
|
||||
fastFileStream.setByteOrder(QDataStream::BigEndian);
|
||||
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
||||
if (GetPlatform() == "PC") {
|
||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||
}
|
||||
|
||||
// Select key based on game.
|
||||
@ -117,7 +117,7 @@ bool FastFile_COD9_PS3::Load(const QByteArray aData) {
|
||||
if (GetPlatform() == "360") {
|
||||
//decompressedData = Compressor::cod9_decryptFastFile(aData);
|
||||
} else if (GetPlatform() == "PC") {
|
||||
decompressedData = Encryption::decryptFastFile_BO2(aData);
|
||||
//decompressedData = Encryption::decryptFastFile_BO2(aData);
|
||||
}
|
||||
|
||||
// For COD9, write out the complete decompressed zone for testing.
|
||||
|
||||
@ -69,9 +69,9 @@ bool FastFile_COD7_Wii::Load(const QString aFilePath) {
|
||||
bool FastFile_COD7_Wii::Load(const QByteArray aData) {
|
||||
QByteArray decompressedData;
|
||||
|
||||
// Create a QDataStream on the input data.
|
||||
QDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||
// Create a XDataStream on the input data.
|
||||
XDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||
|
||||
// Parse header values.
|
||||
SetCompany(pParseFFCompany(&fastFileStream));
|
||||
@ -84,7 +84,7 @@ bool FastFile_COD7_Wii::Load(const QByteArray aData) {
|
||||
SetGame("COD7");
|
||||
|
||||
// For COD7/COD9, use BigEndian.
|
||||
fastFileStream.setByteOrder(QDataStream::BigEndian);
|
||||
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
||||
|
||||
// For COD7, simply decompress from offset 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) {
|
||||
QByteArray decompressedData;
|
||||
|
||||
// Create a QDataStream on the input data.
|
||||
QDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||
// Create a XDataStream on the input data.
|
||||
XDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||
|
||||
// Parse header values.
|
||||
SetCompany(pParseFFCompany(&fastFileStream));
|
||||
@ -81,7 +81,7 @@ bool FastFile_COD8_Wii::Load(const QByteArray aData) {
|
||||
SetVersion(pParseFFVersion(&fastFileStream));
|
||||
|
||||
// For COD7/COD9, use BigEndian.
|
||||
fastFileStream.setByteOrder(QDataStream::BigEndian);
|
||||
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
||||
|
||||
// For COD7, simply decompress from offset 12.
|
||||
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) {
|
||||
QByteArray decompressedData;
|
||||
|
||||
// Create a QDataStream on the input data.
|
||||
QDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||
// Create a XDataStream on the input data.
|
||||
XDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||
|
||||
// Parse header values.
|
||||
SetCompany(pParseFFCompany(&fastFileStream));
|
||||
@ -82,9 +82,9 @@ bool FastFile_COD10_WiiU::Load(const QByteArray aData) {
|
||||
SetGame("COD9");
|
||||
|
||||
// For COD7/COD9, use BigEndian.
|
||||
fastFileStream.setByteOrder(QDataStream::BigEndian);
|
||||
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
||||
if (GetPlatform() == "PC") {
|
||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||
}
|
||||
|
||||
// Select key based on game.
|
||||
@ -115,7 +115,7 @@ bool FastFile_COD10_WiiU::Load(const QByteArray aData) {
|
||||
if (GetPlatform() == "360") {
|
||||
//decompressedData = Compressor::cod9_decryptFastFile(aData);
|
||||
} else if (GetPlatform() == "PC") {
|
||||
decompressedData = Encryption::decryptFastFile_BO2(aData);
|
||||
//decompressedData = Encryption::decryptFastFile_BO2(aData);
|
||||
}
|
||||
|
||||
// For COD9, write out the complete decompressed zone for testing.
|
||||
|
||||
@ -67,9 +67,9 @@ bool FastFile_COD9_WiiU::Load(const QString aFilePath) {
|
||||
bool FastFile_COD9_WiiU::Load(const QByteArray aData) {
|
||||
QByteArray decompressedData;
|
||||
|
||||
// Create a QDataStream on the input data.
|
||||
QDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||
// Create a XDataStream on the input data.
|
||||
XDataStream fastFileStream(aData);
|
||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||
|
||||
// Parse header values.
|
||||
SetCompany(pParseFFCompany(&fastFileStream));
|
||||
@ -82,9 +82,9 @@ bool FastFile_COD9_WiiU::Load(const QByteArray aData) {
|
||||
SetGame("COD9");
|
||||
|
||||
// For COD7/COD9, use BigEndian.
|
||||
fastFileStream.setByteOrder(QDataStream::BigEndian);
|
||||
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
||||
if (GetPlatform() == "PC") {
|
||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||
}
|
||||
|
||||
// Select key based on game.
|
||||
@ -115,7 +115,7 @@ bool FastFile_COD9_WiiU::Load(const QByteArray aData) {
|
||||
if (GetPlatform() == "360") {
|
||||
//decompressedData = Compressor::cod9_decryptFastFile(aData);
|
||||
} else if (GetPlatform() == "PC") {
|
||||
decompressedData = Encryption::decryptFastFile_BO2(aData);
|
||||
//decompressedData = Encryption::decryptFastFile_BO2(aData);
|
||||
}
|
||||
|
||||
// For COD9, write out the complete decompressed zone for testing.
|
||||
|
||||
@ -115,7 +115,7 @@ void FastFile::SetPlatform(const QString aPlatform) {
|
||||
mPlatform = aPlatform;
|
||||
}
|
||||
|
||||
FF_COMPANY FastFile::pParseFFCompany(QDataStream *afastFileStream, quint32 &aCompanyInt) {
|
||||
FF_COMPANY FastFile::pParseFFCompany(XDataStream *afastFileStream, quint32 &aCompanyInt) {
|
||||
LogManager::instance().addEntry("Parsing company into reference...");
|
||||
// Check for null datastream ptr
|
||||
if (!afastFileStream) { return COMPANY_NONE; }
|
||||
@ -137,7 +137,7 @@ FF_COMPANY FastFile::pParseFFCompany(QDataStream *afastFileStream, quint32 &aCom
|
||||
return COMPANY_NONE;
|
||||
}
|
||||
|
||||
FF_COMPANY FastFile::pParseFFCompany(QDataStream *afastFileStream) {
|
||||
FF_COMPANY FastFile::pParseFFCompany(XDataStream *afastFileStream) {
|
||||
LogManager::instance().addEntry("Parsing company...");
|
||||
// Check for null datastream ptr
|
||||
if (!afastFileStream) { return COMPANY_NONE; }
|
||||
@ -157,7 +157,7 @@ FF_COMPANY FastFile::pParseFFCompany(QDataStream *afastFileStream) {
|
||||
return COMPANY_NONE;
|
||||
}
|
||||
|
||||
FF_FILETYPE FastFile::pParseFFFileType(QDataStream *afastFileStream) {
|
||||
FF_FILETYPE FastFile::pParseFFFileType(XDataStream *afastFileStream) {
|
||||
// Parse filetype
|
||||
QByteArray fileTypeData(2, Qt::Uninitialized);
|
||||
afastFileStream->readRawData(fileTypeData.data(), 2);
|
||||
@ -168,7 +168,7 @@ FF_FILETYPE FastFile::pParseFFFileType(QDataStream *afastFileStream) {
|
||||
return FILETYPE_NONE;
|
||||
}
|
||||
|
||||
FF_SIGNAGE FastFile::pParseFFSignage(QDataStream *afastFileStream) {
|
||||
FF_SIGNAGE FastFile::pParseFFSignage(XDataStream *afastFileStream) {
|
||||
// Parse filetype
|
||||
QByteArray signedData(1, Qt::Uninitialized);
|
||||
afastFileStream->readRawData(signedData.data(), 1);
|
||||
@ -181,7 +181,7 @@ FF_SIGNAGE FastFile::pParseFFSignage(QDataStream *afastFileStream) {
|
||||
return SIGNAGE_NONE;
|
||||
}
|
||||
|
||||
QString FastFile::pParseFFMagic(QDataStream *afastFileStream) {
|
||||
QString FastFile::pParseFFMagic(XDataStream *afastFileStream) {
|
||||
// Parse magic
|
||||
QByteArray magicData(3, Qt::Uninitialized);
|
||||
afastFileStream->readRawData(magicData.data(), 3);
|
||||
@ -192,7 +192,7 @@ QString FastFile::pParseFFMagic(QDataStream *afastFileStream) {
|
||||
return "";
|
||||
}
|
||||
|
||||
quint32 FastFile::pParseFFVersion(QDataStream *afastFileStream) {
|
||||
quint32 FastFile::pParseFFVersion(XDataStream *afastFileStream) {
|
||||
// Parse version
|
||||
quint32 version;
|
||||
*afastFileStream >> version;
|
||||
@ -267,7 +267,7 @@ FastFile* FastFile::Open(const QString &aFilePath) {
|
||||
const QString fastFileStem = aFilePath.section("/", -1, -1);
|
||||
LogManager::instance().addEntry(QString("Stem: %1").arg(fastFileStem));
|
||||
|
||||
FastFile* fastFile = FastFileFactory::Create(data);
|
||||
FastFile* fastFile = FastFileFactory::Create(data, fastFileStem);
|
||||
fastFile->SetStem(fastFileStem);
|
||||
|
||||
return fastFile;
|
||||
|
||||
@ -46,12 +46,12 @@ public:
|
||||
virtual void SetGame(const QString aGame);
|
||||
virtual void SetPlatform(const QString aPlatform);
|
||||
|
||||
static FF_COMPANY pParseFFCompany(QDataStream *afastFileStream, quint32 &aCompanyInt);
|
||||
static FF_COMPANY pParseFFCompany(QDataStream *afastFileStream);
|
||||
static FF_FILETYPE pParseFFFileType(QDataStream *afastFileStream);
|
||||
static FF_SIGNAGE pParseFFSignage(QDataStream *afastFileStream);
|
||||
static QString pParseFFMagic(QDataStream *afastFileStream);
|
||||
static quint32 pParseFFVersion(QDataStream *afastFileStream);
|
||||
static FF_COMPANY pParseFFCompany(XDataStream *afastFileStream, quint32 &aCompanyInt);
|
||||
static FF_COMPANY pParseFFCompany(XDataStream *afastFileStream);
|
||||
static FF_FILETYPE pParseFFFileType(XDataStream *afastFileStream);
|
||||
static FF_SIGNAGE pParseFFSignage(XDataStream *afastFileStream);
|
||||
static QString pParseFFMagic(XDataStream *afastFileStream);
|
||||
static quint32 pParseFFVersion(XDataStream *afastFileStream);
|
||||
static QString pCalculateFFPlatform(quint32 aVersion);
|
||||
static QString pCalculateFFGame(quint32 aVersion);
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
#include "360/fastfile_cod5_360.h"
|
||||
#include "360/fastfile_cod6_360.h"
|
||||
#include "360/fastfile_cod7_360.h"
|
||||
#include "360/fastfile_cod7_5_360.h"
|
||||
#include "360/fastfile_cod8_360.h"
|
||||
#include "360/fastfile_cod9_360.h"
|
||||
#include "360/fastfile_cod10_360.h"
|
||||
@ -52,25 +53,26 @@ class FastFile;
|
||||
|
||||
enum FastFile_Platform {
|
||||
PLATFORM_NONE = 0x00,
|
||||
PLATFORM_PC = 0x01,
|
||||
PLATFORM_360 = 0x02,
|
||||
PLATFORM_PS3 = 0x03,
|
||||
PLATFORM_WII = 0x04,
|
||||
PLATFORM_PC = 0x01,
|
||||
PLATFORM_360 = 0x02,
|
||||
PLATFORM_PS3 = 0x03,
|
||||
PLATFORM_WII = 0x04,
|
||||
PLATFORM_WIIU = 0x05
|
||||
};
|
||||
|
||||
enum FastFile_Game {
|
||||
GAME_NONE = 0x00,
|
||||
GAME_COD2 = 0x01,
|
||||
GAME_COD4 = 0x02,
|
||||
GAME_COD5 = 0x03,
|
||||
GAME_COD6 = 0x04,
|
||||
GAME_COD7 = 0x05,
|
||||
GAME_COD8 = 0x06,
|
||||
GAME_COD9 = 0x07,
|
||||
GAME_COD10 = 0x08,
|
||||
GAME_COD11 = 0x09,
|
||||
GAME_COD12 = 0x010
|
||||
GAME_NONE = 0x00,
|
||||
GAME_COD2 = 0x01,
|
||||
GAME_COD4 = 0x02,
|
||||
GAME_COD5 = 0x03,
|
||||
GAME_COD6 = 0x04,
|
||||
GAME_COD7 = 0x05,
|
||||
GAME_COD7_5 = 0x06,
|
||||
GAME_COD8 = 0x07,
|
||||
GAME_COD9 = 0x08,
|
||||
GAME_COD10 = 0x09,
|
||||
GAME_COD11 = 0x10,
|
||||
GAME_COD12 = 0x11
|
||||
};
|
||||
|
||||
class FastFileFactory {
|
||||
@ -185,83 +187,86 @@ public:
|
||||
|
||||
if (aPlatform == PLATFORM_360) {
|
||||
if (aGame == GAME_COD2) {
|
||||
resultFF = new FastFile_COD2_360(aData);
|
||||
resultFF = new FastFile_COD2_360();
|
||||
} else if (aGame == GAME_COD4) {
|
||||
resultFF = new FastFile_COD4_360(aData);
|
||||
resultFF = new FastFile_COD4_360();
|
||||
} else if (aGame == GAME_COD5) {
|
||||
resultFF = new FastFile_COD5_360(aData);
|
||||
resultFF = new FastFile_COD5_360();
|
||||
} else if (aGame == GAME_COD6) {
|
||||
resultFF = new FastFile_COD6_360(aData);
|
||||
resultFF = new FastFile_COD6_360();
|
||||
} else if (aGame == GAME_COD7) {
|
||||
resultFF = new FastFile_COD7_360(aData);
|
||||
resultFF = new FastFile_COD7_360();
|
||||
} else if (aGame == GAME_COD7_5) {
|
||||
resultFF = new FastFile_COD7_5_360();
|
||||
} else if (aGame == GAME_COD8) {
|
||||
resultFF = new FastFile_COD8_360(aData);
|
||||
resultFF = new FastFile_COD8_360();
|
||||
} else if (aGame == GAME_COD9) {
|
||||
resultFF = new FastFile_COD9_360(aData);
|
||||
resultFF = new FastFile_COD9_360();
|
||||
} else if (aGame == GAME_COD10) {
|
||||
resultFF = new FastFile_COD10_360(aData);
|
||||
resultFF = new FastFile_COD10_360();
|
||||
} else if (aGame == GAME_COD11) {
|
||||
resultFF = new FastFile_COD11_360(aData);
|
||||
resultFF = new FastFile_COD11_360();
|
||||
} else if (aGame == GAME_COD12) {
|
||||
resultFF = new FastFile_COD12_360(aData);
|
||||
resultFF = new FastFile_COD12_360();
|
||||
}
|
||||
} else if (aPlatform == PLATFORM_PC) {
|
||||
if (aGame == GAME_COD4) {
|
||||
resultFF = new FastFile_COD4_PC(aData);
|
||||
resultFF = new FastFile_COD4_PC();
|
||||
} else if (aGame == GAME_COD5) {
|
||||
resultFF = new FastFile_COD5_PC(aData);
|
||||
resultFF = new FastFile_COD5_PC();
|
||||
} else if (aGame == GAME_COD6) {
|
||||
resultFF = new FastFile_COD6_PC(aData);
|
||||
resultFF = new FastFile_COD6_PC();
|
||||
} else if (aGame == GAME_COD7) {
|
||||
resultFF = new FastFile_COD7_PC(aData);
|
||||
resultFF = new FastFile_COD7_PC();
|
||||
} else if (aGame == GAME_COD8) {
|
||||
resultFF = new FastFile_COD8_PC(aData);
|
||||
resultFF = new FastFile_COD8_PC();
|
||||
} else if (aGame == GAME_COD9) {
|
||||
resultFF = new FastFile_COD9_PC(aData);
|
||||
resultFF = new FastFile_COD9_PC();
|
||||
} else if (aGame == GAME_COD10) {
|
||||
resultFF = new FastFile_COD10_PC(aData);
|
||||
resultFF = new FastFile_COD10_PC();
|
||||
} else if (aGame == GAME_COD11) {
|
||||
resultFF = new FastFile_COD11_PC(aData);
|
||||
resultFF = new FastFile_COD11_PC();
|
||||
} else if (aGame == GAME_COD12) {
|
||||
resultFF = new FastFile_COD12_PC(aData);
|
||||
resultFF = new FastFile_COD12_PC();
|
||||
}
|
||||
} else if (aPlatform == PLATFORM_PS3) {
|
||||
if (aGame == GAME_COD4) {
|
||||
resultFF = new FastFile_COD4_PS3(aData);
|
||||
resultFF = new FastFile_COD4_PS3();
|
||||
} else if (aGame == GAME_COD5) {
|
||||
resultFF = new FastFile_COD5_PS3(aData);
|
||||
resultFF = new FastFile_COD5_PS3();
|
||||
} else if (aGame == GAME_COD6) {
|
||||
resultFF = new FastFile_COD6_PS3(aData);
|
||||
resultFF = new FastFile_COD6_PS3();
|
||||
} else if (aGame == GAME_COD7) {
|
||||
resultFF = new FastFile_COD7_PS3(aData);
|
||||
resultFF = new FastFile_COD7_PS3();
|
||||
} else if (aGame == GAME_COD8) {
|
||||
resultFF = new FastFile_COD8_PS3(aData);
|
||||
resultFF = new FastFile_COD8_PS3();
|
||||
} else if (aGame == GAME_COD9) {
|
||||
resultFF = new FastFile_COD9_PS3(aData);
|
||||
resultFF = new FastFile_COD9_PS3();
|
||||
} else if (aGame == GAME_COD10) {
|
||||
resultFF = new FastFile_COD10_PS3(aData);
|
||||
resultFF = new FastFile_COD10_PS3();
|
||||
} else if (aGame == GAME_COD11) {
|
||||
resultFF = new FastFile_COD11_PS3(aData);
|
||||
resultFF = new FastFile_COD11_PS3();
|
||||
} else if (aGame == GAME_COD12) {
|
||||
resultFF = new FastFile_COD12_PS3(aData);
|
||||
resultFF = new FastFile_COD12_PS3();
|
||||
}
|
||||
} else if (aPlatform == PLATFORM_WII) {
|
||||
if (aGame == GAME_COD4) {
|
||||
resultFF = new FastFile_COD4_Wii(aData);
|
||||
resultFF = new FastFile_COD4_Wii();
|
||||
} else if (aGame == GAME_COD7) {
|
||||
resultFF = new FastFile_COD7_Wii(aData);
|
||||
resultFF = new FastFile_COD7_Wii();
|
||||
} else if (aGame == GAME_COD8) {
|
||||
resultFF = new FastFile_COD8_Wii(aData);
|
||||
resultFF = new FastFile_COD8_Wii();
|
||||
}
|
||||
} else if (aPlatform == PLATFORM_WIIU) {
|
||||
if (aGame == GAME_COD9) {
|
||||
resultFF = new FastFile_COD9_WiiU(aData);
|
||||
resultFF = new FastFile_COD9_WiiU();
|
||||
} else if (aGame == GAME_COD10) {
|
||||
resultFF = new FastFile_COD10_WiiU(aData);
|
||||
resultFF = new FastFile_COD10_WiiU();
|
||||
}
|
||||
}
|
||||
if (resultFF) {
|
||||
resultFF->SetStem(aStem);
|
||||
resultFF->Load(aData);
|
||||
}
|
||||
return resultFF;
|
||||
}
|
||||
@ -283,7 +288,7 @@ private:
|
||||
|
||||
static FastFile_Platform pGetPlatform(const QByteArray& aData) {
|
||||
const QStringList sections = pGetDataSections(aData);
|
||||
if (sections[0] == "0000") {
|
||||
if (sections[0] == "0000" || sections[0] == "4E58") {
|
||||
return PLATFORM_360;
|
||||
} else if (sections[4] == "0000") {
|
||||
if (sections[5] == "0001" && sections[6] == "78DA") {
|
||||
@ -292,6 +297,8 @@ private:
|
||||
return PLATFORM_360;
|
||||
} else if (sections[5] == "0183" && sections[6] == "7801") {
|
||||
return PLATFORM_360;
|
||||
} else if (sections[5] == "01D9" && sections[6] == "0000") {
|
||||
return PLATFORM_360;
|
||||
} else if (sections[6] == "0101" && sections[7] == "CA3E") {
|
||||
return PLATFORM_360;
|
||||
} else if (sections[6] == "0000" && sections[7] == "0001") {
|
||||
@ -333,6 +340,8 @@ private:
|
||||
return GAME_COD6;
|
||||
} else if (sections[4] == "D901" || sections[5] == "01DD" || sections[5] == "01D9") {
|
||||
return GAME_COD7;
|
||||
} else if (sections[0] == "4E58") {
|
||||
return GAME_COD7_5;
|
||||
} else if (sections[4] == "0100" || sections[5] == "006B" || sections[5] == "0070") {
|
||||
return GAME_COD8;
|
||||
} else if (sections[4] == "9300" || sections[5] == "0092"
|
||||
|
||||
@ -6,6 +6,6 @@ SUBDIRS += core \
|
||||
fastfile \
|
||||
xassets \
|
||||
zonefile \
|
||||
ddsfile \
|
||||
iwifile \
|
||||
ipakfile
|
||||
#ddsfile \
|
||||
#iwifile \
|
||||
#ipakfile
|
||||
|
||||
@ -5,14 +5,10 @@ XAnimDeltaPart::XAnimDeltaPart()
|
||||
, mTrans()
|
||||
, mQuat()
|
||||
{
|
||||
SetName("Animation Delta Part");
|
||||
}
|
||||
|
||||
XAnimDeltaPart::~XAnimDeltaPart()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void XAnimDeltaPart::ParseData(QDataStream *aStream) {
|
||||
void XAnimDeltaPart::ParseData(XDataStream *aStream) {
|
||||
if (GetPtr() == -1) {
|
||||
mTrans.ParsePtr(aStream);
|
||||
mQuat.ParsePtr(aStream);
|
||||
|
||||
@ -9,9 +9,9 @@ class XAnimDeltaPart : public XAsset
|
||||
{
|
||||
public:
|
||||
explicit XAnimDeltaPart();
|
||||
~XAnimDeltaPart();
|
||||
~XAnimDeltaPart() = default;
|
||||
|
||||
void ParseData(QDataStream *aStream) override;
|
||||
void ParseData(XDataStream *aStream) override;
|
||||
void Clear() override;
|
||||
|
||||
const XAnimPartTrans& GetTrans() const;
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
#include "xanimdeltapartquat.h"
|
||||
|
||||
XAnimDeltaPartQuat::XAnimDeltaPartQuat()
|
||||
: XAsset() {
|
||||
: XAsset()
|
||||
{
|
||||
SetName("Animation Delta Part Quat");
|
||||
}
|
||||
|
||||
void XAnimDeltaPartQuat::ParseData(QDataStream *aStream) {
|
||||
void XAnimDeltaPartQuat::ParseData(XDataStream *aStream) {
|
||||
if (GetPtr() == -1) {
|
||||
*aStream >> mSize;
|
||||
mSize = aStream->ParseUInt32(QString("%1 size").arg(GetName()));
|
||||
|
||||
// Parse data
|
||||
mData.ParseData(aStream);
|
||||
|
||||
@ -1,9 +1,3 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef XANIMDELTAPARTQUAT_H
|
||||
#define XANIMDELTAPARTQUAT_H
|
||||
|
||||
@ -14,8 +8,9 @@ class XAnimDeltaPartQuat : public XAsset
|
||||
{
|
||||
public:
|
||||
explicit XAnimDeltaPartQuat();
|
||||
~XAnimDeltaPartQuat() = default;
|
||||
|
||||
void ParseData(QDataStream *aStream) override;
|
||||
void ParseData(XDataStream *aStream) override;
|
||||
|
||||
quint32 GetSize() const;
|
||||
void SetSize(quint32 size);
|
||||
@ -29,8 +24,3 @@ private:
|
||||
};
|
||||
|
||||
#endif // XANIMDELTAPARTQUAT_H
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
#include "xanimdeltapartquatdata.h"
|
||||
|
||||
XAnimDeltaPartQuatData::XAnimDeltaPartQuatData()
|
||||
: XAsset() {
|
||||
: XAsset()
|
||||
{
|
||||
SetName("Animation Delta Part Quat Data");
|
||||
}
|
||||
|
||||
void XAnimDeltaPartQuatData::ParseData(QDataStream *aStream) {
|
||||
void XAnimDeltaPartQuatData::ParseData(XDataStream *aStream) {
|
||||
if (GetPtr() == -1) {
|
||||
// Parse frames
|
||||
mFrames.ParseData(aStream);
|
||||
|
||||
@ -1,9 +1,3 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef XANIMDELTAPARTQUATDATA_H
|
||||
#define XANIMDELTAPARTQUATDATA_H
|
||||
|
||||
@ -14,8 +8,9 @@ class XAnimDeltaPartQuatData : public XAsset
|
||||
{
|
||||
public:
|
||||
explicit XAnimDeltaPartQuatData();
|
||||
~XAnimDeltaPartQuatData() = default;
|
||||
|
||||
void ParseData(QDataStream *aStream) override;
|
||||
void ParseData(XDataStream *aStream) override;
|
||||
|
||||
const XAnimDeltaPartQuatDataFrames& GetFrames() const;
|
||||
void SetFrames(const XAnimDeltaPartQuatDataFrames& frames);
|
||||
@ -29,8 +24,3 @@ private:
|
||||
};
|
||||
|
||||
#endif // XANIMDELTAPARTQUATDATA_H
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
#include "xanimdeltapartquatdataframes.h"
|
||||
|
||||
XAnimDeltaPartQuatDataFrames::XAnimDeltaPartQuatDataFrames()
|
||||
: XAsset() {
|
||||
: XAsset()
|
||||
{
|
||||
SetName("Animation Delta Part Quat Data Frame");
|
||||
}
|
||||
|
||||
quint32 XAnimDeltaPartQuatDataFrames::GetFramesPtr() const {
|
||||
@ -34,12 +36,12 @@ void XAnimDeltaPartQuatDataFrames::SetIndices(const XAnimDynamicIndices& indices
|
||||
mIndices = indices;
|
||||
}
|
||||
|
||||
void XAnimDeltaPartQuatDataFrames::ParseData(QDataStream *aStream) {
|
||||
void XAnimDeltaPartQuatDataFrames::ParseData(XDataStream *aStream) {
|
||||
if (GetPtr() == -1) {
|
||||
*aStream
|
||||
>> mFramesPtr
|
||||
>> mFrames[0]
|
||||
>> mFrames[1];
|
||||
mFramesPtr = aStream->ParseInt32(QString("%1 frames ptr").arg(GetName()));
|
||||
|
||||
mFrames[0] = aStream->ParseInt16(QString("%1 frame %2").arg(GetName()).arg(0));
|
||||
mFrames[1] = aStream->ParseInt16(QString("%1 frame %2").arg(GetName()).arg(1));
|
||||
|
||||
// Parse indices
|
||||
mIndices.ParseData(aStream);
|
||||
|
||||
@ -8,6 +8,7 @@ class XAnimDeltaPartQuatDataFrames : public XAsset
|
||||
{
|
||||
public:
|
||||
explicit XAnimDeltaPartQuatDataFrames();
|
||||
~XAnimDeltaPartQuatDataFrames() = default;
|
||||
|
||||
quint32 GetFramesPtr() const;
|
||||
void SetFramesPtr(quint32 ptr);
|
||||
@ -19,11 +20,11 @@ public:
|
||||
const XAnimDynamicIndices& GetIndices() const;
|
||||
void SetIndices(const XAnimDynamicIndices& indices);
|
||||
|
||||
void ParseData(QDataStream *aStream) override;
|
||||
void ParseData(XDataStream *aStream) override;
|
||||
void Clear() override;
|
||||
|
||||
private:
|
||||
quint32 mFramesPtr = 0;
|
||||
qint32 mFramesPtr = 0;
|
||||
qint16 mFrames[2] = {0};
|
||||
XAnimDynamicIndices mIndices;
|
||||
};
|
||||
|
||||
@ -4,24 +4,17 @@ XAnimDynamicFrames::XAnimDynamicFrames()
|
||||
: XAsset()
|
||||
, mFrames(3)
|
||||
{
|
||||
SetName("Animation Dynamic Frames");
|
||||
}
|
||||
|
||||
XAnimDynamicFrames::~XAnimDynamicFrames()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void XAnimDynamicFrames::ParseData(QDataStream *aStream) {
|
||||
void XAnimDynamicFrames::ParseData(XDataStream *aStream) {
|
||||
if (GetPtr() == -1) {
|
||||
qint32 framePtr;
|
||||
*aStream >> framePtr;
|
||||
|
||||
qint32 framePtr = aStream->ParseInt32(QString("%1 frames ptr").arg(GetName()));
|
||||
if (framePtr == -1)
|
||||
{
|
||||
*aStream
|
||||
>> mFrames[0]
|
||||
>> mFrames[1]
|
||||
>> mFrames[2];
|
||||
mFrames[0] = aStream->ParseUInt8(QString("%1 frame %2").arg(GetName()).arg(0));
|
||||
mFrames[1] = aStream->ParseUInt8(QString("%1 frame %2").arg(GetName()).arg(1));
|
||||
mFrames[2] = aStream->ParseUInt8(QString("%1 frame %2").arg(GetName()).arg(2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
|
||||
#ifndef XANIMDYNAMICFRAMES_H
|
||||
#define XANIMDYNAMICFRAMES_H
|
||||
|
||||
@ -10,9 +9,9 @@ class XAnimDynamicFrames : public XAsset
|
||||
{
|
||||
public:
|
||||
explicit XAnimDynamicFrames();
|
||||
~XAnimDynamicFrames();
|
||||
~XAnimDynamicFrames() = default;
|
||||
|
||||
void ParseData(QDataStream *aStream) override;
|
||||
void ParseData(XDataStream *aStream) override;
|
||||
void Clear() override;
|
||||
|
||||
QVector<quint8> GetFrames() const;
|
||||
|
||||
@ -4,16 +4,12 @@ XAnimDynamicIndices::XAnimDynamicIndices()
|
||||
: XAsset()
|
||||
, mIndices(1)
|
||||
{
|
||||
SetName("Animation Dynamic Indices");
|
||||
}
|
||||
|
||||
XAnimDynamicIndices::~XAnimDynamicIndices()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void XAnimDynamicIndices::ParseData(QDataStream *aStream) {
|
||||
void XAnimDynamicIndices::ParseData(XDataStream *aStream) {
|
||||
if (GetPtr() == -1) {
|
||||
*aStream >> mIndices[0];
|
||||
mIndices[0] = aStream->ParseUInt8(QString("%1 index").arg(GetName()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -9,9 +9,9 @@ class XAnimDynamicIndices : public XAsset
|
||||
{
|
||||
public:
|
||||
explicit XAnimDynamicIndices();
|
||||
~XAnimDynamicIndices();
|
||||
~XAnimDynamicIndices() = default;
|
||||
|
||||
void ParseData(QDataStream *aStream) override;
|
||||
void ParseData(XDataStream *aStream) override;
|
||||
void Clear() override;
|
||||
|
||||
QVector<quint8> GetIndices() const;
|
||||
|
||||
@ -4,21 +4,15 @@ XAnimIndices::XAnimIndices()
|
||||
: XAsset()
|
||||
, mIndex(0)
|
||||
{
|
||||
|
||||
SetName("Animation Indices");
|
||||
}
|
||||
|
||||
XAnimIndices::~XAnimIndices()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void XAnimIndices::ParseData(QDataStream *aStream) {
|
||||
void XAnimIndices::ParseData(XDataStream *aStream) {
|
||||
if (GetPtr() == -1) {
|
||||
qint32 indexPtr;
|
||||
*aStream >> indexPtr;
|
||||
qint32 indexPtr = aStream->ParseInt32(QString("%1 index ptr").arg(GetName()));
|
||||
if (indexPtr == -1)
|
||||
{
|
||||
*aStream >> mIndex;
|
||||
mIndex = aStream->ParseUInt32(QString("%1 index").arg(GetName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,9 +7,9 @@ class XAnimIndices : public XAsset
|
||||
{
|
||||
public:
|
||||
explicit XAnimIndices();
|
||||
~XAnimIndices();
|
||||
~XAnimIndices() = default;
|
||||
|
||||
void ParseData(QDataStream *aStream) override;
|
||||
void ParseData(XDataStream *aStream) override;
|
||||
void Clear() override;
|
||||
|
||||
quint32 GetIndex() const;
|
||||
|
||||
@ -5,19 +5,14 @@ XAnimNotifyInfo::XAnimNotifyInfo()
|
||||
, mName(0)
|
||||
, mTime(0.0f)
|
||||
{
|
||||
|
||||
SetName("Animation Notify Info");
|
||||
}
|
||||
|
||||
XAnimNotifyInfo::~XAnimNotifyInfo()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void XAnimNotifyInfo::ParseData(QDataStream *aStream) {
|
||||
void XAnimNotifyInfo::ParseData(XDataStream *aStream) {
|
||||
if (GetPtr() == -1) {
|
||||
*aStream
|
||||
>> mName
|
||||
>> mTime;
|
||||
|
||||
mName = aStream->ParseUInt32(QString("%1 name").arg(GetName()));
|
||||
mTime = aStream->ParseSingle(QString("%1 time").arg(GetName()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,19 +21,3 @@ void XAnimNotifyInfo::Clear()
|
||||
mName = 0;
|
||||
mTime = 0.0f;
|
||||
}
|
||||
|
||||
quint32 XAnimNotifyInfo::GetName() const {
|
||||
return mName;
|
||||
}
|
||||
|
||||
void XAnimNotifyInfo::SetName(quint32 name) {
|
||||
mName = name;
|
||||
}
|
||||
|
||||
float XAnimNotifyInfo::GetTime() const {
|
||||
return mTime;
|
||||
}
|
||||
|
||||
void XAnimNotifyInfo::SetTime(float time) {
|
||||
mTime = time;
|
||||
}
|
||||
|
||||
@ -7,17 +7,11 @@ class XAnimNotifyInfo : public XAsset
|
||||
{
|
||||
public:
|
||||
explicit XAnimNotifyInfo();
|
||||
~XAnimNotifyInfo();
|
||||
~XAnimNotifyInfo() = default;
|
||||
|
||||
void ParseData(QDataStream *aStream) override;
|
||||
void ParseData(XDataStream *aStream) override;
|
||||
void Clear() override;
|
||||
|
||||
quint32 GetName() const;
|
||||
void SetName(quint32 name);
|
||||
|
||||
float GetTime() const;
|
||||
void SetTime(float time);
|
||||
|
||||
private:
|
||||
quint32 mName;
|
||||
float mTime;
|
||||
|
||||
@ -31,68 +31,49 @@ XAnimParts::XAnimParts()
|
||||
, mDeltaPart()
|
||||
{
|
||||
SetType(ASSET_TYPE_XANIMPARTS);
|
||||
SetName("XAnimParts");
|
||||
SetName("Animation Parts");
|
||||
}
|
||||
|
||||
XAnimParts::~XAnimParts()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void XAnimParts::ParseData(QDataStream *aStream) {
|
||||
void XAnimParts::ParseData(XDataStream *aStream) {
|
||||
if (GetPtr() == -1) {
|
||||
|
||||
mName.ParsePtr(aStream, false);
|
||||
|
||||
// Parse all fields
|
||||
*aStream
|
||||
>> mDataByteCount
|
||||
>> mDataShortCount
|
||||
>> mDataIntCount
|
||||
>> mRandomDataByteCount
|
||||
>> mRandomDataIntCount
|
||||
>> mNumFrames;
|
||||
mDataByteCount = aStream->ParseUInt32(QString("%1 data byte count").arg(GetName()));
|
||||
mDataShortCount = aStream->ParseUInt32(QString("%1 data short count").arg(GetName()));
|
||||
mDataIntCount = aStream->ParseUInt32(QString("%1 data int count").arg(GetName()));
|
||||
mRandomDataByteCount = aStream->ParseUInt32(QString("%1 random date byte count").arg(GetName()));
|
||||
mRandomDataIntCount = aStream->ParseUInt32(QString("%1 random data int count").arg(GetName()));
|
||||
mNumFrames = aStream->ParseUInt32(QString("%1 # frames").arg(GetName()));
|
||||
|
||||
quint8 loopDelta;
|
||||
*aStream >> loopDelta;
|
||||
quint8 loopDelta = aStream->ParseUInt8(QString("%1 loop delta").arg(GetName()));
|
||||
mIsLoop = (loopDelta & 0x1) != 0;
|
||||
mIsDelta = (loopDelta & 0x2) != 0;
|
||||
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
*aStream >> mBoneCount[i];
|
||||
mBoneCount[i] = aStream->ParseUInt8(QString("%1 bone count %2").arg(GetName()).arg(i));
|
||||
}
|
||||
|
||||
*aStream
|
||||
>> mNotifyCount
|
||||
>> mAssetType;
|
||||
|
||||
quint32 pad;
|
||||
*aStream >> pad;
|
||||
mPad = (pad != 0);
|
||||
mNotifyCount = aStream->ParseUInt8(QString("%1 notify count").arg(GetName()));
|
||||
mAssetType = aStream->ParseUInt8(QString("%1 asset type").arg(GetName()));
|
||||
mPad = aStream->ParseUInt32(QString("%1 pad").arg(GetName())) != 0;
|
||||
|
||||
qint32 namesPtr, dataBytePtr, dataShortPtr, dataIntPtr,
|
||||
randomDataShortPtr, randomDataBytePtr, randomDataIntPtr;
|
||||
|
||||
*aStream
|
||||
>> mRandomDataShortCount
|
||||
>> mIndexCount
|
||||
>> mFramerate
|
||||
>> mFrequency
|
||||
>> namesPtr
|
||||
>> mNames
|
||||
>> dataBytePtr
|
||||
>> mDataByte
|
||||
>> dataShortPtr
|
||||
>> mDataShort
|
||||
>> dataIntPtr
|
||||
>> mDataInt
|
||||
>> randomDataShortPtr
|
||||
>> mRandomDataShort
|
||||
>> randomDataBytePtr
|
||||
>> mRandomDataByte
|
||||
>> randomDataIntPtr
|
||||
>> mRandomDataInt;
|
||||
mRandomDataShortCount = aStream->ParseUInt32(QString("%1 random data short count").arg(GetName()));
|
||||
mIndexCount = aStream->ParseUInt32(QString("%1 index count").arg(GetName()));
|
||||
mFramerate = aStream->ParseSingle(QString("%1 frame rate").arg(GetName()));
|
||||
mFrequency = aStream->ParseSingle(QString("%1 frequency").arg(GetName()));
|
||||
namesPtr = aStream->ParseInt32(QString("%1 names ptr").arg(GetName()));
|
||||
dataBytePtr = aStream->ParseInt32(QString("%1 data byte ptr").arg(GetName()));
|
||||
dataShortPtr = aStream->ParseInt32(QString("%1 data short ptr").arg(GetName()));
|
||||
dataIntPtr = aStream->ParseInt32(QString("%1 data int ptr").arg(GetName()));
|
||||
randomDataShortPtr = aStream->ParseInt32(QString("%1 random data short ptr").arg(GetName()));
|
||||
randomDataBytePtr = aStream->ParseInt32(QString("%1 random data byte ptr").arg(GetName()));
|
||||
randomDataIntPtr = aStream->ParseInt32(QString("%1 random data int ptr").arg(GetName()));
|
||||
|
||||
// Parse indices
|
||||
mIndices.ParseData(aStream);
|
||||
@ -102,33 +83,33 @@ void XAnimParts::ParseData(QDataStream *aStream) {
|
||||
mName.ParseData(aStream);
|
||||
if (namesPtr)
|
||||
{
|
||||
|
||||
mNames = aStream->ParseInt32(QString("%1 names").arg(GetName()));
|
||||
}
|
||||
mNotify.ParseData(aStream);
|
||||
mDeltaPart.ParseData(aStream);
|
||||
if (dataBytePtr)
|
||||
{
|
||||
*aStream >> mDataByte;
|
||||
mDataByte = aStream->ParseUInt8(QString("%1 data byte").arg(GetName()));
|
||||
}
|
||||
if (dataShortPtr)
|
||||
{
|
||||
*aStream >> mDataShort;
|
||||
mDataShort = aStream->ParseInt16(QString("%1 data short").arg(GetName()));
|
||||
}
|
||||
if (dataIntPtr)
|
||||
{
|
||||
*aStream >> mDataInt;
|
||||
mDataInt = aStream->ParseInt32(QString("%1 data int").arg(GetName()));
|
||||
}
|
||||
if (randomDataShortPtr)
|
||||
{
|
||||
*aStream >> mDataInt;
|
||||
mRandomDataShort = aStream->ParseInt16(QString("%1 random data short").arg(GetName()));
|
||||
}
|
||||
if (randomDataBytePtr)
|
||||
{
|
||||
*aStream >> mRandomDataByte;
|
||||
mRandomDataByte = aStream->ParseUInt8(QString("%1 random data byte").arg(GetName()));
|
||||
}
|
||||
if (randomDataIntPtr)
|
||||
{
|
||||
*aStream >> mRandomDataInt;
|
||||
mRandomDataInt = aStream->ParseInt32(QString("%1 random data int").arg(GetName()));
|
||||
}
|
||||
mIndices.ParseData(aStream);
|
||||
}
|
||||
|
||||
@ -13,9 +13,9 @@ class XAnimParts : public XAsset
|
||||
{
|
||||
public:
|
||||
explicit XAnimParts();
|
||||
~XAnimParts();
|
||||
~XAnimParts() = default;
|
||||
|
||||
void ParseData(QDataStream *aStream) override;
|
||||
void ParseData(XDataStream *aStream) override;
|
||||
void Clear() override;
|
||||
|
||||
private:
|
||||
@ -43,13 +43,13 @@ private:
|
||||
float mFramerate = 0.0f;
|
||||
float mFrequency = 0.0f;
|
||||
|
||||
quint32 mNames = 0;
|
||||
quint16 mNames = 0;
|
||||
quint8 mDataByte = 0;
|
||||
qint16 mDataShort = 0;
|
||||
int mDataInt = 0;
|
||||
qint32 mDataInt = 0;
|
||||
qint16 mRandomDataShort = 0;
|
||||
quint8 mRandomDataByte = 0;
|
||||
int mRandomDataInt = 0;
|
||||
qint32 mRandomDataInt = 0;
|
||||
XAnimIndices mIndices;
|
||||
XAnimNotifyInfo mNotify;
|
||||
XAnimDeltaPart mDeltaPart;
|
||||
|
||||
@ -6,6 +6,7 @@ XAnimPartTrans::XAnimPartTrans()
|
||||
, mIsSmallTrans(false)
|
||||
, mData()
|
||||
{
|
||||
SetName("Animation Part Trans");
|
||||
}
|
||||
|
||||
XAnimPartTrans::XAnimPartTrans(const XAnimPartTrans &aSrc)
|
||||
@ -17,18 +18,10 @@ XAnimPartTrans::XAnimPartTrans(const XAnimPartTrans &aSrc)
|
||||
|
||||
}
|
||||
|
||||
XAnimPartTrans::~XAnimPartTrans()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void XAnimPartTrans::ParseData(QDataStream *aStream) {
|
||||
void XAnimPartTrans::ParseData(XDataStream *aStream) {
|
||||
if (GetPtr() == -1) {
|
||||
quint8 smallTransByte;
|
||||
*aStream
|
||||
>> mSize
|
||||
>> smallTransByte;
|
||||
mIsSmallTrans = (smallTransByte != 0);
|
||||
mSize = aStream->ParseUInt32(QString("%1 size").arg(GetName()));
|
||||
mIsSmallTrans = aStream->ParseUInt8(QString("%1 is small trans").arg(GetName())) != 0;
|
||||
|
||||
// Parse data
|
||||
mData.ParseData(aStream);
|
||||
|
||||
@ -9,9 +9,9 @@ class XAnimPartTrans : public XAsset
|
||||
public:
|
||||
explicit XAnimPartTrans();
|
||||
XAnimPartTrans(const XAnimPartTrans& aSrc);
|
||||
~XAnimPartTrans();
|
||||
~XAnimPartTrans() = default;
|
||||
|
||||
void ParseData(QDataStream* aStream) override;
|
||||
void ParseData(XDataStream* aStream) override;
|
||||
void Clear() override;
|
||||
|
||||
private:
|
||||
|
||||
@ -5,6 +5,7 @@ XAnimPartTransData::XAnimPartTransData()
|
||||
, mFrames()
|
||||
, mFrame()
|
||||
{
|
||||
SetName("Animation Part Trans Data");
|
||||
}
|
||||
|
||||
XAnimPartTransData::XAnimPartTransData(const XAnimPartTransData &aSrc)
|
||||
@ -15,12 +16,7 @@ XAnimPartTransData::XAnimPartTransData(const XAnimPartTransData &aSrc)
|
||||
|
||||
}
|
||||
|
||||
XAnimPartTransData::~XAnimPartTransData()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void XAnimPartTransData::ParseData(QDataStream *aStream) {
|
||||
void XAnimPartTransData::ParseData(XDataStream *aStream) {
|
||||
if (GetPtr() == -1) {
|
||||
// We need to determine which part of the union to parse
|
||||
// For simplicity, we'll assume it's always frames for now
|
||||
|
||||
@ -9,9 +9,9 @@ class XAnimPartTransData : public XAsset
|
||||
public:
|
||||
explicit XAnimPartTransData();
|
||||
XAnimPartTransData(const XAnimPartTransData &aSrc);
|
||||
~XAnimPartTransData();
|
||||
~XAnimPartTransData() = default;
|
||||
|
||||
void ParseData(QDataStream *aStream) override;
|
||||
void ParseData(XDataStream *aStream) override;
|
||||
void Clear() override;
|
||||
|
||||
private:
|
||||
|
||||
@ -7,22 +7,17 @@ XAnimPartTransFrames::XAnimPartTransFrames()
|
||||
, mFrames()
|
||||
, mIndices()
|
||||
{
|
||||
SetName("Animation Parts Trans Frames");
|
||||
}
|
||||
|
||||
XAnimPartTransFrames::~XAnimPartTransFrames()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void XAnimPartTransFrames::ParseData(QDataStream *aStream) {
|
||||
void XAnimPartTransFrames::ParseData(XDataStream *aStream) {
|
||||
if (GetPtr() == -1) {
|
||||
*aStream
|
||||
>> mMins[0]
|
||||
>> mMins[1]
|
||||
>> mMins[2]
|
||||
>> mMaxs[0]
|
||||
>> mMaxs[1]
|
||||
>> mMaxs[2];
|
||||
mMins[0] = aStream->ParseSingle(QString("%1 min %2").arg(GetName()).arg(0));
|
||||
mMins[1] = aStream->ParseSingle(QString("%1 min %2").arg(GetName()).arg(1));
|
||||
mMins[2] = aStream->ParseSingle(QString("%1 min %2").arg(GetName()).arg(2));
|
||||
mMaxs[0] = aStream->ParseSingle(QString("%1 max %2").arg(GetName()).arg(0));
|
||||
mMaxs[1] = aStream->ParseSingle(QString("%1 max %2").arg(GetName()).arg(1));
|
||||
mMaxs[2] = aStream->ParseSingle(QString("%1 max %2").arg(GetName()).arg(2));
|
||||
|
||||
// Parse frames
|
||||
mFrames.ParseData(aStream);
|
||||
|
||||
@ -11,9 +11,9 @@ class XAnimPartTransFrames : public XAsset
|
||||
{
|
||||
public:
|
||||
explicit XAnimPartTransFrames();
|
||||
~XAnimPartTransFrames();
|
||||
~XAnimPartTransFrames() = default;
|
||||
|
||||
void ParseData(QDataStream *aStream) override;
|
||||
void ParseData(XDataStream *aStream) override;
|
||||
void Clear() override;
|
||||
|
||||
private:
|
||||
|
||||
@ -19,8 +19,6 @@
|
||||
#include "xstringtable.h"
|
||||
#include "xweapondef.h"
|
||||
|
||||
XAsset::
|
||||
|
||||
XAsset::XAsset()
|
||||
: mPtr(0)
|
||||
, mType(ASSET_TYPE_NONE)
|
||||
@ -29,11 +27,6 @@ XAsset::XAsset()
|
||||
|
||||
}
|
||||
|
||||
XAsset::~XAsset()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void XAsset::SetPtr(qint32 aPtr) {
|
||||
mPtr = aPtr;
|
||||
}
|
||||
@ -83,20 +76,9 @@ void XAsset::Clear()
|
||||
mType = ASSET_TYPE_NONE;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
void XAsset::ParsePtr(XDataStream *aStream, bool aDataFlag) {
|
||||
|
||||
mPtr = aStream->ParseInt32(QString("%1 ptr").arg(GetName()));
|
||||
if (aDataFlag && mPtr == -1)
|
||||
{
|
||||
ParseData(aStream);
|
||||
@ -105,10 +87,6 @@ void XAsset::ParsePtr(QDataStream *aStream, bool aDataFlag) {
|
||||
|
||||
XAsset* XAsset::Create(XAssetType aAssetType)
|
||||
{
|
||||
if (mDebug)
|
||||
{
|
||||
qDebug() << QString("Creating XAsset with type %1").arg(XAssetTypeToString(aAssetType));
|
||||
}
|
||||
switch (aAssetType)
|
||||
{
|
||||
case ASSET_TYPE_XANIMPARTS:
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
|
||||
#include "xassettype.h"
|
||||
|
||||
#include <QDataStream>
|
||||
#include "xdatastream.h"
|
||||
#include <QString>
|
||||
#include <QDebug>
|
||||
#include <QIODevice>
|
||||
@ -12,7 +12,7 @@ class XAsset
|
||||
{
|
||||
public:
|
||||
XAsset();
|
||||
virtual ~XAsset();
|
||||
virtual ~XAsset() = default;
|
||||
|
||||
void SetPtr(qint32 aPtr);
|
||||
qint32 GetPtr() const;
|
||||
@ -27,8 +27,8 @@ public:
|
||||
bool IsDebug() const;
|
||||
|
||||
virtual void Clear();
|
||||
virtual void ParsePtr(QDataStream *aStream, bool aDataFlag = true);
|
||||
virtual void ParseData(QDataStream *aStream) = 0;
|
||||
virtual void ParsePtr(XDataStream *aStream, bool aDataFlag = true);
|
||||
virtual void ParseData(XDataStream *aStream) = 0;
|
||||
|
||||
static XAsset* Create(XAssetType aAssetType);
|
||||
static QString XAssetTypeToString(XAssetType type);
|
||||
|
||||
@ -3,41 +3,39 @@
|
||||
|
||||
XAssetHeader::XAssetHeader()
|
||||
: XAsset()
|
||||
, mRawType(0)
|
||||
, mAssetType()
|
||||
, mAssetPtr(0)
|
||||
, mZoneFile(nullptr)
|
||||
{
|
||||
|
||||
SetName("Asset Header");
|
||||
}
|
||||
|
||||
XAssetHeader::XAssetHeader(ZoneFile *aZoneFile)
|
||||
: XAsset()
|
||||
, mRawType(0)
|
||||
, mAssetType()
|
||||
, mAssetPtr(0)
|
||||
, mZoneFile(aZoneFile)
|
||||
{
|
||||
|
||||
SetName("Asset Header");
|
||||
}
|
||||
|
||||
XAssetHeader::~XAssetHeader()
|
||||
void XAssetHeader::ParseData(XDataStream *aStream)
|
||||
{
|
||||
mRawType = aStream->ParseUInt32(QString("%1 raw type").arg(GetName()));
|
||||
mAssetPtr = aStream->ParseInt32(QString("%1 asset ptr").arg(GetName()));
|
||||
|
||||
}
|
||||
mAssetType = mZoneFile->GetType(mRawType);
|
||||
|
||||
void XAssetHeader::ParseData(QDataStream *aStream)
|
||||
{
|
||||
quint32 rawAssetType;
|
||||
*aStream
|
||||
>> rawAssetType
|
||||
>> mAssetPtr;
|
||||
|
||||
mAssetType = mZoneFile->GetType(rawAssetType);
|
||||
qDebug() << "Found asset:" << XAssetTypeToString(mAssetType) << QString::number(mRawType, 16);
|
||||
}
|
||||
|
||||
void XAssetHeader::Clear()
|
||||
{
|
||||
mAssetType = ASSET_TYPE_NONE;
|
||||
mAssetPtr = 0;
|
||||
mRawType = 0;
|
||||
}
|
||||
|
||||
XAssetType XAssetHeader::GetAssetType() const
|
||||
@ -45,6 +43,11 @@ XAssetType XAssetHeader::GetAssetType() const
|
||||
return mAssetType;
|
||||
}
|
||||
|
||||
quint32 XAssetHeader::GetRawAssetType() const
|
||||
{
|
||||
return mRawType;
|
||||
}
|
||||
|
||||
qint32 XAssetHeader::GetAssetPtr() const
|
||||
{
|
||||
return mAssetPtr;
|
||||
|
||||
@ -10,15 +10,17 @@ class XAssetHeader: public XAsset
|
||||
public:
|
||||
explicit XAssetHeader();
|
||||
XAssetHeader(ZoneFile* aZoneFile);
|
||||
~XAssetHeader();
|
||||
~XAssetHeader() = default;
|
||||
|
||||
void ParseData(QDataStream *aStream) override;
|
||||
void ParseData(XDataStream *aStream) override;
|
||||
void Clear() override;
|
||||
|
||||
XAssetType GetAssetType() const;
|
||||
quint32 GetRawAssetType() const;
|
||||
qint32 GetAssetPtr() const;
|
||||
|
||||
private:
|
||||
quint32 mRawType;
|
||||
XAssetType mAssetType;
|
||||
qint32 mAssetPtr;
|
||||
ZoneFile *mZoneFile;
|
||||
|
||||
@ -10,6 +10,8 @@ XAssetList::XAssetList()
|
||||
, mAssetHeaders()
|
||||
, mZoneFile(nullptr)
|
||||
{
|
||||
SetType(ASSET_TYPE_ASSETLIST);
|
||||
SetName("Asset List");
|
||||
}
|
||||
|
||||
XAssetList::XAssetList(ZoneFile* aZoneFile)
|
||||
@ -29,30 +31,23 @@ XAssetList::~XAssetList()
|
||||
|
||||
}
|
||||
|
||||
void XAssetList::ParseData(QDataStream *aStream) {
|
||||
void XAssetList::ParseData(XDataStream *aStream) {
|
||||
// Parse string list
|
||||
if (IsDebug())
|
||||
{
|
||||
qDebug() << QString("[%1] Parsing data for %2").arg(aStream->device()->pos(), 10, 10, QChar('0')).arg(GetName());
|
||||
}
|
||||
mStringList.ParsePtr(aStream);
|
||||
mStringList.ParsePtr(aStream, false);
|
||||
|
||||
// Parse asset count and assets
|
||||
qint32 assetsPtr;
|
||||
*aStream
|
||||
>> mAssetCount
|
||||
>> assetsPtr;
|
||||
if (IsDebug())
|
||||
{
|
||||
qDebug() << QString("[%1] mAssetCount = %2").arg(aStream->device()->pos(), 10, 10, QChar('0')).arg(mAssetCount);
|
||||
qDebug() << QString("[%1] assetsPtr = %2").arg(aStream->device()->pos(), 10, 10, QChar('0')).arg(assetsPtr);
|
||||
}
|
||||
mAssetCount = aStream->ParseUInt32(QString("%1 asset count").arg(GetName()));
|
||||
qint32 assetsPtr = aStream->ParseInt32(QString("%1 assets ptr").arg(GetName()));
|
||||
|
||||
mStringList.ParseData(aStream);
|
||||
|
||||
if (assetsPtr)
|
||||
{
|
||||
for (int i = 0; i < mAssetCount; i++)
|
||||
for (quint32 i = 0; i < mAssetCount; i++)
|
||||
{
|
||||
XAssetHeader assetHeader(mZoneFile);
|
||||
assetHeader.ParseData(aStream);
|
||||
@ -62,11 +57,19 @@ void XAssetList::ParseData(QDataStream *aStream) {
|
||||
|
||||
for (int i = 0; i < mAssetHeaders.size(); i++)
|
||||
{
|
||||
if (aStream->device()->pos() > 98000)
|
||||
{
|
||||
qDebug() << "test";
|
||||
}
|
||||
XAssetHeader assetHeader = mAssetHeaders[i];
|
||||
XAsset* asset = XAsset::Create(assetHeader.GetAssetType());
|
||||
asset->ParseData(aStream);
|
||||
if (asset)
|
||||
{
|
||||
asset->SetPtr(assetHeader.GetAssetPtr());
|
||||
asset->ParseData(aStream);
|
||||
|
||||
mAssets.append(asset);
|
||||
mAssets.append(asset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,9 +14,9 @@ class XAssetList : public XAsset
|
||||
public:
|
||||
explicit XAssetList();
|
||||
XAssetList(ZoneFile* aZoneFile);
|
||||
~XAssetList();
|
||||
~XAssetList() override;
|
||||
|
||||
void ParseData(QDataStream *aStream) override;
|
||||
void ParseData(XDataStream *aStream) override;
|
||||
void Clear() override;
|
||||
|
||||
XScriptStringList GetStringList() const;
|
||||
|
||||
@ -5,7 +5,7 @@ XAudioChannelMap::XAudioChannelMap()
|
||||
, mEntryCount(0)
|
||||
, mEntries(QVector<XAudioChannelMapEntry*>())
|
||||
{
|
||||
|
||||
SetName("Audio Channel Map");
|
||||
}
|
||||
|
||||
XAudioChannelMap::~XAudioChannelMap()
|
||||
@ -32,15 +32,13 @@ void XAudioChannelMap::SetMapEntry(int aIndex, XAudioChannelMapEntry *aEntry)
|
||||
mEntries[aIndex] = aEntry;
|
||||
}
|
||||
|
||||
void XAudioChannelMap::ParseData(QDataStream *aStream)
|
||||
void XAudioChannelMap::ParseData(XDataStream *aStream)
|
||||
{
|
||||
*aStream >> mEntryCount;
|
||||
mEntryCount = aStream->ParseUInt8(QString("%1 entry count").arg(GetName()));
|
||||
|
||||
aStream->skipRawData(3);
|
||||
|
||||
quint32 entriesPtr;
|
||||
*aStream >> entriesPtr;
|
||||
|
||||
quint32 entriesPtr = aStream->ParseInt32(QString("%1 entries ptr").arg(GetName()));
|
||||
if (entriesPtr)
|
||||
{
|
||||
mEntries.resize(mEntryCount);
|
||||
|
||||
@ -17,7 +17,7 @@ public:
|
||||
XAudioChannelMapEntry* GetMapEntry(int aIndex) const;
|
||||
void SetMapEntry(int aIndex, XAudioChannelMapEntry* aEntry);
|
||||
|
||||
virtual void ParseData(QDataStream* aStream) override;
|
||||
virtual void ParseData(XDataStream* aStream) override;
|
||||
virtual void Clear() override;
|
||||
|
||||
private:
|
||||
|
||||
@ -6,7 +6,7 @@ XAudioChannelMapEntry::XAudioChannelMapEntry()
|
||||
, mOutputChannel(0)
|
||||
, mVolume(0.0)
|
||||
{
|
||||
|
||||
SetName("Audio Channel Map Entry");
|
||||
}
|
||||
|
||||
XAudioChannelMapEntry::~XAudioChannelMapEntry()
|
||||
@ -44,16 +44,15 @@ void XAudioChannelMapEntry::SetVolume(float aVolume)
|
||||
mVolume = aVolume;
|
||||
}
|
||||
|
||||
void XAudioChannelMapEntry::ParseData(QDataStream *aStream)
|
||||
void XAudioChannelMapEntry::ParseData(XDataStream *aStream)
|
||||
{
|
||||
*aStream
|
||||
>> mInputChannel
|
||||
>> mOutputChannel;
|
||||
mInputChannel = aStream->ParseUInt8(QString("%1 input channel").arg(GetName()));
|
||||
mOutputChannel = aStream->ParseUInt8(QString("%1 output channel").arg(GetName()));
|
||||
|
||||
// Skip padding bytes in struct
|
||||
aStream->skipRawData(2);
|
||||
|
||||
*aStream >> mVolume;
|
||||
mVolume = aStream->ParseSingle(QString("%1 volume").arg(GetName()));
|
||||
}
|
||||
|
||||
void XAudioChannelMapEntry::Clear()
|
||||
|
||||
@ -18,7 +18,7 @@ public:
|
||||
float GetVolume() const;
|
||||
void SetVolume(float aVolume);
|
||||
|
||||
virtual void ParseData(QDataStream* aStream) override;
|
||||
virtual void ParseData(XDataStream* aStream) override;
|
||||
virtual void Clear() override;
|
||||
|
||||
private:
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
#include "xaudioformatinfo.h"
|
||||
|
||||
XAudioFormatInfo::XAudioFormatInfo()
|
||||
: XAsset()
|
||||
, mStream()
|
||||
{
|
||||
|
||||
SetName("Audio Format Info");
|
||||
}
|
||||
|
||||
XAudioFormatInfo::~XAudioFormatInfo()
|
||||
@ -10,12 +12,14 @@ XAudioFormatInfo::~XAudioFormatInfo()
|
||||
|
||||
}
|
||||
|
||||
void XAudioFormatInfo::ParseData(QDataStream *aStream)
|
||||
void XAudioFormatInfo::ParseData(XDataStream *aStream)
|
||||
{
|
||||
Q_UNUSED(aStream);
|
||||
|
||||
// TODO: Implement ParseData(...) for XAudioFormatInfo
|
||||
}
|
||||
|
||||
void XAudioFormatInfo::Clear()
|
||||
{
|
||||
|
||||
mStream.clear();
|
||||
}
|
||||
|
||||
@ -2,22 +2,21 @@
|
||||
#define XAUDIOFORMATINFO_H
|
||||
|
||||
#include "xasset.h"
|
||||
#include "xaudioxmaformat.h"
|
||||
|
||||
#include <QVector>
|
||||
|
||||
class XAudioXmaFormat;
|
||||
|
||||
class XAudioFormatInfo : public XAsset
|
||||
{
|
||||
public:
|
||||
XAudioFormatInfo();
|
||||
explicit XAudioFormatInfo();
|
||||
~XAudioFormatInfo();
|
||||
|
||||
virtual void ParseData(QDataStream* aStream) override;
|
||||
virtual void ParseData(XDataStream* aStream) override;
|
||||
virtual void Clear() override;
|
||||
|
||||
private:
|
||||
QVector<XAudioXmaFormat*> mStream;
|
||||
QVector<XAudioXmaFormat> mStream;
|
||||
};
|
||||
|
||||
#endif // XAUDIOFORMATINFO_H
|
||||
|
||||
@ -8,7 +8,7 @@ XAudioPacketAligned::XAudioPacketAligned()
|
||||
, aXmaLoop()
|
||||
, mContext()
|
||||
{
|
||||
|
||||
SetName("Audio Packet Aligned");
|
||||
}
|
||||
|
||||
XAudioPacketAligned::~XAudioPacketAligned()
|
||||
@ -16,14 +16,11 @@ XAudioPacketAligned::~XAudioPacketAligned()
|
||||
|
||||
}
|
||||
|
||||
void XAudioPacketAligned::ParseData(QDataStream *aStream)
|
||||
void XAudioPacketAligned::ParseData(XDataStream *aStream)
|
||||
{
|
||||
qint32 bufferPtr, contextPtr;
|
||||
|
||||
*aStream
|
||||
>> bufferPtr
|
||||
>> mBufferSize
|
||||
>> mLoopCount;
|
||||
qint32 bufferPtr = aStream->ParseInt32(QString("%1 buffer ptr").arg(GetName()));
|
||||
mBufferSize = aStream->ParseUInt32(QString("%1 buffer size").arg(GetName()));
|
||||
mLoopCount = aStream->ParseUInt32(QString("%1 loop count").arg(GetName()));
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
@ -31,15 +28,16 @@ void XAudioPacketAligned::ParseData(QDataStream *aStream)
|
||||
loop.ParseData(aStream);
|
||||
}
|
||||
|
||||
*aStream >> contextPtr;
|
||||
qint32 contextPtr = aStream->ParseInt32(QString("%1 context ptr").arg(GetName()));
|
||||
|
||||
if (bufferPtr)
|
||||
{
|
||||
aStream->readRawData(mBuffer.data(), mBufferSize);
|
||||
}
|
||||
|
||||
if (contextPtr)
|
||||
{
|
||||
*aStream >> mContext;
|
||||
mContext = aStream->ParseInt8(QString("%1 context").arg(GetName()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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