From ef5d9a006096b520500af3ee762e476672cf9d29 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sun, 3 Jul 2022 10:57:43 -0500 Subject: [PATCH] use abstract data storage --- app/chunkmodel.cpp | 1 - app/panels/mxch.cpp | 26 +++--- app/panels/mxhd.cpp | 20 ++--- app/panels/mxob.cpp | 18 ++-- app/panels/mxof.cpp | 11 ++- app/panels/riff.cpp | 9 +- lib/CMakeLists.txt | 14 +--- lib/bytearray.cpp | 27 ------ lib/bytearray.h | 24 ------ lib/chunk.cpp | 171 ++++---------------------------------- lib/chunk.h | 49 +++++------ lib/data/mxch.h | 19 ----- lib/data/mxhd.h | 54 ------------ lib/data/mxob.cpp | 27 ------ lib/data/mxob.h | 176 ---------------------------------------- lib/data/mxof.h | 16 ---- lib/data/mxst.h | 20 ----- lib/data/riff.h | 21 ----- lib/sitypes.cpp | 176 ++++++++++++++++++++++++++++++++++++++++ lib/sitypes.h | 194 ++++++++++++++++++++++++++++++++++++++++++++ lib/types.h | 96 ++++++++++++++++++++++ 21 files changed, 543 insertions(+), 626 deletions(-) delete mode 100644 lib/bytearray.cpp delete mode 100644 lib/bytearray.h delete mode 100644 lib/data/mxch.h delete mode 100644 lib/data/mxhd.h delete mode 100644 lib/data/mxob.cpp delete mode 100644 lib/data/mxob.h delete mode 100644 lib/data/mxof.h delete mode 100644 lib/data/mxst.h delete mode 100644 lib/data/riff.h create mode 100644 lib/sitypes.cpp create mode 100644 lib/sitypes.h diff --git a/app/chunkmodel.cpp b/app/chunkmodel.cpp index f1f5f42..87847e6 100644 --- a/app/chunkmodel.cpp +++ b/app/chunkmodel.cpp @@ -1,6 +1,5 @@ #include "chunkmodel.h" -#include #include #define super QAbstractItemModel diff --git a/app/panels/mxch.cpp b/app/panels/mxch.cpp index fd6adb1..e84475f 100644 --- a/app/panels/mxch.cpp +++ b/app/panels/mxch.cpp @@ -1,6 +1,5 @@ #include "mxch.h" -#include #include #include #include @@ -83,34 +82,31 @@ MxChPanel::MxChPanel(QWidget *parent) : void MxChPanel::OnOpeningData(Chunk *chunk) { - MxCh *mxch = chunk->data().cast(); - - flag_edit_->setText(QString::number(mxch->wFlags, 16)); - obj_edit_->setValue(mxch->dwObjectParent); - ms_offset_edit_->setValue(mxch->dwMillisecondOffset); - data_sz_edit_->setValue(mxch->dwDataSize); + flag_edit_->setText(QString::number(chunk->data("Flags"), 16)); + obj_edit_->setValue(chunk->data("Object")); + ms_offset_edit_->setValue(chunk->data("Time")); + data_sz_edit_->setValue(chunk->data("DataSize")); for (QCheckBox *cb : qAsConst(flag_checkboxes_)) { - cb->setChecked(cb->property("flag").toUInt() & mxch->wFlags); + cb->setChecked(cb->property("flag").toUInt() & chunk->data("Flags")); } - QByteArray ba((const char*) chunk->exdata().data(), chunk->exdata().size()); + const Data &data = chunk->data("Data"); + QByteArray ba(data.data(), data.size()); data_edit_->setPlainText(ba.toHex()); } void MxChPanel::OnClosingData(Chunk *chunk) { - MxCh *mxch = chunk->data().cast(); - bool ok; u16 flags = flag_edit_->text().toUShort(&ok, 16); if (ok) { - mxch->wFlags = flags; + chunk->data("Flags") = flags; } - mxch->dwObjectParent = obj_edit_->value(); - mxch->dwMillisecondOffset = ms_offset_edit_->value(); - mxch->dwDataSize = data_sz_edit_->value(); + chunk->data("Object") = u32(obj_edit_->value()); + chunk->data("Time") = u32(ms_offset_edit_->value()); + chunk->data("DataSize") = u32(data_sz_edit_->value()); } void MxChPanel::FlagCheckBoxClicked(bool e) diff --git a/app/panels/mxhd.cpp b/app/panels/mxhd.cpp index 7a18b7d..347ca6c 100644 --- a/app/panels/mxhd.cpp +++ b/app/panels/mxhd.cpp @@ -1,6 +1,5 @@ #include "mxhd.h" -#include #include using namespace si; @@ -50,22 +49,19 @@ MxHdPanel::MxHdPanel(QWidget *parent) void MxHdPanel::OnOpeningData(Chunk *chunk) { - MxHd *mxhd = chunk->data().cast(); - - uint16_t major_ver = mxhd->dwVersion >> 16; - uint16_t minor_ver = mxhd->dwVersion; + si::u32 version = chunk->data("Version"); + uint16_t major_ver = version >> 16; + uint16_t minor_ver = version; major_version_edit_->setValue(major_ver); minor_version_edit_->setValue(minor_ver); - buffer_alignment_edit_->setValue(mxhd->dwBufferSize); - buffer_count_edit_->setValue(mxhd->dwBufferCount); + buffer_alignment_edit_->setValue(chunk->data("BufferSize")); + buffer_count_edit_->setValue(chunk->data("BufferCount")); } void MxHdPanel::OnClosingData(Chunk *chunk) { - MxHd *mxhd = chunk->data().cast(); - - mxhd->dwVersion = (major_version_edit_->value() << 16 | (minor_version_edit_->value() & 0xFFFF)); - mxhd->dwBufferSize = buffer_alignment_edit_->value(); - mxhd->dwBufferCount = buffer_count_edit_->value(); + chunk->data("Version") = (major_version_edit_->value() << 16 | (minor_version_edit_->value() & 0xFFFF)); + chunk->data("BufferSize") = buffer_alignment_edit_->value(); + chunk->data("BufferCount") = buffer_count_edit_->value(); } diff --git a/app/panels/mxob.cpp b/app/panels/mxob.cpp index cacb074..ba96197 100644 --- a/app/panels/mxob.cpp +++ b/app/panels/mxob.cpp @@ -1,6 +1,6 @@ #include "mxob.h" -#include +#include #include using namespace si; @@ -53,18 +53,14 @@ MxObPanel::MxObPanel(QWidget *parent) : void MxObPanel::OnOpeningData(si::Chunk *chunk) { - auto mxob = chunk->data().cast(); - - type_combo_->setCurrentIndex(mxob->wType); - name_edit_->setText(mxob->szName); - filename_edit_->setText(mxob->szFilename); - presenter_edit_->setText(mxob->szPresenter); - obj_id_edit_->setValue(mxob->dwObjectID); + type_combo_->setCurrentIndex(chunk->data("Type")); + name_edit_->setText(QString(chunk->data("Name"))); + filename_edit_->setText(QString(chunk->data("FileName"))); + presenter_edit_->setText(QString(chunk->data("Presenter"))); + obj_id_edit_->setValue(chunk->data("ID")); } void MxObPanel::OnClosingData(si::Chunk *chunk) { - auto mxob = chunk->data().cast(); - - mxob->wType = type_combo_->currentIndex(); + chunk->data("Type") = type_combo_->currentIndex(); } diff --git a/app/panels/mxof.cpp b/app/panels/mxof.cpp index b1acda9..ed841fc 100644 --- a/app/panels/mxof.cpp +++ b/app/panels/mxof.cpp @@ -1,6 +1,5 @@ #include "mxof.h" -#include #include using namespace si; @@ -27,13 +26,13 @@ MxOfPanel::MxOfPanel(QWidget *parent) : void MxOfPanel::OnOpeningData(si::Chunk *chunk) { - u32 *offsets = reinterpret_cast(chunk->exdata().data()); - size_t count = chunk->exdata().size() / sizeof(u32); + const Data &offsets_bytes = chunk->data("Offsets"); + const u32 *offsets = reinterpret_cast(offsets_bytes.data()); + size_t offset_count = offsets_bytes.size() / sizeof(u32); - MxOf *mxof = chunk->data().cast(); - obj_count_edit_->setValue(mxof->dwObjectCount); + obj_count_edit_->setValue(chunk->data("Count")); - for (size_t i=0; iaddItem(QStringLiteral("%1: %2").arg(QString::number(i), addr)); diff --git a/app/panels/riff.cpp b/app/panels/riff.cpp index b78d9ac..28b5d68 100644 --- a/app/panels/riff.cpp +++ b/app/panels/riff.cpp @@ -1,6 +1,5 @@ #include "riff.h" -#include #include using namespace si; @@ -21,16 +20,12 @@ RIFFPanel::RIFFPanel(QWidget *parent) : void RIFFPanel::OnOpeningData(Chunk *chunk) { - RIFF *riff = chunk->data().cast(); - - QString s = QString::fromLatin1((const char *) &riff->dwID, sizeof(u32)); + QString s = QString::fromLatin1(chunk->data("Format").c_str(), sizeof(u32)); id_edit_->setText(s); } void RIFFPanel::OnClosingData(Chunk *chunk) { - RIFF *riff = chunk->data().cast(); - QByteArray d = id_edit_->text().toLatin1(); const int target_sz = sizeof(u32); @@ -43,5 +38,5 @@ void RIFFPanel::OnClosingData(Chunk *chunk) } } - riff->dwID = *(u32*)d.data(); + chunk->data("Format") = *(u32*)d.data(); } diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 74c23ca..0b9a7e0 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -1,21 +1,11 @@ option(LIBWEAVER_BUILD_DOXYGEN "Build Doxygen documentation" OFF) set(LIBWEAVER_SOURCES - # Data types - data/mxch.h - data/mxhd.h - data/mxob.cpp - data/mxob.h - data/mxof.h - data/mxst.h - data/riff.h - - # Main library - bytearray.cpp - bytearray.h chunk.cpp chunk.h common.h + sitypes.cpp + sitypes.h types.h ) diff --git a/lib/bytearray.cpp b/lib/bytearray.cpp deleted file mode 100644 index 88994ee..0000000 --- a/lib/bytearray.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "bytearray.h" - -#include -#include -#include - -namespace si { - -bytearray::bytearray() -{ - -} - -std::string bytearray::hex() const -{ - std::ostringstream ss; - - ss << std::hex << std::uppercase << std::setfill('0'); - - for (size_t i=0; i - -#include "types.h" - -namespace si { - -class bytearray : public std::vector -{ -public: - bytearray(); - - template - T *cast() { return reinterpret_cast(data()); } - - std::string hex() const; - -}; - -} - -#endif // BYTEARRAY_H diff --git a/lib/chunk.cpp b/lib/chunk.cpp index 3c25f12..92a02ed 100644 --- a/lib/chunk.cpp +++ b/lib/chunk.cpp @@ -4,12 +4,7 @@ #include #include -#include "data/mxch.h" -#include "data/mxhd.h" -#include "data/mxob.h" -#include "data/mxof.h" -#include "data/mxst.h" -#include "data/riff.h" +#include "sitypes.h" namespace si { @@ -42,125 +37,18 @@ bool Chunk::Read(const char *f) return Read(file, version, alignment); } -template -void CreateAndReadData(std::ifstream &f, bytearray &data, u32 size) -{ - size_t read_sz = std::min(size_t(size), sizeof(T)); - data.resize(read_sz); - f.read(data.data(), read_sz); -} - -void ReadNullTerminatedString(std::ifstream &f, char *str) -{ - std::string s; - - while (true) { - f.read(str, 1); - if (*str == 0) { - break; - } else { - str++; - } - } -} - -void Read_List(std::ifstream &f, LIST *ls) -{ - f.read((char *) &ls->dwID, sizeof(ls->dwID)); - - if (ls->dwID == Chunk::TYPE_MxCh) { - // MxCh type lists contain an element count - f.read((char *) &ls->dwCount, sizeof(ls->dwCount)); - - // TEMP FOR 1.2 REMOVE - //f.read((char *) &ls->dwCount, sizeof(ls->dwCount)); - } else { - ls->dwCount = 0; - } -} - -void Read_MxOb(std::ifstream &f, Chunk *c, MxOb *ob) -{ - f.read((char *) &ob->wType, sizeof(ob->wType)); - - ReadNullTerminatedString(f, ob->szPresenter); - - f.read((char *) &ob->dwUnknown1, sizeof(ob->dwUnknown1)); - - ReadNullTerminatedString(f, ob->szName); - - f.read((char *) &ob->dwObjectID, sizeof(ob->dwObjectID)); - f.read((char *) &ob->dwUnknown3, sizeof(ob->dwUnknown3)); - f.read((char *) &ob->dwUnknown4, sizeof(ob->dwUnknown4)); - f.read((char *) &ob->dwUnknown5, sizeof(ob->dwUnknown5)); - f.read((char *) &ob->dwUnknown6, sizeof(ob->dwUnknown6)); - f.read((char *) &ob->dwUnknown7, sizeof(ob->dwUnknown7)); - f.read((char *) &ob->dwUnknown8, sizeof(ob->dwUnknown8)); - f.read((char *) &ob->dwUnknown9, sizeof(ob->dwUnknown9)); - f.read((char *) &ob->dwUnknown10, sizeof(ob->dwUnknown10)); - f.read((char *) &ob->dwUnknown11, sizeof(ob->dwUnknown11)); - f.read((char *) &ob->dwUnknown12, sizeof(ob->dwUnknown12)); - f.read((char *) &ob->dwUnknown13, sizeof(ob->dwUnknown13)); - f.read((char *) &ob->dwUnknown14, sizeof(ob->dwUnknown14)); - f.read((char *) &ob->dwUnknown15, sizeof(ob->dwUnknown15)); - f.read((char *) &ob->dwUnknown16, sizeof(ob->dwUnknown16)); - f.read((char *) &ob->dwUnknown17, sizeof(ob->dwUnknown17)); - f.read((char *) &ob->fUnknown18, sizeof(ob->fUnknown18)); - f.read((char *) &ob->dwUnknown19, sizeof(ob->dwUnknown19)); - f.read((char *) &ob->dwUnknown20, sizeof(ob->dwUnknown20)); - f.read((char *) &ob->dwUnknown21, sizeof(ob->dwUnknown21)); - f.read((char *) &ob->fUnknown22, sizeof(ob->fUnknown22)); - f.read((char *) &ob->dwUnknown23, sizeof(ob->dwUnknown23)); - f.read((char *) &ob->dwUnknown24, sizeof(ob->dwUnknown24)); - f.read((char *) &ob->wCreationStringLength, sizeof(ob->wCreationStringLength)); - - if (ob->wCreationStringLength > 0) { - f.read(ob->szCreationString, ob->wCreationStringLength); - } - - switch (static_cast(ob->wType)) { - case MxOb::Presenter: - case MxOb::World: - break; - case MxOb::OBJ: - case MxOb::BMP: - case MxOb::SMK: - case MxOb::WAV: - case MxOb::Event: - ReadNullTerminatedString(f, ob->szFilename); - - if (ob->wType != MxOb::World) { - f.read((char *) &ob->dwUnknown26, sizeof(ob->dwUnknown26)); - f.read((char *) &ob->dwUnknown27, sizeof(ob->dwUnknown27)); - f.read((char *) &ob->dwUnknown28, sizeof(ob->dwUnknown28)); - - f.read((char *) &ob->dwID, sizeof(ob->dwID)); - - f.read((char *) &ob->dwUnknown29, sizeof(ob->dwUnknown29)); - f.read((char *) &ob->dwUnknown30, sizeof(ob->dwUnknown30)); - - if (ob->wType == MxOb::WAV) { - f.read((char *) &ob->dwUnknown31, sizeof(ob->dwUnknown31)); - } - } - break; - case MxOb::TYPE_COUNT: - break; - } -} - bool Chunk::Read(std::ifstream &f, u32 &version, u32 &alignment) { u32 size; - offset_ = f.tellg(); + offset_ = u32(f.tellg()); // Read ID and size, which every chunk starts with f.read((char *) &id_, sizeof(id_)); f.read((char *) &size, sizeof(size)); // Store end of this chunk - u32 pos = f.tellg(); + u32 pos = u32(f.tellg()); u32 end = pos + size; // Read custom data from this chunk @@ -168,54 +56,32 @@ bool Chunk::Read(std::ifstream &f, u32 &version, u32 &alignment) switch (type()) { case TYPE_RIFF: - CreateAndReadData(f, data_, size); - break; - case TYPE_LIST: - data_.resize(sizeof(LIST)); - Read_List(f, data_.cast()); - break; - case TYPE_MxSt: - // MxSt is 0 bytes in size, and an empty struct in C++ is one byte which throws things off, - // so we just create nothing here - size = 0; + RIFF().Read(f, data_, version, size); break; case TYPE_MxHd: - { - CreateAndReadData(f, data_, size); - - MxHd *mxhd = data_.cast(); - alignment = mxhd->dwBufferSize; - version = mxhd->dwVersion; + MxHd().Read(f, data_, version, size); + version = data_["Version"]; + alignment = data_["BufferSize"]; + break; + case TYPE_LIST: + LIST().Read(f, data_, version, size); + break; + case TYPE_MxSt: + MxSt().Read(f, data_, version, size); break; - } case TYPE_MxCh: - CreateAndReadData(f, data_, size); - exdata_.resize(size - sizeof(MxCh)); + MxCh().Read(f, data_, version, size); break; case TYPE_MxOf: - CreateAndReadData(f, data_, size); - exdata_.resize(size - sizeof(MxOf)); + MxOf().Read(f, data_, version, size); break; case TYPE_pad_: + pad_().Read(f, data_, version, size); break; case TYPE_MxOb: - { - data_.resize(sizeof(MxOb)); - Read_MxOb(f, this, data_.cast()); + MxOb().Read(f, data_, version, size); break; } - } - - // Handle unknown data - if (data_.empty() && size > 0) { - data_.resize(size); - f.read((char*)data_.data(), size); - } - - // Handle extended data - if (!exdata_.empty()) { - f.read((char*) exdata_.data(), exdata_.size()); - } // Assume any remaining data is this chunk's children while (f.good() && (size_t(f.tellg()) + 4) < end) { @@ -248,9 +114,6 @@ void Chunk::Clear() // Delete data data_.clear(); - // Delete exdata - exdata_.clear(); - // Delete children for (Children::iterator it = children_.begin(); it != children_.end(); it++) { delete (*it); diff --git a/lib/chunk.h b/lib/chunk.h index 798aa83..90ac3fa 100644 --- a/lib/chunk.h +++ b/lib/chunk.h @@ -2,9 +2,10 @@ #define CHUNK_H #include +#include #include -#include "bytearray.h" +#include "common.h" #include "types.h" namespace si { @@ -24,33 +25,34 @@ public: TYPE_pad_ = 0x20646170 }; - Chunk(); - virtual ~Chunk(); + LIBWEAVER_EXPORT Chunk(); + virtual LIBWEAVER_EXPORT ~Chunk(); - bool Read(const std::string &f); - bool Read(const char *f); - void Clear(); + LIBWEAVER_EXPORT bool Read(const std::string &f); + LIBWEAVER_EXPORT bool Read(const char *f); + LIBWEAVER_EXPORT void Clear(); typedef std::vector Children; - Chunk *GetParent() const { return parent_; } - const Children &GetChildren() const { return children_; } - void AppendChild(Chunk *chunk); - bool RemoveChild(Chunk *chunk); - size_t IndexOfChild(Chunk *chunk); - void InsertChild(size_t index, Chunk *chunk); - Chunk *RemoveChild(size_t index); - Chunk *GetChildAt(size_t index) const { return children_.at(index); } - size_t GetChildCount() const { return children_.size(); } + LIBWEAVER_EXPORT Chunk *GetParent() const { return parent_; } + LIBWEAVER_EXPORT const Children &GetChildren() const { return children_; } + LIBWEAVER_EXPORT void AppendChild(Chunk *chunk); + LIBWEAVER_EXPORT bool RemoveChild(Chunk *chunk); + LIBWEAVER_EXPORT size_t IndexOfChild(Chunk *chunk); + LIBWEAVER_EXPORT void InsertChild(size_t index, Chunk *chunk); + LIBWEAVER_EXPORT Chunk *RemoveChild(size_t index); + LIBWEAVER_EXPORT Chunk *GetChildAt(size_t index) const { return children_.at(index); } + LIBWEAVER_EXPORT size_t GetChildCount() const { return children_.size(); } - Type type() const { return static_cast(id_); } - const u32 &id() const { return id_; } - const u32 &offset() const { return offset_; } - bytearray &data() { return data_; } - bytearray &exdata() { return exdata_; } + LIBWEAVER_EXPORT Type type() const { return static_cast(id_); } + LIBWEAVER_EXPORT const u32 &id() const { return id_; } + LIBWEAVER_EXPORT const u32 &offset() const { return offset_; } - static const char *GetTypeDescription(Type type); - const char *GetTypeDescription() const + LIBWEAVER_EXPORT Data &data(const std::string &key) { return data_[key]; } + LIBWEAVER_EXPORT const Data &data(const std::string &key) const { return data_.at(key); } + + LIBWEAVER_EXPORT static const char *GetTypeDescription(Type type); + LIBWEAVER_EXPORT const char *GetTypeDescription() const { return GetTypeDescription(type()); } @@ -64,8 +66,7 @@ private: u32 id_; u32 offset_; - bytearray data_; - bytearray exdata_; + std::map data_; Chunk *parent_; Children children_; diff --git a/lib/data/mxch.h b/lib/data/mxch.h deleted file mode 100644 index 542716a..0000000 --- a/lib/data/mxch.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef MXCH_H -#define MXCH_H - -#include "common.h" -#include "types.h" - -namespace si { - -LIBWEAVER_PACK(struct MxCh -{ - u16 wFlags; - u32 dwObjectParent; - u32 dwMillisecondOffset; - u32 dwDataSize; -}); - -} - -#endif // MXCH_H diff --git a/lib/data/mxhd.h b/lib/data/mxhd.h deleted file mode 100644 index e2261a7..0000000 --- a/lib/data/mxhd.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef MXHDDATA_H -#define MXHDDATA_H - -#include "types.h" - -namespace si { - -/** - * @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. - */ -struct MxHd -{ - /** - * @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 diff --git a/lib/data/mxob.cpp b/lib/data/mxob.cpp deleted file mode 100644 index ff5de60..0000000 --- a/lib/data/mxob.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "mxob.h" - -const char *si::MxOb::GetTypeName(Type type) -{ - switch (type) { - case SMK: - return "SMK"; - case WAV: - return "WAV"; - case Presenter: - return "MxPresenter"; - case BMP: - return "BMP"; - case OBJ: - return "3D Object"; - case World: - return "World"; - case Event: - return "Event"; - case Animation: - return "Animation"; - case TYPE_COUNT: - break; - } - - return "Unknown"; -} diff --git a/lib/data/mxob.h b/lib/data/mxob.h deleted file mode 100644 index a1ab52f..0000000 --- a/lib/data/mxob.h +++ /dev/null @@ -1,176 +0,0 @@ -#ifndef MXOB_H -#define MXOB_H - -#include - -#include "common.h" -#include "types.h" - -namespace si { - -class MxOb -{ -public: - enum Type - { - /// Smacker video - SMK = 0x03, - - /// WAVE audio - WAV = 0x04, - - /// World object for LegoWorldPresenter - World = 0x06, - - /// Custom MxPresenter - Presenter = 0x07, - - /// Event - Event = 0x08, - - /// Animation - Animation = 0x09, - - /// Bitmap image - BMP = 0x0A, - - /// 3D Object - OBJ = 0x0B, - - /// Total number of types (not a real type) - TYPE_COUNT - }; - - static const char *GetTypeName(Type type); - - /** - * @brief Member of MxObType enum identifying the type of object - */ - u16 wType; - - /** - * @brief The presenter to use (if applicable) - * - * If wType is set to MxOb_Presenter, this will be a string identifying which presenter to use. - */ - char szPresenter[128]; - - /// Currently unknown value - u32 dwUnknown1; - - /** - * @brief Name of this object - */ - char szName[128]; - - /// Currently unknown value - u32 dwObjectID; - - /// Currently unknown value - u32 dwUnknown3; - - /// Currently unknown value - u32 dwUnknown4; - - /// Currently unknown value - u32 dwUnknown5; - - /// Currently unknown value - u32 dwUnknown6; - - /// Currently unknown value - u32 dwUnknown7; - - /// Currently unknown value - u32 dwUnknown8; - - /// Currently unknown value - u32 dwUnknown9; - - /// Currently unknown value - u32 dwUnknown10; - - /// Currently unknown value - u32 dwUnknown11; - - /// Currently unknown value - u32 dwUnknown12; - - /// Currently unknown value - u32 dwUnknown13; - - /// Currently unknown value - u32 dwUnknown14; - - /// Currently unknown value - u32 dwUnknown15; - - /// Currently unknown value - u32 dwUnknown16; - - /// Currently unknown value - u32 dwUnknown17; - - /// Currently unknown value - f32 fUnknown18; - - /// Currently unknown value - u32 dwUnknown19; - - /// Currently unknown value - u32 dwUnknown20; - - /// Currently unknown value - u32 dwUnknown21; - - /// Currently unknown value - f32 fUnknown22; - - /// Currently unknown value - u32 dwUnknown23; - - /// Currently unknown value - u32 dwUnknown24; - - /** - * @brief Length of the szCreationString string - * - * If this is zero, szCreationString takes up no space in the file. - */ - u16 wCreationStringLength; - - char szCreationString[128]; - - /** - * @brief Original source filename - */ - char szFilename[128]; - - /// Currently unknown value - u32 dwUnknown26; - - /// Currently unknown value - u32 dwUnknown27; - - /// Currently unknown value - u32 dwUnknown28; - - /** - * @brief 4-byte identifier for the file type - */ - u32 dwID; - - /// Currently unknown value - u32 dwUnknown29; - - /// Currently unknown value - u32 dwUnknown30; - - /// Currently unknown value - u32 dwUnknown31; - -}; - -} - -#endif // MXOB_H diff --git a/lib/data/mxof.h b/lib/data/mxof.h deleted file mode 100644 index 385a38a..0000000 --- a/lib/data/mxof.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef MXOF_H -#define MXOF_H - -#include "common.h" -#include "types.h" - -namespace si { - -struct MxOf -{ - u32 dwObjectCount; -}; - -} - -#endif // MXOF_H diff --git a/lib/data/mxst.h b/lib/data/mxst.h deleted file mode 100644 index 2f1af78..0000000 --- a/lib/data/mxst.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef MXSTDATA_H -#define MXSTDATA_H - -#include "types.h" - -namespace si { - -/** - * @brief Stream - * - * Appears to encapsulate any streamable object in an Interleaf file. - */ -struct MxSt -{ - -}; - -} - -#endif // MXSTDATA_H diff --git a/lib/data/riff.h b/lib/data/riff.h deleted file mode 100644 index cef12e7..0000000 --- a/lib/data/riff.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef RIFF_H -#define RIFF_H - -#include "types.h" - -namespace si { - -struct RIFF -{ - u32 dwID; -}; - -struct LIST -{ - u32 dwID; - u32 dwCount; -}; - -} - -#endif // RIFFDATA_H diff --git a/lib/sitypes.cpp b/lib/sitypes.cpp new file mode 100644 index 0000000..76c4a92 --- /dev/null +++ b/lib/sitypes.cpp @@ -0,0 +1,176 @@ +#include "sitypes.h" + +#include "chunk.h" + +namespace si { + +Data ReadU32(std::ifstream &is) +{ + u32 u; + is.read((char *) &u, sizeof(u)); + return u; +} + +Data ReadU16(std::ifstream &is) +{ + u16 u; + is.read((char *) &u, sizeof(u)); + return u; +} + +Data ReadString(std::ifstream &is) +{ + bytearray d; + + while (true) { + char c; + is.read(&c, 1); + if (c == 0) { + break; + } + d.push_back(c); + } + + // Append null terminator + d.push_back(0); + + return d; +} + +Data ReadBytes(std::ifstream &is, size_t size) +{ + bytearray d; + + d.resize(size); + is.read(d.data(), size); + + return d; +} + +void RIFF::Read(std::ifstream &is, DataMap &data, u32 version, u32 size) +{ + data["Format"] = ReadU32(is); +} + +void LIST::Read(std::ifstream &is, DataMap &data, u32 version, u32 size) +{ + data["Format"] = ReadU32(is); + + if (data["Format"] == Chunk::TYPE_MxCh) { + data["Count"] = ReadU32(is); + } +} + +void MxSt::Read(std::ifstream &is, DataMap &data, u32 version, u32 size) +{ + // MxSt is a container type only and has no members, so nothing needs to be done here +} + +void MxHd::Read(std::ifstream &is, DataMap &data, u32 version, u32 size) +{ + Data v = ReadU32(is); + data["Version"] = v; + data["BufferSize"] = ReadU32(is); + data["BufferCount"] = ReadU32(is); +} + +void MxCh::Read(std::ifstream &is, DataMap &data, u32 version, u32 size) +{ + data["Flags"] = ReadU16(is); + data["Object"] = ReadU32(is); + data["Time"] = ReadU32(is); + data["DataSize"] = ReadU32(is); + data["Data"] = ReadBytes(is, size - 0xE); +} + +void MxOf::Read(std::ifstream &is, DataMap &data, u32 version, u32 size) +{ + data["Count"] = ReadU32(is); + data["Offsets"] = ReadBytes(is, size - sizeof(u32)); +} + +void pad_::Read(std::ifstream &is, DataMap &data, u32 version, u32 size) +{ + is.seekg(size, std::ios::cur); +} + +const char *MxOb::GetTypeName(Type type) +{ + switch (type) { + case SMK: + return "SMK"; + case WAV: + return "WAV"; + case Presenter: + return "MxPresenter"; + case BMP: + return "BMP"; + case OBJ: + return "3D Object"; + case World: + return "World"; + case Event: + return "Event"; + case Animation: + return "Animation"; + case TYPE_COUNT: + break; + } + + return "Unknown"; +} + +void MxOb::Read(std::ifstream &is, DataMap &data, u32 version, u32 size) +{ + Data obj_type = ReadU16(is); + data["Type"] = obj_type; + data["Presenter"] = ReadString(is); + data["Unknown1"] = ReadU32(is); + data["Name"] = ReadString(is); + data["ID"] = ReadU32(is); + data["Unknown3"] = ReadU32(is); + data["Unknown4"] = ReadU32(is); + data["Unknown5"] = ReadU32(is); + data["Unknown6"] = ReadU32(is); + data["Unknown7"] = ReadU32(is); + data["Unknown8"] = ReadU32(is); + data["Unknown9"] = ReadU32(is); + data["Unknown10"] = ReadU32(is); + data["Unknown11"] = ReadU32(is); + data["Unknown12"] = ReadU32(is); + data["Unknown13"] = ReadU32(is); + data["Unknown14"] = ReadU32(is); + data["Unknown15"] = ReadU32(is); + data["Unknown16"] = ReadU32(is); + data["Unknown17"] = ReadU32(is); + data["Unknown18"] = ReadU32(is); + data["Unknown19"] = ReadU32(is); + data["Unknown20"] = ReadU32(is); + data["Unknown21"] = ReadU32(is); + data["Unknown22"] = ReadU32(is); + data["Unknown23"] = ReadU32(is); + data["Unknown24"] = ReadU32(is); + + Data extra_sz = ReadU16(is); + data["ExtraLength"] = extra_sz; + data["ExtraData"] = ReadBytes(is, extra_sz); + + if (obj_type != Presenter && obj_type != World) { + data["FileName"] = ReadString(is); + + data["Unknown26"] = ReadU32(is); + data["Unknown27"] = ReadU32(is); + data["Unknown28"] = ReadU32(is); + + data["FileType"] = ReadU32(is); + + data["Unknown29"] = ReadU32(is); + data["Unknown30"] = ReadU32(is); + + if (obj_type == MxOb::WAV) { + data["Unknown31"] = ReadU32(is); + } + } +} + +} diff --git a/lib/sitypes.h b/lib/sitypes.h new file mode 100644 index 0000000..e48f5c1 --- /dev/null +++ b/lib/sitypes.h @@ -0,0 +1,194 @@ +#ifndef SI_H +#define SI_H + +#include + +#include "chunk.h" +#include "types.h" + +namespace si { + +/** + * @brief RIFF chunk type + * + * Name | Size | Type | Description + * -------- | -------- | -------- | ----------- + * Format | 4 | u32 | 4-byte ASCII identifier for what type of RIFF this is (usually 'OMNI' in the case of LEGO Island) + */ +class RIFF +{ +public: + virtual ~RIFF(){} + + virtual void Read(std::ifstream &is, DataMap &data, u32 version, u32 size); +}; + +/** + * @brief LIST chunk type + * + * Name | Size | Type | Description + * -------- | -------- | -------- | ----------- + * Format | 4 | u32 | 4-byte ASCII identifier for what type of LIST this is. + * Count | 4 | u32 | (Optional) for 'MxCh' type LISTs, the number of elements in this list. + */ +class LIST : public RIFF +{ +public: + virtual void Read(std::ifstream &is, DataMap &data, u32 version, u32 size); +}; + +/** + * @brief MxHd chunk type + * + * Name | Size | Type | Description + * ----------- | -------- | -------- | ----------- + * Version | 4 | u32 | Version of this SI file stored as two packed 16-bit words, the high word being the major version and the low word being the minor version. + * BufferSize | 4 | u32 | The amount of data to read from disk at a time. + * BufferCount | 4 | u32 | FIXME: Currently not understood what this field does. + */ +class MxHd : public RIFF +{ +public: + virtual void Read(std::ifstream &is, DataMap &data, u32 version, u32 size); +}; + +/** + * @brief MxSt chunk type + * + * MxSt is a container type only, it has none of its own members. + */ +class MxSt : public RIFF +{ +public: + virtual void Read(std::ifstream &is, DataMap &data, u32 version, u32 size); +}; + +/** + * @brief MxCh chunk type + * + * Name | Size | Type | Description + * ---------- | -------- | --------- | ----------- + * Flags | 2 | u16 | Flags determining the behavior of this chunk. + * Object | 4 | u32 | ID of the MxOb that this chunk belongs to. + * Time | 4 | u32 | Time in milliseconds that this chunk's data should be presented at. + * DataSize | 4 | u32 | Size of the data in this chunk. + * Data | DataSize | bytearray | Actual data in chunk. + */ +class MxCh : public RIFF +{ +public: + virtual void Read(std::ifstream &is, DataMap &data, u32 version, u32 size); +}; + +/** + * @brief MxOf chunk type + * + * Name | Size | Type | Description + * ---------- | -------- | ---------------- | ----------- + * Count | 4 | u32 | Number of objects in this list. Not necessarily the number of offsets, as one offset may point to an object with multiple sub-objects. + * Offsets | Count*4 | bytearray/u32[] | List of 4-byte file offsets where objects begin. + */ +class MxOf : public RIFF +{ +public: + virtual void Read(std::ifstream &is, DataMap &data, u32 version, u32 size); +}; + +/** + * @brief pad_ chunk type + * + * Denotes padding to optimize disc reads. Contains no useful information, + * customarily filled with the byte 0xCD. + */ +class pad_ : public RIFF +{ +public: + virtual void Read(std::ifstream &is, DataMap &data, u32 version, u32 size); +}; + +/** + * @brief MxOb chunk type + * + * Name | Size | Type | Description + * ----------- | -------- | ---------------- | ----------- + * Type | 2 | u16 | Type of object (member of MxOb::Type enum) + * Presenter | Variable | string | Null-terminated string identifying the presenter to use (if type is set to `Presenter`) + * Unknown1 | 4 | u32 | + * Name | Variable | string | Null-terminated string identifying object's name + * ID | 4 | u32 | Unique object identifier within file (used to differentiate interleaved MxChs) + * Unknown3 | 4 | u32 | + * Unknown4 | 4 | u32 | + * Unknown5 | 4 | u32 | + * Unknown6 | 4 | u32 | + * Unknown7 | 4 | u32 | + * Unknown8 | 4 | u32 | + * Unknown9 | 4 | u32 | + * Unknown10 | 4 | u32 | + * Unknown11 | 4 | u32 | + * Unknown12 | 4 | u32 | + * Unknown13 | 4 | u32 | + * Unknown14 | 4 | u32 | + * Unknown15 | 4 | u32 | + * Unknown16 | 4 | u32 | + * Unknown17 | 4 | u32 | + * Unknown18 | 4 | u32 | + * Unknown19 | 4 | u32 | + * Unknown20 | 4 | u32 | + * Unknown21 | 4 | u32 | + * Unknown22 | 4 | u32 | + * Unknown23 | 4 | u32 | + * Unknown24 | 4 | u32 | + * ExtraLength | 2 | u16 | + * ExtraData | ExtraLength | bytearray | + * FileName | Variable | string | Original filename of the file represented by this object. + * Unknown26 | 4 | u32 | + * Unknown27 | 4 | u32 | + * Unknown28 | 4 | u32 | + * FileType | 4 | u32 | 4-byte ASCII ID for the file type + * Unknown29 | 4 | u32 | + * Unknown30 | 4 | u32 | + * Unknown31 | 4 | u32 | (Optional) only populated for WAV files + */ +class MxOb : public RIFF +{ +public: + enum Type + { + /// Smacker video + SMK = 0x03, + + /// WAVE audio + WAV = 0x04, + + /// World object for LegoWorldPresenter + World = 0x06, + + /// Custom MxPresenter + Presenter = 0x07, + + /// Event + Event = 0x08, + + /// Animation + Animation = 0x09, + + /// Bitmap image + BMP = 0x0A, + + /// 3D Object + OBJ = 0x0B, + + /// Total number of types (not a real type) + TYPE_COUNT + }; + + // FIXME: sitypes.h probably won't be part of the public API, so this should + // probably be moved + LIBWEAVER_EXPORT static const char *GetTypeName(Type type); + + virtual void Read(std::ifstream &is, DataMap &data, u32 version, u32 size); +}; + +} + +#endif // SI_H diff --git a/lib/types.h b/lib/types.h index bb58f8e..f676d14 100644 --- a/lib/types.h +++ b/lib/types.h @@ -1,6 +1,8 @@ #ifndef TYPES_H #define TYPES_H +#include +#include #include namespace si { @@ -14,6 +16,100 @@ typedef int s32; typedef float f32; typedef double f64; +class bytearray : public std::vector +{ +public: + bytearray() = default; + + template + T *cast() { return reinterpret_cast(data()); } + + template + const T *cast() const { return reinterpret_cast(data()); } + +}; + +class Data +{ +public: + inline Data() + { + data_.resize(sizeof(si::u32)); + //memset(data_.data(), 0, data_.size()); + } + + inline Data(const u32 &u) { set(u); } + inline Data(const bytearray &u) { set(u); } + inline Data(const std::string &u) + { + data_.resize(u.size()); + memcpy(data_.data(), u.data(), u.size()); + } + + inline operator u32() const + { + return toU32(); + } + + inline operator const char *() const + { + return data(); + } + + inline u16 toU16() const { return *data_.cast(); } + inline s16 toS16() const { return *data_.cast(); } + inline u32 toU32() const { return *data_.cast(); } + inline s32 toS32() const { return *data_.cast(); } + inline const char *data() const { return data_.data(); }; + inline char *data() { return data_.data(); }; + inline const char *c_str() const { return this->data(); }; + inline size_t size() const { return data_.size(); } + inline const std::string toString() const + { + // Subtract 1 from size, assuming the last character is a null terminator + return std::string(data_.data(), std::max(size_t(0), data_.size()-1)); + } + + inline bool operator==(int u) const + { + return get() == u; + } + + inline bool operator==(si::u32 u) const + { + return get() == u; + } + + template + inline const T &get() const + { + return *data_.cast(); + } + + template + inline void set(const T &value) + { + data_.resize(sizeof(T)); + memcpy(data_.data(), &value, sizeof(T)); + } + + inline void set(const bytearray &value) { data_ = value; } + +private: + bytearray data_; + +}; + +class Vector3 +{ +public: + f32 x; + f32 y; + f32 z; +}; + +using DataMap = std::map; + } #endif // TYPES_H