diff --git a/src/abr.cpp b/src/abr.cpp index b066a9b..02896ba 100644 --- a/src/abr.cpp +++ b/src/abr.cpp @@ -349,7 +349,7 @@ std::vector> ABR::compute_brushes(const std::string& path return ret; } -std::shared_ptr ABR::parse_vmem() +std::shared_ptr SerializedStreamReader::parse_vmem() { // Virtual Memory Array List auto vmem_version = ru32(); // = 3 @@ -416,7 +416,7 @@ std::shared_ptr ABR::parse_vmem() return ret; } -std::shared_ptr ABR::parse_vlls() +std::shared_ptr SerializedStreamReader::parse_vlls() { auto ret = std::make_shared(); auto count = ru32(); @@ -432,7 +432,7 @@ std::shared_ptr ABR::parse_vlls() return ret; } -std::shared_ptr ABR::parse_text() +std::shared_ptr SerializedStreamReader::parse_text() { auto ret = std::make_shared(); ret->value = rwstring(); @@ -440,7 +440,7 @@ std::shared_ptr ABR::parse_text() return ret; } -std::shared_ptr ABR::parse_objc() +std::shared_ptr SerializedStreamReader::parse_objc() { auto ret = std::make_shared(); ret->name = rwstring(); @@ -462,7 +462,7 @@ std::shared_ptr ABR::parse_objc() return ret; } -std::shared_ptr ABR::parse_untf() +std::shared_ptr SerializedStreamReader::parse_untf() { auto ret = std::make_shared(); ret->unit = rstring(4); @@ -471,7 +471,7 @@ std::shared_ptr ABR::parse_untf() return ret; } -std::shared_ptr ABR::parse_bool() +std::shared_ptr SerializedStreamReader::parse_bool() { auto ret = std::make_shared(); ret->value = ru8(); @@ -479,7 +479,7 @@ std::shared_ptr ABR::parse_bool() return ret; } -std::shared_ptr ABR::parse_long() +std::shared_ptr SerializedStreamReader::parse_long() { auto ret = std::make_shared(); ret->value = ru32(); @@ -487,7 +487,7 @@ std::shared_ptr ABR::parse_long() return ret; } -std::shared_ptr ABR::parse_doub() +std::shared_ptr SerializedStreamReader::parse_doub() { auto ret = std::make_shared(); ret->value = rdbl(); @@ -495,7 +495,7 @@ std::shared_ptr ABR::parse_doub() return ret; } -std::shared_ptr ABR::parse_enum() +std::shared_ptr SerializedStreamReader::parse_enum() { auto ret = std::make_shared(); ret->type = rkey_or_string(); @@ -504,26 +504,26 @@ std::shared_ptr ABR::parse_enum() return ret; } -std::shared_ptr ABR::parse_tdta() +std::shared_ptr SerializedStreamReader::parse_tdta() { auto ret = std::make_shared(); ret->data = rraw(); return ret; } -ABR::ABR() +SerializedStreamReader::SerializedStreamReader() { - m_parser_table = std::map> + m_parser_table = std::map> { - { "VlLs", std::bind(&ABR::parse_vlls, this) }, - { "TEXT", std::bind(&ABR::parse_text, this) }, - { "Objc", std::bind(&ABR::parse_objc, this) }, - { "UntF", std::bind(&ABR::parse_untf, this) }, - { "bool", std::bind(&ABR::parse_bool, this) }, - { "long", std::bind(&ABR::parse_long, this) }, - { "doub", std::bind(&ABR::parse_doub, this) }, - { "enum", std::bind(&ABR::parse_enum, this) }, - { "tdta", std::bind(&ABR::parse_tdta, this) }, + { "VlLs", std::bind(&SerializedStreamReader::parse_vlls, this) }, + { "TEXT", std::bind(&SerializedStreamReader::parse_text, this) }, + { "Objc", std::bind(&SerializedStreamReader::parse_objc, this) }, + { "UntF", std::bind(&SerializedStreamReader::parse_untf, this) }, + { "bool", std::bind(&SerializedStreamReader::parse_bool, this) }, + { "long", std::bind(&SerializedStreamReader::parse_long, this) }, + { "doub", std::bind(&SerializedStreamReader::parse_doub, this) }, + { "enum", std::bind(&SerializedStreamReader::parse_enum, this) }, + { "tdta", std::bind(&SerializedStreamReader::parse_tdta, this) }, }; } @@ -532,7 +532,7 @@ bool ABR::open(const std::string& path) Asset asset; if (asset.open(path.c_str())) { - init(asset.read_all(), asset.m_len, BinaryStream::ByteOrder::BigEndian); + init(asset.read_all(), asset.m_len, BinaryStreamReader::ByteOrder::BigEndian); auto version_major = ru16(); auto version_minor = ru16(); LOG("ABR %d.%d\n", version_major, version_minor); diff --git a/src/abr.h b/src/abr.h index 97b1eb4..893e675 100644 --- a/src/abr.h +++ b/src/abr.h @@ -20,9 +20,61 @@ public: return bint.c[0] == 1 ? ByteOrder::BigEndian : ByteOrder::LittleEndian; } - BinaryStream(const BinaryStream&) = delete; - BinaryStream() = default; - ~BinaryStream() + 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; @@ -39,7 +91,7 @@ public: // 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; } + 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(); } @@ -102,9 +154,6 @@ public: { n = ri8(); j++; - // force sign - if (n >= 128) - n -= 256; // can this even happen? // copy the following char -n + 1 times if (n < 0) { @@ -151,60 +200,115 @@ protected: } return ret; } - 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 - } private: uint8_t *m_ptr = nullptr; uint8_t *m_cur = nullptr; size_t m_size = 0; - bool m_swap = false; - ByteOrder m_byte_order = ByteOrder::Host; }; -class ABR : private BinaryStream +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 wwstring(std::wstring s) + { + wu32(s.size()); + 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; + } + } +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>; @@ -410,11 +514,29 @@ class ABR : private BinaryStream } else { - printf("Error image with %d channels\n", channels.size()); + LOG("Error image with %d channels\n", channels.size()); } return nullptr; } }; +}; + +class SerializedStreamReader : public SerializedStream, public BinaryStreamReader +{ +public: + std::shared_ptr parse_vmem(); // Parse Virtual Memory Array List + std::shared_ptr parse_vlls(); + std::shared_ptr parse_text(); + std::shared_ptr parse_objc(); + std::shared_ptr parse_untf(); + std::shared_ptr parse_bool(); + std::shared_ptr parse_long(); + std::shared_ptr parse_doub(); + std::shared_ptr parse_enum(); + std::shared_ptr parse_tdta(); + + std::map> m_parser_table; + SerializedStreamReader(); std::string rkey_or_string() { @@ -449,30 +571,18 @@ class ABR : private BinaryStream } return nullptr; } +}; +class ABR : private SerializedStreamReader +{ bool section_desc(); bool section_samp(); bool section_patt(); - - std::shared_ptr parse_vmem(); // Parse Virtual Memory Array List - std::shared_ptr parse_vlls(); - std::shared_ptr parse_text(); - std::shared_ptr parse_objc(); - std::shared_ptr parse_untf(); - std::shared_ptr parse_bool(); - std::shared_ptr parse_long(); - std::shared_ptr parse_doub(); - std::shared_ptr parse_enum(); - std::shared_ptr parse_tdta(); - - std::map> m_parser_table; - public: std::vector> m_presets; std::map> m_patterns; std::map> m_samples; - ABR(); bool open(const std::string& path); std::vector> compute_brushes(const std::string& path); };