diff --git a/PanoPainter.vcxproj b/PanoPainter.vcxproj index 695c5f9..0ad5ff6 100644 --- a/PanoPainter.vcxproj +++ b/PanoPainter.vcxproj @@ -201,6 +201,7 @@ + @@ -255,6 +256,7 @@ Create + @@ -327,6 +329,7 @@ + @@ -376,6 +379,7 @@ + diff --git a/PanoPainter.vcxproj.filters b/PanoPainter.vcxproj.filters index 4c19ea1..21a39d2 100644 --- a/PanoPainter.vcxproj.filters +++ b/PanoPainter.vcxproj.filters @@ -309,6 +309,12 @@ Source Files\ui + + Source Files + + + Source Files + @@ -539,6 +545,12 @@ Header Files\ui + + Header Files + + + Header Files + diff --git a/src/abr.cpp b/src/abr.cpp index 64755ec..a662e71 100644 --- a/src/abr.cpp +++ b/src/abr.cpp @@ -1,27 +1,7 @@ #include "pch.h" #include "abr.h" #include "log.h" - -SerializedStream::Type::Ref SerializedStream::instanciate(const std::string& key) -{ - if (m_ctor_table.find(key) != m_ctor_table.end()) - return m_ctor_table[key](); - return nullptr; -} - -std::map> SerializedStream::m_ctor_table = -{ - { "VlLs", []{ return std::make_shared(); } }, - { "TEXT", []{ return std::make_shared(); } }, - { "Objc", []{ return std::make_shared(); } }, - { "UntF", []{ return std::make_shared(); } }, - { "bool", []{ return std::make_shared(); } }, - { "long", []{ return std::make_shared(); } }, - { "doub", []{ return std::make_shared(); } }, - { "enum", []{ return std::make_shared(); } }, - { "tdta", []{ return std::make_shared(); } }, -}; - +#include "asset.h" bool ABR::section_desc() { diff --git a/src/abr.h b/src/abr.h index e69e95b..0c12846 100644 --- a/src/abr.h +++ b/src/abr.h @@ -1,798 +1,9 @@ #pragma once -#include "asset.h" -#include -#include -#include "util.h" -#include "image.h" #include "brush.h" -#include "log.h" +#include "serializer.h" +#include "binary_stream.h" -class BinaryStream -{ -public: - enum class ByteOrder : uint8_t { BigEndian, LittleEndian, Host }; - static ByteOrder sys_order() - { - union { - uint32_t i; - char c[4]; - } bint { 0x01020304 }; - - return bint.c[0] == 1 ? ByteOrder::BigEndian : ByteOrder::LittleEndian; - } - template T swap(T x) - { -#if _MSC_VER >= 1400 - - if (sizeof(T) == 2) - { - auto y = _byteswap_ushort(*reinterpret_cast(&x)); - return *reinterpret_cast(&y); - } - else if (sizeof(T) == 4) - { - auto y = _byteswap_ulong(*reinterpret_cast(&x)); - return *reinterpret_cast(&y); - } - else if (sizeof(T) == 8) - { - auto y = _byteswap_uint64(*reinterpret_cast(&x)); - return *reinterpret_cast(&y); - } -#else - auto p = reinterpret_cast(&x); - if (sizeof(T) == 2) - { - std::swap(p[0], p[1]); - } - else if (sizeof(T) == 4) - { - std::swap(p[0], p[3]); - std::swap(p[1], p[2]); - } - else if (sizeof(T) == 8) - { - std::swap(p[0], p[7]); - std::swap(p[1], p[6]); - std::swap(p[2], p[5]); - std::swap(p[3], p[4]); - } - else - { - static_assert(true, "Should not reach here"); - } - return x; -#endif - } -protected: - bool m_swap = false; - ByteOrder m_byte_order = ByteOrder::Host; -}; - -class BinaryStreamReader : public BinaryStream -{ -public: - BinaryStreamReader(const BinaryStreamReader&) = delete; - BinaryStreamReader() = default; - ~BinaryStreamReader() - { - m_ptr = m_cur = nullptr; - m_size = 0; - } - void init(uint8_t* data_ptr, size_t size, ByteOrder byte_order = ByteOrder::Host) - { - m_ptr = m_cur = data_ptr; - m_size = size; - m_byte_order = byte_order; - m_swap = byte_order == ByteOrder::Host ? false : byte_order != sys_order(); - } - size_t pos() { return std::distance(m_ptr, m_cur); } - void skip(size_t bytes) { m_cur += bytes; } - // snap to the next 4-alignment - void snap() { if ((size_t)m_cur % 4 != 0) m_cur += 4 - (size_t)m_cur % 4; } - bool eof() { return std::distance(m_ptr, m_cur) >= m_size; } - bool has_data(size_t sz) { return std::distance(m_ptr, m_cur + sz) <= m_size; } - uint8_t ru8() { return read(); } - uint16_t ru16() { return m_swap ? swap(read()) : read(); } - uint32_t ru32() { return m_swap ? swap(read()) : read(); } - uint64_t ru64() { return m_swap ? swap(read()) : read(); } - int8_t ri8() { return read(); } - int16_t ri16() { return m_swap ? swap(read()) : read(); } - int32_t ri32() { return m_swap ? swap(read()) : read(); } - int64_t ri64() { return m_swap ? swap(read()) : read(); } - float rflt() { return m_swap ? swap(read()) : read(); } - double rdbl() { return m_swap ? swap(read()) : read(); } - std::string pick(size_t chars) { return { (char*)m_cur, chars }; } - std::string rstring() - { - auto len = ru32(); - return { advance(len), len }; - } - std::string rstring(size_t len) { return { advance(len), len }; } - std::wstring rwstring() - { - auto len = ru32(); - return rwstring(len); - } - std::wstring rwstring(size_t len) - { - auto ptr = advance(len * 2); - //for (int i = 0; i < len; i++) - // std::swap(ptr[i * 2], ptr[i * 2 + 1]); - - // right trim trailing zeroes - auto wptr = (uint16_t*)ptr; - for (int i = len - 1; i >= 0; i--) - if (wptr[i] == 0) len--; - - // wide to UTF-16le - std::wstring_convert> converter; - return converter.from_bytes(ptr, ptr + len * 2); - } - std::string rpascal() - { - auto len = ru8(); - return rstring(len); - } - std::vector rraw() - { - auto size = ru32(); - return rraw(size); - } - std::vector rraw(size_t bytes) - { - std::vector ret(bytes); - std::copy_n(m_cur, bytes, ret.data()); - skip(bytes); - return ret; - } - std::vector rrle(size_t encoded_bytes) - { - std::vector data; - int32_t n; - for (int j = 0; j < encoded_bytes;) - { - n = ri8(); - j++; - // copy the following char -n + 1 times - if (n < 0) - { - // NOP - if (n == -128) - continue; - n = -n + 1; - - j++; - auto ch = ru8(); - for (int c = 0; c < n; c++) - data.push_back(ch); - } - else - { - // read the following n + 1 chars (no compr) - for (int c = 0; c < n + 1; c++, j++) - data.push_back(ru8()); - } - } - return data; - } - std::string rkey_or_string() - { - auto len = ru32(); - if (len == 0) - len = 4; - return rstring(len); - } -protected: - template inline T align4(T x) { return ((x - T{1}) & (~(T{3}))) + T{4}; } - template T read() - { - T ret{}; - if (m_ptr) - { - if (has_data(sizeof(T))) - ret = *reinterpret_cast(m_cur); - m_cur += sizeof(T); - } - return ret; - } - template T* advance(size_t bytes) - { - T* ret = nullptr; - if (m_ptr) - { - if (has_data(bytes)) - ret = reinterpret_cast(m_cur); - m_cur += bytes; - } - return ret; - } -private: - uint8_t *m_ptr = nullptr; - uint8_t *m_cur = nullptr; - size_t m_size = 0; -}; - -class BinaryStreamWriter : public BinaryStream -{ -public: - std::vector m_data; - BinaryStreamWriter(const BinaryStreamWriter&) = delete; - BinaryStreamWriter() = default; - ~BinaryStreamWriter() = default; - void init(ByteOrder byte_order = ByteOrder::Host) - { - m_byte_order = byte_order; - m_swap = byte_order == ByteOrder::Host ? false : byte_order != sys_order(); - } - //size_t pos() { return std::distance(m_ptr, m_cur); } - void skip(size_t bytes, uint8_t fill = 0) { m_data.resize(m_data.size() + bytes); } - // snap to the next 4-alignment - void snap() { if ((size_t)m_data.size() % 4 != 0) m_data.resize(m_data.size() + 4 - (size_t)m_data.size() % 4); } - //bool eof() { return std::distance(m_ptr, m_cur) >= m_size; } - //bool has_data(size_t sz) { return std::distance(m_ptr, m_cur + sz) < m_size; } - void wu8 (uint8_t v ) { return write(v); } - void wu16(uint16_t v) { return m_swap ? write(swap(v)) : write(v); } - void wu32(uint32_t v) { return m_swap ? write(swap(v)) : write(v); } - void wu64(uint64_t v) { return m_swap ? write(swap(v)) : write(v); } - void wi8 (int8_t v ) { return write(v); } - void wi16(int16_t v ) { return m_swap ? write(swap(v)) : write(v); } - void wi32(int32_t v ) { return m_swap ? write(swap(v)) : write(v); } - void wi64(int64_t v ) { return m_swap ? write(swap(v)) : write(v); } - void wflt(float v ) { return m_swap ? write(swap(v)) : write(v); } - void wdbl(double v ) { return m_swap ? write(swap(v)) : write(v); } - //std::string pick(size_t chars) { return { (char*)m_cur, chars }; } - void wstring(std::string s) - { - wu32(s.size()); - write(s.data(), s.size()); - } - void wstring_raw(std::string s) - { - write(s.data(), s.size()); - } - void wwstring(std::wstring s) - { - wu32(s.size()); - std::wstring_convert> converter; - wstring(converter.to_bytes(s)); - } - void wwstring_raw(std::wstring s) - { - std::wstring_convert> converter; - wstring(converter.to_bytes(s)); - } - void wpascal(std::string s) - { - wu8(s.size()); - write(s.data(), s.size()); - } - void wraw(std::vector raw) - { - wu32(raw.size()); - write(raw.data(), raw.size()); - } - void wrle(std::vector data) - { - int idx = 0; - auto ptr = data.data(); - - // find the next sequence and return the position - auto next_seq = [&] () -> std::pair { - size_t i = idx; - while (i < data.size() - 1) - { - size_t count = 0; - for (size_t j = i + 1; j < data.size() && data[i] == data[j]; j++) - count++; - if (count > 0) - return { i, count + 1 }; - i++; - } - return { i + 1, 0 }; - }; - - while (idx < data.size()) - { - auto seq = next_seq(); - // non sequence chars - if (seq.first - idx > 0) - { - wi8(seq.first - idx - 1); - write(ptr + idx, seq.first - idx); - } - if (seq.second > 0) - { - wi8(-(int8_t)(seq.second - 1)); - write(ptr[seq.first]); - } - idx = seq.first + seq.second; - } - } - void wkey_or_string(std::string s) - { - wstring(s); - } -protected: - template void write(T x) - { - uint8_t* bytes = reinterpret_cast(&x); - m_data.insert(m_data.end(), bytes, bytes + sizeof(T)); - } - template void write(const T* ptr, size_t size) - { - const uint8_t* bytes = reinterpret_cast(ptr); - m_data.insert(m_data.end(), bytes, bytes + size * sizeof(T)); - } -}; - -class SerializedStream -{ -public: - struct Type - { - using Vec = std::vector>; - using Map = std::map>; - using Ref = std::shared_ptr; - virtual std::string str(int indent, const std::string& prefix) const - { - return "type"; - } - virtual bool read(BinaryStreamReader& r) { return false; } - virtual void write(BinaryStreamWriter& w) const { } - virtual std::string type_key() const { return ""; } - }; - struct Class : public Type { }; - struct Property : public Type { }; - struct Reference : public Type { }; - struct EnumRef : public Type { }; - struct Offset : public Type { }; - struct Identifier : public Type { }; - struct Index : public Type { }; - struct Name : public Type { }; - struct LargeInteger : public Type { }; - struct Alias : public Type { }; - struct List : public Type - { - Type::Vec items; - virtual std::string type_key() const override { return "VlLs"; } - virtual std::string str(int indent, const std::string& prefix) const override - { - auto ret = std::string(indent, '-') + fmt::format("list: {} items:", items.size()); - for (int i = 0; i < items.size(); i++) - ret += "\n" + items[i]->str(indent + 1, fmt::format("{}) ", i)); - return ret; - } - virtual bool read(BinaryStreamReader& r) override - { - auto count = r.ru32(); - for (int i = 0; i < count; i++) - { - auto type = r.rstring(4); - auto item = instanciate(type); - if (!item || !item->read(r)) - return false; - items.push_back(item); - } - return true; - } - virtual void write(BinaryStreamWriter& w) const override - { - w.wi32(items.size()); - for (auto& i : items) - i->write(w); - } - }; - struct Double : public Type - { - using native_type = double; - double value; - virtual std::string type_key() const override { return "doub"; } - virtual std::string str(int indent, const std::string& prefix) const override - { - return std::string(indent, '-') + prefix + fmt::format("double: {}", value); - } - virtual bool read(BinaryStreamReader& r) override - { - value = r.rdbl(); - return true; - } - virtual void write(BinaryStreamWriter& w) const override - { - w.wdbl(value); - } - }; - struct UnitFloat : public Type - { - using native_type = double; - std::string unit; - double value; - virtual std::string type_key() const override { return "UntF"; } - virtual std::string str(int indent, const std::string& prefix) const override - { - return std::string(indent, '-') + prefix + fmt::format("float: {} ({})", value, unit); - } - virtual bool read(BinaryStreamReader& r) override - { - unit = r.rstring(4); - value = r.rdbl(); - return true; - } - virtual void write(BinaryStreamWriter& w) const override - { - w.wstring_raw(unit); - w.wdbl(value); - } - }; - struct String : public Type - { - using native_type = std::wstring; - std::wstring value; - virtual std::string type_key() const override { return "TEXT"; } - virtual std::string str(int indent, const std::string& prefix) const override - { - return std::string(indent, '-') + prefix + fmt::format("string: {}", wstr2str(value)); - } - virtual bool read(BinaryStreamReader& r) override - { - value = r.rwstring(); - return true; - } - virtual void write(BinaryStreamWriter& w) const override - { - w.wwstring(value); - } - }; - struct Enum : public Type - { - std::string type; - std::string value; - virtual std::string type_key() const override { return "enum"; } - virtual std::string str(int indent, const std::string& prefix) const override - { - return std::string(indent, '-') + prefix + fmt::format("enum {}: {}", type, value); - } - virtual bool read(BinaryStreamReader& r) override - { - type = r.rkey_or_string(); - value = r.rkey_or_string(); - return true; - } - virtual void write(BinaryStreamWriter& w) const override - { - w.wkey_or_string(type); - w.wkey_or_string(value); - } - }; - struct Integer : public Type - { - using native_type = int32_t; - int32_t value; - virtual std::string type_key() const override { return "long"; } - virtual std::string str(int indent, const std::string& prefix) const override - { - return std::string(indent, '-') + prefix + fmt::format("int: {}", value); - } - virtual bool read(BinaryStreamReader& r) override - { - value = r.ri32(); - return true; - } - virtual void write(BinaryStreamWriter& w) const override - { - w.wi32(value); - } - }; - struct Boolean : public Type - { - using native_type = bool; - bool value; - virtual std::string type_key() const override { return "bool"; } - virtual std::string str(int indent, const std::string& prefix) const override - { - return std::string(indent, '-') + prefix + fmt::format("bool: {}", value); - } - virtual bool read(BinaryStreamReader& r) override - { - value = r.ru8(); - return true; - } - virtual void write(BinaryStreamWriter& w) const override - { - w.wu8(value); - } - }; - struct RawData : public Type - { - std::vector data; - virtual std::string type_key() const override { return "tdta"; } - virtual std::string str(int indent, const std::string& prefix) const override - { - return std::string(indent, '-') + prefix + fmt::format("raw: {} bytes", data.size()); - } - virtual bool read(BinaryStreamReader& r) override - { - data = r.rraw(); - return true; - } - virtual void write(BinaryStreamWriter& w) const override - { - w.wraw(data); - } - }; - struct Descriptor : public Type - { - std::wstring name; - std::string class_id; - Type::Map props; - virtual std::string type_key() const override { return "Objc"; } - virtual std::string str(int indent, const std::string& prefix) const override - { - auto ret = std::string(indent, '-') + prefix + - fmt::format("objc {} ({}): {} props:", wstr2str(name), class_id, props.size()); - for (const auto& p : props) - ret += "\n" + p.second->str(indent + 1, fmt::format("'{}' ", p.first)); - return ret; - } - bool has(const std::string& key) const - { - return props.find(key) != props.end(); - } - template std::shared_ptr get(const std::string& key) const - { - return has(key) ? std::dynamic_pointer_cast(props.at(key)) : nullptr; - } - template auto value(const std::string& key) const - { - if (auto v = get(key)) - return v->value; - return decltype(T::value){}; - } - template auto value_or(const std::string& key, const D val) const - { - if (auto v = get(key)) - return v->value; - return val; - } - template void value(const std::string& key, D& dest) const - { - if (auto v = get(key)) - dest = static_cast(v->value); - } - virtual bool read(BinaryStreamReader& r) override - { - name = r.rwstring(); - class_id = r.rkey_or_string(); - auto count = r.ru32(); - for (int i = 0; i < count; i++) - { - auto key = r.rkey_or_string(); - auto type = r.rstring(4); - //printf("prop %s\n", t.c_str()); - auto p = instanciate(type); - if (!p || !p->read(r)) - return false; - if (props.find(key) != props.end()) - LOG("DUPLICATE prop %s\n", key.c_str()); - props[key] = p; - } - return true; - } - virtual void write(BinaryStreamWriter& w) const override - { - w.wwstring(name); - w.wkey_or_string(class_id); - w.wu32(props.size()); - for (auto& p : props) - { - w.wkey_or_string(p.first); - w.wstring(p.second->type_key()); - p.second->write(w); - } - } - }; - struct Rectangle : public Type - { - uint32_t top; - uint32_t left; - uint32_t bottom; - uint32_t right; - uint32_t area() const { return (right - left) * (bottom - top); } - uint32_t width() const { return right - left; } - uint32_t height() const { return bottom - top; } - virtual std::string str(int indent, const std::string& prefix) const override - { - return std::string(indent, '-') + prefix + fmt::format("rect: [{}, {}, {}, {}]", top, left, bottom, right); - } - virtual bool read(BinaryStreamReader& r) override - { - top = r.ru32(); - left = r.ru32(); - bottom = r.ru32(); - right = r.ru32(); - return true; - } - virtual void write(BinaryStreamWriter& w) const override - { - w.wu32(top); - w.wu32(left); - w.wu32(bottom); - w.wu32(right); - } - }; - struct Point : public Type - { - uint32_t x; - uint32_t y; - virtual std::string str(int indent, const std::string& prefix) const override - { - return std::string(indent, '-') + prefix + fmt::format("point: [{}, {}]", x, y); - } - virtual bool read(BinaryStreamReader& r) override - { - x = r.ru32(); - y = r.ru32(); - return true; - } - virtual void write(BinaryStreamWriter& w) const override - { - w.wu32(x); - w.wu32(y); - } - }; - struct Channel : public Type - { - uint32_t depth; - Rectangle rect; - uint8_t compression; - std::vector data; - Channel() = default; - //Channel(uint32_t depth, Rectangle rect, uint8_t compression, std::vector data) : - // depth(depth), rect(rect), compression(compression), data(std::move(data)) { } - virtual bool read(BinaryStreamReader& r) override - { - auto length = r.ru32(); // skip if 0, length is from the next field to the end - if (length == 0) - return true; - depth = r.ru32(); // Pixel depth: 1, 8, 16 or 32 - rect.read(r); - auto depth2 = r.ru16(); // again? - compression = r.ru8(); // 1 = zip - if (depth != 8) - { - LOG("unsupported depth %d bits\n", depth); - r.skip(length - 23); - return true; - } - if (compression == 0) - { - int data_size = (depth >> 3) * rect.area(); - data = r.rraw(data_size); - } - else if (compression == 1) - { - auto start = r.pos(); - auto height = rect.height(); - // contain the compressed length of each scanline - std::vector scanlines; - scanlines.reserve(height); - for (int i = 0; i < height; i++) - scanlines.push_back(r.ru16()); - for (auto sl : scanlines) - { - auto decoded = r.rrle(sl); - data.insert(data.end(), decoded.begin(), decoded.end()); - } - auto len = r.pos() - start; - } - else - { - LOG("unsupported compression mode %d\n", compression); - r.skip(length - 23); - return true; - } - } - virtual void write(BinaryStreamWriter& w) const override - { - } - }; - struct VMArray : public Type - { - uint32_t version; // = 3 - Rectangle rect; - std::vector channels; - VMArray() = default; - //VMArray(uint32_t version, const Rectangle& rect) : version(version), rect(rect) { } - std::shared_ptr image(bool grayscale, bool invert) const - { - int nc = channels.size(); - auto pixels = (channels[0].depth >> 3) * rect.area(); - if (nc == 1 || nc >= 3) - { - auto img = std::make_shared(); - img->comp = 4; - img->width = rect.width(); - img->height = rect.height(); - img->m_data = std::make_unique(pixels * 4); - auto out = reinterpret_cast(img->m_data.get()); - if (grayscale) - { - auto const& raw = channels[0].data; - if (invert) - { - for (int i = 0; i < raw.size(); i++) - out[i] = glm::u8vec4(glm::u8vec3(255 - raw[i]), 255); - } - else - { - for (int i = 0; i < raw.size(); i++) - out[i] = glm::u8vec4(glm::u8vec3(raw[i]), 255); - } - } - else - { - std::fill_n(out, pixels, glm::u8vec4(255)); - for (int ch = 0; ch < std::min(nc, 3); ch++) - { - auto const& raw = channels[ch].data; - if (invert) - { - for (int i = 0; i < raw.size(); i++) - out[i][ch] = 255 - raw[i]; - } - else - { - for (int i = 0; i < raw.size(); i++) - out[i][ch] = raw[i]; - } - } - } - return img; - //stbi_write_png(fmt::format("x64/out/{}.png", uid).c_str(), - // image->rect.width(), image->rect.height(), 4, out.data(), 0); - } - else - { - LOG("Error image with %d channels\n", channels.size()); - } - return nullptr; - } - virtual bool read(BinaryStreamReader& r) override - { - // Virtual Memory Array List - version = r.ru32(); // = 3 - assert(version == 3); - auto vmem_length = r.ru32(); - // TODO: check if at the end there's good data - // check if the bounds are within the parent's size - rect.read(r); - auto vmem_channels = r.ru32(); - // The following is a virtual memory array, - // repeated for the number of channels - // + one for a user mask + one for a sheet mask. - vmem_channels += 2; // user and sheet mask - for (int ch = 0; ch < vmem_channels; ch++) - { - auto array_written = r.ru32(); // skip if 0 - if (array_written == 0) - continue; - channels.emplace_back(); - if (!channels.back().read(r)) - return false; - } - r.snap(); - return true; - } - virtual void write(BinaryStreamWriter& w) const override - { - } - }; -protected: - static Type::Ref instanciate(const std::string& key); - static std::map> m_ctor_table; -}; - -class ABR : public SerializedStream, public BinaryStreamReader +class ABR : public Serializer, public BinaryStreamReader { bool section_desc(); bool section_samp(); diff --git a/src/binary_stream.cpp b/src/binary_stream.cpp new file mode 100644 index 0000000..047f858 --- /dev/null +++ b/src/binary_stream.cpp @@ -0,0 +1,335 @@ +#include "pch.h" +#include "binary_stream.h" + + + +BinaryStreamReader::~BinaryStreamReader() +{ + m_ptr = m_cur = nullptr; + m_size = 0; +} + +void BinaryStreamReader::init(uint8_t* data_ptr, size_t size, ByteOrder byte_order /*= ByteOrder::Host*/) +{ + m_ptr = m_cur = data_ptr; + m_size = size; + m_byte_order = byte_order; + m_swap = byte_order == ByteOrder::Host ? false : byte_order != sys_order(); +} + +size_t BinaryStreamReader::pos() +{ + return std::distance(m_ptr, m_cur); +} + +void BinaryStreamReader::skip(size_t bytes) +{ + m_cur += bytes; +} + +void BinaryStreamReader::snap() +{ + if ((size_t)m_cur % 4 != 0) m_cur += 4 - (size_t)m_cur % 4; +} + +bool BinaryStreamReader::eof() +{ + return std::distance(m_ptr, m_cur) >= m_size; +} + +bool BinaryStreamReader::has_data(size_t sz) +{ + return std::distance(m_ptr, m_cur + sz) <= m_size; +} + +uint8_t BinaryStreamReader::ru8() +{ + return read(); +} + +uint16_t BinaryStreamReader::ru16() +{ + return m_swap ? swap(read()) : read(); +} + +uint32_t BinaryStreamReader::ru32() +{ + return m_swap ? swap(read()) : read(); +} + +uint64_t BinaryStreamReader::ru64() +{ + return m_swap ? swap(read()) : read(); +} + +int8_t BinaryStreamReader::ri8() +{ + return read(); +} + +int16_t BinaryStreamReader::ri16() +{ + return m_swap ? swap(read()) : read(); +} + +int32_t BinaryStreamReader::ri32() +{ + return m_swap ? swap(read()) : read(); +} + +int64_t BinaryStreamReader::ri64() +{ + return m_swap ? swap(read()) : read(); +} + +float BinaryStreamReader::rflt() +{ + return m_swap ? swap(read()) : read(); +} + +double BinaryStreamReader::rdbl() +{ + return m_swap ? swap(read()) : read(); +} + +std::string BinaryStreamReader::pick(size_t chars) +{ + return { (char*)m_cur, chars }; +} + +std::string BinaryStreamReader::rstring(size_t len) +{ + return { advance(len), len }; +} + +std::string BinaryStreamReader::rstring() +{ + auto len = ru32(); + return { advance(len), len }; +} + +std::wstring BinaryStreamReader::rwstring(size_t len) +{ + auto ptr = advance(len * 2); + //for (int i = 0; i < len; i++) + // std::swap(ptr[i * 2], ptr[i * 2 + 1]); + + // right trim trailing zeroes + auto wptr = (uint16_t*)ptr; + for (int i = len - 1; i >= 0; i--) + if (wptr[i] == 0) len--; + + // wide to UTF-16le + std::wstring_convert> converter; + return converter.from_bytes(ptr, ptr + len * 2); +} + +std::wstring BinaryStreamReader::rwstring() +{ + auto len = ru32(); + return rwstring(len); +} + +std::string BinaryStreamReader::rpascal() +{ + auto len = ru8(); + return rstring(len); +} + +std::vector BinaryStreamReader::rraw(size_t bytes) +{ + std::vector ret(bytes); + std::copy_n(m_cur, bytes, ret.data()); + skip(bytes); + return ret; +} + +std::vector BinaryStreamReader::rraw() +{ + auto size = ru32(); + return rraw(size); +} + +std::vector BinaryStreamReader::rrle(size_t encoded_bytes) +{ + std::vector data; + int32_t n; + for (int j = 0; j < encoded_bytes;) + { + n = ri8(); + j++; + // copy the following char -n + 1 times + if (n < 0) + { + // NOP + if (n == -128) + continue; + n = -n + 1; + + j++; + auto ch = ru8(); + for (int c = 0; c < n; c++) + data.push_back(ch); + } + else + { + // read the following n + 1 chars (no compr) + for (int c = 0; c < n + 1; c++, j++) + data.push_back(ru8()); + } + } + return data; +} + +std::string BinaryStreamReader::rkey_or_string() +{ + auto len = ru32(); + if (len == 0) + len = 4; + return rstring(len); +} + +void BinaryStreamWriter::init(ByteOrder byte_order /*= ByteOrder::Host*/) +{ + m_byte_order = byte_order; + m_swap = byte_order == ByteOrder::Host ? false : byte_order != sys_order(); +} + +void BinaryStreamWriter::skip(size_t bytes, uint8_t fill /*= 0*/) +{ + m_data.resize(m_data.size() + bytes); +} + +void BinaryStreamWriter::snap() +{ + if ((size_t)m_data.size() % 4 != 0) m_data.resize(m_data.size() + 4 - (size_t)m_data.size() % 4); +} + +void BinaryStreamWriter::wu8(uint8_t v) +{ + return write(v); +} + +void BinaryStreamWriter::wu16(uint16_t v) +{ + return m_swap ? write(swap(v)) : write(v); +} + +void BinaryStreamWriter::wu32(uint32_t v) +{ + return m_swap ? write(swap(v)) : write(v); +} + +void BinaryStreamWriter::wu64(uint64_t v) +{ + return m_swap ? write(swap(v)) : write(v); +} + +void BinaryStreamWriter::wi8(int8_t v) +{ + return write(v); +} + +void BinaryStreamWriter::wi16(int16_t v) +{ + return m_swap ? write(swap(v)) : write(v); +} + +void BinaryStreamWriter::wi32(int32_t v) +{ + return m_swap ? write(swap(v)) : write(v); +} + +void BinaryStreamWriter::wi64(int64_t v) +{ + return m_swap ? write(swap(v)) : write(v); +} + +void BinaryStreamWriter::wflt(float v) +{ + return m_swap ? write(swap(v)) : write(v); +} + +void BinaryStreamWriter::wdbl(double v) +{ + return m_swap ? write(swap(v)) : write(v); +} + +void BinaryStreamWriter::wstring(std::string s) +{ + wu32(s.size()); + write(s.data(), s.size()); +} + +void BinaryStreamWriter::wstring_raw(std::string s) +{ + write(s.data(), s.size()); +} + +void BinaryStreamWriter::wwstring(std::wstring s) +{ + wu32(s.size()); + std::wstring_convert> converter; + wstring(converter.to_bytes(s)); +} + +void BinaryStreamWriter::wwstring_raw(std::wstring s) +{ + std::wstring_convert> converter; + wstring(converter.to_bytes(s)); +} + +void BinaryStreamWriter::wpascal(std::string s) +{ + wu8(s.size()); + write(s.data(), s.size()); +} + +void BinaryStreamWriter::wraw(std::vector raw) +{ + wu32(raw.size()); + write(raw.data(), raw.size()); +} + +void BinaryStreamWriter::wrle(std::vector data) +{ + int idx = 0; + auto ptr = data.data(); + + // find the next sequence and return the position + auto next_seq = [&]() -> std::pair { + size_t i = idx; + while (i < data.size() - 1) + { + size_t count = 0; + for (size_t j = i + 1; j < data.size() && data[i] == data[j]; j++) + count++; + if (count > 0) + return { i, count + 1 }; + i++; + } + return { i + 1, 0 }; + }; + + while (idx < data.size()) + { + auto seq = next_seq(); + // non sequence chars + if (seq.first - idx > 0) + { + wi8(seq.first - idx - 1); + write(ptr + idx, seq.first - idx); + } + if (seq.second > 0) + { + wi8(-(int8_t)(seq.second - 1)); + write(ptr[seq.first]); + } + idx = seq.first + seq.second; + } +} + +void BinaryStreamWriter::wkey_or_string(std::string s) +{ + wstring(s); +} diff --git a/src/binary_stream.h b/src/binary_stream.h new file mode 100644 index 0000000..7a45bcc --- /dev/null +++ b/src/binary_stream.h @@ -0,0 +1,174 @@ +#pragma once +#include + +class BinaryStream +{ +public: + enum class ByteOrder : uint8_t { BigEndian, LittleEndian, Host }; + static ByteOrder sys_order() + { + union { + uint32_t i; + char c[4]; + } bint{ 0x01020304 }; + + return bint.c[0] == 1 ? ByteOrder::BigEndian : ByteOrder::LittleEndian; + } + template T swap(T x) + { +#if _MSC_VER >= 1400 + + if (sizeof(T) == 2) + { + auto y = _byteswap_ushort(*reinterpret_cast(&x)); + return *reinterpret_cast(&y); + } + else if (sizeof(T) == 4) + { + auto y = _byteswap_ulong(*reinterpret_cast(&x)); + return *reinterpret_cast(&y); + } + else if (sizeof(T) == 8) + { + auto y = _byteswap_uint64(*reinterpret_cast(&x)); + return *reinterpret_cast(&y); + } +#else + auto p = reinterpret_cast(&x); + if (sizeof(T) == 2) + { + std::swap(p[0], p[1]); + } + else if (sizeof(T) == 4) + { + std::swap(p[0], p[3]); + std::swap(p[1], p[2]); + } + else if (sizeof(T) == 8) + { + std::swap(p[0], p[7]); + std::swap(p[1], p[6]); + std::swap(p[2], p[5]); + std::swap(p[3], p[4]); + } + else + { + static_assert(true, "Should not reach here"); + } + return x; +#endif + } +protected: + bool m_swap = false; + ByteOrder m_byte_order = ByteOrder::Host; +}; + +class BinaryStreamReader : public BinaryStream +{ +public: + BinaryStreamReader(const BinaryStreamReader&) = delete; + BinaryStreamReader() = default; + ~BinaryStreamReader(); + void init(uint8_t* data_ptr, size_t size, ByteOrder byte_order = ByteOrder::Host); + size_t pos(); + void skip(size_t bytes); + // snap to the next 4-alignment + void snap(); + bool eof(); + bool has_data(size_t sz); + uint8_t ru8(); + uint16_t ru16(); + uint32_t ru32(); + uint64_t ru64(); + int8_t ri8(); + int16_t ri16(); + int32_t ri32(); + int64_t ri64(); + float rflt(); + double rdbl(); + std::string pick(size_t chars); + std::string rstring(); + std::string rstring(size_t len); + std::wstring rwstring(); + std::wstring rwstring(size_t len); + std::string rpascal(); + std::vector rraw(); + std::vector rraw(size_t bytes); + std::vector rrle(size_t encoded_bytes); + std::string rkey_or_string(); +protected: + template inline T align4(T x) + { + return ((x - T{ 1 }) & (~(T{ 3 }))) + T{ 4 }; + } + template T read() + { + T ret{}; + if (m_ptr) + { + if (has_data(sizeof(T))) + ret = *reinterpret_cast(m_cur); + m_cur += sizeof(T); + } + return ret; + } + template T* advance(size_t bytes) + { + T* ret = nullptr; + if (m_ptr) + { + if (has_data(bytes)) + ret = reinterpret_cast(m_cur); + m_cur += bytes; + } + return ret; + } +private: + uint8_t *m_ptr = nullptr; + uint8_t *m_cur = nullptr; + size_t m_size = 0; +}; + +class BinaryStreamWriter : public BinaryStream +{ +public: + std::vector m_data; + BinaryStreamWriter(const BinaryStreamWriter&) = delete; + BinaryStreamWriter() = default; + ~BinaryStreamWriter() = default; + void init(ByteOrder byte_order = ByteOrder::Host); + void skip(size_t bytes, uint8_t fill = 0); + // snap to the next 4-alignment + void snap(); + void wu8 (uint8_t v); + void wu16(uint16_t v); + void wu32(uint32_t v); + void wu64(uint64_t v); + void wi8 (int8_t v); + void wi16(int16_t v); + void wi32(int32_t v); + void wi64(int64_t v); + void wflt(float v); + void wdbl(double v); + void wstring(std::string s); + void wstring_raw(std::string s); + void wwstring(std::wstring s); + void wwstring_raw(std::wstring s); + void wpascal(std::string s); + void wraw(std::vector raw); + void wrle(std::vector data); + void wkey_or_string(std::string s); +protected: + template void write(T x) + { + uint8_t* bytes = reinterpret_cast(&x); + m_data.insert(m_data.end(), bytes, bytes + sizeof(T)); + } + template void write(const T* ptr, size_t size) + { + const uint8_t* bytes = reinterpret_cast(ptr); + m_data.insert(m_data.end(), bytes, bytes + size * sizeof(T)); + } +}; + + diff --git a/src/main.cpp b/src/main.cpp index 98fe5b4..28260c3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -15,6 +15,7 @@ #include "wacom.h" #include #include +#include "abr.h" #define WM_USER_CLOSE (WM_USER + 1) @@ -445,6 +446,27 @@ void init_vk_map() int main(int argc, char** argv) { + ABR abr; + abr.open("D:\\assets\\ABR\\coldyn.abr"); + + BinaryStreamWriter sw; + abr.m_presets[0]->write(sw); + + std::vector data; + for (int i = 0; i < 10; i++) + data.resize(data.size() + rand() % 10, i % 2); + BinaryStreamWriter w; + w.wrle(data); + BinaryStreamReader r; + r.init(w.m_data.data(), w.m_data.size()); + auto decoded = r.rrle(w.m_data.size()); + + assert(data.size() == decoded.size()); + for (int i = 0; i < data.size(); i++) + { + assert(data[i] == decoded[i]); + } + WNDCLASS wc; PIXELFORMATDESCRIPTOR pfd; diff --git a/src/pch.h b/src/pch.h index 9ef9362..0559a43 100644 --- a/src/pch.h +++ b/src/pch.h @@ -120,6 +120,7 @@ #include #include #include +#include #endif #include diff --git a/src/serializer.cpp b/src/serializer.cpp new file mode 100644 index 0000000..941ce4b --- /dev/null +++ b/src/serializer.cpp @@ -0,0 +1,23 @@ +#include "pch.h" +#include "serializer.h" + +Serializer::Type::Ref Serializer::instanciate(const std::string& key) +{ + if (m_ctor_table.find(key) != m_ctor_table.end()) + return m_ctor_table[key](); + return nullptr; +} + +std::map> Serializer::m_ctor_table = +{ + { "VlLs", [] { return std::make_shared(); } }, + { "TEXT", [] { return std::make_shared(); } }, + { "Objc", [] { return std::make_shared(); } }, + { "UntF", [] { return std::make_shared(); } }, + { "bool", [] { return std::make_shared(); } }, + { "long", [] { return std::make_shared(); } }, + { "doub", [] { return std::make_shared(); } }, + { "enum", [] { return std::make_shared(); } }, + { "tdta", [] { return std::make_shared(); } }, +}; + diff --git a/src/serializer.h b/src/serializer.h new file mode 100644 index 0000000..85d2819 --- /dev/null +++ b/src/serializer.h @@ -0,0 +1,473 @@ +#pragma once +#include "binary_stream.h" +#include "image.h" +#include "util.h" +#include "log.h" + +class Serializer +{ +public: + struct Type + { + using Vec = std::vector>; + using Map = std::map>; + using Ref = std::shared_ptr; + virtual std::string str(int indent, const std::string& prefix) const + { + return "type"; + } + virtual bool read(BinaryStreamReader& r) { return false; } + virtual void write(BinaryStreamWriter& w) const { } + virtual std::string type_key() const { return ""; } + }; + struct Class : public Type { }; + struct Property : public Type { }; + struct Reference : public Type { }; + struct EnumRef : public Type { }; + struct Offset : public Type { }; + struct Identifier : public Type { }; + struct Index : public Type { }; + struct Name : public Type { }; + struct LargeInteger : public Type { }; + struct Alias : public Type { }; + struct List : public Type + { + Type::Vec items; + virtual std::string type_key() const override { return "VlLs"; } + virtual std::string str(int indent, const std::string& prefix) const override + { + auto ret = std::string(indent, '-') + fmt::format("list: {} items:", items.size()); + for (int i = 0; i < items.size(); i++) + ret += "\n" + items[i]->str(indent + 1, fmt::format("{}) ", i)); + return ret; + } + virtual bool read(BinaryStreamReader& r) override + { + auto count = r.ru32(); + for (int i = 0; i < count; i++) + { + auto type = r.rstring(4); + auto item = instanciate(type); + if (!item || !item->read(r)) + return false; + items.push_back(item); + } + return true; + } + virtual void write(BinaryStreamWriter& w) const override + { + w.wi32(items.size()); + for (auto& i : items) + i->write(w); + } + }; + struct Double : public Type + { + using native_type = double; + double value; + virtual std::string type_key() const override { return "doub"; } + virtual std::string str(int indent, const std::string& prefix) const override + { + return std::string(indent, '-') + prefix + fmt::format("double: {}", value); + } + virtual bool read(BinaryStreamReader& r) override + { + value = r.rdbl(); + return true; + } + virtual void write(BinaryStreamWriter& w) const override + { + w.wdbl(value); + } + }; + struct UnitFloat : public Type + { + using native_type = double; + std::string unit; + double value; + virtual std::string type_key() const override { return "UntF"; } + virtual std::string str(int indent, const std::string& prefix) const override + { + return std::string(indent, '-') + prefix + fmt::format("float: {} ({})", value, unit); + } + virtual bool read(BinaryStreamReader& r) override + { + unit = r.rstring(4); + value = r.rdbl(); + return true; + } + virtual void write(BinaryStreamWriter& w) const override + { + w.wstring_raw(unit); + w.wdbl(value); + } + }; + struct String : public Type + { + using native_type = std::wstring; + std::wstring value; + virtual std::string type_key() const override { return "TEXT"; } + virtual std::string str(int indent, const std::string& prefix) const override + { + return std::string(indent, '-') + prefix + fmt::format("string: {}", wstr2str(value)); + } + virtual bool read(BinaryStreamReader& r) override + { + value = r.rwstring(); + return true; + } + virtual void write(BinaryStreamWriter& w) const override + { + w.wwstring(value); + } + }; + struct Enum : public Type + { + std::string type; + std::string value; + virtual std::string type_key() const override { return "enum"; } + virtual std::string str(int indent, const std::string& prefix) const override + { + return std::string(indent, '-') + prefix + fmt::format("enum {}: {}", type, value); + } + virtual bool read(BinaryStreamReader& r) override + { + type = r.rkey_or_string(); + value = r.rkey_or_string(); + return true; + } + virtual void write(BinaryStreamWriter& w) const override + { + w.wkey_or_string(type); + w.wkey_or_string(value); + } + }; + struct Integer : public Type + { + using native_type = int32_t; + int32_t value; + virtual std::string type_key() const override { return "long"; } + virtual std::string str(int indent, const std::string& prefix) const override + { + return std::string(indent, '-') + prefix + fmt::format("int: {}", value); + } + virtual bool read(BinaryStreamReader& r) override + { + value = r.ri32(); + return true; + } + virtual void write(BinaryStreamWriter& w) const override + { + w.wi32(value); + } + }; + struct Boolean : public Type + { + using native_type = bool; + bool value; + virtual std::string type_key() const override { return "bool"; } + virtual std::string str(int indent, const std::string& prefix) const override + { + return std::string(indent, '-') + prefix + fmt::format("bool: {}", value); + } + virtual bool read(BinaryStreamReader& r) override + { + value = r.ru8(); + return true; + } + virtual void write(BinaryStreamWriter& w) const override + { + w.wu8(value); + } + }; + struct RawData : public Type + { + std::vector data; + virtual std::string type_key() const override { return "tdta"; } + virtual std::string str(int indent, const std::string& prefix) const override + { + return std::string(indent, '-') + prefix + fmt::format("raw: {} bytes", data.size()); + } + virtual bool read(BinaryStreamReader& r) override + { + data = r.rraw(); + return true; + } + virtual void write(BinaryStreamWriter& w) const override + { + w.wraw(data); + } + }; + struct Descriptor : public Type + { + std::wstring name; + std::string class_id; + Type::Map props; + virtual std::string type_key() const override { return "Objc"; } + virtual std::string str(int indent, const std::string& prefix) const override + { + auto ret = std::string(indent, '-') + prefix + + fmt::format("objc {} ({}): {} props:", wstr2str(name), class_id, props.size()); + for (const auto& p : props) + ret += "\n" + p.second->str(indent + 1, fmt::format("'{}' ", p.first)); + return ret; + } + bool has(const std::string& key) const + { + return props.find(key) != props.end(); + } + template std::shared_ptr get(const std::string& key) const + { + return has(key) ? std::dynamic_pointer_cast(props.at(key)) : nullptr; + } + template auto value(const std::string& key) const + { + if (auto v = get(key)) + return v->value; + return decltype(T::value){}; + } + template auto value_or(const std::string& key, const D val) const + { + if (auto v = get(key)) + return v->value; + return val; + } + template void value(const std::string& key, D& dest) const + { + if (auto v = get(key)) + dest = static_cast(v->value); + } + virtual bool read(BinaryStreamReader& r) override + { + name = r.rwstring(); + class_id = r.rkey_or_string(); + auto count = r.ru32(); + for (int i = 0; i < count; i++) + { + auto key = r.rkey_or_string(); + auto type = r.rstring(4); + //printf("prop %s\n", t.c_str()); + auto p = instanciate(type); + if (!p || !p->read(r)) + return false; + if (props.find(key) != props.end()) + LOG("DUPLICATE prop %s\n", key.c_str()); + props[key] = p; + } + return true; + } + virtual void write(BinaryStreamWriter& w) const override + { + w.wwstring(name); + w.wkey_or_string(class_id); + w.wu32(props.size()); + for (auto& p : props) + { + w.wkey_or_string(p.first); + w.wstring(p.second->type_key()); + p.second->write(w); + } + } + }; + struct Rectangle : public Type + { + uint32_t top; + uint32_t left; + uint32_t bottom; + uint32_t right; + uint32_t area() const { return (right - left) * (bottom - top); } + uint32_t width() const { return right - left; } + uint32_t height() const { return bottom - top; } + virtual std::string str(int indent, const std::string& prefix) const override + { + return std::string(indent, '-') + prefix + fmt::format("rect: [{}, {}, {}, {}]", top, left, bottom, right); + } + virtual bool read(BinaryStreamReader& r) override + { + top = r.ru32(); + left = r.ru32(); + bottom = r.ru32(); + right = r.ru32(); + return true; + } + virtual void write(BinaryStreamWriter& w) const override + { + w.wu32(top); + w.wu32(left); + w.wu32(bottom); + w.wu32(right); + } + }; + struct Point : public Type + { + uint32_t x; + uint32_t y; + virtual std::string str(int indent, const std::string& prefix) const override + { + return std::string(indent, '-') + prefix + fmt::format("point: [{}, {}]", x, y); + } + virtual bool read(BinaryStreamReader& r) override + { + x = r.ru32(); + y = r.ru32(); + return true; + } + virtual void write(BinaryStreamWriter& w) const override + { + w.wu32(x); + w.wu32(y); + } + }; + struct Channel : public Type + { + uint32_t depth; + Rectangle rect; + uint8_t compression; + std::vector data; + Channel() = default; + //Channel(uint32_t depth, Rectangle rect, uint8_t compression, std::vector data) : + // depth(depth), rect(rect), compression(compression), data(std::move(data)) { } + virtual bool read(BinaryStreamReader& r) override + { + auto length = r.ru32(); // skip if 0, length is from the next field to the end + if (length == 0) + return true; + depth = r.ru32(); // Pixel depth: 1, 8, 16 or 32 + rect.read(r); + auto depth2 = r.ru16(); // again? + compression = r.ru8(); // 1 = zip + if (depth != 8) + { + LOG("unsupported depth %d bits\n", depth); + r.skip(length - 23); + return true; + } + if (compression == 0) + { + int data_size = (depth >> 3) * rect.area(); + data = r.rraw(data_size); + } + else if (compression == 1) + { + auto start = r.pos(); + auto height = rect.height(); + // contain the compressed length of each scanline + std::vector scanlines; + scanlines.reserve(height); + for (int i = 0; i < height; i++) + scanlines.push_back(r.ru16()); + for (auto sl : scanlines) + { + auto decoded = r.rrle(sl); + data.insert(data.end(), decoded.begin(), decoded.end()); + } + auto len = r.pos() - start; + } + else + { + LOG("unsupported compression mode %d\n", compression); + r.skip(length - 23); + return true; + } + } + virtual void write(BinaryStreamWriter& w) const override + { + } + }; + struct VMArray : public Type + { + uint32_t version; // = 3 + Rectangle rect; + std::vector channels; + VMArray() = default; + //VMArray(uint32_t version, const Rectangle& rect) : version(version), rect(rect) { } + std::shared_ptr image(bool grayscale, bool invert) const + { + int nc = channels.size(); + auto pixels = (channels[0].depth >> 3) * rect.area(); + if (nc == 1 || nc >= 3) + { + auto img = std::make_shared(); + img->comp = 4; + img->width = rect.width(); + img->height = rect.height(); + img->m_data = std::make_unique(pixels * 4); + auto out = reinterpret_cast(img->m_data.get()); + if (grayscale) + { + auto const& raw = channels[0].data; + if (invert) + { + for (int i = 0; i < raw.size(); i++) + out[i] = glm::u8vec4(glm::u8vec3(255 - raw[i]), 255); + } + else + { + for (int i = 0; i < raw.size(); i++) + out[i] = glm::u8vec4(glm::u8vec3(raw[i]), 255); + } + } + else + { + std::fill_n(out, pixels, glm::u8vec4(255)); + for (int ch = 0; ch < std::min(nc, 3); ch++) + { + auto const& raw = channels[ch].data; + if (invert) + { + for (int i = 0; i < raw.size(); i++) + out[i][ch] = 255 - raw[i]; + } + else + { + for (int i = 0; i < raw.size(); i++) + out[i][ch] = raw[i]; + } + } + } + return img; + //stbi_write_png(fmt::format("x64/out/{}.png", uid).c_str(), + // image->rect.width(), image->rect.height(), 4, out.data(), 0); + } + else + { + LOG("Error image with %d channels\n", channels.size()); + } + return nullptr; + } + virtual bool read(BinaryStreamReader& r) override + { + // Virtual Memory Array List + version = r.ru32(); // = 3 + assert(version == 3); + auto vmem_length = r.ru32(); + // TODO: check if at the end there's good data + // check if the bounds are within the parent's size + rect.read(r); + auto vmem_channels = r.ru32(); + // The following is a virtual memory array, + // repeated for the number of channels + // + one for a user mask + one for a sheet mask. + vmem_channels += 2; // user and sheet mask + for (int ch = 0; ch < vmem_channels; ch++) + { + auto array_written = r.ru32(); // skip if 0 + if (array_written == 0) + continue; + channels.emplace_back(); + if (!channels.back().read(r)) + return false; + } + r.snap(); + return true; + } + virtual void write(BinaryStreamWriter& w) const override + { + } + }; +protected: + static Type::Ref instanciate(const std::string& key); + static std::map> m_ctor_table; +}; + +