start test changes

This commit is contained in:
itsmattkc 2022-07-17 18:51:16 -07:00
parent a976634681
commit 0a76066185
14 changed files with 509 additions and 752 deletions

View file

@ -4,20 +4,20 @@ find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets Multimedia)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Multimedia)
set(PROJECT_SOURCES
siview/chunkmodel.cpp
siview/chunkmodel.h
siview/panels/mxch.cpp
siview/panels/mxch.h
siview/panels/mxhd.cpp
siview/panels/mxhd.h
siview/panels/mxob.cpp
siview/panels/mxob.h
siview/panels/mxof.cpp
siview/panels/mxof.h
siview/panels/riff.cpp
siview/panels/riff.h
siview/siview.cpp
siview/siview.h
# siview/chunkmodel.cpp
# siview/chunkmodel.h
# siview/panels/mxch.cpp
# siview/panels/mxch.h
# siview/panels/mxhd.cpp
# siview/panels/mxhd.h
# siview/panels/mxob.cpp
# siview/panels/mxob.h
# siview/panels/mxof.cpp
# siview/panels/mxof.h
# siview/panels/riff.cpp
# siview/panels/riff.h
# siview/siview.cpp
# siview/siview.h
viewer/bitmappanel.cpp
viewer/bitmappanel.h
@ -52,7 +52,9 @@ endif()
target_link_libraries(si-edit PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Multimedia libweaver)
target_include_directories(si-edit PRIVATE "${CMAKE_SOURCE_DIR}/lib")
if (NOT MSVC)
target_compile_options(si-edit PRIVATE -Werror)
endif()
set_target_properties(si-edit PROPERTIES
MACOSX_BUNDLE_GUI_IDENTIFIER com.mattkc.SIEdit

View file

@ -6,8 +6,6 @@
#include <QMessageBox>
#include <QSplitter>
#include "siview/siview.h"
using namespace si;
MainWindow::MainWindow(QWidget *parent) :
@ -67,14 +65,18 @@ MainWindow::MainWindow(QWidget *parent) :
void MainWindow::OpenFilename(const QString &s)
{
Chunk si;
if (si.Read(s.toStdString())) {
SIViewDialog d(SIViewDialog::Import, &si, this);
if (d.exec() == QDialog::Accepted) {
model_.SetCore(nullptr);
interleaf_.Parse(&si);
bool r =
#ifdef Q_OS_WINDOWS
interleaf_.Read(s.toStdWString().c_str());
#else
interleaf_.Read(s.toUtf8());
#endif
;
if (r) {
model_.SetCore(&interleaf_);
}
} else {
QMessageBox::critical(this, QString(), tr("Failed to load Interleaf file."));
}
@ -155,17 +157,6 @@ void MainWindow::OpenFile()
void MainWindow::ExportFile()
{
Chunk *c = interleaf_.Export();
SIViewDialog d(SIViewDialog::Export, c, this);
if (d.exec() == QDialog::Accepted) {
QString s = QFileDialog::getSaveFileName(this);
if (!s.isEmpty()) {
if (!c->Write(s.toStdString())) {
QMessageBox::critical(this, QString(), tr("Failed to write SI file."));
}
}
}
delete c;
}
void MainWindow::SelectionChanged(const QModelIndex &index)

View file

@ -1,8 +1,6 @@
option(LIBWEAVER_BUILD_DOXYGEN "Build Doxygen documentation" OFF)
set(LIBWEAVER_SOURCES
chunk.cpp
chunk.h
common.h
core.cpp
core.h
@ -13,6 +11,7 @@ set(LIBWEAVER_SOURCES
sitypes.cpp
sitypes.h
types.h
util.h
)
add_library(libweaver SHARED
@ -20,7 +19,9 @@ add_library(libweaver SHARED
)
target_compile_definitions(libweaver PRIVATE LIBWEAVER_LIBRARY)
if (NOT MSVC)
target_compile_options(libweaver PRIVATE -Werror -Wall -Wextra -Wno-unused-parameter)
endif()
set_target_properties(libweaver PROPERTIES
CXX_STANDARD 98
CXX_STANDARD_REQUIRED ON

View file

@ -1,264 +0,0 @@
#include "chunk.h"
#include <algorithm>
#include <cstring>
#include <iostream>
#include "sitypes.h"
namespace si {
Chunk::Chunk(uint32_t id) :
id_(id),
offset_(0)
{
}
Chunk::~Chunk()
{
Clear();
}
bool Chunk::Read(const std::string &f)
{
return Read(f.c_str());
}
bool Chunk::Read(const char *f)
{
std::ifstream file(f, std::ios::in | std::ios::binary);
if (!file.is_open() || !file.good()) {
return false;
}
uint32_t alignment = 0, version = 0;
return Read(file, version, alignment);
}
bool Chunk::Read(std::ifstream &f, uint32_t &version, uint32_t &alignment)
{
uint32_t size;
offset_ = uint32_t(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
uint32_t pos = uint32_t(f.tellg());
uint32_t end = pos + size;
// Read custom data from this chunk
Clear();
if (RIFF *reader = GetReaderFromType(type())) {
reader->Read(f, data_, version, size);
if (type() == TYPE_MxHd) {
version = data_["Version"];
alignment = data_["BufferSize"];
}
delete reader;
}
// Assume any remaining data is this chunk's children
while (f.good() && (size_t(f.tellg()) + 4) < end) {
// Check alignment, if there's not enough room to for another segment, skip ahead
if (alignment > 0) {
uint32_t offset_in_buffer = f.tellg()%alignment;
if (offset_in_buffer + sizeof(uint32_t)*2 > alignment) {
f.seekg(alignment-offset_in_buffer, std::ios::cur);
}
}
Chunk *child = new Chunk();
child->Read(f, version, alignment);
this->AppendChild(child);
}
if (f.tellg() < end) {
f.seekg(end, std::ios::beg);
}
if (size%2 == 1) {
f.seekg(1, std::ios::cur);
}
return true;
}
bool Chunk::Write(std::ofstream &f, uint32_t &version, uint32_t &alignment) const
{
RIFF *writer = GetReaderFromType(type());
if (alignment != 0) {
// Determine if we have enough space left to write this chunk without the alignment
size_t expected_write = 8;
for (DataMap::const_iterator it=data_.begin(); it!=data_.end(); it++) {
expected_write += it->second.size();
}
size_t start_chunk = f.tellp()/alignment;
size_t end_chunk = (size_t(f.tellp())+expected_write)/alignment;
if (start_chunk != end_chunk) {
// This chunk is going to cross a boundary. We could write padding or split the chunk.
// I'm not exactly sure how Weaver decides which, but I suppose it doesn't matter.
size_t diff = (end_chunk * alignment) - f.tellp();
pad_::WriteArbitraryPadding(f, diff - 8);
/*if (id_ != Chunk::TYPE_MxCh || diff < 0x200) {
// Make padding
pad_::WriteArbitraryPadding(f, diff - 8);
} else {
// Attempt to split chunk
}*/
}
}
// Write 4-byte ID
f.write((const char *) &id_, sizeof(id_));
// Write placeholder for size and store position so we can come back later
uint32_t chunk_size = 0;
std::ios::pos_type size_pos = f.tellp();
f.write((const char *) &chunk_size, sizeof(chunk_size));
if (writer) {
writer->Write(f, data_, version);
if (type() == TYPE_MxHd) {
version = data_.at("Version");
alignment = data_.at("BufferSize");
}
delete writer;
}
for (Children::const_iterator it=GetChildren().begin(); it!=GetChildren().end(); it++) {
static_cast<Chunk*>(*it)->Write(f, version, alignment);
}
// Backtrack and write chunk size
chunk_size = uint32_t(f.tellp()) - (uint32_t(size_pos) + sizeof(uint32_t));
f.seekp(size_pos);
f.write((const char *) &chunk_size, sizeof(chunk_size));
f.seekp(0, std::ios::end);
// Byte align to 2
if (chunk_size%2 == 1) {
const char nothing = 0;
f.write(&nothing, 1);
}
return true;
}
RIFF *Chunk::GetReaderFromType(Type type)
{
switch (type) {
case TYPE_RIFF:
return new RIFF();
case TYPE_MxHd:
return new MxHd();
case TYPE_LIST:
return new LIST();
case TYPE_MxSt:
return new MxSt();
case TYPE_MxCh:
return new MxCh();
case TYPE_MxOf:
return new MxOf();
case TYPE_pad_:
return new pad_();
case TYPE_MxOb:
return new MxOb();
case TYPE_MxDa:
break;
}
return NULL;
}
void Chunk::Clear()
{
// Delete data
data_.clear();
// Delete children
DeleteChildren();
}
bool Chunk::Write(const std::string &f)
{
return Write(f.c_str());
}
bool Chunk::Write(const char *f)
{
std::ofstream file(f, std::ios::out | std::ios::binary);
if (!file.is_open() || !file.good()) {
return false;
}
uint32_t version = 0, alignment = 0;
return Write(file, version, alignment);
}
const char *Chunk::GetTypeDescription(Type type)
{
switch (type) {
case TYPE_RIFF:
return "Resource Interchange File Format";
case TYPE_LIST:
return "List of sub-elements";
case TYPE_MxSt:
return "Stream";
case TYPE_MxHd:
return "Interleaf Header";
case TYPE_MxCh:
return "Data Chunk";
case TYPE_MxOf:
return "Offset Table";
case TYPE_pad_:
return "Padding";
case TYPE_MxOb:
return "Streamable Object";
case TYPE_MxDa:
return "Data";
}
return "Unknown";
}
Chunk *Chunk::FindChildWithType(Type type) const
{
for (Children::const_iterator it=GetChildren().begin(); it!=GetChildren().end(); it++) {
Chunk *chunk = static_cast<Chunk*>(*it);
if (chunk->type() == type) {
return chunk;
} else if (Chunk *grandchild = chunk->FindChildWithType(type)) {
return grandchild;
}
}
return NULL;
}
Chunk *Chunk::FindChildWithOffset(uint32_t offset) const
{
for (Children::const_iterator it=GetChildren().begin(); it!=GetChildren().end(); it++) {
Chunk *chunk = static_cast<Chunk*>(*it);
if (chunk->offset() == offset) {
return chunk;
} else if (Chunk *grandchild = chunk->FindChildWithOffset(offset)) {
return grandchild;
}
}
return NULL;
}
}

View file

@ -1,71 +0,0 @@
#ifndef CHUNK_H
#define CHUNK_H
#include <fstream>
#include <map>
#include <memory>
#include "common.h"
#include "core.h"
#include "sitypes.h"
#include "types.h"
namespace si {
class Chunk : public Core
{
public:
enum Type
{
TYPE_RIFF = 0x46464952,
TYPE_LIST = 0x5453494c,
TYPE_MxSt = 0x7453784d,
TYPE_MxHd = 0x6448784d,
TYPE_MxCh = 0x6843784d,
TYPE_MxOf = 0x664f784d,
TYPE_MxOb = 0x624f784d,
TYPE_MxDa = 0x6144784d,
TYPE_pad_ = 0x20646170
};
LIBWEAVER_EXPORT Chunk(uint32_t id = 0);
virtual LIBWEAVER_EXPORT ~Chunk();
LIBWEAVER_EXPORT bool Read(const std::string &f);
LIBWEAVER_EXPORT bool Read(const char *f);
LIBWEAVER_EXPORT void Clear();
LIBWEAVER_EXPORT bool Write(const std::string &f);
LIBWEAVER_EXPORT bool Write(const char *f);
LIBWEAVER_EXPORT Type type() const { return static_cast<Type>(id_); }
LIBWEAVER_EXPORT const uint32_t &id() const { return id_; }
LIBWEAVER_EXPORT const uint32_t &offset() const { return offset_; }
LIBWEAVER_EXPORT Data &data(const std::string &key) { return data_[key]; }
LIBWEAVER_EXPORT 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());
}
LIBWEAVER_EXPORT Chunk *FindChildWithType(Type type) const;
LIBWEAVER_EXPORT Chunk *FindChildWithOffset(uint32_t offset) const;
private:
bool Read(std::ifstream &f, uint32_t &version, uint32_t &alignment);
bool Write(std::ofstream &f, uint32_t &version, uint32_t &alignment) const;
static RIFF *GetReaderFromType(Type type);
uint32_t id_;
uint32_t offset_;
DataMap data_;
};
}
#endif // CHUNK_H

View file

@ -5,6 +5,8 @@
#include "object.h"
#include "othertypes.h"
#include "sitypes.h"
#include "util.h"
namespace si {
@ -12,7 +14,247 @@ Interleaf::Interleaf()
{
}
bool Interleaf::Parse(Chunk *riff)
void Interleaf::Clear()
{
m_BufferSize = 0;
m_OffsetTable.clear();
m_ObjectIndexTable.clear();
DeleteChildren();
}
bool Interleaf::Read(const char *f)
{
std::ifstream is(f);
if (!is.is_open() || !is.good()) {
return false;
}
return Read(is);
}
bool Interleaf::Read(const wchar_t *f)
{
std::ifstream is(f);
if (!is.is_open() || !is.good()) {
return false;
}
return Read(is);
}
/*bool Interleaf::Write(const char *f) const
{
std::ofstream os(f);
if (!os.is_open() || !os.good()) {
return false;
}
return Write(os);
}
bool Interleaf::Write(const wchar_t *f) const
{
std::ofstream os(f);
if (!os.is_open() || !os.good()) {
return false;
}
return Write(os);
}*/
inline std::string PrintU32AsString(uint32_t u)
{
return std::string((const char *) &u, sizeof(u));
}
bool Interleaf::ReadChunk(Core *parent, std::ifstream &is)
{
uint32_t offset = is.tellg();
uint32_t id = ReadU32(is);
uint32_t size = ReadU32(is);
uint32_t end = uint32_t(is.tellg()) + size;
std::cout << PrintU32AsString(id)
<< " Offset: 0x" << std::hex << offset
<< " Size: " << std::dec << size << std::endl;
switch (static_cast<SI::Type>(id)) {
case SI::RIFF:
{
// Require RIFF type to be OMNI
uint32_t riff_type = ReadU32(is);
std::cout << " Type: " << PrintU32AsString(riff_type) << std::endl;
if (riff_type != RIFF::OMNI) {
return false;
}
break;
}
case SI::MxHd:
{
m_Version = ReadU32(is);
std::cout << " Version: " << m_Version << std::endl;
m_BufferSize = ReadU32(is);
std::cout << " Buffer Size: " << m_BufferSize << std::endl;
if (m_Version < 0x00020002) {
m_BufferCount = ReadU32(is);
std::cout << " Buffer Count: " << m_BufferCount << std::endl;
}
break;
}
case SI::pad_:
is.seekg(size, std::ios::cur);
break;
case SI::MxOf:
{
m_OffsetCount = ReadU32(is);
std::cout << " Count: " << m_OffsetCount << std::endl;
uint32_t i = 0;
while (is.tellg() < end) {
uint32_t offset = ReadU32(is);
std::cout << " " << i << ": 0x" << std::hex << offset << std::endl;
m_OffsetTable.push_back(offset);
i++;
}
break;
}
case SI::LIST:
{
uint32_t list_type = ReadU32(is);
std::cout << " Type: " << PrintU32AsString(list_type) << std::endl;
uint32_t list_count = 0;
if (list_type == SI::MxCh) {
list_count = ReadU32(is);
std::cout << " Count: " << list_count << std::endl;
}
break;
}
case SI::MxSt:
case SI::MxDa:
// Types with no data
break;
case SI::MxOb:
{
Object *o = ReadObject(is);
parent->AppendChild(o);
m_ObjectIndexTable[o->id()] = o;
parent = o;
break;
}
case SI::MxCh:
{
uint16_t flags = ReadU16(is);
uint32_t object = ReadU32(is);
uint32_t time = ReadU32(is);
uint32_t data_sz = ReadU32(is);
bytearray data = ReadBytes(is, size - MxCh::HEADER_SIZE);
Object *o = m_ObjectIndexTable.at(object);
if (!o) {
return false;
}
o->data_.push_back(data);
break;
}
}
std::cout << "Reading children at 0x" << std::hex << is.tellg() << std::endl;
// Assume any remaining data is this chunk's children
while (is.good() && (size_t(is.tellg()) + 4) < end) {
// Check alignment, if there's not enough room to for another segment, skip ahead
if (m_BufferSize > 0) {
uint32_t offset_in_buffer = is.tellg()%m_BufferSize;
if (offset_in_buffer + sizeof(uint32_t)*2 > m_BufferSize) {
is.seekg(m_BufferSize-offset_in_buffer, std::ios::cur);
}
}
// Read next child
if (!ReadChunk(parent, is)) {
return false;
}
}
if (is.tellg() < end) {
is.seekg(end, std::ios::beg);
}
if (size%2 == 1) {
is.seekg(1, std::ios::cur);
}
return true;
}
Object *Interleaf::ReadObject(std::ifstream &is)
{
Object *o = new Object();
o->type_ = static_cast<MxOb::Type>(ReadU16(is));
std::cout << " Type: " << o->type_ << std::endl;
o->presenter_ = ReadString(is);
std::cout << " Presenter: " << o->presenter_ << std::endl;
o->unknown1_ = ReadU32(is);
std::cout << " Unknown1: " << o->unknown1_ << std::endl;
o->name_ = ReadString(is);
std::cout << " Name: " << o->name_ << std::endl;
o->id_ = ReadU32(is);
std::cout << " ID: " << o->id_ << std::endl;
o->flags_ = ReadU32(is);
std::cout << " Flags: " << o->flags_ << std::endl;
o->unknown4_ = ReadU32(is);
std::cout << " Unknown4: " << o->unknown4_ << std::endl;
o->duration_ = ReadU32(is);
std::cout << " Duration: " << o->duration_ << std::endl;
o->loops_ = ReadU32(is);
std::cout << " Loops: " << o->loops_ << std::endl;
o->position_ = ReadVector3(is);
std::cout << " Position: " << o->position_.x << " " << o->position_.y << " " << o->position_.z << std::endl;
o->direction_ = ReadVector3(is);
std::cout << " Direction: " << o->direction_.x << " " << o->direction_.y << " " << o->direction_.z << std::endl;
o->up_ = ReadVector3(is);
std::cout << " Up: " << o->up_.x << " " << o->up_.y << " " << o->up_.z << std::endl;
uint16_t extra_sz = ReadU16(is);
std::cout << " Extra Size: " << extra_sz << std::endl;
o->extra_ = ReadBytes(is, extra_sz);
if (o->type_ != MxOb::Presenter && o->type_ != MxOb::World) {
o->filename_ = ReadString(is);
std::cout << " Filename: " << o->filename_ << std::endl;
o->unknown26_ = ReadU32(is);
std::cout << " Unknown26: " << o->unknown26_ << std::endl;
o->unknown27_ = ReadU32(is);
std::cout << " Unknown27: " << o->unknown27_ << std::endl;
o->unknown28_ = ReadU32(is);
std::cout << " Unknown28: " << o->unknown28_ << std::endl;
o->filetype_ = static_cast<MxOb::FileType>(ReadU32(is));
std::cout << " File Type: " << PrintU32AsString(o->filetype_) << std::endl;
o->unknown29_ = ReadU32(is);
std::cout << " Unknown29: " << o->unknown29_ << std::endl;
o->unknown30_ = ReadU32(is);
std::cout << " Unknown30: " << o->unknown30_ << std::endl;
if (o->filetype_ == MxOb::WAV) {
o->unknown31_ = ReadU32(is);
std::cout << " Unknown31: " << o->unknown31_ << std::endl;
}
}
//std::cout << "Next ID: 0x" << std::hex << is.tellg() << " ";
//std::cout << PrintU32AsString(ReadU32(is));
//std::cout << " After: 0x" << std::hex << is.tellg() << std::endl;
//is.seekg(-4, std::ios::cur);
return o;
}
bool Interleaf::Read(std::ifstream &is)
{
Clear();
return ReadChunk(this, is);
}
/*bool Interleaf::Parse(Chunk *riff)
{
if (riff->id() != Chunk::TYPE_RIFF) {
return false;
@ -213,16 +455,16 @@ Chunk *Interleaf::ExportStream(Object *obj) const
for (std::vector<ChunkStatus>::iterator it=chunk_status.begin(); it!=chunk_status.end(); it++) {
// Check if we've already written all these chunks
if (it->index >= it->object->data().size()) {
/*if (!it->end_chunk) {
if (!it->end_chunk) {
chunklst->AppendChild(ExportMxCh(MxCh::FLAG_END, it->object->id(), it->time));
it->end_chunk = true;
}*/
}
continue;
}
// Find earliest chunk to write
if (!status || it->time < status->time) {
status = it.base();
status = &(*it);
}
}
@ -288,6 +530,6 @@ Chunk *Interleaf::ExportMxCh(uint16_t flags, uint32_t object_id, uint32_t time,
mxch->data("DataSize") = data.size();
mxch->data("Data") = data;
return mxch;
}
}*/
}

View file

@ -1,7 +1,8 @@
#ifndef INTERLEAF_H
#define INTERLEAF_H
#include "chunk.h"
#include <fstream>
#include "core.h"
#include "object.h"
@ -12,17 +13,30 @@ class Interleaf : public Core
public:
LIBWEAVER_EXPORT Interleaf();
LIBWEAVER_EXPORT bool Parse(Chunk *riff);
LIBWEAVER_EXPORT Chunk *Export() const;
LIBWEAVER_EXPORT void Clear();
LIBWEAVER_EXPORT bool Read(const char *f);
LIBWEAVER_EXPORT bool Read(const wchar_t *f);
//LIBWEAVER_EXPORT bool Write(const char *f) const;
//LIBWEAVER_EXPORT bool Write(const wchar_t *f) const;
private:
bool ParseStream(Chunk *chunk);
Chunk *ExportStream(Object *obj) const;
Chunk *ExportMxCh(uint16_t flags, uint32_t object_id, uint32_t time, const bytearray &data = bytearray()) const;
bool Read(std::ifstream &is);
//bool Write(std::ofstream &os) const;
uint32_t version_;
uint32_t buffer_size_;
uint32_t buffer_count_;
bool ReadChunk(Core *parent, std::ifstream &is);
Object *ReadObject(std::ifstream &is);
uint32_t m_Version;
uint32_t m_BufferSize;
uint32_t m_BufferCount;
uint32_t m_OffsetCount;
std::vector<uint32_t> m_OffsetTable;
std::map<uint32_t, Object*> m_ObjectIndexTable;
};

View file

@ -2,6 +2,8 @@
#include <iostream>
#include "util.h"
namespace si {
Object::Object()
@ -10,29 +12,9 @@ Object::Object()
id_ = 0;
}
bool Object::Parse(Chunk *chunk)
/*bool Object::Read(std::ifstream &is)
{
type_ = static_cast<MxOb::Type>(chunk->data("Type").toU16());
presenter_ = chunk->data("Presenter").toString();
unknown1_ = chunk->data("Unknown1");
name_ = chunk->data("Name").toString();
id_ = chunk->data("ID");
flags_ = chunk->data("Flags");
unknown4_ = chunk->data("Unknown4");
duration_ = chunk->data("Duration");
loops_ = chunk->data("Loops");
position_ = chunk->data("Position");
direction_ = chunk->data("Direction");
up_ = chunk->data("Up");
extra_ = chunk->data("ExtraData");
filename_ = chunk->data("FileName").toString();
unknown26_ = chunk->data("Unknown26");
unknown27_ = chunk->data("Unknown27");
unknown28_ = chunk->data("Unknown28");
filetype_ = static_cast<MxOb::FileType>(chunk->data("FileType").toU32());
unknown29_ = chunk->data("Unknown29");
unknown30_ = chunk->data("Unknown30");
unknown31_ = chunk->data("Unknown31");
if (chunk->HasChildren()) {
Chunk *child = static_cast<Chunk*>(chunk->GetChildAt(0));
@ -50,31 +32,30 @@ bool Object::Parse(Chunk *chunk)
return true;
}
Chunk *Object::Export() const
void Object::Write(std::ofstream &os) const
{
Chunk *chunk = new Chunk(Chunk::TYPE_MxOb);
chunk->data("Type") = type_;
chunk->data("Presenter") = presenter_;
chunk->data("Unknown1") = unknown1_;
chunk->data("Name") = name_;
chunk->data("ID") = id_;
chunk->data("Flags") = flags_;
chunk->data("Unknown4") = unknown4_;
chunk->data("Duration") = duration_;
chunk->data("Loops") = loops_;
chunk->data("Position") = position_;
chunk->data("Direction") = direction_;
chunk->data("Up") = up_;
chunk->data("ExtraData") = extra_;
chunk->data("FileName") = filename_;
chunk->data("Unknown26") = unknown26_;
chunk->data("Unknown27") = unknown27_;
chunk->data("Unknown28") = unknown28_;
chunk->data("FileType") = filetype_;
chunk->data("Unknown29") = unknown29_;
chunk->data("Unknown30") = unknown30_;
chunk->data("Unknown31") = unknown31_;
WriteU16(os, type_);
WriteString(os, presenter_);
WriteU32(os, unknown1_);
WriteString(os, name_);
WriteU32(os, id_);
WriteU32(os, flags_);
WriteU32(os, unknown4_);
WriteU32(os, duration_);
WriteU32(os, loops_);
WriteVector3(os, position_);
WriteVector3(os, direction_);
WriteVector3(os, up_);
WriteU16(os, extra_.size());
WriteBytes(os, extra_);
WriteString(os, filename_);
WriteU32(os, unknown26_);
WriteU32(os, unknown27_);
WriteU32(os, unknown28_);
WriteU32(os, filetype_);
WriteU32(os, unknown29_);
WriteU32(os, unknown30_);
WriteU32(os, unknown31_);
if (HasChildren()) {
Chunk *list = new Chunk(Chunk::TYPE_LIST);
@ -89,7 +70,7 @@ Chunk *Object::Export() const
}
return chunk;
}
}*/
bytearray Object::GetNormalizedData() const
{
@ -118,7 +99,7 @@ bytearray Object::ToPackedData(MxOb::FileType filetype, const ChunkedData &chunk
// Copy boilerplate bytes for header
uint32_t *header = reinterpret_cast<uint32_t *>(data.data());
header[0] = Chunk::TYPE_RIFF; // "RIFF"
header[0] = SI::RIFF; // "RIFF"
header[1] = data.size() - 8; // Size of total file
header[2] = 0x45564157; // "WAVE"
header[3] = 0x20746D66; // "fmt "

View file

@ -1,8 +1,8 @@
#ifndef OBJECT_H
#define OBJECT_H
#include "chunk.h"
#include "core.h"
#include "sitypes.h"
#include "types.h"
namespace si {
@ -14,9 +14,6 @@ public:
Object();
bool Parse(Chunk *chunk);
Chunk *Export() const;
void SetChunkedData(const ChunkedData &cd) { data_ = cd; }
LIBWEAVER_EXPORT bytearray GetNormalizedData() const;
@ -38,7 +35,6 @@ public:
Object *FindSubObjectWithID(uint32_t id);
private:
MxOb::Type type_;
std::string presenter_;
uint32_t unknown1_;

59
lib/ptr.h Normal file
View file

@ -0,0 +1,59 @@
#ifndef PTR_H
#define PTR_H
namespace si {
/**
* @brief Smart pointer implementation for versions of C++ < 11
*/
template <typename T>
class Ptr
{
public:
Ptr(T *ptr = 0)
{
data_ = ptr;
ref_count_ = new size_t;
*ref_count_ = 1;
}
~Ptr()
{
*ref_count_--;
if (*ref_count_ == 0) {
delete data_;
delete ref_count_;
}
}
Ptr(const Ptr<T> &other)
{
data_ = other.data_;
ref_count_ = other.ref_count_;
*ref_count_++;
}
Ptr<T> &operator=(const Ptr<T> &other)
{
if (this != other) {
*ref_count_--;
if (*ref_count_ == 0) {
delete data_;
delete ref_count_;
}
data_ = other.data_;
ref_count_ = other.ref_count_;
*ref_count_++;
}
}
private:
T *data_;
size_t *ref_count_;
};
}
#endif // PTR_H

View file

@ -1,217 +1,7 @@
#include "sitypes.h"
#include "chunk.h"
namespace si {
Data ReadU32(std::ifstream &is)
{
uint32_t u;
is.read((char *) &u, sizeof(u));
return u;
}
void WriteU32(std::ofstream &os, uint32_t u)
{
os.write((const char *) &u, sizeof(u));
}
Data ReadU16(std::ifstream &is)
{
uint16_t u;
is.read((char *) &u, sizeof(u));
return u;
}
void WriteU16(std::ofstream &os, uint16_t u)
{
os.write((const char *) &u, sizeof(u));
}
Data ReadU8(std::ifstream &is)
{
uint8_t u;
is.read((char *) &u, sizeof(u));
return u;
}
void WriteU8(std::ofstream &os, uint8_t u)
{
os.write((const char *) &u, sizeof(u));
}
Data ReadVector3(std::ifstream &is)
{
Vector3 u;
is.read((char *) &u, sizeof(u));
return u;
}
void WriteVector3(std::ofstream &os, Vector3 v)
{
os.write((const char *) &v, sizeof(v));
}
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;
}
void WriteString(std::ofstream &os, const std::string &d)
{
if (!d.empty()) {
// Write every byte that isn't null
const char *s = &d[0];
while ((*s) != 0) {
os.write(s, 1);
s++;
}
}
// Ensure null terminator
const char nullterm = 0;
os.write(&nullterm, 1);
}
Data ReadBytes(std::ifstream &is, size_t size)
{
bytearray d;
d.resize(size);
is.read(d.data(), size);
return d;
}
void WriteBytes(std::ofstream &os, const bytearray &ba)
{
os.write(ba.data(), ba.size());
}
void RIFF::Read(std::ifstream &is, DataMap &data, uint32_t version, uint32_t size)
{
data["Format"] = ReadU32(is);
}
void RIFF::Write(std::ofstream &os, const DataMap &data, uint32_t version)
{
WriteU32(os, data.at("Format"));
}
void LIST::Read(std::ifstream &is, DataMap &data, uint32_t version, uint32_t size)
{
data["Format"] = ReadU32(is);
if (data["Format"] == Chunk::TYPE_MxCh) {
data["Count"] = ReadU32(is);
}
}
void LIST::Write(std::ofstream &os, const DataMap &data, uint32_t version)
{
WriteU32(os, data.at("Format"));
if (data.at("Format") == Chunk::TYPE_MxCh) {
WriteU32(os, data.at("Count"));
}
}
void MxSt::Read(std::ifstream &is, DataMap &data, uint32_t version, uint32_t size)
{
// MxSt is a container type only and has no members, so nothing needs to be done here
}
void MxSt::Write(std::ofstream &os, const DataMap &data, uint32_t version)
{
// 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, uint32_t version, uint32_t size)
{
Data v = ReadU32(is);
data["Version"] = v;
data["BufferSize"] = ReadU32(is);
data["BufferCount"] = ReadU32(is);
}
void MxHd::Write(std::ofstream &os, const DataMap &data, uint32_t version)
{
WriteU32(os, data.at("Version"));
WriteU32(os, data.at("BufferSize"));
WriteU32(os, data.at("BufferCount"));
}
void MxCh::Read(std::ifstream &is, DataMap &data, uint32_t version, uint32_t size)
{
data["Flags"] = ReadU16(is);
data["Object"] = ReadU32(is);
data["Time"] = ReadU32(is);
data["DataSize"] = ReadU32(is);
data["Data"] = ReadBytes(is, size - 0xE);
}
void MxCh::Write(std::ofstream &os, const DataMap &data, uint32_t version)
{
WriteU16(os, data.at("Flags"));
WriteU32(os, data.at("Object"));
WriteU32(os, data.at("Time"));
WriteU32(os, data.at("DataSize"));
WriteBytes(os, data.at("Data"));
}
void MxOf::Read(std::ifstream &is, DataMap &data, uint32_t version, uint32_t size)
{
data["Count"] = ReadU32(is);
data["Offsets"] = ReadBytes(is, size - sizeof(uint32_t));
}
void MxOf::Write(std::ofstream &os, const DataMap &data, uint32_t version)
{
WriteU32(os, data.at("Count"));
WriteBytes(os, data.at("Offsets"));
}
void pad_::Read(std::ifstream &is, DataMap &data, uint32_t version, uint32_t size)
{
data["Size"] = size;
is.seekg(size, std::ios::cur);
}
void pad_::Write(std::ofstream &os, const DataMap &data, uint32_t version)
{
uint32_t sz = data.at("Size").toU32();
if (sz > 0) {
bytearray b;
b.resize(sz);
b.fill(0xCD);
WriteBytes(os, b);
}
}
void pad_::WriteArbitraryPadding(std::ofstream &os, uint32_t size)
{
uint32_t pad_id = Chunk::TYPE_pad_;
os.write((const char *) &pad_id, sizeof(uint32_t));
os.write((const char *) &size, sizeof(uint32_t));
bytearray b(size);
b.fill(0xCD);
WriteBytes(os, b);
}
const char *MxOb::GetTypeName(Type type)
{
switch (type) {
@ -266,80 +56,4 @@ std::vector<const char*> MxOb::GetFlagsName(Flags flags)
return names;
}
void MxOb::Read(std::ifstream &is, DataMap &data, uint32_t version, uint32_t 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["Flags"] = ReadU32(is);
data["Unknown4"] = ReadU32(is);
data["Duration"] = ReadU32(is);
data["Loops"] = ReadU32(is);
data["Position"] = ReadVector3(is);
data["Direction"] = ReadVector3(is);
data["Up"] = ReadVector3(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::Sound) {
data["Unknown31"] = ReadU32(is);
}
}
}
void MxOb::Write(std::ofstream &os, const DataMap &data, uint32_t version)
{
const Data &obj_type = data.at("Type");
WriteU16(os, obj_type);
WriteString(os, data.at("Presenter"));
WriteU32(os, data.at("Unknown1"));
WriteString(os, data.at("Name"));
WriteU32(os, data.at("ID"));
WriteU32(os, data.at("Flags"));
WriteU32(os, data.at("Unknown4"));
WriteU32(os, data.at("Duration"));
WriteU32(os, data.at("Loops"));
WriteVector3(os, data.at("Position"));
WriteVector3(os, data.at("Direction"));
WriteVector3(os, data.at("Up"));
const Data &extra = data.at("ExtraData");
WriteU16(os, extra.size());
WriteBytes(os, extra);
if (obj_type != Presenter && obj_type != World) {
WriteString(os, data.at("FileName"));
WriteU32(os, data.at("Unknown26"));
WriteU32(os, data.at("Unknown27"));
WriteU32(os, data.at("Unknown28"));
WriteU32(os, data.at("FileType"));
WriteU32(os, data.at("Unknown29"));
WriteU32(os, data.at("Unknown30"));
if (obj_type == MxOb::Sound) {
WriteU32(os, data.at("Unknown31"));
}
}
}
}

View file

@ -8,6 +8,23 @@
namespace si {
class SI
{
public:
enum Type
{
RIFF = 0x46464952,
LIST = 0x5453494c,
MxSt = 0x7453784d,
MxHd = 0x6448784d,
MxCh = 0x6843784d,
MxOf = 0x664f784d,
MxOb = 0x624f784d,
MxDa = 0x6144784d,
pad_ = 0x20646170
};
};
/**
* @brief RIFF chunk type
*
@ -21,12 +38,6 @@ public:
enum {
OMNI = 0x494e4d4f
};
virtual ~RIFF(){}
virtual void Read(std::ifstream &is, DataMap &data, uint32_t version, uint32_t size);
virtual void Write(std::ofstream &os, const DataMap &data, uint32_t version);
};
/**
@ -40,8 +51,6 @@ public:
class LIST : public RIFF
{
public:
virtual void Read(std::ifstream &is, DataMap &data, uint32_t version, uint32_t size);
virtual void Write(std::ofstream &os, const DataMap &data, uint32_t version);
};
/**
@ -56,8 +65,6 @@ public:
class MxHd : public RIFF
{
public:
virtual void Read(std::ifstream &is, DataMap &data, uint32_t version, uint32_t size);
virtual void Write(std::ofstream &os, const DataMap &data, uint32_t version);
};
/**
@ -68,8 +75,6 @@ public:
class MxSt : public RIFF
{
public:
virtual void Read(std::ifstream &is, DataMap &data, uint32_t version, uint32_t size);
virtual void Write(std::ofstream &os, const DataMap &data, uint32_t version);
};
/**
@ -92,9 +97,6 @@ public:
};
static const uint32_t HEADER_SIZE = 14;
virtual void Read(std::ifstream &is, DataMap &data, uint32_t version, uint32_t size);
virtual void Write(std::ofstream &os, const DataMap &data, uint32_t version);
};
/**
@ -108,8 +110,6 @@ public:
class MxOf : public RIFF
{
public:
virtual void Read(std::ifstream &is, DataMap &data, uint32_t version, uint32_t size);
virtual void Write(std::ofstream &os, const DataMap &data, uint32_t version);
};
/**
@ -121,9 +121,6 @@ public:
class pad_ : public RIFF
{
public:
virtual void Read(std::ifstream &is, DataMap &data, uint32_t version, uint32_t size);
virtual void Write(std::ofstream &os, const DataMap &data, uint32_t version);
static void WriteArbitraryPadding(std::ofstream &os, uint32_t size);
};
@ -235,9 +232,6 @@ public:
// probably be moved
LIBWEAVER_EXPORT static const char *GetTypeName(Type type);
LIBWEAVER_EXPORT static std::vector<const char*> GetFlagsName(Flags flags);
virtual void Read(std::ifstream &is, DataMap &data, uint32_t version, uint32_t size);
virtual void Write(std::ofstream &os, const DataMap &data, uint32_t version);
};
}

View file

@ -147,8 +147,6 @@ private:
};
typedef std::map<std::string, Data> DataMap;
}
#endif // TYPES_H

100
lib/util.h Normal file
View file

@ -0,0 +1,100 @@
#ifndef UTIL_H
#define UTIL_H
#include <fstream>
#include "types.h"
namespace si {
inline uint32_t ReadU32(std::ifstream &is)
{
uint32_t u;
is.read((char *) &u, sizeof(u));
return u;
}
inline void WriteU32(std::ofstream &os, uint32_t u)
{
os.write((const char *) &u, sizeof(u));
}
inline uint16_t ReadU16(std::ifstream &is)
{
uint16_t u;
is.read((char *) &u, sizeof(u));
return u;
}
inline void WriteU16(std::ofstream &os, uint16_t u)
{
os.write((const char *) &u, sizeof(u));
}
inline uint8_t ReadU8(std::ifstream &is)
{
uint8_t u;
is.read((char *) &u, sizeof(u));
return u;
}
inline void WriteU8(std::ofstream &os, uint8_t u)
{
os.write((const char *) &u, sizeof(u));
}
inline Vector3 ReadVector3(std::ifstream &is)
{
Vector3 u;
is.read((char *) &u, sizeof(u));
return u;
}
inline void WriteVector3(std::ofstream &os, Vector3 v)
{
os.write((const char *) &v, sizeof(v));
}
inline std::string ReadString(std::ifstream &is)
{
std::string d;
while (true) {
char c;
is.read(&c, 1);
if (c == 0) {
break;
}
d.push_back(c);
}
return d;
}
inline void WriteString(std::ofstream &os, const std::string &d)
{
os.write(d.c_str(), d.size());
// Ensure null terminator
const char nullterm = 0;
os.write(&nullterm, 1);
}
inline bytearray ReadBytes(std::ifstream &is, size_t size)
{
bytearray d;
d.resize(size);
is.read(d.data(), size);
return d;
}
inline void WriteBytes(std::ofstream &os, const bytearray &ba)
{
os.write(ba.data(), ba.size());
}
}
#endif // UTIL_H