177 lines
4.7 KiB
C++
177 lines
4.7 KiB
C++
#pragma once
|
|
#include <codecvt>
|
|
#include "asset.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<typename T> T swap(T x)
|
|
{
|
|
#if _MSC_VER >= 1400
|
|
|
|
if (sizeof(T) == 2)
|
|
{
|
|
auto y = _byteswap_ushort(*reinterpret_cast<uint16_t*>(&x));
|
|
return *reinterpret_cast<T*>(&y);
|
|
}
|
|
else if (sizeof(T) == 4)
|
|
{
|
|
auto y = _byteswap_ulong(*reinterpret_cast<uint32_t*>(&x));
|
|
return *reinterpret_cast<T*>(&y);
|
|
}
|
|
else if (sizeof(T) == 8)
|
|
{
|
|
auto y = _byteswap_uint64(*reinterpret_cast<uint64_t*>(&x));
|
|
return *reinterpret_cast<T*>(&y);
|
|
}
|
|
#else
|
|
auto p = reinterpret_cast<uint8_t*>(&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);
|
|
bool load(const std::string& path, 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<uint8_t> rraw();
|
|
std::vector<uint8_t> rraw(size_t bytes);
|
|
std::vector<uint8_t> rrle(size_t encoded_bytes);
|
|
std::string rkey_or_string();
|
|
protected:
|
|
template<typename T> inline T align4(T x)
|
|
{
|
|
return ((x - T{ 1 }) & (~(T{ 3 }))) + T{ 4 };
|
|
}
|
|
template<typename T> T read()
|
|
{
|
|
T ret{};
|
|
if (m_ptr)
|
|
{
|
|
if (has_data(sizeof(T)))
|
|
ret = *reinterpret_cast<T*>(m_cur);
|
|
m_cur += sizeof(T);
|
|
}
|
|
return ret;
|
|
}
|
|
template<typename T> T* advance(size_t bytes)
|
|
{
|
|
T* ret = nullptr;
|
|
if (m_ptr)
|
|
{
|
|
if (has_data(bytes))
|
|
ret = reinterpret_cast<T*>(m_cur);
|
|
m_cur += bytes;
|
|
}
|
|
return ret;
|
|
}
|
|
private:
|
|
uint8_t *m_ptr = nullptr;
|
|
uint8_t *m_cur = nullptr;
|
|
size_t m_size = 0;
|
|
Asset m_asset;
|
|
};
|
|
|
|
class BinaryStreamWriter : public BinaryStream
|
|
{
|
|
public:
|
|
std::vector<uint8_t> m_data;
|
|
BinaryStreamWriter(const BinaryStreamWriter&) = delete;
|
|
BinaryStreamWriter() = default;
|
|
~BinaryStreamWriter() = default;
|
|
void init(ByteOrder byte_order = ByteOrder::Host);
|
|
bool save(const std::string& path) const;
|
|
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<uint8_t> raw);
|
|
void wrle(std::vector<uint8_t> data);
|
|
void wkey_or_string(std::string s);
|
|
protected:
|
|
template<typename T> void write(T x)
|
|
{
|
|
uint8_t* bytes = reinterpret_cast<uint8_t*>(&x);
|
|
m_data.insert(m_data.end(), bytes, bytes + sizeof(T));
|
|
}
|
|
template<typename T> void write(const T* ptr, size_t size)
|
|
{
|
|
const uint8_t* bytes = reinterpret_cast<const uint8_t*>(ptr);
|
|
m_data.insert(m_data.end(), bytes, bytes + size * sizeof(T));
|
|
}
|
|
};
|