#pragma once #include "asset.h" #include #include #include "util.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; } BinaryStream(const BinaryParam&) = delete; BinaryStream() = default; ~BinaryStream() { if (m_ptr) delete m_ptr; m_ptr = m_cur = nullptr; m_size = 0; } void init(uint8_t* owned_data_ptr, size_t size, ByteOrder byte_order = ByteOrder::Host) { m_ptr = m_cur = owned_data_ptr; m_size = size; m_byte_order = byte_order; m_swap = byte_order == ByteOrder::Host ? false : byte_order != sys_order(); } void skip(size_t bytes) { m_cur += bytes; } 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]); return std::wstring((wchar_t*)ptr, 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; } 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 : public BinaryStream { 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"; } }; struct Class : public Type { }; struct Property : public Type { }; struct Reference : public Type { }; struct List : public Type { Type::Vec items; virtual std::string str(int indent, const std::string& prefix) const override { //return std::string(indent, '-') + prefix + fmt::format("list: {} items", items.size()); auto ret = std::string(indent, '-') + fmt::format("list: {} props:\n", items.size()); for (int i = 0; i < items.size(); i++) ret += items[i]->str(indent + 1, fmt::format("{}) ", i) + "\n"); return ret; } }; struct Double : public Type { double value; virtual std::string str(int indent, const std::string& prefix) const override { return std::string(indent, '-') + prefix + fmt::format("double: {}", value); } }; struct UnitFloat : public Type { std::string unit; double value; virtual std::string str(int indent, const std::string& prefix) const override { return std::string(indent, '-') + prefix + fmt::format("float: {} ({})", value, unit); } }; struct String : public Type { std::wstring value; virtual std::string str(int indent, const std::string& prefix) const override { return std::string(indent, '-') + prefix + fmt::format("string: {}", wstr2str(value)); } }; struct Enum : public Type { std::string type; std::string value; virtual std::string str(int indent, const std::string& prefix) const override { return std::string(indent, '-') + prefix + fmt::format("enum {}: {}", type, value); } }; struct EnumRef : public Type { }; struct Offset : public Type { }; struct Identifier : public Type { }; struct Index : public Type { }; struct Name : public Type { }; struct Integer : public Type { int32_t value; virtual std::string str(int indent, const std::string& prefix) const override { return std::string(indent, '-') + prefix + fmt::format("int: {}", value); } }; struct LargeInteger : public Type { }; struct Boolean : public Type { bool value; virtual std::string str(int indent, const std::string& prefix) const override { return std::string(indent, '-') + prefix + fmt::format("bool: {}", value); } }; struct Alias : public Type { }; struct Descriptor : public Type { std::wstring name; std::string class_id; Type::Map props; virtual std::string str(int indent, const std::string& prefix) const override { auto ret = std::string(indent, '-') + fmt::format("objc: {} props:", props.size()); for (const auto& p : props) ret += "\n" + p.second->str(indent + 1, fmt::format("'{}' ", p.first)); return ret; } }; public: ABR(); bool open(const std::string& path); private: inline std::string rkey_or_string() { auto len = ru32(); if (len == 0) len = 4; return rstring(len); } bool section_desc(); bool section_samp(); bool section_patt(); 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(); //Type::Ref parse_prop(); Type::Ref call(std::string t) { if (m_parser_table.find(t) != m_parser_table.end()) { auto& method = m_parser_table[t]; return method(); } else if (m_parser_table.find(pick(4)) != m_parser_table.end()) { auto& method = m_parser_table[rstring(4)]; return method(); } return nullptr; } std::map> m_parser_table; };