From 4d05dc8ac820d1203eafb24790d756af3014f04d Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Mon, 11 Jul 2022 14:18:56 -0700 Subject: [PATCH] lib: implement write functions for RIFF classes --- lib/chunk.cpp | 60 +++++++++++++++++++++++++++++++++++++++++++++++-- lib/chunk.h | 7 +++++- lib/sitypes.cpp | 15 ++++++++----- lib/sitypes.h | 20 ++++++++++++++++- lib/types.h | 4 ++++ 5 files changed, 97 insertions(+), 9 deletions(-) diff --git a/lib/chunk.cpp b/lib/chunk.cpp index f282db1..c32f6bb 100644 --- a/lib/chunk.cpp +++ b/lib/chunk.cpp @@ -8,9 +8,10 @@ namespace si { -Chunk::Chunk() +Chunk::Chunk(uint32_t id) : + id_(id), + offset_(0) { - id_ = 0; } Chunk::~Chunk() @@ -89,6 +90,40 @@ bool Chunk::Read(std::ifstream &f, uint32_t &version, uint32_t &alignment) return true; } +bool Chunk::Write(std::ofstream &f, const uint32_t &version) const +{ + // 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 (RIFF *writer = GetReaderFromType(type())) { + writer->Write(f, data_, version); + delete writer; + } + + for (Children::const_iterator it=GetChildren().begin(); it!=GetChildren().end(); it++) { + static_cast(*it)->Write(f, version); + } + + // 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) { @@ -108,6 +143,8 @@ RIFF *Chunk::GetReaderFromType(Type type) return new pad_(); case TYPE_MxOb: return new MxOb(); + case TYPE_MxDa: + break; } return NULL; @@ -122,6 +159,23 @@ void Chunk::Clear() 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; + + return Write(file, version); +} + const char *Chunk::GetTypeDescription(Type type) { switch (type) { @@ -141,6 +195,8 @@ const char *Chunk::GetTypeDescription(Type type) return "Padding"; case TYPE_MxOb: return "Streamable Object"; + case TYPE_MxDa: + return "Data"; } return "Unknown"; diff --git a/lib/chunk.h b/lib/chunk.h index 525a926..1582960 100644 --- a/lib/chunk.h +++ b/lib/chunk.h @@ -24,16 +24,20 @@ public: TYPE_MxCh = 0x6843784d, TYPE_MxOf = 0x664f784d, TYPE_MxOb = 0x624f784d, + TYPE_MxDa = 0x6144784d, TYPE_pad_ = 0x20646170 }; - LIBWEAVER_EXPORT Chunk(); + 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_; } @@ -52,6 +56,7 @@ public: private: bool Read(std::ifstream &f, uint32_t &version, uint32_t &alignment); + bool Write(std::ofstream &f, const uint32_t &version) const; static RIFF *GetReaderFromType(Type type); diff --git a/lib/sitypes.cpp b/lib/sitypes.cpp index b8c30a5..085fd13 100644 --- a/lib/sitypes.cpp +++ b/lib/sitypes.cpp @@ -78,6 +78,7 @@ void WriteString(std::ofstream &os, const std::string &d) const char *s = &d[0]; while ((*s) != 0) { os.write(s, 1); + s++; } } @@ -186,15 +187,19 @@ void MxOf::Write(std::ofstream &os, const DataMap &data, uint32_t version) 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_::WritePadding(std::ofstream &os, size_t size) +void pad_::Write(std::ofstream &os, const DataMap &data, uint32_t version) { - bytearray b; - b.resize(size); - b.fill(0xCD); - WriteBytes(os, b); + uint32_t sz = data.at("Size").toU32(); + if (sz > 0) { + bytearray b; + b.resize(sz); + b.fill(0xCD); + WriteBytes(os, b); + } } const char *MxOb::GetTypeName(Type type) diff --git a/lib/sitypes.h b/lib/sitypes.h index 2bacda6..eb03fa7 100644 --- a/lib/sitypes.h +++ b/lib/sitypes.h @@ -18,6 +18,10 @@ namespace si { class RIFF { public: + enum { + OMNI = 0x494e4d4f + }; + virtual ~RIFF(){} virtual void Read(std::ifstream &is, DataMap &data, uint32_t version, uint32_t size); @@ -81,6 +85,13 @@ public: class MxCh : public RIFF { public: + enum Flag { + FLAG_SPLIT = 0x16, + FLAG_END = 0x2 + }; + + 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); }; @@ -110,7 +121,7 @@ class pad_ : public RIFF { public: virtual void Read(std::ifstream &is, DataMap &data, uint32_t version, uint32_t size); - void WritePadding(std::ofstream &os, size_t size); + virtual void Write(std::ofstream &os, const DataMap &data, uint32_t version); }; /** @@ -146,6 +157,10 @@ class MxOb : public RIFF public: enum Type { + /// Not an MxOb type, this is our identifier for an object that is in the TOC but doesn't + /// actually exist + Null = -1, + /// Video Video = 0x03, @@ -202,6 +217,9 @@ public: /// Bitmap image STL = 0x4C545320, + + /// FLIC animation + FLC = 0x434c4620, }; // FIXME: sitypes.h probably won't be part of the public API, so this should diff --git a/lib/types.h b/lib/types.h index dbb2d5e..9014882 100644 --- a/lib/types.h +++ b/lib/types.h @@ -26,6 +26,10 @@ class bytearray : public std::vector { public: bytearray(){} + bytearray(size_t size) + { + resize(size); + } template T *cast() { return reinterpret_cast(data()); }