Compare commits

..

No commits in common. "main" and "v1.6" have entirely different histories.
main ... v1.6

988 changed files with 51761 additions and 281286 deletions

13
.gitignore vendored
View File

@ -1,10 +1,6 @@
/build/ /build/
/data/dlls/ /data/dlls/
/data/fastfiles/ /data/fastfiles/
/releases/
.vscode/*
.qmake.stash
# Ignore Qt Creator user files # Ignore Qt Creator user files
*.pro.user *.pro.user
@ -14,12 +10,3 @@
*.creator.user *.creator.user
*.creator.user.* *.creator.user.*
*.creator.* *.creator.*
*.ps1
version.txt
*.autosave
*.XMODEL_EXPORT
data/obj/*
libs/*/release/*
libs/*/debug/*
.git.stash
*Makefile*

View File

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

View File

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

View File

@ -6,9 +6,63 @@ SUBDIRS += app
CONFIG += c++17 CONFIG += c++17
SOURCES += $$files($$PWD/*.cpp) SOURCES += \
HEADERS += $$files($$PWD/*.h) aboutdialog.cpp \
FORMS += $$files($$PWD/*.ui) ddsviewer.cpp \
fastfileviewer.cpp \
imagewidget.cpp \
iwiviewer.cpp \
localstringviewer.cpp \
main.cpp \
mainwindow.cpp \
materialviewer.cpp \
preferenceeditor.cpp \
soundviewer.cpp \
stringtableviewer.cpp \
rumblegraphviewer.cpp \
rumblefileviewer.cpp \
techsetviewer.cpp \
xtreewidget.cpp \
xtreewidgetitem.cpp \
zonefileviewer.cpp
HEADERS += \
aboutdialog.h \
d3dbsp_structs.h \
ddsviewer.h \
fastfileviewer.h \
imagewidget.h \
iwiviewer.h \
localstringviewer.h \
mainwindow.h \
materialviewer.h \
preferenceeditor.h \
soundviewer.h \
stringtableviewer.h \
rumblegraphviewer.h \
rumblefileviewer.h \
techsetviewer.h \
xtreewidget.h \
xtreewidgetitem.h \
zonefileviewer.h
FORMS += \
aboutdialog.ui \
ddsviewer.ui \
fastfileviewer.ui \
imagewidget.ui \
iwiviewer.ui \
localstringviewer.ui \
mainwindow.ui \
materialviewer.ui \
modelviewer.ui \
preferenceeditor.ui \
soundviewer.ui \
stringtableviewer.ui \
rumblegraphviewer.ui \
rumblefileviewer.ui \
techsetviewer.ui \
zonefileviewer.ui
RESOURCES += ../data/data.qrc RESOURCES += ../data/data.qrc
@ -17,7 +71,6 @@ LIBS += \
-L$$PWD/../third_party/zlib/lib/ -lzlib \ -L$$PWD/../third_party/zlib/lib/ -lzlib \
-L$$PWD/../third_party/xbox_sdk/lib -lxcompress64 \ -L$$PWD/../third_party/xbox_sdk/lib -lxcompress64 \
-L$$OUT_PWD/../libs/ -lcore \ -L$$OUT_PWD/../libs/ -lcore \
-L$$OUT_PWD/../libs/ -lxassets\
-L$$OUT_PWD/../libs/ -lcompression \ -L$$OUT_PWD/../libs/ -lcompression \
-L$$OUT_PWD/../libs/ -lencryption \ -L$$OUT_PWD/../libs/ -lencryption \
-L$$OUT_PWD/../libs/ -lfastfile \ -L$$OUT_PWD/../libs/ -lfastfile \
@ -37,7 +90,6 @@ INCLUDEPATH += \
$$PWD/../libs/ddsfile \ $$PWD/../libs/ddsfile \
$$PWD/../libs/ipakfile \ $$PWD/../libs/ipakfile \
$$PWD/../libs/iwifile \ $$PWD/../libs/iwifile \
$$PWD/../libs/xassets \
$$PWD/../libs/zonefile $$PWD/../libs/zonefile
DEPENDPATH += \ DEPENDPATH += \
@ -51,11 +103,16 @@ DEPENDPATH += \
$$PWD/../libs/ddsfile \ $$PWD/../libs/ddsfile \
$$PWD/../libs/ipakfile \ $$PWD/../libs/ipakfile \
$$PWD/../libs/iwifile \ $$PWD/../libs/iwifile \
$$PWD/../libs/xassets \
$$PWD/../libs/zonefile $$PWD/../libs/zonefile
# Copy DLLs to Debug folder
QMAKE_POST_LINK += xcopy /Y /E /I \"G:/Projects/Qt/XPlor/third_party/devil_sdk/lib\\*.dll\" \"$$OUT_PWD/debug/\" $$escape_expand(\\n\\t)
QMAKE_POST_LINK += xcopy /Y /E /I \"G:/Projects/Qt/XPlor/third_party/zlib/lib\\*.dll\" \"$$OUT_PWD/debug/\" $$escape_expand(\\n\\t)
QMAKE_POST_LINK += xcopy /Y /E /I \"G:/Projects/Qt/XPlor/third_party/xna/lib\\*.dll\" \"$$OUT_PWD/debug/\" $$escape_expand(\\n\\t)
QMAKE_POST_LINK += xcopy /Y /E /I \"$$PWD/../third_party/xbox_sdk/lib\\*.dll\" \"$$OUT_PWD/debug/\" $$escape_expand(\\n\\t)
win32 { # Copy DLLs to Release folder
QMAKE_POST_LINK = QMAKE_POST_LINK += xcopy /Y /E /I \"G:/Projects/Qt/XPlor/third_party/devil_sdk/lib\\*.dll\" \"$$OUT_PWD/release/\" $$escape_expand(\\n\\t)
QMAKE_POST_LINK += for /D %%G in (\"$$PWD/../third_party/*/lib\") do copy /Y \"%%~G\*.dll\" \"$$OUT_PWD/$$DESTDIR/\" >NUL $$escape_expand(\\n\\t) QMAKE_POST_LINK += xcopy /Y /E /I \"G:/Projects/Qt/XPlor/third_party/zlib/lib\\*.dll\" \"$$OUT_PWD/release/\" $$escape_expand(\\n\\t)
} QMAKE_POST_LINK += xcopy /Y /E /I \"G:/Projects/Qt/XPlor/third_party/xna/lib\\*.dll\" \"$$OUT_PWD/release/\" $$escape_expand(\\n\\t)
QMAKE_POST_LINK += xcopy /Y /E /I \"$$PWD/../third_party/xbox_sdk/lib\\*.dll\" \"$$OUT_PWD/release/\" $$escape_expand(\\n\\t)

View File

@ -14,8 +14,8 @@ DDSViewer::~DDSViewer() {
delete ui; delete ui;
} }
void DDSViewer::SetDDSFile(const DDSFile* aDDSFile) { void DDSViewer::SetDDSFile(std::shared_ptr<DDSFile> aDDSFile) {
mDDSFile = aDDSFile; mDDSFile.swap(aDDSFile);
ui->label_Title->setText(mDDSFile->fileStem + ".dds"); ui->label_Title->setText(mDDSFile->fileStem + ".dds");

View File

@ -16,14 +16,14 @@ public:
explicit DDSViewer(QWidget *parent = nullptr); explicit DDSViewer(QWidget *parent = nullptr);
~DDSViewer(); ~DDSViewer();
void SetDDSFile(const DDSFile *aDDSFile); void SetDDSFile(std::shared_ptr<DDSFile> aDDSFile);
private slots: private slots:
void MipmapIndexChanged(int aMipmapIndex); void MipmapIndexChanged(int aMipmapIndex);
private: private:
Ui::DDSViewer *ui; Ui::DDSViewer *ui;
const DDSFile* mDDSFile; std::shared_ptr<DDSFile> mDDSFile;
}; };
#endif // DDSVIEWER_H #endif // DDSVIEWER_H

View File

@ -1,4 +1,5 @@
#include "fastfileviewer.h" #include "fastfileviewer.h"
#include "asset_structs.h"
#include "ui_fastfileviewer.h" #include "ui_fastfileviewer.h"
FastFileViewer::FastFileViewer(QWidget *parent) FastFileViewer::FastFileViewer(QWidget *parent)
@ -14,8 +15,8 @@ FastFileViewer::~FastFileViewer()
delete ui; delete ui;
} }
void FastFileViewer::SetFastFile(const FastFile* aFastFile) { void FastFileViewer::SetFastFile(std::shared_ptr<FastFile> aFastFile) {
mFastFile = aFastFile; mFastFile.swap(aFastFile);
ui->label_Title->setText(mFastFile->GetStem()); ui->label_Title->setText(mFastFile->GetStem());
ui->comboBox_Company->setCurrentIndex(mFastFile->GetCompany()); ui->comboBox_Company->setCurrentIndex(mFastFile->GetCompany());

View File

@ -1,6 +1,7 @@
#ifndef FASTFILEVIEWER_H #ifndef FASTFILEVIEWER_H
#define FASTFILEVIEWER_H #define FASTFILEVIEWER_H
#include "asset_structs.h"
#include "fastfile.h" #include "fastfile.h"
#include <QWidget> #include <QWidget>
@ -16,10 +17,10 @@ public:
explicit FastFileViewer(QWidget *parent = nullptr); explicit FastFileViewer(QWidget *parent = nullptr);
~FastFileViewer(); ~FastFileViewer();
void SetFastFile(const FastFile *aFastFile); void SetFastFile(std::shared_ptr<FastFile> aFastFile);
private: private:
Ui::FFViewer *ui; Ui::FFViewer *ui;
const FastFile* mFastFile; std::shared_ptr<FastFile> mFastFile;
}; };
#endif // FASTFILEVIEWER_H #endif // FASTFILEVIEWER_H

View File

@ -13,16 +13,16 @@ ImageWidget::~ImageWidget()
delete ui; delete ui;
} }
void ImageWidget::SetImage(std::shared_ptr<QImage> aImage) void ImageWidget::SetImage(std::shared_ptr<Image> aImage)
{ {
mImage = aImage; mImage = aImage;
//ui->lineEdit_Name->setText(aImage->name); ui->lineEdit_Name->setText(aImage->name);
//ui->lineEdit_Role->setText(aImage->materialName); ui->lineEdit_Role->setText(aImage->materialName);
//ui->comboBox_Compression->setCurrentIndex(aImage->compression); ui->comboBox_Compression->setCurrentIndex(aImage->compression);
} }
std::shared_ptr<QImage> ImageWidget::GetImage() std::shared_ptr<Image> ImageWidget::GetImage()
{ {
return mImage; return mImage;
} }

View File

@ -4,6 +4,7 @@
#include "enums.h" #include "enums.h"
#include "dds_structs.h" #include "dds_structs.h"
#include "d3dbsp_structs.h" #include "d3dbsp_structs.h"
#include "asset_structs.h"
#include "ipak_structs.h" #include "ipak_structs.h"
#include <QWidget> #include <QWidget>
@ -20,11 +21,11 @@ public:
explicit ImageWidget(QWidget *parent = nullptr); explicit ImageWidget(QWidget *parent = nullptr);
~ImageWidget(); ~ImageWidget();
void SetImage(std::shared_ptr<QImage> aImage); void SetImage(std::shared_ptr<Image> aImage);
std::shared_ptr<QImage> GetImage(); std::shared_ptr<Image> GetImage();
private: private:
std::shared_ptr<QImage> mImage; std::shared_ptr<Image> mImage;
Ui::ImageWidget *ui; Ui::ImageWidget *ui;
}; };

View File

@ -14,8 +14,8 @@ IWIViewer::~IWIViewer()
delete ui; delete ui;
} }
void IWIViewer::SetIWIFile(const IWIFile* aIWIFile) { void IWIViewer::SetIWIFile(std::shared_ptr<IWIFile> aIWIFile) {
mIWIFile = aIWIFile; mIWIFile.swap(aIWIFile);
ui->label_Title->setText(mIWIFile->fileStem + ".iwi"); ui->label_Title->setText(mIWIFile->fileStem + ".iwi");

View File

@ -18,10 +18,10 @@ public:
void MipmapIndexChanged(int aMipmapIndex); void MipmapIndexChanged(int aMipmapIndex);
void SetIWIFile(const IWIFile *aIWIFile); void SetIWIFile(std::shared_ptr<IWIFile> aIWIFile);
private: private:
Ui::IWIViewer *ui; Ui::IWIViewer *ui;
const IWIFile* mIWIFile; std::shared_ptr<IWIFile> mIWIFile;
}; };
#endif // IWIVIEWER_H #endif // IWIVIEWER_H

View File

@ -37,22 +37,26 @@ void LocalStringViewer::SetFileNotes(const QString aFileNotes) {
ui->plainTextEdit_FileNotes->setPlainText(mFileNotes); ui->plainTextEdit_FileNotes->setPlainText(mFileNotes);
} }
void LocalStringViewer::AddLocalString(XLocalizeEntry aLocalString) { void LocalStringViewer::AddLocalString(LocalString aLocalString) {
mLocalStrings.append(aLocalString); mLocalStrings.append(aLocalString);
ui->tableWidget_Strings->setRowCount(mLocalStrings.size()); ui->tableWidget_Strings->setRowCount(mLocalStrings.size());
ui->groupBox_LocalStrViewer->setTitle(QString("Entries (%1)").arg(mLocalStrings.size())); ui->groupBox_LocalStrViewer->setTitle(QString("Entries (%1)").arg(mLocalStrings.size()));
QTableWidgetItem *aliasItem = new QTableWidgetItem(aLocalString.GetValue()->GetString());
QTableWidgetItem *stringItem = new QTableWidgetItem(aLocalString.GetName()->GetString()); QTableWidgetItem *aliasItem = new QTableWidgetItem(aLocalString.alias);
QTableWidgetItem *stringItem = new QTableWidgetItem(aLocalString.string);
ui->tableWidget_Strings->setItem(mLocalStrings.size() - 1, 0, aliasItem); ui->tableWidget_Strings->setItem(mLocalStrings.size() - 1, 0, aliasItem);
ui->tableWidget_Strings->setItem(mLocalStrings.size() - 1, 1, stringItem); ui->tableWidget_Strings->setItem(mLocalStrings.size() - 1, 1, stringItem);
} }
void LocalStringViewer::SetZoneFile(const ZoneFile* aZoneFile) { void LocalStringViewer::SetZoneFile(std::shared_ptr<ZoneFile> aZoneFile) {
mLocalStrings.clear(); mLocalStrings.clear();
ui->tableWidget_Strings->clear(); ui->tableWidget_Strings->clear();
ui->label_Title->setText(aZoneFile->GetStem().section('.', 0, 0) + ".str"); ui->label_Title->setText(aZoneFile->GetStem().section('.', 0, 0) + ".str");
// for (const LocalString &localStr : aZoneFile->GetAssetMap().localStrings) { for (const LocalString &localStr : aZoneFile->GetAssetMap().localStrings) {
// AddLocalString(localStr); AddLocalString(localStr);
// } }
} }

View File

@ -1,7 +1,7 @@
#ifndef LOCALSTRINGVIEWER_H #ifndef LOCALSTRINGVIEWER_H
#define LOCALSTRINGVIEWER_H #define LOCALSTRINGVIEWER_H
#include "xlocalizeentry.h" #include "asset_structs.h"
#include "zonefile.h" #include "zonefile.h"
#include <QWidget> #include <QWidget>
@ -20,15 +20,15 @@ public:
void SetVersion(quint32 aVersion); void SetVersion(quint32 aVersion);
void SetConfigPath(const QString aConfigPath); void SetConfigPath(const QString aConfigPath);
void SetFileNotes(const QString aFileNotes); void SetFileNotes(const QString aFileNotes);
void AddLocalString(XLocalizeEntry aLocalString); void AddLocalString(LocalString aLocalString);
void SetZoneFile(const ZoneFile *aZoneFile); void SetZoneFile(std::shared_ptr<ZoneFile> aZoneFile);
private: private:
Ui::LocalStringViewer *ui; Ui::LocalStringViewer *ui;
quint32 mVersion; quint32 mVersion;
QString mConfigPath; QString mConfigPath;
QString mFileNotes; QString mFileNotes;
QVector<XLocalizeEntry> mLocalStrings; QVector<LocalString> mLocalStrings;
}; };
#endif // LOCALSTRINGVIEWER_H #endif // LOCALSTRINGVIEWER_H

View File

@ -1,7 +1,4 @@
#include "mainwindow.h" #include "mainwindow.h"
#include "qtimer.h"
#include "ui_mainwindow.h"
#include "aboutdialog.h" #include "aboutdialog.h"
#include "fastfile.h" #include "fastfile.h"
#include "highlighter_gsc.h" #include "highlighter_gsc.h"
@ -10,10 +7,12 @@
#include "highlighter_rumble.h" #include "highlighter_rumble.h"
#include "materialviewer.h" #include "materialviewer.h"
#include "preferenceeditor.h" #include "preferenceeditor.h"
#include "reportissuedialog.h" #include "rumblefileviewer.h"
#include "rumblegraphviewer.h" #include "rumblegraphviewer.h"
#include "soundviewer.h"
#include "stringtableviewer.h" #include "stringtableviewer.h"
#include "techsetviewer.h" #include "techsetviewer.h"
#include "ui_mainwindow.h"
#include "fastfile_factory.h" #include "fastfile_factory.h"
#include "iwifile.h" #include "iwifile.h"
#include "ddsfile.h" #include "ddsfile.h"
@ -23,11 +22,13 @@
#include "ipak_structs.h" #include "ipak_structs.h"
#include "iwiviewer.h" #include "iwiviewer.h"
#include "localstringviewer.h" #include "localstringviewer.h"
#include "imagewidget.h"
#include "xtreewidget.h"
#include "zonefileviewer.h" #include "zonefileviewer.h"
#include "techsetviewer.h" #include "techsetviewer.h"
#include "logmanager.h" #include "logmanager.h"
#include <QtMath> #include <qmath.h>
MainWindow::MainWindow(QWidget *parent) MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), ui(new Ui::MainWindow) { : QMainWindow(parent), ui(new Ui::MainWindow) {
@ -35,12 +36,10 @@ MainWindow::MainWindow(QWidget *parent)
setAcceptDrops(true); setAcceptDrops(true);
XAsset::SetDebug(true);
mTypeMap = QMap<QString, int>(); mTypeMap = QMap<QString, int>();
mTypeOrder = QStringList(); mTypeOrder = QStringList();
mRawFileMap = QMap<QString, QString>(); mRawFileMap = QMap<QString, QString>();
//mImageMap = QMap<QString, Image>(); mImageMap = QMap<QString, Image>();
mTreeMap = QMap<QString, QTreeWidgetItem *>(); mTreeMap = QMap<QString, QTreeWidgetItem *>();
mStrTableMap = QMap<QString, QVector<QPair<QString, QString>>>(); mStrTableMap = QMap<QString, QVector<QPair<QString, QString>>>();
mBSPVersion = 0; mBSPVersion = 0;
@ -50,23 +49,13 @@ MainWindow::MainWindow(QWidget *parent)
mTreeWidget = new XTreeWidget(this); mTreeWidget = new XTreeWidget(this);
mLogWidget = new QPlainTextEdit(this); mLogWidget = new QPlainTextEdit(this);
//ModelViewer *mModelViewer = new ModelViewer(container);
//mModelViewer->setAcceptDrops(false);
mProgressBar = new QProgressBar(this); mProgressBar = new QProgressBar(this);
mProgressBar->setMaximum(100); // Default max value mProgressBar->setMaximum(100); // Default max value
mProgressBar->setVisible(false); // Initially hidden mProgressBar->setVisible(false); // Initially hidden
connect(ui->actionRun_Tests, &QAction::triggered, this, [](bool checked) {
Q_UNUSED(checked);
});
connect(ui->actionReport_Issue, &QAction::triggered, this, [this](bool checked) {
Q_UNUSED(checked);
ReportIssueDialog issueDialog("https://git.redline.llc", "njohnson", "XPlor", "4738c4d2efd123efac1506c68c59b285c646df9f", this);
if (issueDialog.exec() == QDialog::Accepted) {
}
});
connect(&StatusBarManager::instance(), &StatusBarManager::statusUpdated, connect(&StatusBarManager::instance(), &StatusBarManager::statusUpdated,
this, &MainWindow::HandleStatusUpdate); this, &MainWindow::HandleStatusUpdate);
@ -159,7 +148,7 @@ MainWindow::MainWindow(QWidget *parent)
ui->tabWidget->clear(); ui->tabWidget->clear();
}); });
connect(mTreeWidget, &XTreeWidget::RawFileSelected, this, [this](const XRawFile* rawFile, const QString aParentName) { connect(mTreeWidget, &XTreeWidget::RawFileSelected, this, [this](std::shared_ptr<RawFile> rawFile, const QString aParentName) {
QTabWidget *rawTabWidget = new QTabWidget(this); QTabWidget *rawTabWidget = new QTabWidget(this);
rawTabWidget->setProperty("PARENT_NAME", QVariant::fromValue(aParentName)); rawTabWidget->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
@ -168,13 +157,13 @@ MainWindow::MainWindow(QWidget *parent)
scriptEditor->setProperty("PARENT_NAME", QVariant::fromValue(aParentName)); scriptEditor->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
scriptEditor->setFont(QFont("Consolas")); scriptEditor->setFont(QFont("Consolas"));
// if (rawFile->contents.isEmpty()) { if (rawFile->contents.isEmpty()) {
// scriptEditor->setPlainText("EMPTY"); scriptEditor->setPlainText("EMPTY");
// } else { } else {
// scriptEditor->setPlainText(rawFile->contents); scriptEditor->setPlainText(rawFile->contents);
// } }
QString fileStem;// = rawFile->path.split('/').last(); QString fileStem = rawFile->path.split('/').last();
for (int i = 0; i < ui->tabWidget->count(); i++) { for (int i = 0; i < ui->tabWidget->count(); i++) {
if (ui->tabWidget->tabText(i) == fileStem) { if (ui->tabWidget->tabText(i) == fileStem) {
delete scriptEditor; delete scriptEditor;
@ -186,7 +175,7 @@ MainWindow::MainWindow(QWidget *parent)
QFontMetrics metrics(scriptEditor->font()); QFontMetrics metrics(scriptEditor->font());
scriptEditor->setTabStopDistance(tabStopSpaces * metrics.horizontalAdvance(' ')); scriptEditor->setTabStopDistance(tabStopSpaces * metrics.horizontalAdvance(' '));
QSyntaxHighlighter *highlighter = nullptr; QSyntaxHighlighter *highlighter;
if (fileStem.contains(".gsc")) { if (fileStem.contains(".gsc")) {
highlighter = new Highlighter_GSC(scriptEditor->document()); highlighter = new Highlighter_GSC(scriptEditor->document());
} else if (fileStem.contains(".cfg")) { } else if (fileStem.contains(".cfg")) {
@ -202,12 +191,12 @@ MainWindow::MainWindow(QWidget *parent)
rawTabWidget->addTab(scriptEditor, "Text Editor"); rawTabWidget->addTab(scriptEditor, "Text Editor");
ui->tabWidget->addTab(rawTabWidget, fileStem); ui->tabWidget->addTab(rawTabWidget, fileStem);
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, Utils::CreateAssetIcon(ASSET_TYPE_RUMBLE)); ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, ZoneFile::AssetTypeToIcon(ASSET_RUMBLE));
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1); ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
return; return;
} else if (fileStem.contains(".shock")) { } else if (fileStem.contains(".shock")) {
highlighter = new Highlighter_Shock(scriptEditor->document()); highlighter = new Highlighter_Shock(scriptEditor->document());
} /*else if (rawFile->contents.left(6) == "RUMBLE") { } else if (rawFile->contents.left(6) == "RUMBLE") {
RumbleFileViewer *rmbFileViewer = new RumbleFileViewer(this); RumbleFileViewer *rmbFileViewer = new RumbleFileViewer(this);
rmbFileViewer->setProperty("PARENT_NAME", QVariant::fromValue(aParentName)); rmbFileViewer->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
rmbFileViewer->SetRumbleFile(rawFile); rmbFileViewer->SetRumbleFile(rawFile);
@ -216,61 +205,59 @@ MainWindow::MainWindow(QWidget *parent)
rawTabWidget->addTab(scriptEditor, "Text Editor"); rawTabWidget->addTab(scriptEditor, "Text Editor");
ui->tabWidget->addTab(rawTabWidget, fileStem); ui->tabWidget->addTab(rawTabWidget, fileStem);
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, Utils::CreateAssetIcon(ASSET_TYPE_RUMBLE)); ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, ZoneFile::AssetTypeToIcon(ASSET_RUMBLE));
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1); ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
return; return;
}*/ else {
delete highlighter;
} }
ui->tabWidget->addTab(scriptEditor, fileStem); ui->tabWidget->addTab(scriptEditor, fileStem);
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, Utils::CreateAssetIcon(ASSET_TYPE_RAWFILE)); ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, ZoneFile::AssetTypeToIcon(ASSET_RAW_FILE));
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1); ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
}); });
// connect(mTreeWidget, &XTreeWidget::ImageSelected, this, [this](std::shared_ptr<Image> image, const QString aParentName) { connect(mTreeWidget, &XTreeWidget::ImageSelected, this, [this](std::shared_ptr<Image> image, const QString aParentName) {
// ImageWidget *mImageWidget = new ImageWidget(this); ImageWidget *mImageWidget = new ImageWidget(this);
// mImageWidget->setAcceptDrops(false); mImageWidget->setAcceptDrops(false);
// mImageWidget->SetImage(image); mImageWidget->SetImage(image);
// mImageWidget->setProperty("PARENT_NAME", QVariant::fromValue(aParentName)); mImageWidget->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
// QString fileStem = image->materialName; QString fileStem = image->materialName;
// for (int i = 0; i < ui->tabWidget->count(); i++) { for (int i = 0; i < ui->tabWidget->count(); i++) {
// if (ui->tabWidget->tabText(i) == fileStem) { if (ui->tabWidget->tabText(i) == fileStem) {
// delete mImageWidget; delete mImageWidget;
// return; return;
// } }
// } }
// ui->tabWidget->addTab(mImageWidget, fileStem); ui->tabWidget->addTab(mImageWidget, fileStem);
// ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, Utils::CreateAssetIcon(ASSET_TYPE_IMAGE)); ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, ZoneFile::AssetTypeToIcon(ASSET_IMAGE));
// ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1); ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
// }); });
// connect(mTreeWidget, &XTreeWidget::MenuSelected, this, [](std::shared_ptr<Menu> menu, const QString aParentName) { connect(mTreeWidget, &XTreeWidget::MenuSelected, this, [](std::shared_ptr<Menu> menu, const QString aParentName) {
// Q_UNUSED(menu); Q_UNUSED(menu);
// }); });
connect(mTreeWidget, &XTreeWidget::MaterialSelected, this, [this](const XMaterial* material, const QString aParentName) { connect(mTreeWidget, &XTreeWidget::MaterialSelected, this, [this](std::shared_ptr<Material> material, const QString aParentName) {
MaterialViewer *matViewer = new MaterialViewer(this); MaterialViewer *matViewer = new MaterialViewer(this);
matViewer->setAcceptDrops(false); matViewer->setAcceptDrops(false);
matViewer->SetMaterial(material); matViewer->SetMaterial(material);
matViewer->setProperty("PARENT_NAME", QVariant::fromValue(aParentName)); matViewer->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
// QString fileStem = material->name; QString fileStem = material->name;
// for (int i = 0; i < ui->tabWidget->count(); i++) { for (int i = 0; i < ui->tabWidget->count(); i++) {
// if (ui->tabWidget->tabText(i) == fileStem) { if (ui->tabWidget->tabText(i) == fileStem) {
// delete matViewer; delete matViewer;
// return; return;
// } }
// } }
//ui->tabWidget->addTab(matViewer, fileStem); ui->tabWidget->addTab(matViewer, fileStem);
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, Utils::CreateAssetIcon(ASSET_TYPE_MATERIAL)); ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, ZoneFile::AssetTypeToIcon(ASSET_MATERIAL));
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1); ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
}); });
connect(mTreeWidget, &XTreeWidget::DDSFileSelected, this, [this](const DDSFile* ddsFile, const QString aParentName) { connect(mTreeWidget, &XTreeWidget::DDSFileSelected, this, [this](std::shared_ptr<DDSFile> ddsFile, const QString aParentName) {
DDSViewer *ddsViewer = new DDSViewer(this); DDSViewer *ddsViewer = new DDSViewer(this);
ddsViewer->setAcceptDrops(false); ddsViewer->setAcceptDrops(false);
ddsViewer->SetDDSFile(ddsFile); ddsViewer->SetDDSFile(ddsFile);
@ -285,11 +272,11 @@ MainWindow::MainWindow(QWidget *parent)
} }
ui->tabWidget->addTab(ddsViewer, fileStem); ui->tabWidget->addTab(ddsViewer, fileStem);
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, Utils::CreateAssetIcon(ASSET_TYPE_IMAGE)); ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, ZoneFile::AssetTypeToIcon(ASSET_IMAGE));
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1); ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
}); });
connect(mTreeWidget, &XTreeWidget::IWIFileSelected, this, [this](const IWIFile* iwiFile, const QString aParentName) { connect(mTreeWidget, &XTreeWidget::IWIFileSelected, this, [this](std::shared_ptr<IWIFile> iwiFile, const QString aParentName) {
IWIViewer *iwiViewer = new IWIViewer(this); IWIViewer *iwiViewer = new IWIViewer(this);
iwiViewer->setAcceptDrops(false); iwiViewer->setAcceptDrops(false);
iwiViewer->SetIWIFile(iwiFile); iwiViewer->SetIWIFile(iwiFile);
@ -304,11 +291,11 @@ MainWindow::MainWindow(QWidget *parent)
} }
ui->tabWidget->addTab(iwiViewer, fileStem); ui->tabWidget->addTab(iwiViewer, fileStem);
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, Utils::CreateAssetIcon(ASSET_TYPE_IMAGE)); ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, ZoneFile::AssetTypeToIcon(ASSET_IMAGE));
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1); ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
}); });
connect(mTreeWidget, &XTreeWidget::FastFileSelected, this, [this](const FastFile* aFastFile, const QString aParentName) { connect(mTreeWidget, &XTreeWidget::FastFileSelected, this, [this](std::shared_ptr<FastFile> aFastFile, const QString aParentName) {
FastFileViewer *fastFileViewer = new FastFileViewer(this); FastFileViewer *fastFileViewer = new FastFileViewer(this);
fastFileViewer->setAcceptDrops(false); fastFileViewer->setAcceptDrops(false);
fastFileViewer->SetFastFile(aFastFile); fastFileViewer->SetFastFile(aFastFile);
@ -323,11 +310,11 @@ MainWindow::MainWindow(QWidget *parent)
} }
ui->tabWidget->addTab(fastFileViewer, fileStem); ui->tabWidget->addTab(fastFileViewer, fileStem);
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, Utils::CreateAssetIcon("FF")); ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, ZoneFile::AssetTypeToIcon(ASSET_FAST_FILE));
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1); ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
}); });
connect(mTreeWidget, &XTreeWidget::ZoneFileSelected, this, [this](const ZoneFile* aZoneFile, const QString aParentName) { connect(mTreeWidget, &XTreeWidget::ZoneFileSelected, this, [this](std::shared_ptr<ZoneFile> aZoneFile, const QString aParentName) {
ZoneFileViewer *zoneFileViewer = new ZoneFileViewer(this); ZoneFileViewer *zoneFileViewer = new ZoneFileViewer(this);
zoneFileViewer->setAcceptDrops(false); zoneFileViewer->setAcceptDrops(false);
zoneFileViewer->SetZoneFile(aZoneFile); zoneFileViewer->SetZoneFile(aZoneFile);
@ -354,11 +341,11 @@ MainWindow::MainWindow(QWidget *parent)
scrollArea->setWidget(containerWidget); scrollArea->setWidget(containerWidget);
ui->tabWidget->addTab(scrollArea, fileStem); ui->tabWidget->addTab(scrollArea, fileStem);
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, Utils::CreateAssetIcon("ZF")); ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, ZoneFile::AssetTypeToIcon(ASSET_ZONE_FILE));
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1); ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
}); });
connect(mTreeWidget, &XTreeWidget::LocalStringSelected, this, [this](const ZoneFile* aZoneFile, const QString aParentName) { connect(mTreeWidget, &XTreeWidget::LocalStringSelected, this, [this](std::shared_ptr<ZoneFile> aZoneFile, const QString aParentName) {
LocalStringViewer *localStrViewer = new LocalStringViewer(this); LocalStringViewer *localStrViewer = new LocalStringViewer(this);
localStrViewer->setAcceptDrops(false); localStrViewer->setAcceptDrops(false);
localStrViewer->SetZoneFile(aZoneFile); localStrViewer->SetZoneFile(aZoneFile);
@ -373,17 +360,17 @@ MainWindow::MainWindow(QWidget *parent)
} }
ui->tabWidget->addTab(localStrViewer, fileStem); ui->tabWidget->addTab(localStrViewer, fileStem);
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, Utils::CreateAssetIcon(ASSET_TYPE_LOCALIZE_ENTRY)); ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, ZoneFile::AssetTypeToIcon(ASSET_LOCAL_STRING));
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1); ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
}); });
connect(mTreeWidget, &XTreeWidget::TechSetSelected, this, [this](const XMaterialTechniqueSet* aTechSet, const QString aParentName) { connect(mTreeWidget, &XTreeWidget::TechSetSelected, this, [this](std::shared_ptr<TechSet> aTechSet, const QString aParentName) {
TechSetViewer *techSetViewer = new TechSetViewer(this); TechSetViewer *techSetViewer = new TechSetViewer(this);
techSetViewer->setAcceptDrops(false); techSetViewer->setAcceptDrops(false);
techSetViewer->SetTechSet(aTechSet); techSetViewer->SetTechSet(aTechSet);
techSetViewer->setProperty("PARENT_NAME", QVariant::fromValue(aParentName)); techSetViewer->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
QString fileStem = aTechSet->GetName(); QString fileStem = aTechSet->name;
for (int i = 0; i < ui->tabWidget->count(); i++) { for (int i = 0; i < ui->tabWidget->count(); i++) {
if (ui->tabWidget->tabText(i) == fileStem) { if (ui->tabWidget->tabText(i) == fileStem) {
delete techSetViewer; delete techSetViewer;
@ -391,18 +378,18 @@ MainWindow::MainWindow(QWidget *parent)
} }
} }
ui->tabWidget->addTab(techSetViewer, aTechSet->GetName()); ui->tabWidget->addTab(techSetViewer, aTechSet->name);
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, Utils::CreateAssetIcon(ASSET_TYPE_TECHNIQUE_SET)); ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, ZoneFile::AssetTypeToIcon(ASSET_TECH_SET));
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1); ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
}); });
connect(mTreeWidget, &XTreeWidget::StrTableSelected, this, [this](const XStringTable* aStrTable, const QString aParentName) { connect(mTreeWidget, &XTreeWidget::StrTableSelected, this, [this](std::shared_ptr<StringTable> aStrTable, const QString aParentName) {
StringTableViewer *strTableViewer = new StringTableViewer(this); StringTableViewer *strTableViewer = new StringTableViewer(this);
strTableViewer->setAcceptDrops(false); strTableViewer->setAcceptDrops(false);
strTableViewer->SetStringTable(aStrTable); strTableViewer->SetStringTable(aStrTable);
strTableViewer->setProperty("PARENT_NAME", QVariant::fromValue(aParentName)); strTableViewer->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
QString fileStem = aStrTable->GetName()->GetString(); QString fileStem = aStrTable->name;
for (int i = 0; i < ui->tabWidget->count(); i++) { for (int i = 0; i < ui->tabWidget->count(); i++) {
if (ui->tabWidget->tabText(i) == fileStem) { if (ui->tabWidget->tabText(i) == fileStem) {
delete strTableViewer; delete strTableViewer;
@ -411,28 +398,28 @@ MainWindow::MainWindow(QWidget *parent)
} }
ui->tabWidget->addTab(strTableViewer, fileStem); ui->tabWidget->addTab(strTableViewer, fileStem);
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, Utils::CreateAssetIcon(ASSET_TYPE_STRINGTABLE)); ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, ZoneFile::AssetTypeToIcon(ASSET_STRING_TABLE));
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1); ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
}); });
// connect(mTreeWidget, &XTreeWidget::SoundSelected, this, [this](std::shared_ptr<Sound> aSound, const QString aParentName) { connect(mTreeWidget, &XTreeWidget::SoundSelected, this, [this](std::shared_ptr<Sound> aSound, const QString aParentName) {
// SoundViewer *soundViewer = new SoundViewer(this); SoundViewer *soundViewer = new SoundViewer(this);
// soundViewer->setAcceptDrops(false); soundViewer->setAcceptDrops(false);
// soundViewer->SetSound(aSound); soundViewer->SetSound(aSound);
// soundViewer->setProperty("PARENT_NAME", QVariant::fromValue(aParentName)); soundViewer->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
// QString fileStem = aSound->path.split('/').last(); QString fileStem = aSound->path.split('/').last();
// for (int i = 0; i < ui->tabWidget->count(); i++) { for (int i = 0; i < ui->tabWidget->count(); i++) {
// if (ui->tabWidget->tabText(i) == fileStem) { if (ui->tabWidget->tabText(i) == fileStem) {
// delete soundViewer; delete soundViewer;
// return; return;
// } }
// } }
// ui->tabWidget->addTab(soundViewer, fileStem); ui->tabWidget->addTab(soundViewer, fileStem);
// ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, Utils::CreateAssetIcon(ASSET_TYPE_SOUND)); ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, ZoneFile::AssetTypeToIcon(ASSET_SOUND));
// ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1); ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
// }); });
connect(mTreeWidget, &XTreeWidget::ItemSelected, this, [this](const QString itemText) { connect(mTreeWidget, &XTreeWidget::ItemSelected, this, [this](const QString itemText) {
for (int i = 0; i < ui->tabWidget->count(); i++) { for (int i = 0; i < ui->tabWidget->count(); i++) {
@ -533,22 +520,7 @@ bool MainWindow::OpenFastFile(const QString aFastFilePath) {
return false; return false;
} }
FastFile* fastFile = FastFile::Open(aFastFilePath); std::shared_ptr<FastFile> fastFile = FastFileFactory::Create(aFastFilePath);
fastFile->SetStem(fastFileStem);
mTreeWidget->AddFastFile(fastFile);
// Open zone file after decompressing ff and writing
return true;
}
bool MainWindow::OpenFastFile(const QByteArray& aFastFileData, const QString aFastFilePath) {
const QString fastFileStem = aFastFilePath.section("/", -1, -1);
if (mTreeWidget->HasFastFile(fastFileStem)) {
LogManager::instance().addError("Can't add duplicate file!");
return false;
}
FastFile* fastFile = FastFile::Open(aFastFileData);
fastFile->SetStem(fastFileStem); fastFile->SetStem(fastFileStem);
mTreeWidget->AddFastFile(fastFile); mTreeWidget->AddFastFile(fastFile);
@ -563,13 +535,11 @@ bool MainWindow::OpenFastFile(const QByteArray& aFastFileData, const QString aFa
and opens the selected file. and opens the selected file.
*/ */
bool MainWindow::OpenFastFile() { bool MainWindow::OpenFastFile() {
// Open file dialog to steam apps const QString fastFileName = Utils::GetOpenFastFileName();
const QString steamPath = "C:/Program Files (x86)/Steam/steamapps/common/Call of Duty World at War/zone/english/"; if (!OpenFastFile(fastFileName)) {
qDebug() << "Failed to open Fast file!";
QFileDialog::getOpenFileContent(tr("Fast File (*.ff);;All Files (*.*)"), [this](const QString &fileName, const QByteArray &data){ return false;
OpenFastFile(data, fileName); }
});
return true; return true;
} }
@ -583,7 +553,7 @@ bool MainWindow::OpenZoneFile(const QString aZoneFilePath, bool fromFF) {
Q_UNUSED(aZoneFilePath); Q_UNUSED(aZoneFilePath);
Q_UNUSED(fromFF); Q_UNUSED(fromFF);
// ZoneFile* zoneFile = ZoneFile::Create(); //ZoneFile zoneFile;
//if (!zoneFile.Load(aZoneFilePath)) { //if (!zoneFile.Load(aZoneFilePath)) {
// qDebug() << "Error: Failed to load zone file!"; // qDebug() << "Error: Failed to load zone file!";
// return false; // return false;
@ -594,14 +564,8 @@ bool MainWindow::OpenZoneFile(const QString aZoneFilePath, bool fromFF) {
} }
bool MainWindow::OpenZoneFile() { bool MainWindow::OpenZoneFile() {
// Open file dialog to steam apps const QString zoneFileName = Utils::GetOpenZoneFileName();
const QString steamPath = "C:/Program Files (x86)/Steam/steamapps/common/Call of Duty World at War/zone/english/"; if (!OpenZoneFile(zoneFileName)) {
const QString zoneFilePath = QFileDialog::getOpenFileName(this, "Open Zone File", steamPath, "Zone File (*.zone);;All Files (*.*)");
if (zoneFilePath.isNull()) {
// User pressed cancel
return false;
} else if (!QFile::exists(zoneFilePath)) {
QMessageBox::warning(this, "Warning!", QString("%1 does not exist!.").arg(zoneFilePath));
qDebug() << "Failed to open Zone file!"; qDebug() << "Failed to open Zone file!";
return false; return false;
} }
@ -673,7 +637,7 @@ quint32 DXT3 = 0x33545844; // 'DXT3'
quint32 DXT5 = 0x35545844; // 'DXT5' quint32 DXT5 = 0x35545844; // 'DXT5'
int MainWindow::LoadFile_IWI(const QString aFilePath) { int MainWindow::LoadFile_IWI(const QString aFilePath) {
mTreeWidget->AddIWIFile(new IWIFile(aFilePath)); mTreeWidget->AddIWIFile(std::make_shared<IWIFile>(aFilePath));
return 0; return 0;
} }
@ -684,7 +648,7 @@ int MainWindow::LoadFile_DDSFiles(const QStringList aFilePaths) {
qDebug() << "Error: Invalid filename " << filePath; qDebug() << "Error: Invalid filename " << filePath;
return -1; return -1;
} }
mTreeWidget->AddDDSFile(new DDSFile(filePath)); mTreeWidget->AddDDSFile(std::make_shared<DDSFile>(filePath));
} }
return 0; return 0;
} }
@ -716,7 +680,7 @@ int MainWindow::LoadFile_DDS(const QString aFilePath) {
qDebug() << "Error: Invalid filename " << aFilePath; qDebug() << "Error: Invalid filename " << aFilePath;
return -1; return -1;
} }
mTreeWidget->AddDDSFile(new DDSFile(aFilePath)); mTreeWidget->AddDDSFile(std::make_shared<DDSFile>(aFilePath));
return 0; return 0;
} }
@ -789,7 +753,7 @@ int MainWindow::LoadFile_IPAK(const QString aFilePath) {
QVector<IPAKIndexEntry> entries = QVector<IPAKIndexEntry>(); QVector<IPAKIndexEntry> entries = QVector<IPAKIndexEntry>();
QVector<IPAKSection> sections = QVector<IPAKSection>(header.sectionCount); QVector<IPAKSection> sections = QVector<IPAKSection>(header.sectionCount);
for (quint32 i = 0; i < header.sectionCount; i++) { for (uint i = 0; i < header.sectionCount; i++) {
IPAKSection currentSection; IPAKSection currentSection;
stream >> currentSection; stream >> currentSection;
sections << currentSection; sections << currentSection;
@ -811,7 +775,7 @@ int MainWindow::LoadFile_IPAK(const QString aFilePath) {
<< " - Count: " << chunkHeader.count << "\n" << " - Count: " << chunkHeader.count << "\n"
<< " - Offset: " << chunkHeader.offset; << " - Offset: " << chunkHeader.offset;
for (quint32 j = 0; j < 31; j++) { for (uint j = 0; j < 31; j++) {
IPAKDataChunkCommand command; IPAKDataChunkCommand command;
stream >> command; stream >> command;
if (!command.size) { continue; } if (!command.size) { continue; }
@ -821,7 +785,7 @@ int MainWindow::LoadFile_IPAK(const QString aFilePath) {
<< " - Compressed: " << command.compressed; << " - Compressed: " << command.compressed;
} }
for (quint32 j = 0; j < chunkHeader.count; j++) { for (uint j = 0; j < chunkHeader.count; j++) {
auto command = chunkHeader.commands[j]; auto command = chunkHeader.commands[j];
qDebug() << "Reading from " << stream.device()->pos(); qDebug() << "Reading from " << stream.device()->pos();
@ -846,7 +810,7 @@ int MainWindow::LoadFile_IPAK(const QString aFilePath) {
stream.skipRawData(sizeof(quint32) * (31 - chunkHeader.count)); stream.skipRawData(sizeof(quint32) * (31 - chunkHeader.count));
qDebug() << stream.device()->pos(); qDebug() << stream.device()->pos();
} else if (sectionType == "Index") { } else if (sectionType == "Index") {
for (quint32 j = 0; j < currentSection.itemCount; j++) { for (uint j = 0; j < currentSection.itemCount; j++) {
IPAKIndexEntry entry; IPAKIndexEntry entry;
stream >> entry; stream >> entry;

View File

@ -2,6 +2,7 @@
#define MAINWINDOW_H #define MAINWINDOW_H
#include "d3dbsp_structs.h" #include "d3dbsp_structs.h"
#include "asset_structs.h"
#include "xtreewidget.h" #include "xtreewidget.h"
#include <QMainWindow> #include <QMainWindow>
@ -15,6 +16,7 @@
#include <QPlainTextEdit> #include <QPlainTextEdit>
#include <QMimeData> #include <QMimeData>
#include <QProgressBar> #include <QProgressBar>
#include <windows.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
namespace Ui { namespace Ui {
@ -33,7 +35,6 @@ public:
private slots: private slots:
bool OpenFastFile(const QString aFastFilePath); bool OpenFastFile(const QString aFastFilePath);
bool OpenFastFile(const QByteArray& aFastFileData, const QString aFastFilePath);
bool OpenFastFile(); bool OpenFastFile();
bool OpenZoneFile(const QString aZoneFilePath, bool fromFF = false); bool OpenZoneFile(const QString aZoneFilePath, bool fromFF = false);
@ -63,7 +64,7 @@ private:
quint32 mTagCount; quint32 mTagCount;
quint32 mRecordCount; quint32 mRecordCount;
QMap<QString, QString> mRawFileMap; QMap<QString, QString> mRawFileMap;
//QMap<QString, Image> mImageMap; QMap<QString, Image> mImageMap;
QMap<QString, QTreeWidgetItem*> mTreeMap; QMap<QString, QTreeWidgetItem*> mTreeMap;
QMap<QString, QVector<QPair<QString, QString>>> mStrTableMap; QMap<QString, QVector<QPair<QString, QString>>> mStrTableMap;
XTreeWidget *mTreeWidget; XTreeWidget *mTreeWidget;

View File

@ -50,7 +50,7 @@
<height>21</height> <height>21</height>
</rect> </rect>
</property> </property>
<widget class="QMenu" name="MenuDef"> <widget class="QMenu" name="menuFile">
<property name="title"> <property name="title">
<string>File</string> <string>File</string>
</property> </property>
@ -117,17 +117,9 @@
</property> </property>
<addaction name="actionAbout"/> <addaction name="actionAbout"/>
<addaction name="actionCheck_for_Updates"/> <addaction name="actionCheck_for_Updates"/>
<addaction name="actionReport_Issue"/>
</widget> </widget>
<widget class="QMenu" name="menuTools"> <addaction name="menuFile"/>
<property name="title">
<string>Tools</string>
</property>
<addaction name="actionRun_Tests"/>
</widget>
<addaction name="MenuDef"/>
<addaction name="menuEdit"/> <addaction name="menuEdit"/>
<addaction name="menuTools"/>
<addaction name="menuHelp"/> <addaction name="menuHelp"/>
</widget> </widget>
<widget class="QToolBar" name="toolBar"> <widget class="QToolBar" name="toolBar">
@ -361,16 +353,6 @@
<string>Preferences...</string> <string>Preferences...</string>
</property> </property>
</action> </action>
<action name="actionReport_Issue">
<property name="text">
<string>Report Issue</string>
</property>
</action>
<action name="actionRun_Tests">
<property name="text">
<string>Run Tests</string>
</property>
</action>
</widget> </widget>
<resources> <resources>
<include location="../data/data.qrc"/> <include location="../data/data.qrc"/>

View File

@ -3,41 +3,33 @@
MaterialViewer::MaterialViewer(QWidget *parent) MaterialViewer::MaterialViewer(QWidget *parent)
: QWidget(parent) : QWidget(parent)
, ui(new Ui::MaterialViewer) , ui(new Ui::MaterialViewer) {
{
ui->setupUi(this); ui->setupUi(this);
} }
MaterialViewer::~MaterialViewer() MaterialViewer::~MaterialViewer() {
{
delete ui; delete ui;
} }
QString ToHexStr(quint32 in) QString ToHexStr(quint32 in) {
{
return QString("%1").arg(in, 8, 16, QChar('0')).toUpper(); return QString("%1").arg(in, 8, 16, QChar('0')).toUpper();
} }
void MaterialViewer::SetMaterial(const XMaterial* aMaterial) void MaterialViewer::SetMaterial(std::shared_ptr<Material> aMaterial) {
{ ui->lineEdit_NamePtr->setText(ToHexStr(aMaterial->namePtr));
Q_UNUSED(aMaterial); ui->lineEdit_Name->setText(aMaterial->name);
ui->lineEdit_RefPtr->setText(ToHexStr(aMaterial->refNamePtr));
// TODO: Fill in MaterialViewer::SetMaterial ui->lineEdit_RefName->setText(aMaterial->refName);
QString unknownStr = "";
// ui->lineEdit_NamePtr->setText(ToHexStr(aMaterial->namePtr)); foreach (quint32 unknownPtr, aMaterial->pointers) {
// ui->lineEdit_Name->setText(aMaterial->name); unknownStr += ToHexStr(unknownPtr) + "\n";
// ui->lineEdit_RefPtr->setText(ToHexStr(aMaterial->refNamePtr)); }
// ui->lineEdit_RefName->setText(aMaterial->refName); ui->lineEdit_Unknowns->setText(unknownStr);
// QString unknownStr = ""; ui->lineEdit_StateA->setText(ToHexStr(aMaterial->stateBits[0]));
// foreach (quint32 unknownPtr, aMaterial->pointers) { ui->lineEdit_StateA->setText(ToHexStr(aMaterial->stateBits[1]));
// unknownStr += ToHexStr(unknownPtr) + "\n"; ui->spinBox_TextureCount->setValue(aMaterial->textureCount);
// } ui->spinBox_ConstCount->setValue(aMaterial->constCount);
// ui->lineEdit_Unknowns->setText(unknownStr); ui->lineEdit_TechSetPtr->setText(ToHexStr(aMaterial->techSetPtr));
// ui->lineEdit_StateA->setText(ToHexStr(aMaterial->stateBits[0])); ui->lineEdit_TexturePtr->setText(ToHexStr(aMaterial->texturePtr));
// ui->lineEdit_StateA->setText(ToHexStr(aMaterial->stateBits[1])); ui->lineEdit_ConstantPtr->setText(ToHexStr(aMaterial->constPtr));
// ui->spinBox_TextureCount->setValue(aMaterial->textureCount);
// ui->spinBox_ConstCount->setValue(aMaterial->constCount);
// ui->lineEdit_TechSetPtr->setText(ToHexStr(aMaterial->techSetPtr));
// ui->lineEdit_TexturePtr->setText(ToHexStr(aMaterial->texturePtr));
// ui->lineEdit_ConstantPtr->setText(ToHexStr(aMaterial->constPtr));
} }

View File

@ -1,7 +1,7 @@
#ifndef MATERIALVIEWER_H #ifndef MATERIALVIEWER_H
#define MATERIALVIEWER_H #define MATERIALVIEWER_H
#include "xmaterial.h" #include "asset_structs.h"
#include <QWidget> #include <QWidget>
#include <QScrollArea> #include <QScrollArea>
@ -18,7 +18,7 @@ public:
explicit MaterialViewer(QWidget *parent = nullptr); explicit MaterialViewer(QWidget *parent = nullptr);
~MaterialViewer(); ~MaterialViewer();
void SetMaterial(const XMaterial *aMaterial); void SetMaterial(std::shared_ptr<Material> aMaterial);
private: private:
Ui::MaterialViewer *ui; Ui::MaterialViewer *ui;

View File

@ -1,103 +0,0 @@
#include "reportissuedialog.h"
#include "qjsonarray.h"
#include "ui_reportissuedialog.h"
#include <QJsonDocument>
#include <QJsonObject>
#include <QMessageBox>
#include <QNetworkRequest>
ReportIssueDialog::ReportIssueDialog(const QString &giteaBaseUrl,
const QString &repoOwner,
const QString &repoName,
const QString &accessToken,
QWidget *parent) :
QDialog(parent),
ui(new Ui::ReportIssueDialog),
networkManager(new QNetworkAccessManager(this)),
giteaBaseUrl(giteaBaseUrl),
repoOwner(repoOwner),
repoName(repoName),
accessToken(accessToken)
{
ui->setupUi(this);
connect(networkManager, &QNetworkAccessManager::finished, this, &ReportIssueDialog::onNetworkReplyFinished);
}
ReportIssueDialog::~ReportIssueDialog()
{
delete ui;
}
void ReportIssueDialog::on_buttonSend_clicked()
{
QString title = ui->lineEditSummary->text().trimmed();
QString details = ui->textEditDetails->toPlainText().trimmed();
QString contact = ui->lineEditContact->text().trimmed();
if (title.isEmpty()) {
QMessageBox::warning(this, tr("Input Error"), tr("Please enter a summary/title for the issue."));
return;
}
QString body = details;
if (!contact.isEmpty()) {
body += QString("\n\nContact info:\n%1").arg(contact);
}
ui->buttonSend->setEnabled(false);
sendIssueReport(title, body, contact);
}
void ReportIssueDialog::on_buttonCancel_clicked()
{
reject();
}
void ReportIssueDialog::sendIssueReport(const QString &title, const QString &body, const QString &/*contact*/)
{
// Compose URL: e.g. https://gitea.example.com/api/v1/repos/{owner}/{repo}/issues
QUrl url(QString("%1/api/v1/repos/%2/%3/issues").arg(giteaBaseUrl).arg(repoOwner).arg(repoName));
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
if (!accessToken.isEmpty()) {
request.setRawHeader("Authorization", "token " + accessToken.toUtf8());
}
// Compose JSON body
QJsonObject json;
json["title"] = title;
json["body"] = body;
json["labels"] = QJsonArray{12};
QJsonDocument doc(json);
QByteArray data = doc.toJson();
networkManager->post(request, data);
}
void ReportIssueDialog::onNetworkReplyFinished(QNetworkReply *reply)
{
ui->buttonSend->setEnabled(true);
QByteArray responseData = reply->readAll();
QString responseStr = QString::fromUtf8(responseData);
if (reply->error() != QNetworkReply::NoError) {
QString errorStr = reply->errorString();
if (errorStr.isEmpty()) errorStr = "Unknown network error";
QMessageBox::critical(this, tr("Error"), tr("Failed to send issue report:\n%1\nResponse:\n%2").arg(errorStr).arg(responseStr));
} else {
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if (status == 201) {
QMessageBox::information(this, tr("Success"), tr("Issue reported successfully!"));
accept();
} else {
QMessageBox::warning(this, tr("Failed"), tr("Unexpected response from server (%1):\n%2").arg(status).arg(responseStr));
}
}
reply->deleteLater();
}

View File

@ -1,43 +0,0 @@
#ifndef REPORTISSUEDIALOG_H
#define REPORTISSUEDIALOG_H
#include <QDialog>
#include <QNetworkAccessManager>
#include <QNetworkReply>
namespace Ui {
class ReportIssueDialog;
}
class ReportIssueDialog : public QDialog
{
Q_OBJECT
public:
explicit ReportIssueDialog(const QString &giteaBaseUrl,
const QString &repoOwner,
const QString &repoName,
const QString &accessToken,
QWidget *parent = nullptr);
~ReportIssueDialog();
private slots:
void on_buttonSend_clicked();
void on_buttonCancel_clicked();
void onNetworkReplyFinished(QNetworkReply *reply);
private:
Ui::ReportIssueDialog *ui;
QNetworkAccessManager *networkManager;
QString giteaBaseUrl;
QString repoOwner;
QString repoName;
QString accessToken;
void sendIssueReport(const QString &title, const QString &body, const QString &contact);
};
#endif // REPORTISSUEDIALOG_H

View File

@ -1,84 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ReportIssueDialog</class>
<widget class="QDialog" name="ReportIssueDialog">
<property name="windowTitle">
<string>Report a Problem</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="labelInstructions">
<property name="text">
<string>Please describe the problem you encountered. Well use this info to help fix it.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="labelSummary">
<property name="text">
<string>Summary (short title):</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditSummary" />
</item>
<item>
<widget class="QLabel" name="labelDetails">
<property name="text">
<string>Details (what happened?):</string>
</property>
</widget>
</item>
<item>
<widget class="QTextEdit" name="textEditDetails" />
</item>
<item>
<widget class="QLabel" name="labelContact">
<property name="text">
<string>Your contact (email or name, optional):</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditContact" />
</item>
<item>
<layout class="QHBoxLayout" name="buttonLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="buttonSend">
<property name="text">
<string>Send Report</string>
</property>
<property name="default">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonCancel">
<property name="text">
<string>Cancel</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -18,41 +18,41 @@ RumbleFileViewer::~RumbleFileViewer() {
delete ui; delete ui;
} }
void RumbleFileViewer::SetRumbleFile(XRawFile *aRumbleFile) { void RumbleFileViewer::SetRumbleFile(std::shared_ptr<RawFile> aRumbleFile) {
mRumbleFile = aRumbleFile; mRumbleFile = aRumbleFile;
ui->tableWidget_Properties->clear(); ui->tableWidget_Properties->clear();
// const QString magic = aRumbleFile->contents.left(6); const QString magic = aRumbleFile->contents.left(6);
// if (magic != "RUMBLE") { if (magic != "RUMBLE") {
// qDebug() << "Rumble file has invalid magic: " << magic; qDebug() << "Rumble file has invalid magic: " << magic;
// return; return;
// } }
// int firstIndex = 0; int firstIndex = 0;
// int secondIndex = 0; int secondIndex = 0;
// int thirdIndex = 0; int thirdIndex = 0;
// int startIndex = 0; int startIndex = 0;
// for (int i = 0; i < aRumbleFile->contents.count("\\") / 2; i++) { for (int i = 0; i < aRumbleFile->contents.count("\\") / 2; i++) {
// ui->tableWidget_Properties->setRowCount(i + 1); ui->tableWidget_Properties->setRowCount(i + 1);
// ui->spinBox_Entries->setValue(i + 1); ui->spinBox_Entries->setValue(i + 1);
// firstIndex = aRumbleFile->contents.indexOf("\\", startIndex); firstIndex = aRumbleFile->contents.indexOf("\\", startIndex);
// secondIndex = aRumbleFile->contents.indexOf("\\", firstIndex + 1); secondIndex = aRumbleFile->contents.indexOf("\\", firstIndex + 1);
// thirdIndex = aRumbleFile->contents.indexOf("\\", secondIndex + 1); thirdIndex = aRumbleFile->contents.indexOf("\\", secondIndex + 1);
// if (thirdIndex == -1) { if (thirdIndex == -1) {
// thirdIndex = aRumbleFile->contents.size(); thirdIndex = aRumbleFile->contents.size();
// } }
// const QString keyStr = aRumbleFile->contents.mid(firstIndex + 1, secondIndex - firstIndex - 1); const QString keyStr = aRumbleFile->contents.mid(firstIndex + 1, secondIndex - firstIndex - 1);
// QTableWidgetItem *keyItem = new QTableWidgetItem(keyStr); QTableWidgetItem *keyItem = new QTableWidgetItem(keyStr);
// ui->tableWidget_Properties->setItem(i, 0, keyItem); ui->tableWidget_Properties->setItem(i, 0, keyItem);
// const QString valStr = aRumbleFile->contents.mid(secondIndex + 1, thirdIndex - secondIndex - 1); const QString valStr = aRumbleFile->contents.mid(secondIndex + 1, thirdIndex - secondIndex - 1);
// QTableWidgetItem *valueItem = new QTableWidgetItem(valStr); QTableWidgetItem *valueItem = new QTableWidgetItem(valStr);
// ui->tableWidget_Properties->setItem(i, 1, valueItem); ui->tableWidget_Properties->setItem(i, 1, valueItem);
// startIndex = thirdIndex; startIndex = thirdIndex;
// } }
} }

View File

@ -1,8 +1,8 @@
#ifndef RUMBLEFILEVIEWER_H #ifndef RUMBLEFILEVIEWER_H
#define RUMBLEFILEVIEWER_H #define RUMBLEFILEVIEWER_H
#include "xrawfile.h" #include "asset_structs.h"
#include "zonefile.h"
#include <QWidget> #include <QWidget>
namespace Ui { namespace Ui {
@ -17,12 +17,12 @@ public:
explicit RumbleFileViewer(QWidget *parent = nullptr); explicit RumbleFileViewer(QWidget *parent = nullptr);
~RumbleFileViewer(); ~RumbleFileViewer();
void SetRumbleFile(XRawFile* aRumbleFile); void SetRumbleFile(std::shared_ptr<RawFile> aRumbleFile);
private: private:
Ui::RumbleFileViewer *ui; Ui::RumbleFileViewer *ui;
quint32 mPropertyCount; quint32 mPropertyCount;
XRawFile* mRumbleFile; std::shared_ptr<RawFile> mRumbleFile;
}; };
#endif // RUMBLEFILEVIEWER_H #endif // RUMBLEFILEVIEWER_H

View File

@ -19,10 +19,10 @@ RumbleGraphViewer::~RumbleGraphViewer() {
delete ui; delete ui;
} }
void RumbleGraphViewer::SetRumbleGraphFile(const XRawFile* aRawFile) { void RumbleGraphViewer::SetRumbleGraphFile(const std::shared_ptr<RawFile> aRawFile) {
mRumbleGraphFile = aRawFile; mRumbleGraphFile = aRawFile;
XDataStream rawFileStream;//(mRumbleGraphFile->contents.toLatin1()); QDataStream rawFileStream(mRumbleGraphFile->contents.toLatin1());
QByteArray magic(15, Qt::Uninitialized); QByteArray magic(15, Qt::Uninitialized);
rawFileStream.readRawData(magic.data(), 15); rawFileStream.readRawData(magic.data(), 15);

View File

@ -1,7 +1,7 @@
#ifndef RUMBLEGRAPHVIEWER_H #ifndef RUMBLEGRAPHVIEWER_H
#define RUMBLEGRAPHVIEWER_H #define RUMBLEGRAPHVIEWER_H
#include "xrawfile.h" #include "asset_structs.h"
#include "zonefile.h" #include "zonefile.h"
#include <QWidget> #include <QWidget>
@ -18,13 +18,13 @@ public:
~RumbleGraphViewer(); ~RumbleGraphViewer();
void SetEntryCount(quint32 aCount); void SetEntryCount(quint32 aCount);
void SetRumbleGraphFile(const XRawFile *aRawFile); void SetRumbleGraphFile(const std::shared_ptr<RawFile> aRawFile);
void SetZoneFile(ZoneFile* aZoneFile); void SetZoneFile(std::shared_ptr<ZoneFile> aZoneFile);
private: private:
Ui::RumbleGraphViewer *ui; Ui::RumbleGraphViewer *ui;
quint32 mEntryCount; quint32 mEntryCount;
const XRawFile* mRumbleGraphFile; std::shared_ptr<RawFile> mRumbleGraphFile;
}; };
#endif // RUMBLEGRAPHVIEWER_H #endif // RUMBLEGRAPHVIEWER_H

View File

@ -61,17 +61,17 @@ SoundViewer::~SoundViewer()
delete ui; delete ui;
} }
// void SoundViewer::SetSound(std::shared_ptr<Sound> aSound) void SoundViewer::SetSound(std::shared_ptr<Sound> aSound)
// { {
// buffer->setData(aSound->data); buffer->setData(aSound->data);
// if (!buffer->open(QIODevice::ReadOnly)) { if (!buffer->open(QIODevice::ReadOnly)) {
// qWarning() << "Failed to open QBuffer."; qWarning() << "Failed to open QBuffer.";
// return; return;
// } }
// ui->groupBox->setTitle(aSound->path); ui->groupBox->setTitle(aSound->path);
// player->setSourceDevice(buffer); player->setSourceDevice(buffer);
// } }
void SoundViewer::SetOutput(QAudioOutput *aOutput) { void SoundViewer::SetOutput(QAudioOutput *aOutput) {
if (!aOutput) { return; } if (!aOutput) { return; }

View File

@ -1,6 +1,8 @@
#ifndef SOUNDVIEWER_H #ifndef SOUNDVIEWER_H
#define SOUNDVIEWER_H #define SOUNDVIEWER_H
#include "asset_structs.h"
#include <QWidget> #include <QWidget>
#include <QMediaPlayer> #include <QMediaPlayer>
#include <QBuffer> #include <QBuffer>
@ -20,7 +22,7 @@ public:
explicit SoundViewer(QWidget *parent = nullptr); explicit SoundViewer(QWidget *parent = nullptr);
~SoundViewer(); ~SoundViewer();
//void SetSound(std::shared_ptr<Sound> aSound); void SetSound(std::shared_ptr<Sound> aSound);
void SetOutput(QAudioOutput *aOutput); void SetOutput(QAudioOutput *aOutput);
private: private:

View File

@ -13,21 +13,22 @@ StringTableViewer::~StringTableViewer()
delete ui; delete ui;
} }
void StringTableViewer::SetStringTable(const XStringTable *aStringTable) { void StringTableViewer::SetStringTable(std::shared_ptr<StringTable> aStringTable) {
ui->tableWidget_Strings->clear(); ui->tableWidget_Strings->clear();
ui->tableWidget_Strings->setRowCount(aStringTable->GetRowCount()); ui->tableWidget_Strings->setRowCount(aStringTable->rowCount);
ui->tableWidget_Strings->setColumnCount(aStringTable->GetColumnCount()); ui->tableWidget_Strings->setColumnCount(aStringTable->columnCount);
int currentIndex = 0; int currentIndex = 0;
for (auto value : *aStringTable->GetValues()) { for (const QString &key : aStringTable->content.keys()) {
const QString value = aStringTable->content[key];
QTableWidgetItem *tableKeyItem = new QTableWidgetItem(); QTableWidgetItem *tableKeyItem = new QTableWidgetItem();
tableKeyItem->setText(value->GetName()); tableKeyItem->setText(key);
ui->tableWidget_Strings->setItem(currentIndex, 0, tableKeyItem); ui->tableWidget_Strings->setItem(currentIndex, 0, tableKeyItem);
QTableWidgetItem *tableValItem = new QTableWidgetItem(); QTableWidgetItem *tableValItem = new QTableWidgetItem();
tableValItem->setText(value->GetString()); tableValItem->setText(value);
ui->tableWidget_Strings->setItem(currentIndex, 1, tableValItem); ui->tableWidget_Strings->setItem(currentIndex, 1, tableValItem);
currentIndex++; currentIndex++;

View File

@ -1,8 +1,7 @@
#ifndef STRINGTABLEVIEWER_H #ifndef STRINGTABLEVIEWER_H
#define STRINGTABLEVIEWER_H #define STRINGTABLEVIEWER_H
#include "xstringtable.h" #include "asset_structs.h"
#include <QWidget> #include <QWidget>
namespace Ui { namespace Ui {
@ -17,7 +16,7 @@ public:
explicit StringTableViewer(QWidget *parent = nullptr); explicit StringTableViewer(QWidget *parent = nullptr);
~StringTableViewer(); ~StringTableViewer();
void SetStringTable(const XStringTable *aStringTable); void SetStringTable(std::shared_ptr<StringTable> aStringTable);
private: private:
Ui::StringTableViewer *ui; Ui::StringTableViewer *ui;

View File

@ -13,13 +13,13 @@ TechSetViewer::~TechSetViewer()
delete ui; delete ui;
} }
void TechSetViewer::SetTechSet(const XMaterialTechniqueSet* aTechSet) { void TechSetViewer::SetTechSet(std::shared_ptr<TechSet> aTechSet) {
//ui->listWidget_Ptrs->clear(); ui->listWidget_Ptrs->clear();
ui->label_Title->setText(aTechSet->GetName()); ui->label_Title->setText(aTechSet->name);
// int ptrIndex = 1; int ptrIndex = 1;
//for (auto ptr : aTechSet->pointers) { for (auto ptr : aTechSet->pointers) {
// ui->listWidget_Ptrs->addItem(QString("Pointer %1: %2").arg(ptrIndex).arg(ptr)); ui->listWidget_Ptrs->addItem(QString("Pointer %1: %2").arg(ptrIndex).arg(ptr));
// ptrIndex++; ptrIndex++;
//} }
} }

View File

@ -1,8 +1,7 @@
#ifndef TECHSETVIEWER_H #ifndef TECHSETVIEWER_H
#define TECHSETVIEWER_H #define TECHSETVIEWER_H
#include "xmaterialtechniqueset.h" #include "asset_structs.h"
#include <QWidget> #include <QWidget>
namespace Ui { namespace Ui {
@ -17,7 +16,7 @@ public:
explicit TechSetViewer(QWidget *parent = nullptr); explicit TechSetViewer(QWidget *parent = nullptr);
~TechSetViewer(); ~TechSetViewer();
void SetTechSet(const XMaterialTechniqueSet *aTechSet); void SetTechSet(std::shared_ptr<TechSet> aTechSet);
private: private:
Ui::TechSetViewer *ui; Ui::TechSetViewer *ui;

View File

@ -6,14 +6,14 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>880</width> <width>961</width>
<height>559</height> <height>756</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>Form</string> <string>Form</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_3"> <layout class="QVBoxLayout" name="verticalLayout_2">
<item> <item>
<widget class="QLabel" name="label_Title"> <widget class="QLabel" name="label_Title">
<property name="font"> <property name="font">
@ -29,120 +29,46 @@
</widget> </widget>
</item> </item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_7"> <layout class="QHBoxLayout" name="horizontalLayout">
<item> <item>
<widget class="QGroupBox" name="groupBox"> <widget class="QGroupBox" name="groupBox">
<property name="title"> <property name="title">
<string>Set Parameters</string> <string>Unknown Pointers:</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout"> <widget class="QListWidget" name="listWidget_Ptrs"/>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Name:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit_Name">
<property name="placeholderText">
<string>Technique set name</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>World Vertex Format:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinBox_WorldVertFormat"/>
</item>
</layout>
</item>
<item>
<widget class="QListWidget" name="listWidget_Techniques"/>
</item> </item>
</layout> </layout>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QGroupBox" name="groupBox_2"> <spacer name="horizontalSpacer">
<property name="title"> <property name="orientation">
<string>Current Technique</string> <enum>Qt::Orientation::Horizontal</enum>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_2"> <property name="sizeHint" stdset="0">
<item> <size>
<layout class="QHBoxLayout" name="horizontalLayout_4"> <width>40</width>
<item> <height>20</height>
<widget class="QLabel" name="label_4"> </size>
<property name="text">
<string>Name:</string>
</property> </property>
</widget> </spacer>
</item>
<item>
<widget class="QLineEdit" name="lineEdit_TechniqueName">
<property name="placeholderText">
<string>Technique set name</string>
</property>
</widget>
</item> </item>
</layout> </layout>
</item> </item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_5"> <spacer name="verticalSpacer">
<item> <property name="orientation">
<widget class="QLabel" name="label_5"> <enum>Qt::Orientation::Vertical</enum>
<property name="text">
<string>Flags:</string>
</property> </property>
</widget> <property name="sizeHint" stdset="0">
</item> <size>
<item> <width>20</width>
<widget class="QSpinBox" name="spinBox_Flags"/> <height>363</height>
</item> </size>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>Pass Count:</string>
</property> </property>
</widget> </spacer>
</item>
<item>
<widget class="QSpinBox" name="spinBox_PassCount"/>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Material Pass</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item> </item>
</layout> </layout>
</widget> </widget>

View File

@ -5,10 +5,10 @@
XTreeWidget::XTreeWidget(QWidget *parent) XTreeWidget::XTreeWidget(QWidget *parent)
: QTreeWidget(parent) { : QTreeWidget(parent) {
mFastFiles = QMap<QString, const FastFile*>(); mFastFiles = QMap<QString, std::shared_ptr<FastFile>>();
mZoneFiles = QMap<QString, const ZoneFile*>(); mZoneFiles = QMap<QString, std::shared_ptr<ZoneFile>>();
mDDSFiles = QMap<QString, const DDSFile*>(); mDDSFiles = QMap<QString, std::shared_ptr<DDSFile>>();
mIWIFiles = QMap<QString, const IWIFile*>(); mIWIFiles = QMap<QString, std::shared_ptr<IWIFile>>();
setContextMenuPolicy(Qt::CustomContextMenu); setContextMenuPolicy(Qt::CustomContextMenu);
setSelectionMode(QTreeWidget::SingleSelection); setSelectionMode(QTreeWidget::SingleSelection);
@ -37,7 +37,7 @@ XTreeWidget::~XTreeWidget() {
} }
void XTreeWidget::AddFastFile(FastFile* aFastFile) { void XTreeWidget::AddFastFile(std::shared_ptr<FastFile> aFastFile) {
XTreeWidgetItem *fastFileItem = new XTreeWidgetItem(this); XTreeWidgetItem *fastFileItem = new XTreeWidgetItem(this);
fastFileItem->setText(0, aFastFile->GetStem()); fastFileItem->setText(0, aFastFile->GetStem());
fastFileItem->setIcon(0, Utils::CreateAssetIcon("FF")); fastFileItem->setIcon(0, Utils::CreateAssetIcon("FF"));
@ -83,189 +83,211 @@ void XTreeWidget::AddFastFile(FastFile* aFastFile) {
sortByColumn(0, Qt::AscendingOrder); sortByColumn(0, Qt::AscendingOrder);
} }
void XTreeWidget::AddZoneFile(const ZoneFile* aZoneFile, XTreeWidgetItem *aParentItem) { void XTreeWidget::AddZoneFile(std::shared_ptr<ZoneFile> aZoneFile, XTreeWidgetItem *aParentItem) {
XTreeWidgetItem *zoneItem; XTreeWidgetItem *zoneItem;
if (aParentItem != nullptr) { if (aParentItem != nullptr) {
zoneItem = new XTreeWidgetItem(aParentItem); zoneItem = new XTreeWidgetItem(aParentItem);
} else { } else {
zoneItem = new XTreeWidgetItem(this); zoneItem = new XTreeWidgetItem(this);
} }
zoneItem->setIcon(0, Utils::CreateAssetIcon("ZF")); zoneItem->setIcon(0, ZoneFile::AssetTypeToIcon(ASSET_ZONE_FILE));
zoneItem->setText(0, aZoneFile->GetBaseStem() + ".zone"); zoneItem->setText(0, aZoneFile->GetBaseStem() + ".zone");
XAssetList assetList = aZoneFile->GetAssetList(); auto assetMap = aZoneFile->GetAssetMap();
QVector<XAsset*> localizeEntries;
for (int i = 0; i < assetList.Size(); i++) if (!assetMap.localStrings.isEmpty()) {
{ QIcon localStrIcon = ZoneFile::AssetTypeToIcon(ASSET_LOCAL_STRING);
XAsset *currentAsset = assetList.GetAsset(i);
if (currentAsset->GetType() == ASSET_TYPE_LOCALIZE_ENTRY) XTreeWidgetItem *localStrRoot = new XTreeWidgetItem(zoneItem);
{ localStrRoot->setText(0, "String Files");
localizeEntries.append(currentAsset); localStrRoot->setIcon(0, localStrIcon);
} else if (currentAsset->GetType() == ASSET_TYPE_LOCALIZE_ENTRY) localStrRoot->SetCategory(CATEGORY_TYPE);
{
localizeEntries.append(currentAsset); XTreeWidgetItem *localStrItem = new XTreeWidgetItem(localStrRoot);
localStrItem->setText(0, aZoneFile->GetStem().section('.', 0, 0) + ".str");
localStrItem->setIcon(0, localStrIcon);
}
if (!assetMap.techSets.isEmpty()) {
QIcon techSetIcon = ZoneFile::AssetTypeToIcon(ASSET_TECH_SET);
XTreeWidgetItem *techSetRoot = new XTreeWidgetItem(zoneItem);
techSetRoot->setText(0, "Tech Sets");
techSetRoot->setIcon(0, techSetIcon);
techSetRoot->SetCategory(CATEGORY_TYPE);
for (TechSet techSet : assetMap.techSets) {
XTreeWidgetItem *techSetItem = new XTreeWidgetItem(techSetRoot);
techSetItem->setText(0, techSet.name);
techSetItem->setIcon(0, techSetIcon);
} }
} }
if (!assetMap.rawFiles.isEmpty()) {
QIcon rawFileIcon = ZoneFile::AssetTypeToIcon(ASSET_RAW_FILE);
// if (!assetMap.localizeEntries.isEmpty()) { XTreeWidgetItem *rawFileRoot = new XTreeWidgetItem(zoneItem);
// QIcon localStrIcon = Utils::CreateAssetIcon(ASSET_TYPE_LOCALIZE_ENTRY); rawFileRoot->setText(0, "Raw Files");
rawFileRoot->setIcon(0, rawFileIcon);
rawFileRoot->SetCategory(CATEGORY_TYPE);
for (RawFile rawFile : assetMap.rawFiles) {
if (!rawFile.length) { continue; }
// XTreeWidgetItem *localStrRoot = new XTreeWidgetItem(zoneItem); XTreeWidgetItem *tempItem = rawFileRoot;
// localStrRoot->setText(0, "String Files"); const QStringList pathParts = rawFile.path.split('/');
// localStrRoot->setIcon(0, localStrIcon); for (const QString &pathPart : pathParts) {
// localStrRoot->SetCategory(CATEGORY_TYPE); bool childFound = false;
for (int i = 0; i < tempItem->childCount(); i++) {
QTreeWidgetItem *rawChildItem = tempItem->child(i);
XTreeWidgetItem *childItem = dynamic_cast<XTreeWidgetItem*>(rawChildItem);
if (childItem->text(0) == pathPart) {
tempItem = childItem;
// XTreeWidgetItem *localStrItem = new XTreeWidgetItem(localStrRoot); childFound = true;
// localStrItem->setText(0, aZoneFile->GetStem().section('.', 0, 0) + ".str"); break;
// localStrItem->setIcon(0, localStrIcon); }
// } }
// if (!assetMap.techSets.isEmpty()) { const QString rawFileStr = QString("%1 [%2-%3]").arg(pathPart).arg(rawFile.startPos).arg(rawFile.endPos);
// QIcon techSetIcon = Utils::CreateAssetIcon(ASSET_TYPE_TECHNIQUE_SET); //rawFileStr = pathPart;
if (pathPart == pathParts.last()) {
XTreeWidgetItem *rawFileItem = new XTreeWidgetItem(tempItem);
rawFileItem->setText(0, rawFileStr);
// XTreeWidgetItem *techSetRoot = new XTreeWidgetItem(zoneItem); tempItem = rawFileItem;
// techSetRoot->setText(0, "Tech Sets"); } else if (!childFound) {
// techSetRoot->setIcon(0, techSetIcon); tempItem = new XTreeWidgetItem(tempItem);
// techSetRoot->SetCategory(CATEGORY_TYPE); tempItem->setText(0, rawFileStr);
}
// for (auto techSet : assetMap.techSets) { }
// XTreeWidgetItem *techSetItem = new XTreeWidgetItem(techSetRoot); tempItem->setIcon(0, rawFileIcon);
// techSetItem->setText(0, techSet.name); }
// techSetItem->setIcon(0, techSetIcon); }
// }
// }
// if (!assetMap.rawFiles.isEmpty()) { if (!assetMap.menuFiles.isEmpty()) {
// QIcon rawFileIcon = Utils::CreateAssetIcon(ASSET_TYPE_RAWFILE); QIcon menuFileIcon = ZoneFile::AssetTypeToIcon(ASSET_MENU);
// XTreeWidgetItem *rawFileRoot = new XTreeWidgetItem(zoneItem); XTreeWidgetItem *menuRoot = new XTreeWidgetItem(zoneItem);
// rawFileRoot->setText(0, "Raw Files"); menuRoot->setText(0, "Menu Files");
// rawFileRoot->setIcon(0, rawFileIcon); menuRoot->setIcon(0, menuFileIcon);
// rawFileRoot->SetCategory(CATEGORY_TYPE); menuRoot->SetCategory(CATEGORY_TYPE);
// for (auto rawFile : assetMap.rawFiles) {
// if (!rawFile.length) { continue; }
// XTreeWidgetItem *tempItem = rawFileRoot; int menuIndex = 1;
// // const QStringList pathParts = rawFile->path.split('/'); for (MenuFile menuFile : assetMap.menuFiles) {
// // for (const QString &pathPart : pathParts) { XTreeWidgetItem *menuFileRoot = new XTreeWidgetItem(menuRoot);
// // bool childFound = false; menuFileRoot->setText(0, QString("Menu %1").arg(menuIndex));
// // for (int i = 0; i < tempItem->childCount(); i++) { for (Menu menu : menuFile.menuDefs) {
// // QTreeWidgetItem *rawChildItem = tempItem->child(i); XTreeWidgetItem *menuItem = new XTreeWidgetItem(menuFileRoot);
// // XTreeWidgetItem *childItem = dynamic_cast<XTreeWidgetItem*>(rawChildItem); menuItem->setText(0, menu.filePath);
// // if (childItem->text(0) == pathPart) { menuItem->setIcon(0, menuFileIcon);
// // tempItem = childItem; }
menuIndex++;
}
}
// // childFound = true; if (!assetMap.images.isEmpty()) {
// // break; QIcon imageIcon = ZoneFile::AssetTypeToIcon(ASSET_IMAGE);
// // }
// // }
// // const QString rawFileStr = pathPart;// = QString("%1 [%2-%3]").arg(pathPart).arg(rawFile.startPos).arg(rawFile.endPos); XTreeWidgetItem *imageRoot = new XTreeWidgetItem(zoneItem);
// // if (pathPart == pathParts.last()) { imageRoot->setText(0, "Images");
// // XTreeWidgetItem *rawFileItem = new XTreeWidgetItem(tempItem); imageRoot->setIcon(0, imageIcon);
// // rawFileItem->setText(0, rawFileStr); imageRoot->SetCategory(CATEGORY_TYPE);
// // tempItem = rawFileItem; for (Image image : assetMap.images) {
// // } else if (!childFound) { XTreeWidgetItem *imageItem = new XTreeWidgetItem(imageRoot);
// // tempItem = new XTreeWidgetItem(tempItem); imageItem->setText(0, image.materialName);
// // tempItem->setText(0, rawFileStr); imageItem->setIcon(0, imageIcon);
// // } }
}
// // } if (!assetMap.models.isEmpty()) {
// tempItem->setIcon(0, rawFileIcon); QIcon modelIcon = ZoneFile::AssetTypeToIcon(ASSET_MODEL);
// }
// }
// if (!assetMap.menuDefinitions.isEmpty()) { XTreeWidgetItem *modelsRoot = new XTreeWidgetItem(zoneItem);
// // QIcon MenuDefIcon = Utils::CreateAssetIcon(ASSET_TYPE_MENU); modelsRoot->setText(0, "Models");
modelsRoot->setIcon(0, modelIcon);
modelsRoot->SetCategory(CATEGORY_TYPE);
// // XTreeWidgetItem *menuRoot = new XTreeWidgetItem(zoneItem); for (Model model: assetMap.models) {
// // menuRoot->setText(0, "Menu Files"); XTreeWidgetItem *modelItem = new XTreeWidgetItem(modelsRoot);
// // menuRoot->setIcon(0, MenuDefIcon); modelItem->setText(0, model.modelName);
// // menuRoot->SetCategory(CATEGORY_TYPE); modelItem->setIcon(0, modelIcon);
}
}
// // int menuIndex = 1; if (!assetMap.materials.isEmpty()) {
// // for (MenuDef menuDef : assetMap.menuDefinitions) { QIcon materialIcon = ZoneFile::AssetTypeToIcon(ASSET_MATERIAL);
// // XTreeWidgetItem *MenuDefRoot = new XTreeWidgetItem(menuRoot);
// // MenuDefRoot->setText(0, QString("Menu %1").arg(menuIndex));
// // for (Menu menu : menuDef.men) {
// // XTreeWidgetItem *menuItem = new XTreeWidgetItem(MenuDefRoot);
// // menuItem->setText(0, menu.filePath);
// // menuItem->setIcon(0, MenuDefIcon);
// // }
// // menuIndex++;
// // }
// }
// if (!assetMap.images.isEmpty()) { XTreeWidgetItem *materialsRoot = new XTreeWidgetItem(zoneItem);
// // QIcon imageIcon = Utils::CreateAssetIcon(ASSET_TYPE_IMAGE); materialsRoot->setText(0, "Materials");
materialsRoot->setIcon(0, materialIcon);
materialsRoot->SetCategory(CATEGORY_TYPE);
// // XTreeWidgetItem *imageRoot = new XTreeWidgetItem(zoneItem); for (Material material: assetMap.materials) {
// // imageRoot->setText(0, "Images"); XTreeWidgetItem *materialItem = new XTreeWidgetItem(materialsRoot);
// // imageRoot->setIcon(0, imageIcon); materialItem->setText(0, material.name);
// // imageRoot->SetCategory(CATEGORY_TYPE); materialItem->setIcon(0, materialIcon);
}
}
// // for (Image image : assetMap.images) { if (!assetMap.stringTables.isEmpty()) {
// // XTreeWidgetItem *imageItem = new XTreeWidgetItem(imageRoot); QIcon stringTableIcon = ZoneFile::AssetTypeToIcon(ASSET_STRING_TABLE);
// // imageItem->setText(0, image.materialName);
// // imageItem->setIcon(0, imageIcon);
// // }
// }
// if (!assetMap.models.isEmpty()) { XTreeWidgetItem *strTableRoot = new XTreeWidgetItem(zoneItem);
// QIcon modelIcon = Utils::CreateAssetIcon(ASSET_TYPE_XMODEL); strTableRoot->setText(0, "String Tables");
strTableRoot->setIcon(0, stringTableIcon);
strTableRoot->SetCategory(CATEGORY_TYPE);
// XTreeWidgetItem *modelsRoot = new XTreeWidgetItem(zoneItem); for (StringTable strTable: assetMap.stringTables) {
// modelsRoot->setText(0, "Models"); XTreeWidgetItem *modelItem = new XTreeWidgetItem(strTableRoot);
// modelsRoot->setIcon(0, modelIcon); modelItem->setText(0, strTable.name);
// modelsRoot->SetCategory(CATEGORY_TYPE); modelItem->setIcon(0, stringTableIcon);
}
}
// for (auto model: assetMap.models) { if (!assetMap.sounds.isEmpty()) {
// XTreeWidgetItem *modelItem = new XTreeWidgetItem(modelsRoot); QIcon soundIcon = ZoneFile::AssetTypeToIcon(ASSET_SOUND);
// modelItem->setText(0, model.name);
// modelItem->setIcon(0, modelIcon);
// }
// }
// if (!assetMap.materials.isEmpty()) { XTreeWidgetItem *soundsRoot = new XTreeWidgetItem(zoneItem);
// QIcon materialIcon = Utils::CreateAssetIcon(ASSET_TYPE_MATERIAL); soundsRoot->setText(0, "Sounds");
soundsRoot->setIcon(0, soundIcon);
soundsRoot->SetCategory(CATEGORY_TYPE);
for (SoundAsset soundAsset : assetMap.sounds) {
for (Sound sound : soundAsset.sounds) {
XTreeWidgetItem *tempItem = soundsRoot;
// XTreeWidgetItem *materialsRoot = new XTreeWidgetItem(zoneItem); if (!sound.dataLength) { continue; }
// materialsRoot->setText(0, "Materials");
// materialsRoot->setIcon(0, materialIcon);
// materialsRoot->SetCategory(CATEGORY_TYPE);
// for (auto material: assetMap.materials) { for (const QString &pathPart : sound.path.split('/')) {
// XTreeWidgetItem *materialItem = new XTreeWidgetItem(materialsRoot); if (pathPart.isEmpty()) { continue; }
// //materialItem->setText(0, material.name);
// materialItem->setIcon(0, materialIcon);
// }
// }
// if (!assetMap.stringTables.isEmpty()) { bool childFound = false;
// QIcon stringTableIcon = Utils::CreateAssetIcon(ASSET_TYPE_STRINGTABLE); for (int i = 0; i < tempItem->childCount(); i++) {
XTreeWidgetItem *childItem = dynamic_cast<XTreeWidgetItem*>(tempItem->child(i));
if (childItem->text(0) == pathPart) {
tempItem = childItem;
// XTreeWidgetItem *strTableRoot = new XTreeWidgetItem(zoneItem); childFound = true;
// strTableRoot->setText(0, "String Tables"); break;
// strTableRoot->setIcon(0, stringTableIcon); }
// strTableRoot->SetCategory(CATEGORY_TYPE); }
// for (auto strTable: assetMap.stringTables) { if (pathPart.contains(".wav")) {
// XTreeWidgetItem *modelItem = new XTreeWidgetItem(strTableRoot); XTreeWidgetItem *soundItem = new XTreeWidgetItem(tempItem);
// modelItem->setText(0, strTable.name); soundItem->setText(0, pathPart);
// modelItem->setIcon(0, stringTableIcon);
// }
// }
// if (!assetMap.sounds.isEmpty()) { tempItem = soundItem;
// QIcon soundIcon = Utils::CreateAssetIcon(ASSET_TYPE_SOUND); } else if (!childFound) {
tempItem = new XTreeWidgetItem(tempItem);
tempItem->setText(0, pathPart);
}
// XTreeWidgetItem *soundsRoot = new XTreeWidgetItem(zoneItem); }
// soundsRoot->setText(0, "Sounds"); tempItem->setIcon(0, soundIcon);
// soundsRoot->setIcon(0, soundIcon); }
// soundsRoot->SetCategory(CATEGORY_TYPE); }
// } }
mZoneFiles[aZoneFile->GetBaseStem() + ".zone"] = aZoneFile; mZoneFiles[aZoneFile->GetBaseStem() + ".zone"] = aZoneFile;
} }
@ -302,7 +324,7 @@ void XTreeWidget::PrepareContextMenu(const QPoint &pos) {
QMenu *exportSubmenu = new QMenu("Export...", this); QMenu *exportSubmenu = new QMenu("Export...", this);
contextMenu->addMenu(exportSubmenu); contextMenu->addMenu(exportSubmenu);
const DDSFile* ddsFile = mDDSFiles[fileStem]; std::shared_ptr<DDSFile> ddsFile = mDDSFiles[fileStem];
QAction *exportIWIAction = new QAction("Export as IWI"); QAction *exportIWIAction = new QAction("Export as IWI");
exportSubmenu->addAction(exportIWIAction); exportSubmenu->addAction(exportIWIAction);
@ -346,7 +368,7 @@ void XTreeWidget::PrepareContextMenu(const QPoint &pos) {
QMenu *exportSubmenu = new QMenu("Export...", this); QMenu *exportSubmenu = new QMenu("Export...", this);
contextMenu->addMenu(exportSubmenu); contextMenu->addMenu(exportSubmenu);
const IWIFile* iwiFile = mIWIFiles[fileStem]; std::shared_ptr<IWIFile> iwiFile = mIWIFiles[fileStem];
QAction *exportDDSAction = new QAction("Export as DDS"); QAction *exportDDSAction = new QAction("Export as DDS");
exportSubmenu->addAction(exportDDSAction); exportSubmenu->addAction(exportDDSAction);
@ -475,7 +497,7 @@ void XTreeWidget::PrepareContextMenu(const QPoint &pos) {
QMenu *exportSubmenu = new QMenu("Export...", this); QMenu *exportSubmenu = new QMenu("Export...", this);
contextMenu->addMenu(exportSubmenu); contextMenu->addMenu(exportSubmenu);
const FastFile* fastFile = mFastFiles[fileStem]; std::shared_ptr<FastFile> fastFile = mFastFiles[fileStem];
QAction *exportFastFileAction = new QAction("Export Fast File"); QAction *exportFastFileAction = new QAction("Export Fast File");
exportSubmenu->addAction(exportFastFileAction); exportSubmenu->addAction(exportFastFileAction);
@ -490,13 +512,13 @@ void XTreeWidget::PrepareContextMenu(const QPoint &pos) {
}); });
QAction *exportZoneFileAction = new QAction("Export Zone File"); QAction *exportZoneFileAction = new QAction("Export Zone File");
exportSubmenu->addAction(exportZoneFileAction); exportSubmenu->addAction(exportZoneFileAction);
connect(exportZoneFileAction, &QAction::triggered, this, [](bool checked) { connect(exportZoneFileAction, &QAction::triggered, this, [fastFile](bool checked) {
Q_UNUSED(checked); Q_UNUSED(checked);
// const QString zoneFilePath = QFileDialog::getSaveFileName( const QString zoneFilePath = QFileDialog::getSaveFileName(
// nullptr, "Export Zone File...", QDir::currentPath(), nullptr, "Export Zone File...", QDir::currentPath(),
// "Zone File (*.zone);;All Files(*.*)"); "Zone File (*.zone);;All Files(*.*)");
//fastFile->GetZoneFile()->SaveZoneFile(zoneFilePath); fastFile->GetZoneFile()->SaveZoneFile(zoneFilePath);
}); });
} else if (activeText.contains(".zone")) { } else if (activeText.contains(".zone")) {
const QString fileStem = activeText; const QString fileStem = activeText;
@ -508,7 +530,7 @@ void XTreeWidget::PrepareContextMenu(const QPoint &pos) {
QMenu *exportSubmenu = new QMenu("Export...", this); QMenu *exportSubmenu = new QMenu("Export...", this);
contextMenu->addMenu(exportSubmenu); contextMenu->addMenu(exportSubmenu);
//const ZoneFile* zoneFile = mZoneFiles[fileStem]; std::shared_ptr<ZoneFile> zoneFile = mZoneFiles[fileStem];
QAction *exportZoneFileAction = new QAction("Export Zone File"); QAction *exportZoneFileAction = new QAction("Export Zone File");
exportSubmenu->addAction(exportZoneFileAction); exportSubmenu->addAction(exportZoneFileAction);
@ -530,41 +552,41 @@ void XTreeWidget::PrepareContextMenu(const QPoint &pos) {
} }
} }
if (parentItem && parentItem != invisibleRootItem() && parentItem->text(0).contains(".zone")) { if (parentItem && parentItem != invisibleRootItem() && parentItem->text(0).contains(".zone")) {
//const QString fileStem = parentItem->text(0).section('.', 0, 0); const QString fileStem = parentItem->text(0).section('.', 0, 0);
// QVector<LoadedSound> LoadedSounds = mZoneFiles[fileStem]->GetAssetMap().sounds; QVector<SoundAsset> soundAssets = mZoneFiles[fileStem]->GetAssetMap().sounds;
// for (LoadedSound LoadedSound : LoadedSounds) { for (SoundAsset soundAsset : soundAssets) {
// for (Sound sound : LoadedSound.sounds) { for (Sound sound : soundAsset.sounds) {
// if (sound.path.contains(activeText)) { if (sound.path.contains(activeText)) {
// QMenu *exportSubmenu = new QMenu("Export...", this); QMenu *exportSubmenu = new QMenu("Export...", this);
// contextMenu->addMenu(exportSubmenu); contextMenu->addMenu(exportSubmenu);
// QAction *exportWAVAction = new QAction("Export as WAV File"); QAction *exportWAVAction = new QAction("Export as WAV File");
// exportSubmenu->addAction(exportWAVAction); exportSubmenu->addAction(exportWAVAction);
// connect(exportWAVAction, &QAction::triggered, this, [sound](bool checked) { connect(exportWAVAction, &QAction::triggered, this, [sound](bool checked) {
// Q_UNUSED(checked); Q_UNUSED(checked);
// QDir dir = QDir::currentPath(); QDir dir = QDir::currentPath();
// if (!dir.exists("exports/")) { if (!dir.exists("exports/")) {
// dir.mkdir("exports/"); dir.mkdir("exports/");
// } }
// if (!dir.exists("exports/sounds/")) { if (!dir.exists("exports/sounds/")) {
// dir.mkdir("exports/sounds/"); dir.mkdir("exports/sounds/");
// } }
// const QString fileName = "exports/sounds/" + sound.path.split('/').last(); const QString fileName = "exports/sounds/" + sound.path.split('/').last();
// QFile wavFile(fileName); QFile wavFile(fileName);
// if (!wavFile.open(QIODevice::WriteOnly)) { if (!wavFile.open(QIODevice::WriteOnly)) {
// qDebug() << "Failed to write wav file!"; qDebug() << "Failed to write wav file!";
// return; return;
// } }
// wavFile.write(sound.data); wavFile.write(sound.data);
// wavFile.close(); wavFile.close();
// }); });
// break; break;
// } }
// } }
// } }
} }
} else if (activeItem && activeText == "Sounds") { } else if (activeItem && activeText == "Sounds") {
XTreeWidgetItem *parentItem = dynamic_cast<XTreeWidgetItem*>(activeItem->parent()); XTreeWidgetItem *parentItem = dynamic_cast<XTreeWidgetItem*>(activeItem->parent());
@ -577,39 +599,39 @@ void XTreeWidget::PrepareContextMenu(const QPoint &pos) {
} }
if (parentItem && parentItem != invisibleRootItem() && parentItem->text(0).contains(".zone")) { if (parentItem && parentItem != invisibleRootItem() && parentItem->text(0).contains(".zone")) {
const QString fileStem = parentItem->text(0).section('.', 0, 0); const QString fileStem = parentItem->text(0).section('.', 0, 0);
//auto zoneFile = mZoneFiles[fileStem]; auto zoneFile = mZoneFiles[fileStem];
QMenu *exportSubmenu = new QMenu("Export...", this); QMenu *exportSubmenu = new QMenu("Export...", this);
contextMenu->addMenu(exportSubmenu); contextMenu->addMenu(exportSubmenu);
QAction *exportAllWAVAction = new QAction("Export ALL as WAV Files"); QAction *exportAllWAVAction = new QAction("Export ALL as WAV Files");
exportSubmenu->addAction(exportAllWAVAction); exportSubmenu->addAction(exportAllWAVAction);
connect(exportAllWAVAction, &QAction::triggered, this, [](bool checked) { connect(exportAllWAVAction, &QAction::triggered, this, [zoneFile](bool checked) {
Q_UNUSED(checked); Q_UNUSED(checked);
// for (LoadedSound LoadedSound : zoneFile->GetAssetMap().sounds) { for (SoundAsset soundAsset : zoneFile->GetAssetMap().sounds) {
// for (Sound sound : LoadedSound.sounds) { for (Sound sound : soundAsset.sounds) {
// if (!sound.dataLength) { continue; } if (!sound.dataLength) { continue; }
// QDir dir = QDir::currentPath(); QDir dir = QDir::currentPath();
// if (!dir.exists("exports/")) { if (!dir.exists("exports/")) {
// dir.mkdir("exports/"); dir.mkdir("exports/");
// } }
// if (!dir.exists("exports/sounds/")) { if (!dir.exists("exports/sounds/")) {
// dir.mkdir("exports/sounds/"); dir.mkdir("exports/sounds/");
// } }
// const QString fileName = "exports/sounds/" + sound.path.split('/').last(); const QString fileName = "exports/sounds/" + sound.path.split('/').last();
// QFile wavFile(fileName); QFile wavFile(fileName);
// if (!wavFile.open(QIODevice::WriteOnly)) { if (!wavFile.open(QIODevice::WriteOnly)) {
// qDebug() << "Failed to write wav file!"; qDebug() << "Failed to write wav file!";
// return; return;
// } }
// wavFile.write(sound.data); wavFile.write(sound.data);
// wavFile.close(); wavFile.close();
// } }
// } }
}); });
} }
} }
@ -631,19 +653,20 @@ void XTreeWidget::ItemSelectionChanged() {
XTreeWidgetItem *parentItem = dynamic_cast<XTreeWidgetItem*>(selectedItem->parent()); XTreeWidgetItem *parentItem = dynamic_cast<XTreeWidgetItem*>(selectedItem->parent());
/*if (selectedText.contains(".dds")) { if (selectedText.contains(".dds")) {
if (!mDDSFiles.contains(selectedText)) { if (!mDDSFiles.contains(selectedText)) {
LogManager::instance().addError("Could not find " + selectedText + " in DDS map!"); LogManager::instance().addError("Could not find " + selectedText + " in DDS map!");
return; return;
} }
emit DDSFileSelected(mDDSFiles[selectedText], selectedText); std::shared_ptr<DDSFile> ddsFile = mDDSFiles[selectedText];
emit DDSFileSelected(ddsFile, selectedText);
} else if (selectedText.contains(".iwi")) { } else if (selectedText.contains(".iwi")) {
if (!mIWIFiles.contains(selectedText)) { if (!mIWIFiles.contains(selectedText)) {
LogManager::instance().addError("Could not find " + selectedText + " in IWI map!"); LogManager::instance().addError("Could not find " + selectedText + " in IWI map!");
return; return;
} }
emit IWIFileSelected(mIWIFiles[selectedText], selectedText); emit IWIFileSelected(mIWIFiles[selectedText], selectedText);
} else */if (selectedText.contains(".ff")) { } else if (selectedText.contains(".ff")) {
if (!mFastFiles.contains(selectedText)) { if (!mFastFiles.contains(selectedText)) {
LogManager::instance().addError("Could not find " + selectedText + " in Fast File map!"); LogManager::instance().addError("Could not find " + selectedText + " in Fast File map!");
return; return;
@ -665,22 +688,34 @@ void XTreeWidget::ItemSelectionChanged() {
XTreeWidgetItem *grandpaItem = dynamic_cast<XTreeWidgetItem*>(parentItem->parent()); XTreeWidgetItem *grandpaItem = dynamic_cast<XTreeWidgetItem*>(parentItem->parent());
if (grandpaItem && grandpaItem->text(0).contains(".zone")) { if (grandpaItem && grandpaItem->text(0).contains(".zone")) {
const QString fileStem = grandpaItem->text(0).section('.', 0, 0); const QString fileStem = grandpaItem->text(0).section('.', 0, 0);
// QVector<Image> images = mZoneFiles[fileStem]->GetAssetMap().images; QVector<Image> images = mZoneFiles[fileStem]->GetAssetMap().images;
// for (Image image : images) { for (Image image : images) {
// if (image.materialName == selectedText) { if (image.materialName == selectedText) {
// emit ImageSelected(std::make_shared<Image>(image), fileStem); emit ImageSelected(std::make_shared<Image>(image), fileStem);
// break; break;
// }
// }
} }
} /*else if (parentItem && (parentItem->text(0) == "Tech Sets")) { }
}
} else if (parentItem && (parentItem->text(0) == "Tech Sets")) {
XTreeWidgetItem *grandpaItem = dynamic_cast<XTreeWidgetItem*>(parentItem->parent()); XTreeWidgetItem *grandpaItem = dynamic_cast<XTreeWidgetItem*>(parentItem->parent());
if (grandpaItem && grandpaItem->text(0).contains(".zone")) { if (grandpaItem && grandpaItem->text(0).contains(".zone")) {
const QString fileStem = grandpaItem->text(0).section('.', 0, 0); const QString fileStem = grandpaItem->text(0).section('.', 0, 0);
auto techsets = mZoneFiles[fileStem]->GetAssetList().techSets; auto techsets = mZoneFiles[fileStem]->GetAssetMap().techSets;
for (auto techset : techsets) { for (auto techset : techsets) {
if (techset.name == selectedText) { if (techset.name == selectedText) {
emit TechSetSelected(new MaterialTechSet(techset), fileStem); emit TechSetSelected(std::make_shared<TechSet>(techset), fileStem);
break;
}
}
}
} else if (parentItem && (parentItem->text(0) == "Tech Sets")) {
XTreeWidgetItem *grandpaItem = dynamic_cast<XTreeWidgetItem*>(parentItem->parent());
if (grandpaItem && grandpaItem->text(0).contains(".zone")) {
const QString fileStem = grandpaItem->text(0).section('.', 0, 0);
auto techsets = mZoneFiles[fileStem]->GetAssetMap().techSets;
for (auto techset : techsets) {
if (techset.name == selectedText) {
emit TechSetSelected(std::make_shared<TechSet>(techset), fileStem);
break; break;
} }
} }
@ -689,12 +724,12 @@ void XTreeWidget::ItemSelectionChanged() {
XTreeWidgetItem *grandpaItem = dynamic_cast<XTreeWidgetItem*>(parentItem->parent()); XTreeWidgetItem *grandpaItem = dynamic_cast<XTreeWidgetItem*>(parentItem->parent());
if (grandpaItem && grandpaItem->text(0).contains(".zone")) { if (grandpaItem && grandpaItem->text(0).contains(".zone")) {
const QString fileStem = grandpaItem->text(0).section('.', 0, 0); const QString fileStem = grandpaItem->text(0).section('.', 0, 0);
auto materials = mZoneFiles[fileStem]->GetAssetMap().materials; QVector<Material> materials = mZoneFiles[fileStem]->GetAssetMap().materials;
for (auto material : materials) { for (Material material : materials) {
// if (material.name == selectedText) { if (material.name == selectedText) {
// emit MaterialSelected(std::make_shared<Material>(material), fileStem); emit MaterialSelected(std::make_shared<Material>(material), fileStem);
// break; break;
// } }
} }
} }
} else if (parentItem && selectedText.contains(".wav")) { } else if (parentItem && selectedText.contains(".wav")) {
@ -708,15 +743,15 @@ void XTreeWidget::ItemSelectionChanged() {
} }
if (grandpaItem && grandpaItem != invisibleRootItem() && grandpaItem->text(0).contains(".zone")) { if (grandpaItem && grandpaItem != invisibleRootItem() && grandpaItem->text(0).contains(".zone")) {
const QString fileStem = grandpaItem->text(0).section('.', 0, 0); const QString fileStem = grandpaItem->text(0).section('.', 0, 0);
// QVector<LoadedSound> LoadedSounds = mZoneFiles[fileStem]->GetAssetMap().sounds; QVector<SoundAsset> soundAssets = mZoneFiles[fileStem]->GetAssetMap().sounds;
// for (LoadedSound LoadedSound : LoadedSounds) { for (SoundAsset soundAsset : soundAssets) {
// for (Sound sound : LoadedSound.sounds) { for (Sound sound : soundAsset.sounds) {
// if (sound.path.contains(selectedText)) { if (sound.path.contains(selectedText)) {
// emit SoundSelected(std::make_shared<Sound>(sound), fileStem); emit SoundSelected(std::make_shared<Sound>(sound), fileStem);
// break; break;
// } }
// } }
// } }
} }
} else if (selectedItem->GetCategory() != CATEGORY_TYPE) { } else if (selectedItem->GetCategory() != CATEGORY_TYPE) {
XTreeWidgetItem *zoneRoot = selectedItem; XTreeWidgetItem *zoneRoot = selectedItem;
@ -737,17 +772,17 @@ void XTreeWidget::ItemSelectionChanged() {
return; return;
} }
auto rawFiles = mZoneFiles[fileStem]->GetAssetMap().rawFiles; QVector<RawFile> rawFiles = mZoneFiles[fileStem]->GetAssetMap().rawFiles;
for (auto rawFile : rawFiles) { for (RawFile rawFile : rawFiles) {
//if (rawFile->path.split('/').last() == selectedText) { if (rawFile.path.split('/').last() == selectedText) {
// emit RawFileSelected(std::make_shared<RawFile>(rawFile), fileStem); emit RawFileSelected(std::make_shared<RawFile>(rawFile), fileStem);
// return; return;
//} }
}
} }
}*/
} }
const ZoneFile* XTreeWidget::FindZoneFile(const QString aStem) { std::shared_ptr<ZoneFile> XTreeWidget::FindZoneFile(const QString aStem) {
foreach (auto zoneFile, mZoneFiles) { foreach (auto zoneFile, mZoneFiles) {
if (zoneFile->GetStem() == aStem) { if (zoneFile->GetStem() == aStem) {
return zoneFile; return zoneFile;
@ -756,7 +791,7 @@ const ZoneFile* XTreeWidget::FindZoneFile(const QString aStem) {
return nullptr; return nullptr;
} }
const FastFile *XTreeWidget::FindFastFile(const QString aStem) { std::shared_ptr<FastFile> XTreeWidget::FindFastFile(const QString aStem) {
foreach (auto fastFile, mFastFiles) { foreach (auto fastFile, mFastFiles) {
if (fastFile->GetStem() == aStem) { if (fastFile->GetStem() == aStem) {
return fastFile; return fastFile;
@ -773,7 +808,7 @@ bool XTreeWidget::HasFastFile(const QString aStem) {
return FindFastFile(aStem) != nullptr; return FindFastFile(aStem) != nullptr;
} }
void XTreeWidget::AddIWIFile(IWIFile* aIWIFile) { void XTreeWidget::AddIWIFile(std::shared_ptr<IWIFile> aIWIFile) {
const QString iwiFileName = QString(aIWIFile->fileStem + ".iwi"); const QString iwiFileName = QString(aIWIFile->fileStem + ".iwi");
for (int i = 0; i < invisibleRootItem()->childCount(); i++) { for (int i = 0; i < invisibleRootItem()->childCount(); i++) {
@ -784,12 +819,12 @@ void XTreeWidget::AddIWIFile(IWIFile* aIWIFile) {
} }
XTreeWidgetItem *iwiItem = new XTreeWidgetItem(this); XTreeWidgetItem *iwiItem = new XTreeWidgetItem(this);
iwiItem->setIcon(0, Utils::CreateAssetIcon(ASSET_TYPE_IMAGE)); iwiItem->setIcon(0, ZoneFile::AssetTypeToIcon(ASSET_IMAGE));
iwiItem->setText(0, iwiFileName); iwiItem->setText(0, iwiFileName);
mIWIFiles[aIWIFile->fileStem.section(".", 0, 0)] = aIWIFile; mIWIFiles[aIWIFile->fileStem.section(".", 0, 0)] = aIWIFile;
} }
void XTreeWidget::AddDDSFile(DDSFile* aDDSFile) { void XTreeWidget::AddDDSFile(std::shared_ptr<DDSFile> aDDSFile) {
const QString ddsFileName = QString(aDDSFile->fileStem + ".dds"); const QString ddsFileName = QString(aDDSFile->fileStem + ".dds");
for (int i = 0; i < invisibleRootItem()->childCount(); i++) { for (int i = 0; i < invisibleRootItem()->childCount(); i++) {
@ -800,7 +835,7 @@ void XTreeWidget::AddDDSFile(DDSFile* aDDSFile) {
} }
XTreeWidgetItem *ddsItem = new XTreeWidgetItem(this); XTreeWidgetItem *ddsItem = new XTreeWidgetItem(this);
ddsItem->setIcon(0, Utils::CreateAssetIcon(ASSET_TYPE_IMAGE)); ddsItem->setIcon(0, ZoneFile::AssetTypeToIcon(ASSET_IMAGE));
ddsItem->setText(0, ddsFileName); ddsItem->setText(0, ddsFileName);
mDDSFiles[aDDSFile->fileStem.section(".", 0, 0)] = aDDSFile; mDDSFiles[aDDSFile->fileStem.section(".", 0, 0)] = aDDSFile;
} }

View File

@ -2,16 +2,13 @@
#define XTREEWIDGET_H #define XTREEWIDGET_H
#include "d3dbsp_structs.h" #include "d3dbsp_structs.h"
#include "asset_structs.h"
#include "ddsfile.h" #include "ddsfile.h"
#include "iwifile.h" #include "iwifile.h"
#include "fastfile.h" #include "fastfile.h"
#include "xloadedsound.h"
#include "xtreewidgetitem.h" #include "xtreewidgetitem.h"
#include "zonefile.h" #include "zonefile.h"
#include "xrawfile.h" #include "utils.h"
#include "xgfximage.h"
#include "xstringtable.h"
#include "xmenudef.h"
#include <QTreeWidget> #include <QTreeWidget>
#include <QFileDialog> #include <QFileDialog>
@ -23,31 +20,31 @@ public:
explicit XTreeWidget(QWidget *parent = nullptr); explicit XTreeWidget(QWidget *parent = nullptr);
~XTreeWidget(); ~XTreeWidget();
void AddFastFile(FastFile* aFastFile); void AddFastFile(std::shared_ptr<FastFile> aFastFile);
void AddZoneFile(const ZoneFile *aZoneFile, XTreeWidgetItem *aParentItem = nullptr); void AddZoneFile(std::shared_ptr<ZoneFile> aZoneFile, XTreeWidgetItem *aParentItem = nullptr);
void AddIWIFile(IWIFile* aIWIFile); void AddIWIFile(std::shared_ptr<IWIFile> aIWIFile);
void AddDDSFile(DDSFile* aDDSFile); void AddDDSFile(std::shared_ptr<DDSFile> aDDSFile);
const ZoneFile *FindZoneFile(const QString aStem); std::shared_ptr<ZoneFile> FindZoneFile(const QString aStem);
const FastFile* FindFastFile(const QString aStem); std::shared_ptr<FastFile> FindFastFile(const QString aStem);
bool HasZoneFile(const QString aStem); bool HasZoneFile(const QString aStem);
bool HasFastFile(const QString aStem); bool HasFastFile(const QString aStem);
void CloseFastFile(const QString aFFName); void CloseFastFile(const QString aFFName);
signals: signals:
void DDSFileSelected(const DDSFile* aDDSFile, const QString aParentName); void DDSFileSelected(std::shared_ptr<DDSFile> aDDSFile, const QString aParentName);
void IWIFileSelected(const IWIFile* aIWIFile, const QString aParentName); void IWIFileSelected(std::shared_ptr<IWIFile> aIWIFile, const QString aParentName);
void FastFileSelected(const FastFile* aFastFile, const QString aParentName); void FastFileSelected(std::shared_ptr<FastFile> aFastFile, const QString aParentName);
void ZoneFileSelected(const ZoneFile* aZoneFile, const QString aParentName); void ZoneFileSelected(std::shared_ptr<ZoneFile> aZoneFile, const QString aParentName);
void LocalStringSelected(const ZoneFile* aZoneFile, const QString aParentName); void LocalStringSelected(std::shared_ptr<ZoneFile> aZoneFile, const QString aParentName);
void RawFileSelected(const XRawFile* aRawFile, const QString aParentName); void RawFileSelected(std::shared_ptr<RawFile> aRawFile, const QString aParentName);
void ImageSelected(const XGfxImage* aImage, const QString aParentName); void ImageSelected(std::shared_ptr<Image> aImage, const QString aParentName);
void TechSetSelected(const XMaterialTechniqueSet* aZoneFile, const QString aParentName); void TechSetSelected(std::shared_ptr<TechSet> aZoneFile, const QString aParentName);
void StrTableSelected(const XStringTable* aStrTable, const QString aParentName); void StrTableSelected(std::shared_ptr<StringTable> aStrTable, const QString aParentName);
void MenuSelected(const XMenuDef* aMenu, const QString aParentName); void MenuSelected(std::shared_ptr<Menu> aMenu, const QString aParentName);
void SoundSelected(const XLoadedSound* aSound, const QString aParentName); void SoundSelected(std::shared_ptr<Sound> aSound, const QString aParentName);
void MaterialSelected(const XMaterial* aMaterial, const QString aParentName); void MaterialSelected(std::shared_ptr<Material> aMaterial, const QString aParentName);
void ItemSelected(const QString itemText); void ItemSelected(const QString itemText);
void ItemClosed(const QString itemText); void ItemClosed(const QString itemText);
@ -58,10 +55,10 @@ protected:
void PrepareContextMenu(const QPoint &pos); void PrepareContextMenu(const QPoint &pos);
private: private:
QMap<QString, const FastFile*> mFastFiles; QMap<QString, std::shared_ptr<FastFile>> mFastFiles;
QMap<QString, const ZoneFile*> mZoneFiles; QMap<QString, std::shared_ptr<ZoneFile>> mZoneFiles;
QMap<QString, const DDSFile*> mDDSFiles; QMap<QString, std::shared_ptr<DDSFile>> mDDSFiles;
QMap<QString, const IWIFile*> mIWIFiles; QMap<QString, std::shared_ptr<IWIFile>> mIWIFiles;
}; };
#endif // XTREEWIDGET_H #endif // XTREEWIDGET_H

View File

@ -69,7 +69,7 @@ void ZoneFileViewer::SortTags(const QString &aSearchText) {
ui->listWidget_Tags->addItems(sortedTags); ui->listWidget_Tags->addItems(sortedTags);
} }
void ZoneFileViewer::SetZoneFile(const ZoneFile* aZoneFile) { void ZoneFileViewer::SetZoneFile(std::shared_ptr<ZoneFile> aZoneFile) {
mZoneFile = aZoneFile; mZoneFile = aZoneFile;
ui->tableWidget_RecordCounts->clearContents(); ui->tableWidget_RecordCounts->clearContents();
@ -88,36 +88,37 @@ void ZoneFileViewer::SetZoneFile(const ZoneFile* aZoneFile) {
ui->groupBox_Tags->show(); ui->groupBox_Tags->show();
} }
QMap<XAssetType, int> recordCounts = QMap<XAssetType, int>(); QMap<QString, int> recordCounts = QMap<QString, int>();
QVector<QPair<XAssetType, int>> assetOccurances = QVector<QPair<XAssetType, int>>(); QVector<QPair<QString, int>> assetOccurances = QVector<QPair<QString, int>>();
for (XAssetType type : mZoneFile->GetTypes()) { for (const QString &record : mZoneFile->GetRecords()) {
if (!recordCounts.contains(type)) { if (!recordCounts.contains(record)) {
recordCounts[type] = 0; recordCounts[record] = 0;
} }
recordCounts[type]++; recordCounts[record]++;
if (!assetOccurances.isEmpty() && assetOccurances.last().first == type) { if (!assetOccurances.isEmpty() && assetOccurances.last().first == record) {
assetOccurances.last().second++; assetOccurances.last().second++;
continue; continue;
} }
QPair<XAssetType, int> assetOccurance(type, 1); QPair<QString, int> assetOccurance(record, 1);
assetOccurances << assetOccurance; assetOccurances << assetOccurance;
} }
ui->tableWidget_RecordOrder->setRowCount(assetOccurances.size()); ui->tableWidget_RecordOrder->setRowCount(assetOccurances.size());
int assetIndex = 0; int assetIndex = 0;
foreach (auto assetOccurance, assetOccurances) { foreach (auto assetOccurance, assetOccurances) {
XAssetType assetType = assetOccurance.first; const QString record = assetOccurance.first;
AssetType assetType = mZoneFile->AssetStrToEnum(record);
int assetCount = assetOccurance.second; int assetCount = assetOccurance.second;
QIcon assetIcon = Utils::CreateAssetIcon(assetType); QIcon assetIcon = mZoneFile->AssetTypeToIcon(assetType);
if (assetIcon.isNull()) { if (assetIcon.isNull()) {
qDebug() << "Icon is null for record: " << assetType; qDebug() << "Icon is null for record: " << record;
} }
QTableWidgetItem *recordItem = new QTableWidgetItem(QString::number(assetType, 16)); QTableWidgetItem *recordItem = new QTableWidgetItem(record.toUpper());
QTableWidgetItem *recordStrItem = new QTableWidgetItem(XAsset::XAssetTypeToString(assetType)); QTableWidgetItem *recordStrItem = new QTableWidgetItem(mZoneFile->AssetEnumToStr(assetType));
QTableWidgetItem *recordCountItem = new QTableWidgetItem(QString::number(assetCount)); QTableWidgetItem *recordCountItem = new QTableWidgetItem(QString::number(assetCount));
recordItem->setIcon(assetIcon); recordItem->setIcon(assetIcon);
@ -129,18 +130,19 @@ void ZoneFileViewer::SetZoneFile(const ZoneFile* aZoneFile) {
} }
int recordIndex = 0; int recordIndex = 0;
for (XAssetType assetType : recordCounts.keys()) { for (const QString &record : recordCounts.keys()) {
int recordCount = recordCounts[assetType]; int recordCount = recordCounts[record];
QIcon assetIcon = Utils::CreateAssetIcon(assetType); AssetType assetType = mZoneFile->AssetStrToEnum(record);
QIcon assetIcon = mZoneFile->AssetTypeToIcon(assetType);
if (assetIcon.isNull()) { if (assetIcon.isNull()) {
qDebug() << "Icon is null for record: " << assetType; qDebug() << "Icon is null for record: " << record;
} }
ui->tableWidget_RecordCounts->setRowCount(recordIndex + 1); ui->tableWidget_RecordCounts->setRowCount(recordIndex + 1);
QTableWidgetItem *recordItem = new QTableWidgetItem(QString::number(assetType, 16)); QTableWidgetItem *recordItem = new QTableWidgetItem(record.toUpper());
QTableWidgetItem *recordCountStrItem = new QTableWidgetItem(XAsset::XAssetTypeToString(assetType)); QTableWidgetItem *recordCountStrItem = new QTableWidgetItem(mZoneFile->AssetEnumToStr(assetType));
QTableWidgetItem *recordCountItem = new QTableWidgetItem(QString::number(recordCount)); QTableWidgetItem *recordCountItem = new QTableWidgetItem(QString::number(recordCount));
recordItem->setIcon(assetIcon); recordItem->setIcon(assetIcon);

View File

@ -18,7 +18,7 @@ public:
explicit ZoneFileViewer(QWidget *parent = nullptr); explicit ZoneFileViewer(QWidget *parent = nullptr);
~ZoneFileViewer(); ~ZoneFileViewer();
void SetZoneFile(const ZoneFile *aZoneFile); void SetZoneFile(std::shared_ptr<ZoneFile> aZoneFile);
public slots: public slots:
void SortTags(const QString &aSearchText); void SortTags(const QString &aSearchText);
@ -27,7 +27,7 @@ public slots:
private: private:
Ui::ZoneFileViewer *ui; Ui::ZoneFileViewer *ui;
const ZoneFile* mZoneFile; std::shared_ptr<ZoneFile> mZoneFile;
}; };
#endif // ZONEFILEVIEWER_H #endif // ZONEFILEVIEWER_H

View File

@ -20,6 +20,7 @@
<file>icons/Icon_Editor.png</file> <file>icons/Icon_Editor.png</file>
<file>icons/Icon_Views.png</file> <file>icons/Icon_Views.png</file>
<file>icons/Icon_Tree.png</file> <file>icons/Icon_Tree.png</file>
<file>icons/Icon_Copy.png</file>
<file>icons/Icon_Cut.png</file> <file>icons/Icon_Cut.png</file>
<file>icons/Icon_Find.png</file> <file>icons/Icon_Find.png</file>
<file>icons/Icon_NewFile.png</file> <file>icons/Icon_NewFile.png</file>

BIN
data/icons/Icon_Copy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 316 B

View File

@ -1,10 +1,13 @@
#include "compression.h" #include "compression.h"
#include "minilzo.h" #include "minilzo.h"
#define XBOXAPI __declspec(dllimport)
#include "xcompress.h" #include "xcompress.h"
#include <QLibrary> #include <QLibrary>
#include <QDebug> #include <QDebug>
#include <QFile> #include <QFile>
#include <QDataStream>
QByteArray Compression::CompressXMem(const QByteArray &data) QByteArray Compression::CompressXMem(const QByteArray &data)
{ {
@ -31,8 +34,7 @@ QByteArray Compression::CompressXMem(const QByteArray &data)
return output; return output;
} }
QByteArray Compression::DecompressXMem(const QByteArray &data, QByteArray Compression::DecompressXMem(const QByteArray &data, int flags, int windowSize, int partSize)
int flags, int windowSize, int partSize)
{ {
if (data.isEmpty()) if (data.isEmpty())
return {}; return {};
@ -42,49 +44,27 @@ QByteArray Compression::DecompressXMem(const QByteArray &data,
lzxParams.WindowSize = windowSize; lzxParams.WindowSize = windowSize;
lzxParams.CompressionPartitionSize = partSize; lzxParams.CompressionPartitionSize = partSize;
QByteArray internalState(0x94933, Qt::Uninitialized); XMEMDECOMPRESSION_CONTEXT ctx = nullptr;
if (FAILED(XMemCreateDecompressionContext(XMEMCODEC_LZX, &lzxParams, 0, &ctx)) || !ctx)
XMEMDECOMPRESSION_CONTEXT ctx = XMemInitializeDecompressionContext(
XMEMCODEC_LZX, &lzxParams, 1,
internalState.data(), internalState.size());
if (!ctx || XMemResetDecompressionContext(ctx)) {
qWarning() << "Failed to init LZX context";
return {}; return {};
}
QByteArray output; // Allocate large enough buffer for decompression (16 MB is a safe upper bound)
output.reserve(16 * 1024 * 1024); // rough guess const SIZE_T kMaxOutSize = 16 * 1024 * 1024;
QByteArray output(static_cast<int>(kMaxOutSize), Qt::Uninitialized);
SIZE_T actualSize = kMaxOutSize;
const quint8 *nextIn = reinterpret_cast<const quint8*>(data.constData()); HRESULT hr = XMemDecompress(ctx,
SIZE_T availIn = data.size(); output.data(), &actualSize,
data.constData(), data.size() + 16);
QByteArray scratch(0x10000, Qt::Uninitialized); // 64 KB chunks XMemDestroyDecompressionContext(ctx);
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)) { if (FAILED(hr)) {
qWarning() << "XMemDecompressStream failed, hr=" << hr; qWarning() << "XMemDecompress failed with HRESULT:" << hr;
XMemDestroyDecompressionContext(ctx);
return {}; return {};
} }
if (inSize == 0 && outSize == 0) output.resize(static_cast<int>(actualSize));
break; // no progress
output.append(scratch.constData(), static_cast<int>(outSize));
nextIn += inSize;
availIn -= inSize;
}
XMemDestroyDecompressionContext(ctx);
return output; return output;
} }
@ -100,18 +80,19 @@ quint32 Compression::CalculateAdler32Checksum(const QByteArray &data) {
qint64 Compression::FindZlibOffset(const QByteArray &bytes) qint64 Compression::FindZlibOffset(const QByteArray &bytes)
{ {
QDataStream stream(bytes); static const QByteArray iwffs("IWffs");
auto idx = bytes.indexOf(iwffs);
if (idx != -1)
return idx + 0x4000;
while (!stream.atEnd()) const char header = 0x78; // z-lib: 0x78 [FLG]
int pos = -1;
while ((pos = bytes.indexOf(header, pos + 1)) != -1)
{ {
QByteArray testSegment = stream.device()->peek(2).toHex().toUpper(); QByteArray window = bytes.mid(pos, 0x20);
if (testSegment == "7801" || if (!window.contains(QByteArray::fromHex("000000")) &&
testSegment == "785E" || !window.contains(QByteArray::fromHex("FFFFFF")))
testSegment == "789C" || return pos;
testSegment == "78DA") {
return stream.device()->pos();
}
stream.skipRawData(1);
} }
return -1; return -1;
} }
@ -314,12 +295,11 @@ QByteArray Compression::CompressDeflateWithSettings(const QByteArray &aData, int
} }
QByteArray Compression::DecompressLZO(const QByteArray &aCompressedData, quint32 aDestSize) { QByteArray Compression::DecompressLZO(const QByteArray &aCompressedData, quint32 aDestSize) {
QByteArray dst;
static bool ok = (lzo_init() == LZO_E_OK); static bool ok = (lzo_init() == LZO_E_OK);
if (!ok) if (!ok)
throw std::runtime_error("lzo_init failed"); throw std::runtime_error("lzo_init failed");
dst = QByteArray(aDestSize, Qt::Uninitialized); QByteArray dst(aDestSize, Qt::Uninitialized);
lzo_uint out = aDestSize; lzo_uint out = aDestSize;
int rc = lzo1x_decompress_safe( int rc = lzo1x_decompress_safe(

View File

@ -3,7 +3,7 @@
#include "QtZlib/zlib.h" #include "QtZlib/zlib.h"
//#include <windows.h> #include <windows.h>
#include <QtGlobal> #include <QtGlobal>
#include <stddef.h> #include <stddef.h>
#include <QByteArray> #include <QByteArray>

View File

@ -3,9 +3,15 @@ TEMPLATE = lib
CONFIG += staticlib c++17 CONFIG += staticlib c++17
DEFINES += MINILZO_USE_STATIC DEFINES += MINILZO_USE_STATIC
SOURCES += $$files($$PWD/*.cpp, true) \ SOURCES += \
$$files($$PWD/*.c, true) compression.cpp \
HEADERS += $$files($$PWD/*.h, true) minilzo.c \
lzoconf.h \
lzodefs.h
HEADERS += \
compression.h \
minilzo.h
LIBS += \ LIBS += \
-L$$PWD/../../third_party/xbox_sdk/lib -lxcompress64 \ -L$$PWD/../../third_party/xbox_sdk/lib -lxcompress64 \

View File

@ -57,7 +57,7 @@
/* get OS and architecture defines */ /* get OS and architecture defines */
#ifndef __LZODEFS_H_INCLUDED #ifndef __LZODEFS_H_INCLUDED
#include <lzodefs.h> #include <lzo/lzodefs.h>
#endif #endif
@ -105,7 +105,7 @@ extern "C" {
# define LZO_INT_MAX 9223372036854775807LL # define LZO_INT_MAX 9223372036854775807LL
# define LZO_INT_MIN (-1LL - LZO_INT_MAX) # define LZO_INT_MIN (-1LL - LZO_INT_MAX)
# elif (LZO_ABI_IP32L64) /* MIPS R5900 */ # elif (LZO_ABI_IP32L64) /* MIPS R5900 */
typedef quint32 lzo_uint; typedef unsigned int lzo_uint;
typedef int lzo_int; typedef int lzo_int;
# define LZO_SIZEOF_LZO_INT LZO_SIZEOF_INT # define LZO_SIZEOF_LZO_INT LZO_SIZEOF_INT
# define LZO_TYPEOF_LZO_INT LZO_TYPEOF_INT # define LZO_TYPEOF_LZO_INT LZO_TYPEOF_INT

View File

@ -2847,7 +2847,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF_LONG # define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF_LONG
#elif (LZO_SIZEOF_INT == 2) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT16E_T == LZO_TYPEOF_SHORT) #elif (LZO_SIZEOF_INT == 2) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT16E_T == LZO_TYPEOF_SHORT)
# define lzo_int16e_t int # define lzo_int16e_t int
# define lzo_uint16e_t quint32 # define lzo_uint16e_t unsigned int
# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF_INT # define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF_INT
#elif (LZO_SIZEOF_SHORT == 2) #elif (LZO_SIZEOF_SHORT == 2)
# define lzo_int16e_t short int # define lzo_int16e_t short int
@ -2856,14 +2856,14 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
#elif 1 && !(LZO_CFG_TYPE_NO_MODE_HI) && (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x025f00ul) || LZO_CC_LLVM) #elif 1 && !(LZO_CFG_TYPE_NO_MODE_HI) && (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x025f00ul) || LZO_CC_LLVM)
# if !(LZO_LANG_ASSEMBLER) # if !(LZO_LANG_ASSEMBLER)
typedef int lzo_int16e_hi_t__ __attribute__((__mode__(__HI__))); typedef int lzo_int16e_hi_t__ __attribute__((__mode__(__HI__)));
typedef quint32 lzo_uint16e_hi_t__ __attribute__((__mode__(__HI__))); typedef unsigned int lzo_uint16e_hi_t__ __attribute__((__mode__(__HI__)));
# endif # endif
# define lzo_int16e_t lzo_int16e_hi_t__ # define lzo_int16e_t lzo_int16e_hi_t__
# define lzo_uint16e_t lzo_uint16e_hi_t__ # define lzo_uint16e_t lzo_uint16e_hi_t__
# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF___MODE_HI # define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF___MODE_HI
#elif (LZO_SIZEOF___INT16 == 2) #elif (LZO_SIZEOF___INT16 == 2)
# define lzo_int16e_t __int16 # define lzo_int16e_t __int16
# define lzo_uint16e_t quint32 # define lzo_uint16e_t unsigned __int16
# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF___INT16 # define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF___INT16
#else #else
#endif #endif
@ -2883,7 +2883,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF_LONG # define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF_LONG
#elif (LZO_SIZEOF_INT == 4) #elif (LZO_SIZEOF_INT == 4)
# define lzo_int32e_t int # define lzo_int32e_t int
# define lzo_uint32e_t quint32 # define lzo_uint32e_t unsigned int
# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF_INT # define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF_INT
#elif (LZO_SIZEOF_SHORT == 4) #elif (LZO_SIZEOF_SHORT == 4)
# define lzo_int32e_t short int # define lzo_int32e_t short int
@ -2896,7 +2896,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
#elif 1 && !(LZO_CFG_TYPE_NO_MODE_SI) && (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x025f00ul) || LZO_CC_LLVM) && (__INT_MAX__+0 > 2147483647L) #elif 1 && !(LZO_CFG_TYPE_NO_MODE_SI) && (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x025f00ul) || LZO_CC_LLVM) && (__INT_MAX__+0 > 2147483647L)
# if !(LZO_LANG_ASSEMBLER) # if !(LZO_LANG_ASSEMBLER)
typedef int lzo_int32e_si_t__ __attribute__((__mode__(__SI__))); typedef int lzo_int32e_si_t__ __attribute__((__mode__(__SI__)));
typedef quint32 lzo_uint32e_si_t__ __attribute__((__mode__(__SI__))); typedef unsigned int lzo_uint32e_si_t__ __attribute__((__mode__(__SI__)));
# endif # endif
# define lzo_int32e_t lzo_int32e_si_t__ # define lzo_int32e_t lzo_int32e_si_t__
# define lzo_uint32e_t lzo_uint32e_si_t__ # define lzo_uint32e_t lzo_uint32e_si_t__
@ -2904,7 +2904,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
#elif 1 && !(LZO_CFG_TYPE_NO_MODE_SI) && (LZO_CC_GNUC >= 0x025f00ul) && defined(__AVR__) && (__LONG_MAX__+0 == 32767L) #elif 1 && !(LZO_CFG_TYPE_NO_MODE_SI) && (LZO_CC_GNUC >= 0x025f00ul) && defined(__AVR__) && (__LONG_MAX__+0 == 32767L)
# if !(LZO_LANG_ASSEMBLER) # if !(LZO_LANG_ASSEMBLER)
typedef int lzo_int32e_si_t__ __attribute__((__mode__(__SI__))); typedef int lzo_int32e_si_t__ __attribute__((__mode__(__SI__)));
typedef quint32 lzo_uint32e_si_t__ __attribute__((__mode__(__SI__))); typedef unsigned int lzo_uint32e_si_t__ __attribute__((__mode__(__SI__)));
# endif # endif
# define lzo_int32e_t lzo_int32e_si_t__ # define lzo_int32e_t lzo_int32e_si_t__
# define lzo_uint32e_t lzo_uint32e_si_t__ # define lzo_uint32e_t lzo_uint32e_si_t__
@ -2913,7 +2913,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF___MODE_SI # define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF___MODE_SI
#elif (LZO_SIZEOF___INT32 == 4) #elif (LZO_SIZEOF___INT32 == 4)
# define lzo_int32e_t __int32 # define lzo_int32e_t __int32
# define lzo_uint32e_t quint32 # define lzo_uint32e_t unsigned __int32
# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF___INT32 # define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF___INT32
#else #else
#endif #endif
@ -2937,7 +2937,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
#endif #endif
#if (LZO_SIZEOF_INT == 8) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG) #if (LZO_SIZEOF_INT == 8) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG)
# define lzo_int64e_t int # define lzo_int64e_t int
# define lzo_uint64e_t quint32 # define lzo_uint64e_t unsigned int
# define LZO_TYPEOF_LZO_INT64E_T LZO_TYPEOF_INT # define LZO_TYPEOF_LZO_INT64E_T LZO_TYPEOF_INT
#elif (LZO_SIZEOF_LONG == 8) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF_LONG_LONG) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF___INT64) #elif (LZO_SIZEOF_LONG == 8) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF_LONG_LONG) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF___INT64)
# define lzo_int64e_t long int # define lzo_int64e_t long int
@ -2984,7 +2984,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
# define LZO_TYPEOF_LZO_INT32L_T LZO_TYPEOF_LZO_INT32E_T # define LZO_TYPEOF_LZO_INT32L_T LZO_TYPEOF_LZO_INT32E_T
#elif (LZO_SIZEOF_INT >= 4) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG) #elif (LZO_SIZEOF_INT >= 4) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG)
# define lzo_int32l_t int # define lzo_int32l_t int
# define lzo_uint32l_t quint32 # define lzo_uint32l_t unsigned int
# define LZO_SIZEOF_LZO_INT32L_T LZO_SIZEOF_INT # define LZO_SIZEOF_LZO_INT32L_T LZO_SIZEOF_INT
# define LZO_TYPEOF_LZO_INT32L_T LZO_SIZEOF_INT # define LZO_TYPEOF_LZO_INT32L_T LZO_SIZEOF_INT
#elif (LZO_SIZEOF_LONG >= 4) #elif (LZO_SIZEOF_LONG >= 4)
@ -3057,7 +3057,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
#elif (LZO_CC_MSC && (_MSC_VER >= 1300) && (LZO_SIZEOF_VOID_P == 4) && (LZO_SIZEOF_INT == 4)) #elif (LZO_CC_MSC && (_MSC_VER >= 1300) && (LZO_SIZEOF_VOID_P == 4) && (LZO_SIZEOF_INT == 4))
# if !(LZO_LANG_ASSEMBLER) # if !(LZO_LANG_ASSEMBLER)
typedef __w64 int lzo_intptr_t; typedef __w64 int lzo_intptr_t;
typedef __w64 quint32 lzo_uintptr_t; typedef __w64 unsigned int lzo_uintptr_t;
# endif # endif
# define lzo_intptr_t lzo_intptr_t # define lzo_intptr_t lzo_intptr_t
# define lzo_uintptr_t lzo_uintptr_t # define lzo_uintptr_t lzo_uintptr_t
@ -3070,7 +3070,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_SHORT # define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_SHORT
#elif (LZO_SIZEOF_INT >= LZO_SIZEOF_VOID_P) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG) #elif (LZO_SIZEOF_INT >= LZO_SIZEOF_VOID_P) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG)
# define lzo_intptr_t int # define lzo_intptr_t int
# define lzo_uintptr_t quint32 # define lzo_uintptr_t unsigned int
# define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_INT # define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_INT
# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_INT # define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_INT
#elif (LZO_SIZEOF_LONG >= LZO_SIZEOF_VOID_P) #elif (LZO_SIZEOF_LONG >= LZO_SIZEOF_VOID_P)
@ -3104,7 +3104,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LONG # define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LONG
# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_LONG # define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_LONG
#elif (LZO_WORDSIZE == LZO_SIZEOF_INT) #elif (LZO_WORDSIZE == LZO_SIZEOF_INT)
# define lzo_word_t quint32 # define lzo_word_t unsigned int
# define lzo_sword_t int # define lzo_sword_t int
# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_INT # define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_INT
# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_INT # define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_INT

View File

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

View File

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

View File

@ -2,15 +2,23 @@ QT += core widgets
TEMPLATE = lib TEMPLATE = lib
CONFIG += staticlib c++17 CONFIG += staticlib c++17
SOURCES += $$files($$PWD/*.cpp, true) \ SOURCES += \
xdatastream.cpp highlighter_cfg.cpp \
HEADERS += $$files($$PWD/*.h, true) \ highlighter_shock.cpp \
xdatastream.h highlighter_rumble.cpp \
highlighter_gsc.cpp \
logmanager.cpp \
statusbarmanager.cpp
LIBS += -L$$OUT_PWD/../libs/xassets -lxassets HEADERS += \
enums.h \
INCLUDEPATH += $$PWD/../xassets highlighter_cfg.h \
highlighter_shock.h \
DEPENDPATH += $$PWD/../xassets highlighter_rumble.h \
highlighter_gsc.h \
logmanager.h \
stringutils.h \
utils.h \
statusbarmanager.h
DESTDIR = $$OUT_PWD/../ DESTDIR = $$OUT_PWD/../

View File

@ -3,6 +3,28 @@
#include <QString> #include <QString>
enum FF_PLATFORM {
FF_PLATFORM_NONE = 0x00, // No platform
FF_PLATFORM_XBOX = 0x01, // Xbox 360
FF_PLATFORM_PS3 = 0x02, // Playstation 3
FF_PLATFORM_PC = 0x03, // PC
FF_PLATFORM_WII = 0x04, // WII
FF_PLATFORM_WIIU = 0x05 // WII U
};
enum FF_GAME {
FF_GAME_NONE = 0x00, // No game
FF_GAME_COD1 = 0x01, // Call of Duty
FF_GAME_COD2 = 0x02, // Call of Duty 2
FF_GAME_COD3 = 0x03, // Call of Duty 3
FF_GAME_COD4 = 0x04, // Modern Warware 1
FF_GAME_COD5 = 0x05, // World at War
FF_GAME_COD6 = 0x06, // Modern Warfare 2
FF_GAME_COD7 = 0x07, // Black Ops 1
FF_GAME_COD8 = 0x08, // Modern Warfare 3
FF_GAME_COD9 = 0x09, // Black Ops 2
};
enum IWI_VERSION { enum IWI_VERSION {
IWI_VERSION_COD2 = 0x05, // 05 CoD2 IWI_VERSION_COD2 = 0x05, // 05 CoD2
IWI_VERSION_COD4 = 0x06, // 06 CoD4 IWI_VERSION_COD4 = 0x06, // 06 CoD4
@ -410,7 +432,7 @@ enum MENU_FONT_TYPE{
UI_FONT_DEFAULT = 0, // auto-chose betwen big/reg/small UI_FONT_DEFAULT = 0, // auto-chose betwen big/reg/small
UI_FONT_NORMAL = 1, UI_FONT_NORMAL = 1,
UI_FONT_BIG = 2, UI_FONT_BIG = 2,
UI_GameFontMALL = 3, UI_FONT_SMALL = 3,
UI_FONT_BOLD = 4, UI_FONT_BOLD = 4,
UI_FONT_CONSOLE = 5, UI_FONT_CONSOLE = 5,
UI_FONT_OBJECTIVE = 6, UI_FONT_OBJECTIVE = 6,

View File

@ -2,19 +2,15 @@
#define UTILS_H #define UTILS_H
#include "enums.h" #include "enums.h"
#include "QtZlib/zlib.h"
#include "qdir.h"
#include "qicon.h"
#include "xasset.h"
#include "xassettype.h"
#include <QMetaEnum> #include <QString>
#include <QtZlib/zlib.h>
#include <QFileDialog>
#include <QMessageBox>
#include <QPainter> #include <QPainter>
#include <QCryptographicHash> #include <QCryptographicHash>
class Utils : public QObject { class Utils {
Q_OBJECT
public: public:
static bool ExportData(const QString aFileName, const QByteArray aData) { static bool ExportData(const QString aFileName, const QByteArray aData) {
QDir workingDir = QDir::currentPath(); QDir workingDir = QDir::currentPath();
@ -34,29 +30,6 @@ public:
b = (b & 0xAA) >> 1 | (b & 0x55) << 1; b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
return b; return b;
} }
static QIcon CreateAssetIcon(XAssetType aAssetType, QColor color = QColor()) {
const QString assetTypeStr = XAsset::XAssetTypeToString(aAssetType);
QString assetAbbr;
for (int i = 0; i < assetTypeStr.length(); i++)
{
if (assetTypeStr[i].isUpper())
{
assetAbbr += assetTypeStr[i];
}
}
return CreateAssetIcon(assetAbbr, color);
// QString name;
// const QStringList parts = assetTypeStr.split('_').mid(1);
// foreach (const QString part, parts) {
// name += part[0];
// }
// if (parts.size() == 1) {
// name += parts.first()[1];
// }
// return CreateAssetIcon(name, color);
}
static QIcon CreateAssetIcon(const QString& name, QColor color = QColor()) { static QIcon CreateAssetIcon(const QString& name, QColor color = QColor()) {
constexpr int iconSize = 32; constexpr int iconSize = 32;
constexpr int padding = 4; constexpr int padding = 4;
@ -223,7 +196,7 @@ public:
return color; return color;
} }
static bool ReadUntilString(XDataStream* stream, const QString& targetString) { static bool ReadUntilString(QDataStream* stream, const QString& targetString) {
if (!stream || targetString.isEmpty()) { if (!stream || targetString.isEmpty()) {
return false; // Invalid input return false; // Invalid input
} }
@ -257,7 +230,7 @@ public:
return false; return false;
} }
static bool ReadUntilHex(XDataStream* stream, const QString& hexString) { static bool ReadUntilHex(QDataStream* stream, const QString& hexString) {
if (!stream || hexString.isEmpty() || hexString.size() % 2 != 0) { if (!stream || hexString.isEmpty() || hexString.size() % 2 != 0) {
return false; // Invalid input return false; // Invalid input
} }
@ -407,6 +380,34 @@ public:
return PadInt4(size) - size; return PadInt4(size) - size;
} }
static QString GetOpenFastFileName(QWidget *parent = nullptr) {
// Open file dialog to steam apps
const QString steamPath = "C:/Program Files (x86)/Steam/steamapps/common/Call of Duty World at War/zone/english/";
const QString fastFilePath = QFileDialog::getOpenFileName(parent, "Open Fast File", steamPath, "Fast File (*.ff);;All Files (*.*)");
if (fastFilePath.isNull()) {
// User pressed cancel
return "";
} else if (!QFile::exists(fastFilePath)) {
QMessageBox::warning(parent, "Warning!", QString("%1 does not exist!.").arg(fastFilePath));
return "";
}
return fastFilePath;
}
static QString GetOpenZoneFileName(QWidget *parent = nullptr) {
// Open file dialog to steam apps
const QString steamPath = "C:/Program Files (x86)/Steam/steamapps/common/Call of Duty World at War/zone/english/";
const QString zoneFilePath = QFileDialog::getOpenFileName(parent, "Open Zone File", steamPath, "Zone File (*.zone);;All Files (*.*)");
if (zoneFilePath.isNull()) {
// User pressed cancel
return "";
} else if (!QFile::exists(zoneFilePath)) {
QMessageBox::warning(parent, "Warning!", QString("%1 does not exist!.").arg(zoneFilePath));
return nullptr;
}
return zoneFilePath;
}
static QString CompanyEnumToStr(FF_COMPANY aCompany) { static QString CompanyEnumToStr(FF_COMPANY aCompany) {
switch (aCompany) { switch (aCompany) {
case COMPANY_NONE: case COMPANY_NONE:

View File

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

View File

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

View File

@ -35,7 +35,7 @@ DDSPixelFormat DDSFile::CalculatePixelFormat(quint8 aIWIFormat) {
return ddsPixelFormat; return ddsPixelFormat;
} }
void DDSFile::SetupExportDirs() const { void DDSFile::SetupExportDirs() {
QDir dir = QDir::currentPath(); QDir dir = QDir::currentPath();
if (!dir.exists("exports/")) { if (!dir.exists("exports/")) {
dir.mkdir("exports/"); dir.mkdir("exports/");
@ -89,92 +89,92 @@ DDSFile::DDSFile(const QString &aFilePath)
} }
DDSFile::DDSFile(const QByteArray aDDSData, const QString aFileStem) { DDSFile::DDSFile(const QByteArray aDDSData, const QString aFileStem) {
// QDataStream ddsIn(aDDSData); QDataStream ddsIn(aDDSData);
// ddsIn.setByteOrder(QDataStream::LittleEndian); ddsIn.setByteOrder(QDataStream::LittleEndian);
// DDSHeader ddsHeader; DDSHeader ddsHeader;
// if (ddsIn.readRawData(reinterpret_cast<char*>(&ddsHeader), sizeof(DDSHeader)) != sizeof(DDSHeader)) { if (ddsIn.readRawData(reinterpret_cast<char*>(&ddsHeader), sizeof(DDSHeader)) != sizeof(DDSHeader)) {
// qDebug() << "Error: Failed to read DDSHeader from QByteArray!"; qDebug() << "Error: Failed to read DDSHeader from QByteArray!";
// return; return;
// } }
// fileStem = aFileStem; fileStem = aFileStem;
// header = ddsHeader; header = ddsHeader;
// // Ensure DevIL is initialized once globally // Ensure DevIL is initialized once globally
// static bool devilInitialized = false; static bool devilInitialized = false;
// if (!devilInitialized) { if (!devilInitialized) {
// ilInit(); ilInit();
// devilInitialized = true; devilInitialized = true;
// } }
// // Generate and bind an image // Generate and bind an image
// ILuint imageID; ILuint imageID;
// ilGenImages(1, &imageID); ilGenImages(1, &imageID);
// ilBindImage(imageID); ilBindImage(imageID);
// ilEnable(IL_ORIGIN_SET); ilEnable(IL_ORIGIN_SET);
// ilOriginFunc(IL_ORIGIN_UPPER_LEFT); ilOriginFunc(IL_ORIGIN_UPPER_LEFT);
// // Load DDS file // Load DDS file
// if (!ilLoadL(IL_DDS, aDDSData.constData(), aDDSData.size())) { if (!ilLoadL(IL_DDS, aDDSData.constData(), aDDSData.size())) {
// ILuint devilError = ilGetError(); ILuint devilError = ilGetError();
// qDebug() << "DevIL Error while loading DDS: " << devilError; qDebug() << "DevIL Error while loading DDS: " << devilError;
// ilDeleteImages(1, &imageID); ilDeleteImages(1, &imageID);
// return; return;
// } }
// // Get mipmap count // Get mipmap count
// ILint numMipmaps = ilGetInteger(IL_NUM_MIPMAPS); ILint numMipmaps = ilGetInteger(IL_NUM_MIPMAPS);
// qDebug() << "Number of mipmaps: " << numMipmaps; qDebug() << "Number of mipmaps: " << numMipmaps;
// // Loop over all mipmap levels (0 is the base image) // Loop over all mipmap levels (0 is the base image)
// for (ILint level = 0; level <= numMipmaps; ++level) { for (ILint level = 0; level <= numMipmaps; ++level) {
// ilBindImage(imageID); ilBindImage(imageID);
// if (!ilActiveMipmap(level)) { if (!ilActiveMipmap(level)) {
// qDebug() << "DevIL failed to activate mipmap level" << level; qDebug() << "DevIL failed to activate mipmap level" << level;
// continue; continue;
// } }
// // Get mipmap properties // Get mipmap properties
// int width = ilGetInteger(IL_IMAGE_WIDTH); int width = ilGetInteger(IL_IMAGE_WIDTH);
// int height = ilGetInteger(IL_IMAGE_HEIGHT); int height = ilGetInteger(IL_IMAGE_HEIGHT);
// int depth = ilGetInteger(IL_IMAGE_DEPTH); int depth = ilGetInteger(IL_IMAGE_DEPTH);
// int format = ilGetInteger(IL_IMAGE_FORMAT); int format = ilGetInteger(IL_IMAGE_FORMAT);
// int bpp = 0; int bpp = 0;
// switch (format) { switch (format) {
// case IL_RGB: case IL_RGB:
// bpp = 3; bpp = 3;
// break; break;
// case IL_RGBA: case IL_RGBA:
// bpp = 4; bpp = 4;
// break; break;
// default: default:
// qDebug() << "Unsupported image format."; qDebug() << "Unsupported image format.";
// continue; continue;
// } }
// int dataSize = width * height * depth * bpp; int dataSize = width * height * depth * bpp;
// ILubyte *data = ilGetData(); ILubyte *data = ilGetData();
// if (!data) { if (!data) {
// qDebug() << "Error: DevIL returned null data for mipmap level" << level; qDebug() << "Error: DevIL returned null data for mipmap level" << level;
// continue; continue;
// } }
// // Create a mipmap structure // Create a mipmap structure
// DDSMipmap mipmap; DDSMipmap mipmap;
// mipmap.width = width; mipmap.width = width;
// mipmap.height = height; mipmap.height = height;
// mipmap.data = QByteArray(reinterpret_cast<const char*>(data), dataSize); mipmap.data = QByteArray(reinterpret_cast<const char*>(data), dataSize);
// mipmap.size = dataSize; mipmap.size = dataSize;
// // Store in DDS file // Store in DDS file
// mipmaps.append(mipmap); mipmaps.append(mipmap);
// } }
// ilDeleteImages(1, &imageID); ilDeleteImages(1, &imageID);
} }
DDSFile::DDSFile(const DDSFile &ddsFile) : DDSFile::DDSFile(const DDSFile &ddsFile) :
@ -248,7 +248,7 @@ DDSFile &DDSFile::operator=(const DDSFile &other) {
} }
// Write a DDS file from a DDSFile object // Write a DDS file from a DDSFile object
bool DDSFile::SaveDDS() const { bool DDSFile::SaveDDS() {
SetupExportDirs(); SetupExportDirs();
QFile file("exports/dds/" + fileStem + ".dds"); QFile file("exports/dds/" + fileStem + ".dds");
@ -268,7 +268,7 @@ bool DDSFile::SaveDDS() const {
return true; return true;
} }
bool DDSFile::SaveIWI() const { bool DDSFile::SaveIWI() {
SetupExportDirs(); SetupExportDirs();
IWIFile iwiFile(*this); IWIFile iwiFile(*this);
@ -279,7 +279,7 @@ bool DDSFile::SaveIWI() const {
return true; return true;
} }
bool DDSFile::SavePNG() const { bool DDSFile::SavePNG() {
SetupExportDirs(); SetupExportDirs();
int mipmapIndex = 1; int mipmapIndex = 1;
@ -311,7 +311,7 @@ bool DDSFile::SavePNG() const {
return true; return true;
} }
bool DDSFile::SaveJPG() const { bool DDSFile::SaveJPG() {
SetupExportDirs(); SetupExportDirs();
int mipmapIndex = 1; int mipmapIndex = 1;

View File

@ -9,7 +9,7 @@
#include <QVector> #include <QVector>
#include <QDebug> #include <QDebug>
#include <QImage> #include <QImage>
//#include <IL/il.h> #include <IL/il.h>
struct DDSPixelFormat { struct DDSPixelFormat {
quint32 size; quint32 size;
@ -68,12 +68,12 @@ public:
DDSFile(const DDSFile &ddsFile); DDSFile(const DDSFile &ddsFile);
DDSFile& operator=(const DDSFile& other); DDSFile& operator=(const DDSFile& other);
bool SaveDDS() const; bool SaveDDS();
bool SaveIWI() const; bool SaveIWI();
bool SavePNG() const; bool SavePNG();
bool SaveJPG() const; bool SaveJPG();
void SetupExportDirs() const; void SetupExportDirs();
static DDSPixelFormat CalculatePixelFormat(quint8 aIWIFormat); static DDSPixelFormat CalculatePixelFormat(quint8 aIWIFormat);
private: private:

View File

@ -2,21 +2,26 @@ QT += core
TEMPLATE = lib TEMPLATE = lib
CONFIG += staticlib c++17 CONFIG += staticlib c++17
SOURCES += $$files($$PWD/*.cpp, true) SOURCES += \
HEADERS += $$files($$PWD/*.h, true) ddsfile.cpp
HEADERS += \
dds_structs.h \
ddsfile.h \
enums.h
LIBS += \ LIBS += \
#-L$$PWD/../../third_party/devil_sdk/lib/ -lDevIL \ -L$$PWD/../../third_party/devil_sdk/lib/ -lDevIL \
#-L$$PWD/../../third_party/devil_sdk/lib/ -lILU \ -L$$PWD/../../third_party/devil_sdk/lib/ -lILU \
#-L$$PWD/../../third_party/devil_sdk/lib/ -lILUT \ -L$$PWD/../../third_party/devil_sdk/lib/ -lILUT \
-L$$OUT_PWD/../libs/iwifile -liwifile -L$$OUT_PWD/../libs/iwifile -liwifile
INCLUDEPATH += \ INCLUDEPATH += \
$$PWD/../iwifile/ \ $$PWD/../iwifile/ \
#$$PWD/../../third_party/devil_sdk/include/ $$PWD/../../third_party/devil_sdk/include/
DEPENDPATH += \ DEPENDPATH += \
$$PWD/../iwifile/ \ $$PWD/../iwifile/ \
#$$PWD/../../third_party/devil_sdk/include/ $$PWD/../../third_party/devil_sdk/include/
DESTDIR = $$OUT_PWD/../ DESTDIR = $$OUT_PWD/../

View File

@ -430,7 +430,7 @@ enum MENU_FONT_TYPE{
UI_FONT_DEFAULT = 0, // auto-chose betwen big/reg/small UI_FONT_DEFAULT = 0, // auto-chose betwen big/reg/small
UI_FONT_NORMAL = 1, UI_FONT_NORMAL = 1,
UI_FONT_BIG = 2, UI_FONT_BIG = 2,
UI_GameFontMALL = 3, UI_FONT_SMALL = 3,
UI_FONT_BOLD = 4, UI_FONT_BOLD = 4,
UI_FONT_CONSOLE = 5, UI_FONT_CONSOLE = 5,
UI_FONT_OBJECTIVE = 6, UI_FONT_OBJECTIVE = 6,

View File

@ -1,5 +1,15 @@
/* ecrypt-portable.h */ /* ecrypt-portable.h */
/*
* WARNING: the conversions defined below are implemented as macros,
* and should be used carefully. They should NOT be used with
* parameters which perform some action. E.g., the following two lines
* are not equivalent:
*
* 1) ++x; y = ROTL32(x, n);
* 2) y = ROTL32(++x, n);
*/
/* /*
* *** Please do not edit this file. *** * *** Please do not edit this file. ***
* *
@ -17,10 +27,10 @@
/* /*
* The following types are defined (if available): * The following types are defined (if available):
* *
* u8: quint32eger type, at least 8 bits * u8: unsigned integer type, at least 8 bits
* u16: quint32eger type, at least 16 bits * u16: unsigned integer type, at least 16 bits
* u32: quint32eger type, at least 32 bits * u32: unsigned integer type, at least 32 bits
* u64: quint32eger type, at least 64 bits * u64: unsigned integer type, at least 64 bits
* *
* s8, s16, s32, s64 -> signed counterparts of u8, u16, u32, u64 * s8, s16, s32, s64 -> signed counterparts of u8, u16, u32, u64
* *

View File

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

View File

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

View File

@ -2,8 +2,20 @@ QT += core
TEMPLATE = lib TEMPLATE = lib
CONFIG += staticlib c++17 CONFIG += staticlib c++17
SOURCES += $$files($$PWD/*.cpp, true) SOURCES += \
HEADERS += $$files($$PWD/*.h, true) salsa20.cpp \
sha1.cpp \
encryption.cpp
HEADERS += \
ecrypt-config.h \
ecrypt-machine.h \
ecrypt-portable.h \
ecrypt-sync.h \
encryption.h \
os_types.h \
config_win32.h \
sha1.h
app.depends += \ app.depends += \
compression compression

View File

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

View File

@ -10,7 +10,7 @@ Still 100% Public Domain
Corrected a problem which generated improper hash values on 16 bit machines Corrected a problem which generated improper hash values on 16 bit machines
Routine SHA1Update changed from Routine SHA1Update changed from
void SHA1Update(SHA1_CTX* context, unsigned char* data, quint32 void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int
len) len)
to to
void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned
@ -27,7 +27,7 @@ be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million
"a"s). "a"s).
I also changed the declaration of variables i & j in SHA1Update to I also changed the declaration of variables i & j in SHA1Update to
unsigned long from quint32 for the same reason. unsigned long from unsigned int for the same reason.
These changes should make no difference to any 32 bit implementations since These changes should make no difference to any 32 bit implementations since
an an
@ -94,6 +94,7 @@ void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]);
/* blk0() and blk() perform the initial expand. */ /* blk0() and blk() perform the initial expand. */
/* I got the idea of expanding during the round function from SSLeay */ /* I got the idea of expanding during the round function from SSLeay */
/* FIXME: can we do this in an endian-proof way? */
#ifdef WORDS_BIGENDIAN #ifdef WORDS_BIGENDIAN
#define blk0(i) block->l[i] #define blk0(i) block->l[i]
#else #else

View File

@ -36,7 +36,7 @@ FastFile_COD10_360::~FastFile_COD10_360() {
} }
QByteArray FastFile_COD10_360::GetBinaryData() const { QByteArray FastFile_COD10_360::GetBinaryData() {
return QByteArray(); return QByteArray();
} }
@ -69,9 +69,15 @@ bool FastFile_COD10_360::Load(const QString aFilePath) {
bool FastFile_COD10_360::Load(const QByteArray aData) { bool FastFile_COD10_360::Load(const QByteArray aData) {
QByteArray decompressedData; QByteArray decompressedData;
// Create a XDataStream on the input data. // Create a QDataStream on the input data.
XDataStream fastFileStream(aData); QDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::LittleEndian); fastFileStream.setByteOrder(QDataStream::LittleEndian);
// For COD7/COD9, use BigEndian.
fastFileStream.setByteOrder(QDataStream::BigEndian);
// Select key based on game.
QByteArray key = QByteArray::fromHex("0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3");
// Read the 8-byte magic. // Read the 8-byte magic.
QByteArray fileMagic(8, Qt::Uninitialized); QByteArray fileMagic(8, Qt::Uninitialized);
@ -90,7 +96,7 @@ bool FastFile_COD10_360::Load(const QByteArray aData) {
QByteArray rsaSignature(256, Qt::Uninitialized); QByteArray rsaSignature(256, Qt::Uninitialized);
fastFileStream.readRawData(rsaSignature.data(), 256); fastFileStream.readRawData(rsaSignature.data(), 256);
decompressedData = Encryption::DecryptFile(aData, fileName, "0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3"); decompressedData = Encryption::decryptFastFile_BO2(aData);
// For COD9, write out the complete decompressed zone for testing. // For COD9, write out the complete decompressed zone for testing.
QFile testFile("exports/" + GetBaseStem() + ".zone"); QFile testFile("exports/" + GetBaseStem() + ".zone");
@ -98,16 +104,12 @@ bool FastFile_COD10_360::Load(const QByteArray aData) {
testFile.write(decompressedData); testFile.write(decompressedData);
testFile.close(); testFile.close();
} }
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
// Load the zone file with the decompressed data (using an Xbox platform flag). // Load the zone file with the decompressed data (using an Xbox platform flag).
ZoneFile_COD10_360* zoneFile = new ZoneFile_COD10_360(); ZoneFile_COD10_360 zoneFile;
zoneFile->SetStem(GetBaseStem() + ".zone"); zoneFile.SetStem(GetBaseStem() + ".zone");
if (!zoneFile->Load(decompressedData)) { zoneFile.Load(decompressedData);
qWarning() << "Failed to load ZoneFile!"; SetZoneFile(std::make_shared<ZoneFile_COD10_360>(zoneFile));
return false;
}
SetZoneFile(zoneFile);
return true; return true;
} }

View File

@ -11,7 +11,7 @@ public:
FastFile_COD10_360(const QString aFilePath); FastFile_COD10_360(const QString aFilePath);
~FastFile_COD10_360(); ~FastFile_COD10_360();
QByteArray GetBinaryData() const override; QByteArray GetBinaryData() override;
bool Load(const QString aFilePath) override; bool Load(const QString aFilePath) override;
bool Load(const QByteArray aData) override; bool Load(const QByteArray aData) override;

View File

@ -38,7 +38,7 @@ FastFile_COD11_360::~FastFile_COD11_360() {
} }
QByteArray FastFile_COD11_360::GetBinaryData() const { QByteArray FastFile_COD11_360::GetBinaryData() {
return QByteArray(); return QByteArray();
} }
@ -68,84 +68,40 @@ bool FastFile_COD11_360::Load(const QString aFilePath) {
return true; return true;
} }
enum DB_CompressorType : qint32
{
DB_COMPRESSOR_INVALID = 0x0,
DB_COMPRESSOR_ZLIB = 0x1,
DB_COMPRESSOR_LZX = 0x2,
DB_COMPRESSOR_PASSTHROUGH = 0x3,
};
bool FastFile_COD11_360::Load(const QByteArray aData) { bool FastFile_COD11_360::Load(const QByteArray aData) {
QByteArray decompressedData; QByteArray decompressedData;
// Prepare data stream for parsing // Prepare data stream for parsing
XDataStream fastFileStream(aData); QDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::BigEndian); fastFileStream.setByteOrder(QDataStream::LittleEndian);
// Verify magic header // Verify magic header
QByteArray fileMagic(8, Qt::Uninitialized); QByteArray fileMagic(8, Qt::Uninitialized);
fastFileStream.readRawData(fileMagic.data(), 8); fastFileStream.readRawData(fileMagic.data(), 8);
quint32 version = fastFileStream.ParseUInt32(); if (fileMagic != "TAff0000") {
qWarning() << "Invalid fast file magic for COD12!";
fastFileStream.skipRawData(1);
DB_CompressorType compressorType = (DB_CompressorType)fastFileStream.ParseInt8();
fastFileStream.skipRawData(10);
qint32 blockCount = fastFileStream.ParseInt32();
if (version != 1838)
{
qWarning() << "Invalid fast file version:" << version << "!";
return false; return false;
} }
if (blockCount > 17280) // Skip: File size (4 bytes), flags/version (4 bytes), unknown (8 bytes), build tag (32 bytes), RSA signature (256 bytes)
{ fastFileStream.skipRawData(4 + 4 + 8 + 32 + 256); // total 304 bytes skipped so far + 8 bytes magic = 312 bytes at correct position.
qWarning() << "Fast file has too many blocks:" << blockCount << "> 17280!";
return false;
}
fastFileStream.skipRawData(12 * blockCount);
qint32 startPos = fastFileStream.ParseInt32(); // Correctly positioned at 0x138
Q_UNUSED(startPos); QByteArray encryptedData = aData.mid(0x138);
decompressedData = Encryption::decryptFastFile_BO3(encryptedData);
qint32 endPos = fastFileStream.ParseInt32(); // Output for verification/testing
Q_UNUSED(endPos);
if (fileMagic == "S1ffu100")
{
QByteArray compressedData = aData.mid(fastFileStream.device()->pos());
if (compressorType == DB_COMPRESSOR_ZLIB)
{
decompressedData = Compression::DecompressZLIB(compressedData);
}
else if (compressorType == DB_COMPRESSOR_LZX)
{
decompressedData = Compression::DecompressXMem(compressedData, 0, 0x80000, 0);
}
}
else if (fileMagic == "S1ff0100")
{
}
else
{
qWarning() << "Invalid fast file magic:" << fileMagic << "!";
return false;
}
Utils::ExportData(GetBaseStem() + ".zone", decompressedData); Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
// Load the zone file with decompressed data // Load the zone file with decompressed data
ZoneFile_COD11_360* zoneFile = new ZoneFile_COD11_360(); ZoneFile_COD11_360 zoneFile;
zoneFile->SetStem(GetBaseStem() + ".zone"); zoneFile.SetStem(GetBaseStem() + ".zone");
if (!zoneFile->Load(decompressedData)) { if (!zoneFile.Load(decompressedData)) {
qWarning() << "Failed to load ZoneFile!"; qWarning() << "Failed to load ZoneFile!";
return false; return false;
} }
SetZoneFile(zoneFile);
SetZoneFile(std::make_shared<ZoneFile_COD11_360>(zoneFile));
return true; return true;
} }

View File

@ -11,7 +11,7 @@ public:
FastFile_COD11_360(const QString aFilePath); FastFile_COD11_360(const QString aFilePath);
~FastFile_COD11_360(); ~FastFile_COD11_360();
QByteArray GetBinaryData() const override; QByteArray GetBinaryData() override;
bool Load(const QString aFilePath) override; bool Load(const QString aFilePath) override;
bool Load(const QByteArray aData) override; bool Load(const QByteArray aData) override;

View File

@ -38,7 +38,7 @@ FastFile_COD12_360::~FastFile_COD12_360() {
} }
QByteArray FastFile_COD12_360::GetBinaryData() const { QByteArray FastFile_COD12_360::GetBinaryData() {
return QByteArray(); return QByteArray();
} }
@ -72,80 +72,36 @@ bool FastFile_COD12_360::Load(const QByteArray aData) {
QByteArray decompressedData; QByteArray decompressedData;
// Prepare data stream for parsing // Prepare data stream for parsing
XDataStream fastFileStream(aData); QDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::LittleEndian); fastFileStream.setByteOrder(QDataStream::LittleEndian);
// Skip header magic // Verify magic header
fastFileStream.skipRawData(8); QByteArray fileMagic(8, Qt::Uninitialized);
fastFileStream.readRawData(fileMagic.data(), 8);
quint32 version; if (fileMagic != "TAff0000") {
fastFileStream >> version; qWarning() << "Invalid fast file magic for COD12!";
quint8 unknownFlag, compressionFlag, platformFlag, encryptionFlag;
fastFileStream >> unknownFlag >> compressionFlag >> platformFlag >> encryptionFlag;
if (compressionFlag != 1) {
qDebug() << "Invalid fastfile compression: " << compressionFlag;
return false;
} else if (platformFlag != 4) {
qDebug() << "Invalid platform: " << platformFlag;
return false;
} else if (encryptionFlag != 0) {
qDebug() << "Decryption not supported yet!";
return false; return false;
} }
fastFileStream.skipRawData(128); // Skip: File size (4 bytes), flags/version (4 bytes), unknown (8 bytes), build tag (32 bytes), RSA signature (256 bytes)
fastFileStream.skipRawData(4 + 4 + 8 + 32 + 256); // total 304 bytes skipped so far + 8 bytes magic = 312 bytes at correct position.
quint64 size; // Correctly positioned at 0x138
fastFileStream >> size; QByteArray encryptedData = aData.mid(0x138);
decompressedData = Encryption::decryptFastFile_BO3(encryptedData);
fastFileStream.skipRawData(432);
int consumed = 0;
while(consumed < size)
{
// Read Block Header
quint32 compressedSize, decompressedSize, blockSize, blockPosition;
fastFileStream >> compressedSize >> decompressedSize >> blockSize >> blockPosition;
// Validate the block position, it should match
if(blockPosition != fastFileStream.device()->pos() - 16)
{
qDebug() << "Block Position does not match Stream Position.";
return false;
}
// Check for padding blocks
if(decompressedSize == 0)
{
fastFileStream.device()->read((((fastFileStream.device()->pos()) + ((0x800000) - 1)) & ~((0x800000) - 1)) - fastFileStream.device()->pos());
continue;
}
fastFileStream.device()->read(2);
QByteArray compressedData(compressedSize - 2, Qt::Uninitialized);
qDebug() << "Data position: " << fastFileStream.device()->pos() << " - Size: " << compressedSize;
fastFileStream.readRawData(compressedData.data(), compressedSize - 2);
decompressedData.append(Compression::DecompressDeflate(compressedData));
consumed += decompressedSize;
// Sinze Fast Files are aligns, we must skip the full block
fastFileStream.device()->seek(blockPosition + 16 + blockSize);
}
// Output for verification/testing // Output for verification/testing
Utils::ExportData(GetBaseStem() + ".zone", decompressedData); Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
// Load the zone file with decompressed data // Load the zone file with decompressed data
ZoneFile_COD12_360* zoneFile = new ZoneFile_COD12_360(); ZoneFile_COD12_360 zoneFile;
zoneFile->SetStem(GetBaseStem() + ".zone"); zoneFile.SetStem(GetBaseStem() + ".zone");
if (!zoneFile->Load(decompressedData)) { if (!zoneFile.Load(decompressedData)) {
qWarning() << "Failed to load ZoneFile!"; qWarning() << "Failed to load ZoneFile!";
return false; return false;
} }
SetZoneFile(zoneFile);
SetZoneFile(std::make_shared<ZoneFile_COD12_360>(zoneFile));
return true; return true;
} }

View File

@ -11,7 +11,7 @@ public:
FastFile_COD12_360(const QString aFilePath); FastFile_COD12_360(const QString aFilePath);
~FastFile_COD12_360(); ~FastFile_COD12_360();
QByteArray GetBinaryData() const override; QByteArray GetBinaryData() override;
bool Load(const QString aFilePath) override; bool Load(const QString aFilePath) override;
bool Load(const QByteArray aData) override; bool Load(const QByteArray aData) override;

View File

@ -38,7 +38,7 @@ FastFile_COD2_360::~FastFile_COD2_360() {
} }
QByteArray FastFile_COD2_360::GetBinaryData() const { QByteArray FastFile_COD2_360::GetBinaryData() {
return QByteArray(); return QByteArray();
} }
@ -68,9 +68,9 @@ bool FastFile_COD2_360::Load(const QString aFilePath) {
} }
bool FastFile_COD2_360::Load(const QByteArray aData) { bool FastFile_COD2_360::Load(const QByteArray aData) {
// Create a XDataStream on the input data. // Create a QDataStream on the input data.
XDataStream fastFileStream(aData); QDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::LittleEndian); fastFileStream.setByteOrder(QDataStream::LittleEndian);
Utils::ReadUntilHex(&fastFileStream, "78"); Utils::ReadUntilHex(&fastFileStream, "78");
QByteArray compressedData = aData.mid(fastFileStream.device()->pos()); QByteArray compressedData = aData.mid(fastFileStream.device()->pos());
@ -79,13 +79,10 @@ bool FastFile_COD2_360::Load(const QByteArray aData) {
Utils::ExportData(GetBaseStem() + ".zone", decompressedData); Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
// Load the zone file with the decompressed data (using an Xbox platform flag). // Load the zone file with the decompressed data (using an Xbox platform flag).
ZoneFile_COD2_360* zoneFile = new ZoneFile_COD2_360(); ZoneFile_COD2_360 zoneFile;
zoneFile->SetStem(GetBaseStem() + ".zone"); zoneFile.SetStem(GetBaseStem() + ".zone");
if (!zoneFile->Load(decompressedData)) { zoneFile.Load(decompressedData);
qWarning() << "Failed to load ZoneFile!"; SetZoneFile(std::make_shared<ZoneFile_COD2_360>(zoneFile));
return false;
}
SetZoneFile(zoneFile);
return true; return true;
} }

View File

@ -11,7 +11,7 @@ public:
FastFile_COD2_360(const QString aFilePath); FastFile_COD2_360(const QString aFilePath);
~FastFile_COD2_360(); ~FastFile_COD2_360();
QByteArray GetBinaryData() const override; QByteArray GetBinaryData() override;
bool Load(const QString aFilePath) override; bool Load(const QString aFilePath) override;
bool Load(const QByteArray aData) override; bool Load(const QByteArray aData) override;

View File

@ -39,7 +39,7 @@ FastFile_COD4_360::~FastFile_COD4_360() {
} }
QByteArray FastFile_COD4_360::GetBinaryData() const { QByteArray FastFile_COD4_360::GetBinaryData() {
return QByteArray(); return QByteArray();
} }
@ -80,9 +80,9 @@ bool FastFile_COD4_360::Load(const QByteArray aData) {
// For COD5, simply decompress from offset 12. // For COD5, simply decompress from offset 12.
decompressedData = Compression::DecompressZLIB(aData.mid(12)); decompressedData = Compression::DecompressZLIB(aData.mid(12));
} else if (header == "IWff0100") { } else if (header == "IWff0100") {
// Create a XDataStream on the input data. // Create a QDataStream on the input data.
XDataStream fastFileStream(aData.mid(12)); QDataStream fastFileStream(aData.mid(12));
fastFileStream.setByteOrder(XDataStream::LittleEndian); fastFileStream.setByteOrder(QDataStream::LittleEndian);
QByteArray magic(8, Qt::Uninitialized); QByteArray magic(8, Qt::Uninitialized);
fastFileStream.readRawData(magic.data(), 8); fastFileStream.readRawData(magic.data(), 8);
@ -126,15 +126,14 @@ bool FastFile_COD4_360::Load(const QByteArray aData) {
} }
decompressedData = Compression::DecompressZLIB(compressedData); decompressedData = Compression::DecompressZLIB(compressedData);
} }
Utils::ExportData(GetBaseStem() + ".zone", decompressedData); Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
ZoneFile_COD4_360* zoneFile = new ZoneFile_COD4_360(); ZoneFile_COD4_360 zoneFile;
zoneFile->SetStem(GetBaseStem() + ".zone"); zoneFile.SetStem(GetBaseStem() + ".zone");
if (!zoneFile->Load(decompressedData)) { zoneFile.Load(decompressedData);
qWarning() << "Failed to load ZoneFile!"; SetZoneFile(std::make_shared<ZoneFile_COD4_360>(zoneFile));
return false;
}
SetZoneFile(zoneFile);
return true; return true;
} }

View File

@ -11,7 +11,7 @@ public:
FastFile_COD4_360(const QString aFilePath); FastFile_COD4_360(const QString aFilePath);
~FastFile_COD4_360(); ~FastFile_COD4_360();
QByteArray GetBinaryData() const override; QByteArray GetBinaryData() override;
bool Load(const QString aFilePath) override; bool Load(const QString aFilePath) override;
bool Load(const QByteArray aData) override; bool Load(const QByteArray aData) override;

View File

@ -39,7 +39,7 @@ FastFile_COD5_360::~FastFile_COD5_360() {
} }
QByteArray FastFile_COD5_360::GetBinaryData() const { QByteArray FastFile_COD5_360::GetBinaryData() {
return QByteArray(); return QByteArray();
} }
@ -80,13 +80,10 @@ bool FastFile_COD5_360::Load(const QByteArray aData) {
Utils::ExportData(GetBaseStem() + ".zone", decompressedData); Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
ZoneFile_COD5_360* zoneFile = new ZoneFile_COD5_360(); ZoneFile_COD5_360 zoneFile;
zoneFile->SetStem(GetBaseStem() + ".zone"); zoneFile.SetStem(GetBaseStem() + ".zone");
if (!zoneFile->Load(decompressedData)) { zoneFile.Load(decompressedData);
qWarning() << "Failed to load ZoneFile!"; SetZoneFile(std::make_shared<ZoneFile_COD5_360>(zoneFile));
return false;
}
SetZoneFile(zoneFile);
return true; return true;
} }

View File

@ -11,7 +11,7 @@ public:
FastFile_COD5_360(const QString aFilePath); FastFile_COD5_360(const QString aFilePath);
~FastFile_COD5_360(); ~FastFile_COD5_360();
QByteArray GetBinaryData() const override; QByteArray GetBinaryData() override;
bool Load(const QString aFilePath) override; bool Load(const QString aFilePath) override;
bool Load(const QByteArray aData) override; bool Load(const QByteArray aData) override;

View File

@ -39,7 +39,7 @@ FastFile_COD6_360::~FastFile_COD6_360() {
} }
QByteArray FastFile_COD6_360::GetBinaryData() const { QByteArray FastFile_COD6_360::GetBinaryData() {
return QByteArray(); return QByteArray();
} }
@ -70,55 +70,39 @@ bool FastFile_COD6_360::Load(const QString aFilePath) {
} }
bool FastFile_COD6_360::Load(const QByteArray aData) { bool FastFile_COD6_360::Load(const QByteArray aData) {
XDataStream fastFileStream(aData); const qint64 zlibOffset = Compression::FindZlibOffset(aData);
fastFileStream.setByteOrder(XDataStream::BigEndian); if (zlibOffset == -1)
QByteArray magic(8, Qt::Uninitialized);
fastFileStream.readRawData(magic.data(), 8);
quint32 version = fastFileStream.ParseUInt32();
if (version != 269)
{ {
qDebug() << QString("Invalid version: %1!").arg(version); qWarning() << "Z-Lib stream not found";
return false;
}
QByteArray compressed = aData.mid(zlibOffset);
// 2. Try plain decompression first ------------------------------
QByteArray decompressed = Compression::DecompressZLIB(compressed);
// 3. If that failed or looks too small, try stripping hash blocks
if (decompressed.isEmpty() || decompressed.size() < 1024)
{
QByteArray stripped = Compression::StripHashBlocks(compressed);
QByteArray retry = Compression::DecompressZLIB(stripped);
if (!retry.isEmpty())
decompressed.swap(retry);
}
if (decompressed.isEmpty())
{
qWarning() << "Unable to decompress fast-file";
return false; return false;
} }
bool localPatch = fastFileStream.ParseBool(); // Optional keep a copy on disk for quick inspection
Q_UNUSED(localPatch); Utils::ExportData(GetBaseStem() + ".zone", decompressed);
quint8 compressor = fastFileStream.ParseUInt8(); // 4. Forward to zone-file loader --------------------------------
Q_UNUSED(compressor); auto zoneFile = std::make_shared<ZoneFile_COD6_360>();
zoneFile->SetStem(GetStem());
// Skip fastfile date/time zoneFile->Load(decompressed);
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();
zoneFile->SetStem(GetBaseStem() + ".zone");
if (!zoneFile->Load(decompressedData)) {
qWarning() << "Failed to load ZoneFile!";
return false;
}
SetZoneFile(zoneFile); SetZoneFile(zoneFile);
return true; return true;

View File

@ -11,7 +11,7 @@ public:
FastFile_COD6_360(const QString aFilePath); FastFile_COD6_360(const QString aFilePath);
~FastFile_COD6_360(); ~FastFile_COD6_360();
QByteArray GetBinaryData() const override; QByteArray GetBinaryData() override;
bool Load(const QString aFilePath) override; bool Load(const QString aFilePath) override;
bool Load(const QByteArray aData) override; bool Load(const QByteArray aData) override;

View File

@ -38,7 +38,7 @@ FastFile_COD7_360::~FastFile_COD7_360() {
} }
QByteArray FastFile_COD7_360::GetBinaryData() const { QByteArray FastFile_COD7_360::GetBinaryData() {
return QByteArray(); return QByteArray();
} }
@ -71,11 +71,19 @@ bool FastFile_COD7_360::Load(const QString aFilePath) {
bool FastFile_COD7_360::Load(const QByteArray aData) { bool FastFile_COD7_360::Load(const QByteArray aData) {
QByteArray decompressedData; QByteArray decompressedData;
// Create a XDataStream on the input data. // Create a QDataStream on the input data.
XDataStream fastFileStream(aData); QDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::BigEndian);
fastFileStream.skipRawData(16); // Load the zone file with the decompressed data (using an Xbox platform flag).
ZoneFile_COD7_360 zoneFile;
zoneFile.SetStem(GetBaseStem() + ".zone");
// For COD7/COD9, use BigEndian.
fastFileStream.setByteOrder(QDataStream::BigEndian);
// Select key based on game.
QByteArray key = QByteArray::fromHex("1ac1d12d527c59b40eca619120ff8217ccff09cd16896f81b829c7f52793405d");
fastFileStream.skipRawData(4);
// Read the 8-byte magic. // Read the 8-byte magic.
QByteArray fileMagic(8, Qt::Uninitialized); QByteArray fileMagic(8, Qt::Uninitialized);
@ -97,8 +105,6 @@ bool FastFile_COD7_360::Load(const QByteArray aData) {
QByteArray rsaSignature(256, Qt::Uninitialized); QByteArray rsaSignature(256, Qt::Uninitialized);
fastFileStream.readRawData(rsaSignature.data(), 256); fastFileStream.readRawData(rsaSignature.data(), 256);
QByteArray key = QByteArray::fromHex("1ac1d12d527c59b40eca619120ff8217ccff09cd16896f81b829c7f52793405d");
// Now the stream should be positioned at 0x13C, where sections begin. // Now the stream should be positioned at 0x13C, where sections begin.
int sectionIndex = 0; int sectionIndex = 0;
while (true) { while (true) {
@ -136,15 +142,10 @@ bool FastFile_COD7_360::Load(const QByteArray aData) {
sectionIndex++; sectionIndex++;
} }
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
ZoneFile_COD7_360* zoneFile = new ZoneFile_COD7_360(); zoneFile.Load(decompressedData);
zoneFile->SetStem(GetBaseStem() + ".zone");
if (!zoneFile->Load(decompressedData)) { SetZoneFile(std::make_shared<ZoneFile_COD7_360>(zoneFile));
qWarning() << "Failed to load ZoneFile!";
return false;
}
SetZoneFile(zoneFile);
return true; return true;
} }

View File

@ -11,7 +11,7 @@ public:
FastFile_COD7_360(const QString aFilePath); FastFile_COD7_360(const QString aFilePath);
~FastFile_COD7_360(); ~FastFile_COD7_360();
QByteArray GetBinaryData() const override; QByteArray GetBinaryData() override;
bool Load(const QString aFilePath) override; bool Load(const QString aFilePath) override;
bool Load(const QByteArray aData) override; bool Load(const QByteArray aData) override;

View File

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

View File

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

View File

@ -36,7 +36,7 @@ FastFile_COD8_360::~FastFile_COD8_360() {
} }
QByteArray FastFile_COD8_360::GetBinaryData() const { QByteArray FastFile_COD8_360::GetBinaryData() {
return QByteArray(); return QByteArray();
} }
@ -69,12 +69,15 @@ bool FastFile_COD8_360::Load(const QString aFilePath) {
bool FastFile_COD8_360::Load(const QByteArray aData) { bool FastFile_COD8_360::Load(const QByteArray aData) {
QByteArray decompressedData; QByteArray decompressedData;
// Create a XDataStream on the input data. // Create a QDataStream on the input data.
XDataStream fastFileStream(aData); QDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::LittleEndian); fastFileStream.setByteOrder(QDataStream::LittleEndian);
// For COD7/COD9, use BigEndian. // For COD7/COD9, use BigEndian.
fastFileStream.setByteOrder(XDataStream::BigEndian); fastFileStream.setByteOrder(QDataStream::BigEndian);
// Select key based on game.
QByteArray key = QByteArray::fromHex("0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3");
// Read the 8-byte magic. // Read the 8-byte magic.
QByteArray fileMagic(8, Qt::Uninitialized); QByteArray fileMagic(8, Qt::Uninitialized);
@ -89,7 +92,11 @@ bool FastFile_COD8_360::Load(const QByteArray aData) {
QByteArray fileName(32, Qt::Uninitialized); QByteArray fileName(32, Qt::Uninitialized);
fastFileStream.readRawData(fileName.data(), 32); fastFileStream.readRawData(fileName.data(), 32);
decompressedData = Encryption::DecryptFile(aData, fileName, "0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3"); // Skip the RSA signature (256 bytes).
QByteArray rsaSignature(256, Qt::Uninitialized);
fastFileStream.readRawData(rsaSignature.data(), 256);
decompressedData = Encryption::decryptFastFile_BO2(aData);
// For COD9, write out the complete decompressed zone for testing. // For COD9, write out the complete decompressed zone for testing.
QFile testFile("exports/" + GetBaseStem() + ".zone"); QFile testFile("exports/" + GetBaseStem() + ".zone");
@ -99,13 +106,10 @@ bool FastFile_COD8_360::Load(const QByteArray aData) {
} }
// Load the zone file with the decompressed data (using an Xbox platform flag). // Load the zone file with the decompressed data (using an Xbox platform flag).
ZoneFile_COD8_360* zoneFile = new ZoneFile_COD8_360(); ZoneFile_COD8_360 zoneFile;
zoneFile->SetStem(GetBaseStem() + ".zone"); zoneFile.SetStem(GetBaseStem() + ".zone");
if (!zoneFile->Load(decompressedData)) { zoneFile.Load(decompressedData);
qWarning() << "Failed to load ZoneFile!"; SetZoneFile(std::make_shared<ZoneFile_COD8_360>(zoneFile));
return false;
}
SetZoneFile(zoneFile);
return true; return true;
} }

View File

@ -11,7 +11,7 @@ public:
FastFile_COD8_360(const QString aFilePath); FastFile_COD8_360(const QString aFilePath);
~FastFile_COD8_360(); ~FastFile_COD8_360();
QByteArray GetBinaryData() const override; QByteArray GetBinaryData() override;
bool Load(const QString aFilePath) override; bool Load(const QString aFilePath) override;
bool Load(const QByteArray aData) override; bool Load(const QByteArray aData) override;

View File

@ -36,7 +36,7 @@ FastFile_COD9_360::~FastFile_COD9_360() {
} }
QByteArray FastFile_COD9_360::GetBinaryData() const { QByteArray FastFile_COD9_360::GetBinaryData() {
return QByteArray(); return QByteArray();
} }
@ -69,12 +69,15 @@ bool FastFile_COD9_360::Load(const QString aFilePath) {
bool FastFile_COD9_360::Load(const QByteArray aData) { bool FastFile_COD9_360::Load(const QByteArray aData) {
QByteArray decompressedData; QByteArray decompressedData;
// Create a XDataStream on the input data. // Create a QDataStream on the input data.
XDataStream fastFileStream(aData); QDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::LittleEndian); fastFileStream.setByteOrder(QDataStream::LittleEndian);
// For COD7/COD9, use BigEndian. // For COD7/COD9, use BigEndian.
fastFileStream.setByteOrder(XDataStream::BigEndian); fastFileStream.setByteOrder(QDataStream::BigEndian);
// Select key based on game.
QByteArray key = QByteArray::fromHex("0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3");
// Read the 8-byte magic. // Read the 8-byte magic.
QByteArray fileMagic(8, Qt::Uninitialized); QByteArray fileMagic(8, Qt::Uninitialized);
@ -93,7 +96,7 @@ bool FastFile_COD9_360::Load(const QByteArray aData) {
QByteArray rsaSignature(256, Qt::Uninitialized); QByteArray rsaSignature(256, Qt::Uninitialized);
fastFileStream.readRawData(rsaSignature.data(), 256); fastFileStream.readRawData(rsaSignature.data(), 256);
decompressedData = Encryption::DecryptFile(aData, fileName, "0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3"); decompressedData = Encryption::decryptFastFile_BO2(aData);
// For COD9, write out the complete decompressed zone for testing. // For COD9, write out the complete decompressed zone for testing.
QFile testFile("exports/" + GetBaseStem() + ".zone"); QFile testFile("exports/" + GetBaseStem() + ".zone");
@ -103,13 +106,10 @@ bool FastFile_COD9_360::Load(const QByteArray aData) {
} }
// Load the zone file with the decompressed data (using an Xbox platform flag). // Load the zone file with the decompressed data (using an Xbox platform flag).
ZoneFile_COD9_360* zoneFile = new ZoneFile_COD9_360(); ZoneFile_COD9_360 zoneFile;
zoneFile->SetStem(GetBaseStem() + ".zone"); zoneFile.SetStem(GetBaseStem() + ".zone");
if (!zoneFile->Load(decompressedData)) { zoneFile.Load(decompressedData);
qWarning() << "Failed to load ZoneFile!"; SetZoneFile(std::make_shared<ZoneFile_COD9_360>(zoneFile));
return false;
}
SetZoneFile(zoneFile);
return true; return true;
} }

View File

@ -11,7 +11,7 @@ public:
FastFile_COD9_360(const QString aFilePath); FastFile_COD9_360(const QString aFilePath);
~FastFile_COD9_360(); ~FastFile_COD9_360();
QByteArray GetBinaryData() const override; QByteArray GetBinaryData() override;
bool Load(const QString aFilePath) override; bool Load(const QString aFilePath) override;
bool Load(const QByteArray aData) override; bool Load(const QByteArray aData) override;

View File

@ -36,7 +36,7 @@ FastFile_COD10_PC::~FastFile_COD10_PC() {
} }
QByteArray FastFile_COD10_PC::GetBinaryData() const { QByteArray FastFile_COD10_PC::GetBinaryData() {
return QByteArray(); return QByteArray();
} }
@ -69,9 +69,9 @@ bool FastFile_COD10_PC::Load(const QString aFilePath) {
bool FastFile_COD10_PC::Load(const QByteArray aData) { bool FastFile_COD10_PC::Load(const QByteArray aData) {
QByteArray decompressedData; QByteArray decompressedData;
// Create a XDataStream on the input data. // Create a QDataStream on the input data.
XDataStream fastFileStream(aData); QDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::LittleEndian); fastFileStream.setByteOrder(QDataStream::LittleEndian);
// Parse header values. // Parse header values.
SetCompany(pParseFFCompany(&fastFileStream)); SetCompany(pParseFFCompany(&fastFileStream));
@ -84,13 +84,18 @@ bool FastFile_COD10_PC::Load(const QByteArray aData) {
SetGame("COD9"); SetGame("COD9");
// For COD7/COD9, use BigEndian. // For COD7/COD9, use BigEndian.
fastFileStream.setByteOrder(XDataStream::BigEndian); fastFileStream.setByteOrder(QDataStream::BigEndian);
if (GetPlatform() == "PC") { if (GetPlatform() == "PC") {
fastFileStream.setByteOrder(XDataStream::LittleEndian); fastFileStream.setByteOrder(QDataStream::LittleEndian);
} }
// Select key based on game. // Select key based on game.
QByteArray key = QByteArray::fromHex("641D8A2FE31D3AA63622BBC9CE8587229D42B0F8ED9B924130BF88B65EDC50BE"); QByteArray key;
if (GetPlatform() == "360") {
key = QByteArray::fromHex("0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3");
} else if (GetPlatform() == "PC") {
key = QByteArray::fromHex("641D8A2FE31D3AA63622BBC9CE8587229D42B0F8ED9B924130BF88B65EDC50BE");
}
// Read the 8-byte magic. // Read the 8-byte magic.
QByteArray fileMagic(8, Qt::Uninitialized); QByteArray fileMagic(8, Qt::Uninitialized);
@ -109,7 +114,11 @@ bool FastFile_COD10_PC::Load(const QByteArray aData) {
QByteArray rsaSignature(256, Qt::Uninitialized); QByteArray rsaSignature(256, Qt::Uninitialized);
fastFileStream.readRawData(rsaSignature.data(), 256); fastFileStream.readRawData(rsaSignature.data(), 256);
//decompressedData = Encryption::decryptFastFile_BO2(aData); if (GetPlatform() == "360") {
//decompressedData = Compressor::cod9_decryptFastFile(aData);
} else if (GetPlatform() == "PC") {
decompressedData = Encryption::decryptFastFile_BO2(aData);
}
// For COD9, write out the complete decompressed zone for testing. // For COD9, write out the complete decompressed zone for testing.
QFile testFile("exports/" + GetBaseStem() + ".zone"); QFile testFile("exports/" + GetBaseStem() + ".zone");
@ -117,16 +126,12 @@ bool FastFile_COD10_PC::Load(const QByteArray aData) {
testFile.write(decompressedData); testFile.write(decompressedData);
testFile.close(); testFile.close();
} }
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
// Load the zone file with the decompressed data (using an Xbox platform flag). // Load the zone file with the decompressed data (using an Xbox platform flag).
ZoneFile_COD10_PC* zoneFile = new ZoneFile_COD10_PC(); ZoneFile_COD10_PC zoneFile;
zoneFile->SetStem(GetBaseStem() + ".zone"); zoneFile.SetStem(GetBaseStem() + ".zone");
if (!zoneFile->Load(decompressedData)) { zoneFile.Load(decompressedData);
qWarning() << "Failed to load ZoneFile!"; SetZoneFile(std::make_shared<ZoneFile_COD10_PC>(zoneFile));
return false;
}
SetZoneFile(zoneFile);
return true; return true;
} }

View File

@ -11,7 +11,7 @@ public:
FastFile_COD10_PC(const QString aFilePath); FastFile_COD10_PC(const QString aFilePath);
~FastFile_COD10_PC(); ~FastFile_COD10_PC();
QByteArray GetBinaryData() const override; QByteArray GetBinaryData() override;
bool Load(const QString aFilePath) override; bool Load(const QString aFilePath) override;
bool Load(const QByteArray aData) override; bool Load(const QByteArray aData) override;

View File

@ -36,7 +36,7 @@ FastFile_COD11_PC::~FastFile_COD11_PC() {
} }
QByteArray FastFile_COD11_PC::GetBinaryData() const { QByteArray FastFile_COD11_PC::GetBinaryData() {
return QByteArray(); return QByteArray();
} }
@ -69,9 +69,9 @@ bool FastFile_COD11_PC::Load(const QString aFilePath) {
bool FastFile_COD11_PC::Load(const QByteArray aData) { bool FastFile_COD11_PC::Load(const QByteArray aData) {
QByteArray decompressedData; QByteArray decompressedData;
// Create a XDataStream on the input data. // Create a QDataStream on the input data.
XDataStream fastFileStream(aData); QDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::LittleEndian); fastFileStream.setByteOrder(QDataStream::LittleEndian);
// Parse header values. // Parse header values.
SetCompany(pParseFFCompany(&fastFileStream)); SetCompany(pParseFFCompany(&fastFileStream));
@ -80,11 +80,22 @@ bool FastFile_COD11_PC::Load(const QByteArray aData) {
SetMagic(pParseFFMagic(&fastFileStream)); SetMagic(pParseFFMagic(&fastFileStream));
quint32 version = pParseFFVersion(&fastFileStream); quint32 version = pParseFFVersion(&fastFileStream);
SetVersion(version); SetVersion(version);
SetPlatform(pCalculateFFPlatform(version));
SetGame("COD9");
fastFileStream.setByteOrder(XDataStream::LittleEndian); // For COD7/COD9, use BigEndian.
fastFileStream.setByteOrder(QDataStream::BigEndian);
if (GetPlatform() == "PC") {
fastFileStream.setByteOrder(QDataStream::LittleEndian);
}
// Select key based on game. // Select key based on game.
QByteArray key = QByteArray::fromHex("641D8A2FE31D3AA63622BBC9CE8587229D42B0F8ED9B924130BF88B65EDC50BE"); QByteArray key;
if (GetPlatform() == "360") {
key = QByteArray::fromHex("0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3");
} else if (GetPlatform() == "PC") {
key = QByteArray::fromHex("641D8A2FE31D3AA63622BBC9CE8587229D42B0F8ED9B924130BF88B65EDC50BE");
}
// Read the 8-byte magic. // Read the 8-byte magic.
QByteArray fileMagic(8, Qt::Uninitialized); QByteArray fileMagic(8, Qt::Uninitialized);
@ -103,7 +114,11 @@ bool FastFile_COD11_PC::Load(const QByteArray aData) {
QByteArray rsaSignature(256, Qt::Uninitialized); QByteArray rsaSignature(256, Qt::Uninitialized);
fastFileStream.readRawData(rsaSignature.data(), 256); fastFileStream.readRawData(rsaSignature.data(), 256);
//decompressedData = Encryption::decryptFastFile_BO2(aData); if (GetPlatform() == "360") {
//decompressedData = Compressor::cod9_decryptFastFile(aData);
} else if (GetPlatform() == "PC") {
decompressedData = Encryption::decryptFastFile_BO2(aData);
}
// For COD9, write out the complete decompressed zone for testing. // For COD9, write out the complete decompressed zone for testing.
QFile testFile("exports/" + GetBaseStem() + ".zone"); QFile testFile("exports/" + GetBaseStem() + ".zone");
@ -111,16 +126,12 @@ bool FastFile_COD11_PC::Load(const QByteArray aData) {
testFile.write(decompressedData); testFile.write(decompressedData);
testFile.close(); testFile.close();
} }
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
// Load the zone file with the decompressed data (using an Xbox platform flag). // Load the zone file with the decompressed data (using an Xbox platform flag).
ZoneFile_COD11_PC* zoneFile = new ZoneFile_COD11_PC(); ZoneFile_COD11_PC zoneFile;
zoneFile->SetStem(GetBaseStem() + ".zone"); zoneFile.SetStem(GetBaseStem() + ".zone");
if (!zoneFile->Load(decompressedData)) { zoneFile.Load(decompressedData);
qWarning() << "Failed to load ZoneFile!"; SetZoneFile(std::make_shared<ZoneFile_COD11_PC>(zoneFile));
return false;
}
SetZoneFile(zoneFile);
return true; return true;
} }

View File

@ -11,7 +11,7 @@ public:
FastFile_COD11_PC(const QString aFilePath); FastFile_COD11_PC(const QString aFilePath);
~FastFile_COD11_PC(); ~FastFile_COD11_PC();
QByteArray GetBinaryData() const override; QByteArray GetBinaryData() override;
bool Load(const QString aFilePath) override; bool Load(const QString aFilePath) override;
bool Load(const QByteArray aData) override; bool Load(const QByteArray aData) override;

View File

@ -39,7 +39,7 @@ FastFile_COD12_PC::~FastFile_COD12_PC() {
} }
QByteArray FastFile_COD12_PC::GetBinaryData() const { QByteArray FastFile_COD12_PC::GetBinaryData() {
return QByteArray(); return QByteArray();
} }
@ -72,9 +72,13 @@ bool FastFile_COD12_PC::Load(const QString aFilePath) {
bool FastFile_COD12_PC::Load(const QByteArray aData) { bool FastFile_COD12_PC::Load(const QByteArray aData) {
QByteArray decompressedData; QByteArray decompressedData;
// Create a XDataStream on the input data. // Create a QDataStream on the input data.
XDataStream fastFileStream(aData); QDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::LittleEndian); fastFileStream.setByteOrder(QDataStream::LittleEndian);
// Load the zone file with the decompressed data (using an Xbox platform flag).
ZoneFile_COD12_PC zoneFile;
zoneFile.SetStem(GetBaseStem() + ".zone");
// Skip header magic // Skip header magic
fastFileStream.skipRawData(8); fastFileStream.skipRawData(8);
@ -136,16 +140,12 @@ bool FastFile_COD12_PC::Load(const QByteArray aData) {
// Sinze Fast Files are aligns, we must skip the full block // Sinze Fast Files are aligns, we must skip the full block
fastFileStream.device()->seek(blockPosition + 16 + blockSize); fastFileStream.device()->seek(blockPosition + 16 + blockSize);
} }
Utils::ExportData(GetBaseStem() + ".zone", decompressedData); Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
// Load the zone file with the decompressed data (using an Xbox platform flag). zoneFile.Load(decompressedData);
ZoneFile_COD12_PC* zoneFile = new ZoneFile_COD12_PC();
zoneFile->SetStem(GetBaseStem() + ".zone"); SetZoneFile(std::make_shared<ZoneFile_COD12_PC>(zoneFile));
if (!zoneFile->Load(decompressedData)) {
qWarning() << "Failed to load ZoneFile!";
return false;
}
SetZoneFile(zoneFile);
return true; return true;
} }

View File

@ -11,7 +11,7 @@ public:
FastFile_COD12_PC(const QString aFilePath); FastFile_COD12_PC(const QString aFilePath);
~FastFile_COD12_PC(); ~FastFile_COD12_PC();
QByteArray GetBinaryData() const override; QByteArray GetBinaryData() override;
bool Load(const QString aFilePath) override; bool Load(const QString aFilePath) override;
bool Load(const QByteArray aData) override; bool Load(const QByteArray aData) override;

View File

@ -39,7 +39,7 @@ FastFile_COD4_PC::~FastFile_COD4_PC() {
} }
QByteArray FastFile_COD4_PC::GetBinaryData() const { QByteArray FastFile_COD4_PC::GetBinaryData() {
return QByteArray(); return QByteArray();
} }
@ -75,22 +75,19 @@ bool FastFile_COD4_PC::Load(const QByteArray aData) {
StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/data", 1000); StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/data", 1000);
QByteArray decompressedData; QByteArray decompressedData;
// Create a XDataStream on the input data. // Create a QDataStream on the input data.
XDataStream fastFileStream(aData); QDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::LittleEndian); fastFileStream.setByteOrder(QDataStream::LittleEndian);
// For COD5, simply decompress from offset 12. // For COD5, simply decompress from offset 12.
decompressedData = Compression::DecompressZLIB(aData.mid(12)); decompressedData = Compression::DecompressZLIB(aData.mid(12));
Utils::ExportData(GetBaseStem() + ".zone", decompressedData); Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
ZoneFile_COD4_PC* zoneFile = new ZoneFile_COD4_PC(); ZoneFile_COD4_PC zoneFile;
zoneFile->SetStem(GetBaseStem() + ".zone"); zoneFile.SetStem(GetBaseStem() + ".zone");
if (!zoneFile->Load(decompressedData)) { zoneFile.Load(decompressedData);
qWarning() << "Failed to load ZoneFile!"; SetZoneFile(std::make_shared<ZoneFile_COD4_PC>(zoneFile));
return false;
}
SetZoneFile(zoneFile);
return true; return true;
} }

View File

@ -11,7 +11,7 @@ public:
FastFile_COD4_PC(const QString aFilePath); FastFile_COD4_PC(const QString aFilePath);
~FastFile_COD4_PC(); ~FastFile_COD4_PC();
QByteArray GetBinaryData() const override; QByteArray GetBinaryData() override;
bool Load(const QString aFilePath) override; bool Load(const QString aFilePath) override;
bool Load(const QByteArray aData) override; bool Load(const QByteArray aData) override;

View File

@ -39,7 +39,7 @@ FastFile_COD5_PC::~FastFile_COD5_PC() {
} }
QByteArray FastFile_COD5_PC::GetBinaryData() const { QByteArray FastFile_COD5_PC::GetBinaryData() {
return QByteArray(); return QByteArray();
} }
@ -75,22 +75,19 @@ bool FastFile_COD5_PC::Load(const QByteArray aData) {
StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/data", 1000); StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/data", 1000);
QByteArray decompressedData; QByteArray decompressedData;
// Create a XDataStream on the input data. // Create a QDataStream on the input data.
XDataStream fastFileStream(aData); QDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::LittleEndian); fastFileStream.setByteOrder(QDataStream::LittleEndian);
// For COD5, simply decompress from offset 12. // For COD5, simply decompress from offset 12.
decompressedData = Compression::DecompressZLIB(aData.mid(12)); decompressedData = Compression::DecompressZLIB(aData.mid(12));
Utils::ExportData(GetBaseStem() + ".zone", decompressedData); Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
ZoneFile_COD5_PC* zoneFile = new ZoneFile_COD5_PC(); ZoneFile_COD5_PC zoneFile;
zoneFile->SetStem(GetBaseStem() + ".zone"); zoneFile.SetStem(GetBaseStem() + ".zone");
if (!zoneFile->Load(decompressedData)) { zoneFile.Load(decompressedData);
qWarning() << "Failed to load ZoneFile!"; SetZoneFile(std::make_shared<ZoneFile_COD5_PC>(zoneFile));
return false;
}
SetZoneFile(zoneFile);
return true; return true;
} }

View File

@ -11,7 +11,7 @@ public:
FastFile_COD5_PC(const QString aFilePath); FastFile_COD5_PC(const QString aFilePath);
~FastFile_COD5_PC(); ~FastFile_COD5_PC();
QByteArray GetBinaryData() const override; QByteArray GetBinaryData() override;
bool Load(const QString aFilePath) override; bool Load(const QString aFilePath) override;
bool Load(const QByteArray aData) override; bool Load(const QByteArray aData) override;

View File

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

View File

@ -11,7 +11,7 @@ public:
FastFile_COD6_PC(const QString aFilePath); FastFile_COD6_PC(const QString aFilePath);
~FastFile_COD6_PC(); ~FastFile_COD6_PC();
QByteArray GetBinaryData() const override; QByteArray GetBinaryData() override;
bool Load(const QString aFilePath) override; bool Load(const QString aFilePath) override;
bool Load(const QByteArray aData) override; bool Load(const QByteArray aData) override;

View File

@ -39,7 +39,7 @@ FastFile_COD7_PC::~FastFile_COD7_PC() {
} }
QByteArray FastFile_COD7_PC::GetBinaryData() const { QByteArray FastFile_COD7_PC::GetBinaryData() {
return QByteArray(); return QByteArray();
} }
@ -72,9 +72,9 @@ bool FastFile_COD7_PC::Load(const QString aFilePath) {
bool FastFile_COD7_PC::Load(const QByteArray aData) { bool FastFile_COD7_PC::Load(const QByteArray aData) {
QByteArray decompressedData; QByteArray decompressedData;
// Create a XDataStream on the input data. // Create a QDataStream on the input data.
XDataStream fastFileStream(aData); QDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::LittleEndian); fastFileStream.setByteOrder(QDataStream::LittleEndian);
// Parse header values. // Parse header values.
SetCompany(pParseFFCompany(&fastFileStream)); SetCompany(pParseFFCompany(&fastFileStream));
@ -83,22 +83,88 @@ bool FastFile_COD7_PC::Load(const QByteArray aData) {
SetMagic(pParseFFMagic(&fastFileStream)); SetMagic(pParseFFMagic(&fastFileStream));
quint32 version = pParseFFVersion(&fastFileStream); quint32 version = pParseFFVersion(&fastFileStream);
SetVersion(version); SetVersion(version);
SetPlatform("360"); SetPlatform(pCalculateFFPlatform(version));
SetGame("COD7"); SetGame("COD7");
// Assume the first 12 bytes are a header; the rest is zlib-compressed zone data. // Load the zone file with the decompressed data (using an Xbox platform flag).
const QByteArray compressedData = aData.mid(12); ZoneFile_COD7_PC zoneFile;
decompressedData = Compression::DecompressZLIB(compressedData); zoneFile.SetStem(GetBaseStem() + ".zone");
Utils::ExportData(GetBaseStem() + ".zone", decompressedData); // For COD7/COD9, use BigEndian.
fastFileStream.setByteOrder(QDataStream::LittleEndian);
ZoneFile_COD7_PC* zoneFile = new ZoneFile_COD7_PC(); // Select key based on game.
zoneFile->SetStem(GetBaseStem() + ".zone"); QByteArray key;
if (!zoneFile->Load(decompressedData)) { fastFileStream.skipRawData(4);
qWarning() << "Failed to load ZoneFile!"; 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; return false;
} }
SetZoneFile(zoneFile); fastFileStream.skipRawData(4);
// Read IV table name (32 bytes).
QByteArray fileName(32, Qt::Uninitialized);
fastFileStream.readRawData(fileName.data(), 32);
// Build the IV table from the fileName.
QByteArray ivTable = Encryption::InitIVTable(fileName);
// Skip the RSA signature (256 bytes).
QByteArray rsaSignature(256, Qt::Uninitialized);
fastFileStream.readRawData(rsaSignature.data(), 256);
// Now the stream should be positioned at 0x13C, where sections begin.
int sectionIndex = 0;
while (true) {
qint32 sectionSize = 0;
fastFileStream >> sectionSize;
qDebug() << "Section index:" << sectionIndex << "Size:" << sectionSize
<< "Pos:" << fastFileStream.device()->pos();
if (sectionSize == 0)
break;
// Read the section data.
QByteArray sectionData;
sectionData.resize(sectionSize);
fastFileStream.readRawData(sectionData.data(), sectionSize);
// Compute the IV for this section.
QByteArray iv = Encryption::GetIV(ivTable, sectionIndex);
// Decrypt the section using Salsa20.
QByteArray decData = Encryption::salsa20DecryptSection(sectionData, key, iv);
// Compute SHA1 hash of the decrypted data.
QByteArray sectionHash = QCryptographicHash::hash(decData, QCryptographicHash::Sha1);
// Update the IV table based on the section hash.
Encryption::UpdateIVTable(ivTable, sectionIndex, sectionHash);
// Build a compressed data buffer by prepending the two-byte zlib header.
QByteArray compressedData;
compressedData.append(char(0x78));
compressedData.append(char(0x01));
compressedData.append(decData);
decompressedData.append(Compression::DecompressZLIB(compressedData));
sectionIndex++;
}
zoneFile.Load(decompressedData);
SetZoneFile(std::make_shared<ZoneFile_COD7_PC>(zoneFile));
return true; return true;
} }

View File

@ -11,7 +11,7 @@ public:
FastFile_COD7_PC(const QString aFilePath); FastFile_COD7_PC(const QString aFilePath);
~FastFile_COD7_PC(); ~FastFile_COD7_PC();
QByteArray GetBinaryData() const override; QByteArray GetBinaryData() override;
bool Load(const QString aFilePath) override; bool Load(const QString aFilePath) override;
bool Load(const QByteArray aData) override; bool Load(const QByteArray aData) override;

View File

@ -39,7 +39,7 @@ FastFile_COD8_PC::~FastFile_COD8_PC() {
} }
QByteArray FastFile_COD8_PC::GetBinaryData() const { QByteArray FastFile_COD8_PC::GetBinaryData() {
return QByteArray(); return QByteArray();
} }
@ -72,27 +72,99 @@ bool FastFile_COD8_PC::Load(const QString aFilePath) {
bool FastFile_COD8_PC::Load(const QByteArray aData) { bool FastFile_COD8_PC::Load(const QByteArray aData) {
QByteArray decompressedData; QByteArray decompressedData;
// Create a XDataStream on the input data. // Create a QDataStream on the input data.
XDataStream fastFileStream(aData); QDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::LittleEndian); fastFileStream.setByteOrder(QDataStream::LittleEndian);
// Parse header values. // Parse header values.
SetCompany(pParseFFCompany(&fastFileStream)); SetCompany(pParseFFCompany(&fastFileStream));
SetType(pParseFFFileType(&fastFileStream)); SetType(pParseFFFileType(&fastFileStream));
SetSignage(pParseFFSignage(&fastFileStream)); SetSignage(pParseFFSignage(&fastFileStream));
SetMagic(pParseFFMagic(&fastFileStream)); SetMagic(pParseFFMagic(&fastFileStream));
SetVersion(pParseFFVersion(&fastFileStream)); quint32 version = pParseFFVersion(&fastFileStream);
SetVersion(version);
SetPlatform(pCalculateFFPlatform(version));
SetGame("COD7");
decompressedData = Compression::DecompressZLIB(aData.mid(21)); // Load the zone file with the decompressed data (using an Xbox platform flag).
Utils::ExportData(GetBaseStem() + ".zone", decompressedData); ZoneFile_COD8_PC zoneFile;
zoneFile.SetStem(GetBaseStem() + ".zone");
ZoneFile_COD8_PC* zoneFile = new ZoneFile_COD8_PC(); // For COD7/COD9, use BigEndian.
zoneFile->SetStem(GetBaseStem() + ".zone"); fastFileStream.setByteOrder(QDataStream::LittleEndian);
if (!zoneFile->Load(decompressedData)) {
qWarning() << "Failed to load ZoneFile!"; // 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; return false;
} }
SetZoneFile(zoneFile); fastFileStream.skipRawData(4);
// Read IV table name (32 bytes).
QByteArray fileName(32, Qt::Uninitialized);
fastFileStream.readRawData(fileName.data(), 32);
// Build the IV table from the fileName.
QByteArray ivTable = Encryption::InitIVTable(fileName);
// Skip the RSA signature (256 bytes).
QByteArray rsaSignature(256, Qt::Uninitialized);
fastFileStream.readRawData(rsaSignature.data(), 256);
// Now the stream should be positioned at 0x13C, where sections begin.
int sectionIndex = 0;
while (true) {
qint32 sectionSize = 0;
fastFileStream >> sectionSize;
qDebug() << "Section index:" << sectionIndex << "Size:" << sectionSize
<< "Pos:" << fastFileStream.device()->pos();
if (sectionSize == 0)
break;
// Read the section data.
QByteArray sectionData;
sectionData.resize(sectionSize);
fastFileStream.readRawData(sectionData.data(), sectionSize);
// Compute the IV for this section.
QByteArray iv = Encryption::GetIV(ivTable, sectionIndex);
// Decrypt the section using Salsa20.
QByteArray decData = Encryption::salsa20DecryptSection(sectionData, key, iv);
// Compute SHA1 hash of the decrypted data.
QByteArray sectionHash = QCryptographicHash::hash(decData, QCryptographicHash::Sha1);
// Update the IV table based on the section hash.
Encryption::UpdateIVTable(ivTable, sectionIndex, sectionHash);
// Build a compressed data buffer by prepending the two-byte zlib header.
QByteArray compressedData;
compressedData.append(char(0x78));
compressedData.append(char(0x01));
compressedData.append(decData);
decompressedData.append(Compression::DecompressZLIB(compressedData));
sectionIndex++;
}
zoneFile.Load(decompressedData);
SetZoneFile(std::make_shared<ZoneFile_COD8_PC>(zoneFile));
return true; return true;
} }

View File

@ -11,7 +11,7 @@ public:
FastFile_COD8_PC(const QString aFilePath); FastFile_COD8_PC(const QString aFilePath);
~FastFile_COD8_PC(); ~FastFile_COD8_PC();
QByteArray GetBinaryData() const override; QByteArray GetBinaryData() override;
bool Load(const QString aFilePath) override; bool Load(const QString aFilePath) override;
bool Load(const QByteArray aData) override; bool Load(const QByteArray aData) override;

View File

@ -36,7 +36,7 @@ FastFile_COD9_PC::~FastFile_COD9_PC() {
} }
QByteArray FastFile_COD9_PC::GetBinaryData() const { QByteArray FastFile_COD9_PC::GetBinaryData() {
return QByteArray(); return QByteArray();
} }
@ -67,18 +67,37 @@ bool FastFile_COD9_PC::Load(const QString aFilePath) {
} }
bool FastFile_COD9_PC::Load(const QByteArray aData) { bool FastFile_COD9_PC::Load(const QByteArray aData) {
// Create a XDataStream on the input data. QByteArray decompressedData;
XDataStream fastFileStream(aData);
fastFileStream.setByteOrder(XDataStream::LittleEndian); // Create a QDataStream on the input data.
QDataStream fastFileStream(aData);
fastFileStream.setByteOrder(QDataStream::LittleEndian);
// Parse header values. // Parse header values.
SetCompany(pParseFFCompany(&fastFileStream)); SetCompany(pParseFFCompany(&fastFileStream));
SetType(pParseFFFileType(&fastFileStream)); SetType(pParseFFFileType(&fastFileStream));
SetSignage(pParseFFSignage(&fastFileStream)); SetSignage(pParseFFSignage(&fastFileStream));
SetMagic(pParseFFMagic(&fastFileStream)); SetMagic(pParseFFMagic(&fastFileStream));
SetVersion(pParseFFVersion(&fastFileStream)); quint32 version = pParseFFVersion(&fastFileStream);
SetVersion(version);
SetPlatform(pCalculateFFPlatform(version));
SetGame("COD9");
// Validate the fastfile magic. // For COD7/COD9, use BigEndian.
fastFileStream.setByteOrder(QDataStream::BigEndian);
if (GetPlatform() == "PC") {
fastFileStream.setByteOrder(QDataStream::LittleEndian);
}
// Select key based on game.
QByteArray key;
if (GetPlatform() == "360") {
key = QByteArray::fromHex("0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3");
} else if (GetPlatform() == "PC") {
key = QByteArray::fromHex("641D8A2FE31D3AA63622BBC9CE8587229D42B0F8ED9B924130BF88B65EDC50BE");
}
// Read the 8-byte magic.
QByteArray fileMagic(8, Qt::Uninitialized); QByteArray fileMagic(8, Qt::Uninitialized);
fastFileStream.readRawData(fileMagic.data(), 8); fastFileStream.readRawData(fileMagic.data(), 8);
if (fileMagic != "PHEEBs71") { if (fileMagic != "PHEEBs71") {
@ -87,100 +106,32 @@ bool FastFile_COD9_PC::Load(const QByteArray aData) {
} }
fastFileStream.skipRawData(4); fastFileStream.skipRawData(4);
// Read IV seed name (32 bytes). // Read IV table name (32 bytes).
QByteArray nameKey(32, Qt::Uninitialized); QByteArray fileName(32, Qt::Uninitialized);
fastFileStream.readRawData(nameKey.data(), 32); fastFileStream.readRawData(fileName.data(), 32);
// --- Salsa20 + IV setup --- // Skip the RSA signature (256 bytes).
static QVector<quint32> ivCounter(4, 1); QByteArray rsaSignature(256, Qt::Uninitialized);
QByteArray ivTable = Encryption::InitIVTable(nameKey); fastFileStream.readRawData(rsaSignature.data(), 256);
ivCounter.fill(1); // reset global counters
// Skip RSA signature (0x100) if (GetPlatform() == "360") {
fastFileStream.skipRawData(0x100); //decompressedData = Compressor::cod9_decryptFastFile(aData);
} else if (GetPlatform() == "PC") {
// Decrypt + decompress loop decompressedData = Encryption::decryptFastFile_BO2(aData);
QByteArray finalZone;
int chunkIndex = 0;
while (!fastFileStream.atEnd()) {
quint32 dataLength = 0;
fastFileStream >> dataLength;
if (dataLength == 0)
break;
QByteArray encryptedBlock(dataLength, Qt::Uninitialized);
if (fastFileStream.readRawData(encryptedBlock.data(), dataLength) != dataLength) {
qWarning() << "Unexpected EOF while reading block";
break;
} }
// Derive IV for this chunk // For COD9, write out the complete decompressed zone for testing.
QByteArray iv = Encryption::GetIV(ivTable, chunkIndex % 4); QFile testFile("exports/" + GetBaseStem() + ".zone");
if(testFile.open(QIODevice::WriteOnly)) {
// Salsa20 decryption testFile.write(decompressedData);
QByteArray decryptedBlock = Encryption::salsa20DecryptSection( testFile.close();
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; // Load the zone file with the decompressed data (using an Xbox platform flag).
if (have > 0) ZoneFile_COD9_PC zoneFile;
decompressedData.append(buffer.constData(), have); zoneFile.SetStem(GetBaseStem() + ".zone");
zoneFile.Load(decompressedData);
} while (ret != Z_STREAM_END); SetZoneFile(std::make_shared<ZoneFile_COD9_PC>(zoneFile));
inflateEnd(&strm);
finalZone.append(decompressedData);
// Update IV table for next block
Encryption::UpdateIVTable(ivTable, chunkIndex % 4, sha1Hash);
chunkIndex++;
}
// Export decompressed zone
Utils::ExportData(GetBaseStem() + ".zone", finalZone);
// Load zone file
ZoneFile_COD9_PC* zoneFile = new ZoneFile_COD9_PC();
zoneFile->SetStem(GetBaseStem() + ".zone");
if (!zoneFile->Load(finalZone)) {
qWarning() << "Failed to load ZoneFile!";
return false;
}
SetZoneFile(zoneFile);
return true;
return true; return true;
} }

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