From 0a76066185d88a1561c43074d17f4c3109250265 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sun, 17 Jul 2022 18:51:16 -0700 Subject: [PATCH] start test changes --- app/CMakeLists.txt | 32 ++--- app/mainwindow.cpp | 33 ++---- lib/CMakeLists.txt | 7 +- lib/chunk.cpp | 264 ----------------------------------------- lib/chunk.h | 71 ----------- lib/interleaf.cpp | 252 ++++++++++++++++++++++++++++++++++++++- lib/interleaf.h | 32 +++-- lib/object.cpp | 77 +++++------- lib/object.h | 6 +- lib/ptr.h | 59 ++++++++++ lib/sitypes.cpp | 286 --------------------------------------------- lib/sitypes.h | 40 +++---- lib/types.h | 2 - lib/util.h | 100 ++++++++++++++++ 14 files changed, 509 insertions(+), 752 deletions(-) delete mode 100644 lib/chunk.cpp delete mode 100644 lib/chunk.h create mode 100644 lib/ptr.h create mode 100644 lib/util.h diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 2e8a13d..b921032 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -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") -target_compile_options(si-edit PRIVATE -Werror) +if (NOT MSVC) + target_compile_options(si-edit PRIVATE -Werror) +endif() set_target_properties(si-edit PROPERTIES MACOSX_BUNDLE_GUI_IDENTIFIER com.mattkc.SIEdit diff --git a/app/mainwindow.cpp b/app/mainwindow.cpp index 8b44594..b3f04d5 100644 --- a/app/mainwindow.cpp +++ b/app/mainwindow.cpp @@ -6,8 +6,6 @@ #include #include -#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); - model_.SetCore(&interleaf_); - } + model_.SetCore(nullptr); + + 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) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 60d7d14..c3a047d 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -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) -target_compile_options(libweaver PRIVATE -Werror -Wall -Wextra -Wno-unused-parameter) +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 diff --git a/lib/chunk.cpp b/lib/chunk.cpp deleted file mode 100644 index 1c093d1..0000000 --- a/lib/chunk.cpp +++ /dev/null @@ -1,264 +0,0 @@ -#include "chunk.h" - -#include -#include -#include - -#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(*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(¬hing, 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(*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(*it); - if (chunk->offset() == offset) { - return chunk; - } else if (Chunk *grandchild = chunk->FindChildWithOffset(offset)) { - return grandchild; - } - } - - return NULL; -} - -} diff --git a/lib/chunk.h b/lib/chunk.h deleted file mode 100644 index 8d81d16..0000000 --- a/lib/chunk.h +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef CHUNK_H -#define CHUNK_H - -#include -#include -#include - -#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(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 diff --git a/lib/interleaf.cpp b/lib/interleaf.cpp index 9ebe47d..e906513 100644 --- a/lib/interleaf.cpp +++ b/lib/interleaf.cpp @@ -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(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(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(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::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; -} +}*/ } diff --git a/lib/interleaf.h b/lib/interleaf.h index f6f1040..b74c007 100644 --- a/lib/interleaf.h +++ b/lib/interleaf.h @@ -1,7 +1,8 @@ #ifndef INTERLEAF_H #define INTERLEAF_H -#include "chunk.h" +#include + #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 m_OffsetTable; + + std::map m_ObjectIndexTable; }; diff --git a/lib/object.cpp b/lib/object.cpp index f2de968..91c242c 100644 --- a/lib/object.cpp +++ b/lib/object.cpp @@ -2,6 +2,8 @@ #include +#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(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(chunk->data("FileType").toU32()); - unknown29_ = chunk->data("Unknown29"); - unknown30_ = chunk->data("Unknown30"); - unknown31_ = chunk->data("Unknown31"); + if (chunk->HasChildren()) { Chunk *child = static_cast(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(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 " diff --git a/lib/object.h b/lib/object.h index 50ea13b..93662a5 100644 --- a/lib/object.h +++ b/lib/object.h @@ -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_; diff --git a/lib/ptr.h b/lib/ptr.h new file mode 100644 index 0000000..4314d43 --- /dev/null +++ b/lib/ptr.h @@ -0,0 +1,59 @@ +#ifndef PTR_H +#define PTR_H + +namespace si { + +/** + * @brief Smart pointer implementation for versions of C++ < 11 + */ +template +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 &other) + { + data_ = other.data_; + ref_count_ = other.ref_count_; + *ref_count_++; + } + + Ptr &operator=(const Ptr &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 diff --git a/lib/sitypes.cpp b/lib/sitypes.cpp index 2a8456e..710eda1 100644 --- a/lib/sitypes.cpp +++ b/lib/sitypes.cpp @@ -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 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")); - } - } -} - } diff --git a/lib/sitypes.h b/lib/sitypes.h index cc9e37b..50c70da 100644 --- a/lib/sitypes.h +++ b/lib/sitypes.h @@ -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 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); }; } diff --git a/lib/types.h b/lib/types.h index 805e4b2..0c3f3cc 100644 --- a/lib/types.h +++ b/lib/types.h @@ -147,8 +147,6 @@ private: }; -typedef std::map DataMap; - } #endif // TYPES_H diff --git a/lib/util.h b/lib/util.h new file mode 100644 index 0000000..5b28787 --- /dev/null +++ b/lib/util.h @@ -0,0 +1,100 @@ +#ifndef UTIL_H +#define UTIL_H + +#include + +#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