Feature: Implement MxHd type

This commit is contained in:
itsmattkc 2022-06-24 10:46:25 -07:00
parent 6442e5d513
commit 4f7b4eead4
12 changed files with 334 additions and 3 deletions

View file

@ -4,6 +4,11 @@ find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets)
set(PROJECT_SOURCES
panels/mxhd.cpp
panels/mxhd.h
panels/panel.cpp
panels/panel.h
chunkmodel.cpp
chunkmodel.h
main.cpp

View file

@ -7,9 +7,11 @@
#include <QTreeWidget>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow{parent}
QMainWindow{parent},
last_set_data_(nullptr)
{
auto splitter = new QSplitter();
splitter->setChildrenCollapsible(false);
this->setCentralWidget(splitter);
model_.SetChunk(&chunk_);
@ -17,8 +19,20 @@ MainWindow::MainWindow(QWidget *parent) :
auto tree = new QTreeView();
tree->setModel(&model_);
splitter->addWidget(tree);
connect(tree->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &MainWindow::SelectionChanged);
config_stack_ = new QStackedWidget();
splitter->addWidget(config_stack_);
panel_blank_ = new Panel();
config_stack_->addWidget(panel_blank_);
panel_mxhd_ = new MxHdPanel();
config_stack_->addWidget(panel_mxhd_);
InitializeMenuBar();
splitter->setSizes({99999, 99999});
}
void MainWindow::InitializeMenuBar()
@ -40,11 +54,48 @@ void MainWindow::InitializeMenuBar()
setMenuBar(menubar);
}
void MainWindow::SetPanel(Panel *panel, Data *data)
{
auto current = static_cast<Panel*>(config_stack_->currentWidget());
current->SetData(nullptr);
config_stack_->setCurrentWidget(panel);
panel->SetData(data);
last_set_data_ = data;
}
void MainWindow::OpenFile()
{
QString s = QFileDialog::getOpenFileName(this, QString(), QString(), tr("Interleaf Files (*.si)"));
if (!s.isEmpty()) {
model_.SetChunk(nullptr);
SetPanel(panel_blank_, nullptr);
chunk_.Read(s.toStdString());
model_.SetChunk(&chunk_);
}
}
void MainWindow::SelectionChanged(const QModelIndex &index)
{
Panel *panel_to_set = panel_blank_;
Data *data = nullptr;
if (Chunk *c = static_cast<Chunk*>(index.internalPointer())) {
data = c->data();
switch (c->type()) {
case Chunk::MxHd:
panel_to_set = panel_mxhd_;
break;
case Chunk::RIFF:
case Chunk::LIST:
case Chunk::MxSt:
case Chunk::pad_:
break;
}
}
if (panel_to_set != config_stack_->currentWidget() || data != last_set_data_) {
SetPanel(panel_to_set, data);
}
}

View file

@ -3,8 +3,11 @@
#include <chunk.h>
#include <QMainWindow>
#include <QStackedWidget>
#include "chunkmodel.h"
#include "panels/mxhd.h"
#include "panels/panel.h"
class MainWindow : public QMainWindow
{
@ -19,14 +22,25 @@ private:
void InitializeMenuBar();
void SetPanel(Panel *panel, Data *data);
ChunkModel model_;
Chunk chunk_;
QStackedWidget *config_stack_;
Panel *panel_blank_;
MxHdPanel *panel_mxhd_;
Data *last_set_data_;
private slots:
void OpenFile();
//bool SaveFile();
//bool SaveFileAs();
void SelectionChanged(const QModelIndex &index);
};
#endif // MAINWINDOW_H

74
app/panels/mxhd.cpp Normal file
View file

@ -0,0 +1,74 @@
#include "mxhd.h"
#include <QGridLayout>
#include <QLabel>
MxHdPanel::MxHdPanel(QWidget *parent)
: Panel{parent}
{
auto outer = new QVBoxLayout(this);
auto layout = new QGridLayout();
outer->addLayout(layout);
int row = 0;
auto version_layout = new QHBoxLayout();
layout->addLayout(version_layout, row, 0, 1, 2);
version_layout->addWidget(new QLabel(tr("Major Version")));
major_version_edit_ = new QSpinBox();
major_version_edit_->setMinimum(0);
major_version_edit_->setMaximum(UINT16_MAX);
version_layout->addWidget(major_version_edit_);
version_layout->addWidget(new QLabel(tr("Minor Version")));
minor_version_edit_ = new QSpinBox();
minor_version_edit_->setMinimum(0);
minor_version_edit_->setMaximum(UINT16_MAX);
version_layout->addWidget(minor_version_edit_);
row++;
layout->addWidget(new QLabel(tr("Buffer Alignment")), row, 0);
buffer_alignment_edit_ = new QSpinBox();
buffer_alignment_edit_->setMinimum(0);
buffer_alignment_edit_->setMaximum(INT_MAX); // Technically this is UINT32_MAX but QSpinBox only supports int
layout->addWidget(buffer_alignment_edit_, row, 1);
row++;
layout->addWidget(new QLabel(tr("Buffer Count")), row, 0);
buffer_count_edit_ = new QSpinBox();
buffer_count_edit_->setMinimum(0);
buffer_count_edit_->setMaximum(INT_MAX); // Technically this is UINT32_MAX but QSpinBox only supports int
layout->addWidget(buffer_count_edit_, row, 1);
outer->addStretch();
}
void MxHdPanel::OnOpeningData(Data *data)
{
MxHd *mxhd = static_cast<MxHd *>(data);
uint16_t major_ver = mxhd->dwVersion >> 16;
uint16_t minor_ver = mxhd->dwVersion;
major_version_edit_->setValue(major_ver);
minor_version_edit_->setValue(minor_ver);
buffer_alignment_edit_->setValue(mxhd->dwBufferSize);
buffer_count_edit_->setValue(mxhd->dwBufferCount);
}
void MxHdPanel::OnClosingData(Data *data)
{
MxHd *mxhd = static_cast<MxHd *>(data);
mxhd->dwVersion = (major_version_edit_->value() << 16 | (minor_version_edit_->value() & 0xFFFF));
mxhd->dwBufferSize = buffer_alignment_edit_->value();
mxhd->dwBufferCount = buffer_count_edit_->value();
}

32
app/panels/mxhd.h Normal file
View file

@ -0,0 +1,32 @@
#ifndef MXHDPANEL_H
#define MXHDPANEL_H
#include <data/mxhd.h>
#include <QLineEdit>
#include <QSpinBox>
#include "panel.h"
class MxHdPanel : public Panel
{
Q_OBJECT
public:
explicit MxHdPanel(QWidget *parent = nullptr);
signals:
protected:
virtual void OnOpeningData(Data *data) override;
virtual void OnClosingData(Data *data) override;
private:
QSpinBox *major_version_edit_;
QSpinBox *minor_version_edit_;
QSpinBox *buffer_alignment_edit_;
QSpinBox *buffer_count_edit_;
};
#endif // MXHDPANEL_H

21
app/panels/panel.cpp Normal file
View file

@ -0,0 +1,21 @@
#include "panel.h"
Panel::Panel(QWidget *parent)
: QWidget{parent},
data_(nullptr)
{
}
void Panel::SetData(Data *data)
{
if (data_) {
OnClosingData(data_);
}
data_ = data;
if (data_) {
OnOpeningData(data_);
}
}

27
app/panels/panel.h Normal file
View file

@ -0,0 +1,27 @@
#ifndef PANEL_H
#define PANEL_H
#include <data/data.h>
#include <QWidget>
class Panel : public QWidget
{
Q_OBJECT
public:
explicit Panel(QWidget *parent = nullptr);
Data *GetData() const { return data_; }
void SetData(Data *data);
signals:
protected:
virtual void OnOpeningData(Data *data){}
virtual void OnClosingData(Data *data){}
private:
Data *data_;
};
#endif // PANEL_H

View file

@ -1,9 +1,13 @@
add_library(libweaver SHARED
option(LIBWEAVER_BUILD_DOXYGEN "Build Doxygen documentation" OFF)
set(LIBWEAVER_SOURCES
# Data types
data/data.cpp
data/data.h
data/generic.cpp
data/generic.h
data/mxhd.cpp
data/mxhd.h
data/mxst.cpp
data/mxst.h
data/riff.cpp
@ -18,8 +22,21 @@ add_library(libweaver SHARED
types.h
)
add_library(libweaver SHARED
${LIBWEAVER_SOURCES}
)
target_compile_definitions(libweaver PRIVATE LIBWEAVER_LIBRARY)
set_target_properties(libweaver PROPERTIES
CXX_STANDARD 98
CXX_STANDARD_REQUIRED ON
)
if(LIBWEAVER_BUILD_DOXYGEN)
find_package(Doxygen)
set(DOXYGEN_PROJECT_NAME "libweaver")
set(DOXYGEN_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/docs")
set(DOXYGEN_EXTRACT_ALL "YES")
set(DOXYGEN_EXTRACT_PRIVATE "YES")
doxygen_add_docs(docs ALL ${LIBWEAVER_SOURCES})
endif()

View file

@ -4,6 +4,7 @@
#include <iostream>
#include "data/generic.h"
#include "data/mxhd.h"
#include "data/mxst.h"
#include "data/riff.h"
@ -140,6 +141,10 @@ Data *Chunk::CreateDataFromID(u32 id)
return new RIFFData();
case MxSt:
return new MxStData();
case MxHd:
return new ::MxHd();
case pad_:
return new GenericData();
}
return new GenericData();
@ -154,6 +159,10 @@ const char *Chunk::GetTypeDescription(Type type)
return "List of sub-elements";
case MxSt:
return "MxStreamer";
case MxHd:
return "Interleaf Header";
case pad_:
return "Padding";
}
return "Unknown";

View file

@ -14,7 +14,9 @@ public:
{
RIFF = 0x46464952,
LIST = 0x5453494c,
MxSt = 0x7453784d
MxSt = 0x7453784d,
MxHd = 0x6448784d,
pad_ = 0x20646170
};
Chunk();
@ -39,6 +41,7 @@ public:
Type type() const { return static_cast<Type>(id_); }
const u32 &id() const { return id_; }
Data *data() const { return data_; }
static Data *CreateDataFromID(u32 id);

22
lib/data/mxhd.cpp Normal file
View file

@ -0,0 +1,22 @@
#include "mxhd.h"
MxHd::MxHd()
{
}
void MxHd::Read(std::ifstream &f, u32 sz)
{
// Read version information
f.read((char *) &dwVersion, sizeof(dwVersion));
if (dwVersion == 0x00010000) { // 1.0
// This MxHd is only 8 bytes long
// FIXME: Not actually sure yet what the second 4 bytes are for, so we just read them into here
f.read((char *) &dwBufferSize, sizeof(dwBufferSize));
} else {
// Version 2.2 has buffer size and buffer count, known due to the leaked .SS files on Korean
f.read((char *) &dwBufferSize, sizeof(dwBufferSize));
f.read((char *) &dwBufferCount, sizeof(dwBufferCount));
}
}

56
lib/data/mxhd.h Normal file
View file

@ -0,0 +1,56 @@
#ifndef MXHDDATA_H
#define MXHDDATA_H
#include "data.h"
/**
* @brief The main header section of an Interleaf file.
*
* MxHd is generally the first section to appear in an Interleaf file. It contains information
* about the file as a whole, including version information and settings for how the file should
* be streamed.
*/
class MxHd : public Data
{
public:
MxHd();
virtual void Read(std::ifstream &f, u32 sz);
/**
* @brief The version of this Interleaf file.
*
* This is stored as two 16-bit words inside a 32-bit dword - the high word being the major
* version and the low word being the minor version.
*
* If the version is 0x00010000, as it is in Warhammer: Shadow of the Horned Rat and early builds
* of LEGO Island, the resulting version is 1.0. If the version is 0x00020002, as it is in the
* retail release of LEGO Island, the resulting version number is 2.2.
*/
u32 dwVersion;
/**
* @brief The amount of data to read from disk at a time
*
* MxStreamer will read data from the file in chunks of this size. This means all sections of the
* file must be aligned around multiples of this number, i.e. a section starting before a multiple
* of this number must either end before it if possible, or padding should be used to make it
* start immediately on one. If dwBufferSize is 0x20000, sections must not cross 0x20000, 0x40000,
* 0x60000, 0x80000, etc. If a section does, it will cause an out of bounds read as the game
* tries to read past the buffer that it's allocated and read into.
*/
u32 dwBufferSize;
/**
* @brief Buffer number
*
* It is currently not known exactly what this value does. Source .SS files leaked on the Korean
* ISO call it "buffersNum", implying it's the number of buffers to read at a time (in tandem with
* dwBufferSize), however that behavior has not been tested yet. This field also does not exist
* on version 1.0 SI files.
*/
u32 dwBufferCount;
};
#endif // MXHDDATA_H