use abstract data storage

This commit is contained in:
itsmattkc 2022-07-03 10:57:43 -05:00
parent 6eb38edad9
commit ef5d9a0060
21 changed files with 543 additions and 626 deletions

View file

@ -1,6 +1,5 @@
#include "chunkmodel.h"
#include <data/riff.h>
#include <iostream>
#define super QAbstractItemModel

View file

@ -1,6 +1,5 @@
#include "mxch.h"
#include <data/mxch.h>
#include <QFontDatabase>
#include <QGroupBox>
#include <QLabel>
@ -83,34 +82,31 @@ MxChPanel::MxChPanel(QWidget *parent) :
void MxChPanel::OnOpeningData(Chunk *chunk)
{
MxCh *mxch = chunk->data().cast<MxCh>();
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<MxCh>();
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)

View file

@ -1,6 +1,5 @@
#include "mxhd.h"
#include <data/mxhd.h>
#include <QLabel>
using namespace si;
@ -50,22 +49,19 @@ MxHdPanel::MxHdPanel(QWidget *parent)
void MxHdPanel::OnOpeningData(Chunk *chunk)
{
MxHd *mxhd = chunk->data().cast<MxHd>();
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>();
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();
}

View file

@ -1,6 +1,6 @@
#include "mxob.h"
#include <data/mxob.h>
#include <sitypes.h>
#include <QLabel>
using namespace si;
@ -53,18 +53,14 @@ MxObPanel::MxObPanel(QWidget *parent) :
void MxObPanel::OnOpeningData(si::Chunk *chunk)
{
auto mxob = chunk->data().cast<MxOb>();
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>();
mxob->wType = type_combo_->currentIndex();
chunk->data("Type") = type_combo_->currentIndex();
}

View file

@ -1,6 +1,5 @@
#include "mxof.h"
#include <data/mxof.h>
#include <QLabel>
using namespace si;
@ -27,13 +26,13 @@ MxOfPanel::MxOfPanel(QWidget *parent) :
void MxOfPanel::OnOpeningData(si::Chunk *chunk)
{
u32 *offsets = reinterpret_cast<u32*>(chunk->exdata().data());
size_t count = chunk->exdata().size() / sizeof(u32);
const Data &offsets_bytes = chunk->data("Offsets");
const u32 *offsets = reinterpret_cast<const u32*>(offsets_bytes.data());
size_t offset_count = offsets_bytes.size() / sizeof(u32);
MxOf *mxof = chunk->data().cast<MxOf>();
obj_count_edit_->setValue(mxof->dwObjectCount);
obj_count_edit_->setValue(chunk->data("Count"));
for (size_t i=0; i<count; i++) {
for (size_t i=0; i<offset_count; i++) {
QString addr = QStringLiteral("0x%1").arg(offsets[i], 8, 16, QChar('0'));
list_->addItem(QStringLiteral("%1: %2").arg(QString::number(i), addr));

View file

@ -1,6 +1,5 @@
#include "riff.h"
#include <data/riff.h>
#include <QLabel>
using namespace si;
@ -21,16 +20,12 @@ RIFFPanel::RIFFPanel(QWidget *parent) :
void RIFFPanel::OnOpeningData(Chunk *chunk)
{
RIFF *riff = chunk->data().cast<RIFF>();
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<RIFF>();
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();
}

View file

@ -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
)

View file

@ -1,27 +0,0 @@
#include "bytearray.h"
#include <iomanip>
#include <ios>
#include <sstream>
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<size(); i++) {
ss << std::setw(2) << at(i);
}
return ss.str();
}
}

View file

@ -1,24 +0,0 @@
#ifndef BYTEARRAY_H
#define BYTEARRAY_H
#include <string>
#include "types.h"
namespace si {
class bytearray : public std::vector<s8>
{
public:
bytearray();
template <typename T>
T *cast() { return reinterpret_cast<T*>(data()); }
std::string hex() const;
};
}
#endif // BYTEARRAY_H

View file

@ -4,12 +4,7 @@
#include <cstring>
#include <iostream>
#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 <typename T>
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<MxOb::Type>(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<RIFF>(f, data_, size);
break;
case TYPE_LIST:
data_.resize(sizeof(LIST));
Read_List(f, data_.cast<LIST>());
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<MxHd>(f, data_, size);
MxHd *mxhd = data_.cast<MxHd>();
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<MxCh>(f, data_, size);
exdata_.resize(size - sizeof(MxCh));
MxCh().Read(f, data_, version, size);
break;
case TYPE_MxOf:
CreateAndReadData<MxOf>(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>());
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);

View file

@ -2,9 +2,10 @@
#define CHUNK_H
#include <fstream>
#include <map>
#include <memory>
#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<Chunk*> 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<Type>(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<Type>(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<std::string, Data> data_;
Chunk *parent_;
Children children_;

View file

@ -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

View file

@ -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

View file

@ -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";
}

View file

@ -1,176 +0,0 @@
#ifndef MXOB_H
#define MXOB_H
#include <string>
#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

View file

@ -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

View file

@ -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

View file

@ -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

176
lib/sitypes.cpp Normal file
View file

@ -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);
}
}
}
}

194
lib/sitypes.h Normal file
View file

@ -0,0 +1,194 @@
#ifndef SI_H
#define SI_H
#include <fstream>
#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

View file

@ -1,6 +1,8 @@
#ifndef TYPES_H
#define TYPES_H
#include <map>
#include <string>
#include <vector>
namespace si {
@ -14,6 +16,100 @@ typedef int s32;
typedef float f32;
typedef double f64;
class bytearray : public std::vector<s8>
{
public:
bytearray() = default;
template <typename T>
T *cast() { return reinterpret_cast<T*>(data()); }
template <typename T>
const T *cast() const { return reinterpret_cast<const T*>(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<si::u16>(); }
inline s16 toS16() const { return *data_.cast<si::s16>(); }
inline u32 toU32() const { return *data_.cast<si::u32>(); }
inline s32 toS32() const { return *data_.cast<si::s32>(); }
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<int>() == u;
}
inline bool operator==(si::u32 u) const
{
return get<si::u32>() == u;
}
template <typename T>
inline const T &get() const
{
return *data_.cast<T>();
}
template <typename T>
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<std::string, Data>;
}
#endif // TYPES_H