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;
+};
+
+