xenia-canary/third_party/crunch/crnlib/crn_data_stream_serializer.h

469 lines
15 KiB
C++

// File: data_stream_serializer.h
// See Copyright Notice and license at the end of inc/crnlib.h
#pragma once
#include "crn_data_stream.h"
namespace crnlib
{
// Defaults to little endian mode.
class data_stream_serializer
{
public:
data_stream_serializer() : m_pStream(NULL), m_little_endian(true) { }
data_stream_serializer(data_stream* pStream) : m_pStream(pStream), m_little_endian(true) { }
data_stream_serializer(data_stream& stream) : m_pStream(&stream), m_little_endian(true) { }
data_stream_serializer(const data_stream_serializer& other) : m_pStream(other.m_pStream), m_little_endian(other.m_little_endian) { }
data_stream_serializer& operator= (const data_stream_serializer& rhs) { m_pStream = rhs.m_pStream; m_little_endian = rhs.m_little_endian; return *this; }
data_stream* get_stream() const { return m_pStream; }
void set_stream(data_stream* pStream) { m_pStream = pStream; }
const dynamic_string& get_name() const { return m_pStream ? m_pStream->get_name() : g_empty_dynamic_string; }
bool get_error() { return m_pStream ? m_pStream->get_error() : false; }
bool get_little_endian() const { return m_little_endian; }
void set_little_endian(bool little_endian) { m_little_endian = little_endian; }
bool write(const void* pBuf, uint len)
{
return m_pStream->write(pBuf, len) == len;
}
bool read(void* pBuf, uint len)
{
return m_pStream->read(pBuf, len) == len;
}
// size = size of each element, count = number of elements, returns actual count of elements written
uint write(const void* pBuf, uint size, uint count)
{
uint actual_size = size * count;
if (!actual_size)
return 0;
uint n = m_pStream->write(pBuf, actual_size);
if (n == actual_size)
return count;
return n / size;
}
// size = size of each element, count = number of elements, returns actual count of elements read
uint read(void* pBuf, uint size, uint count)
{
uint actual_size = size * count;
if (!actual_size)
return 0;
uint n = m_pStream->read(pBuf, actual_size);
if (n == actual_size)
return count;
return n / size;
}
bool write_chars(const char* pBuf, uint len)
{
return write(pBuf, len);
}
bool read_chars(char* pBuf, uint len)
{
return read(pBuf, len);
}
bool skip(uint len)
{
return m_pStream->skip(len) == len;
}
template<typename T>
bool write_object(const T& obj)
{
if (m_little_endian == c_crnlib_little_endian_platform)
return write(&obj, sizeof(obj));
else
{
uint8 buf[sizeof(T)];
uint buf_size = sizeof(T);
void* pBuf = buf;
utils::write_obj(obj, pBuf, buf_size, m_little_endian);
return write(buf, sizeof(T));
}
}
template<typename T>
bool read_object(T& obj)
{
if (m_little_endian == c_crnlib_little_endian_platform)
return read(&obj, sizeof(obj));
else
{
uint8 buf[sizeof(T)];
if (!read(buf, sizeof(T)))
return false;
uint buf_size = sizeof(T);
const void* pBuf = buf;
utils::read_obj(obj, pBuf, buf_size, m_little_endian);
return true;
}
}
template<typename T>
bool write_value(T value)
{
return write_object(value);
}
template<typename T>
T read_value(const T& on_error_value = T())
{
T result;
if (!read_object(result))
result = on_error_value;
return result;
}
template<typename T>
bool write_enum(T e)
{
int val = static_cast<int>(e);
return write_object(val);
}
template<typename T>
T read_enum()
{
return static_cast<T>(read_value<int>());
}
// Writes uint using a simple variable length code (VLC).
bool write_uint_vlc(uint val)
{
do
{
uint8 c = static_cast<uint8>(val) & 0x7F;
if (val <= 0x7F)
c |= 0x80;
if (!write_value(c))
return false;
val >>= 7;
} while (val);
return true;
}
// Reads uint using a simple variable length code (VLC).
bool read_uint_vlc(uint& val)
{
val = 0;
uint shift = 0;
for ( ; ; )
{
if (shift >= 32)
return false;
uint8 c;
if (!read_object(c))
return false;
val |= ((c & 0x7F) << shift);
shift += 7;
if (c & 0x80)
break;
}
return true;
}
bool write_c_str(const char* p)
{
uint len = static_cast<uint>(strlen(p));
if (!write_uint_vlc(len))
return false;
return write_chars(p, len);
}
bool read_c_str(char* pBuf, uint buf_size)
{
uint len;
if (!read_uint_vlc(len))
return false;
if ((len + 1) > buf_size)
return false;
pBuf[len] = '\0';
return read_chars(pBuf, len);
}
bool write_string(const dynamic_string& str)
{
if (!write_uint_vlc(str.get_len()))
return false;
return write_chars(str.get_ptr(), str.get_len());
}
bool read_string(dynamic_string& str)
{
uint len;
if (!read_uint_vlc(len))
return false;
if (!str.set_len(len))
return false;
if (len)
{
if (!read_chars(str.get_ptr_raw(), len))
return false;
if (memchr(str.get_ptr(), 0, len) != NULL)
{
str.truncate(0);
return false;
}
}
return true;
}
template<typename T>
bool write_vector(const T& vec)
{
if (!write_uint_vlc(vec.size()))
return false;
for (uint i = 0; i < vec.size(); i++)
{
*this << vec[i];
if (get_error())
return false;
}
return true;
};
template<typename T>
bool read_vector(T& vec, uint num_expected = UINT_MAX)
{
uint size;
if (!read_uint_vlc(size))
return false;
if ((size * sizeof(T::value_type)) >= 2U*1024U*1024U*1024U)
return false;
if ((num_expected != UINT_MAX) && (size != num_expected))
return false;
vec.resize(size);
for (uint i = 0; i < vec.size(); i++)
{
*this >> vec[i];
if (get_error())
return false;
}
return true;
}
bool read_entire_file(crnlib::vector<uint8>& buf)
{
return m_pStream->read_array(buf);
}
bool write_entire_file(const crnlib::vector<uint8>& buf)
{
return m_pStream->write_array(buf);
}
// Got this idea from the Molly Rocket forums.
// fmt may contain the characters "1", "2", or "4".
bool writef(char *fmt, ...)
{
va_list v;
va_start(v, fmt);
while (*fmt)
{
switch (*fmt++)
{
case '1':
{
const uint8 x = static_cast<uint8>(va_arg(v, uint));
if (!write_value(x))
return false;
}
case '2':
{
const uint16 x = static_cast<uint16>(va_arg(v, uint));
if (!write_value(x))
return false;
}
case '4':
{
const uint32 x = static_cast<uint32>(va_arg(v, uint));
if (!write_value(x))
return false;
}
case ' ':
case ',':
{
break;
}
default:
{
CRNLIB_ASSERT(0);
return false;
}
}
}
va_end(v);
return true;
}
// Got this idea from the Molly Rocket forums.
// fmt may contain the characters "1", "2", or "4".
bool readf(char *fmt, ...)
{
va_list v;
va_start(v, fmt);
while (*fmt)
{
switch (*fmt++)
{
case '1':
{
uint8* x = va_arg(v, uint8*);
CRNLIB_ASSERT(x);
if (!read_object(*x))
return false;
}
case '2':
{
uint16* x = va_arg(v, uint16*);
CRNLIB_ASSERT(x);
if (!read_object(*x))
return false;
}
case '4':
{
uint32* x = va_arg(v, uint32*);
CRNLIB_ASSERT(x);
if (!read_object(*x))
return false;
}
case ' ':
case ',':
{
break;
}
default:
{
CRNLIB_ASSERT(0);
return false;
}
}
}
va_end(v);
return true;
}
private:
data_stream* m_pStream;
bool m_little_endian;
};
// Write operators
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, bool val) { serializer.write_value(val); return serializer; }
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, int8 val) { serializer.write_value(val); return serializer; }
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, uint8 val) { serializer.write_value(val); return serializer; }
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, int16 val) { serializer.write_value(val); return serializer; }
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, uint16 val) { serializer.write_value(val); return serializer; }
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, int32 val) { serializer.write_value(val); return serializer; }
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, uint32 val) { serializer.write_uint_vlc(val); return serializer; }
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, int64 val) { serializer.write_value(val); return serializer; }
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, uint64 val) { serializer.write_value(val); return serializer; }
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, long val) { serializer.write_value(val); return serializer; }
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, unsigned long val) { serializer.write_value(val); return serializer; }
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, float val) { serializer.write_value(val); return serializer; }
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, double val) { serializer.write_value(val); return serializer; }
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, const char* p) { serializer.write_c_str(p); return serializer; }
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, const dynamic_string& str)
{
serializer.write_string(str);
return serializer;
}
template<typename T>
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, const crnlib::vector<T>& vec)
{
serializer.write_vector(vec);
return serializer;
}
template<typename T>
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, const T* p)
{
serializer.write_object(*p);
return serializer;
}
// Read operators
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, bool& val) { serializer.read_object(val); return serializer; }
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, int8& val) { serializer.read_object(val); return serializer; }
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, uint8& val) { serializer.read_object(val); return serializer; }
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, int16& val) { serializer.read_object(val); return serializer; }
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, uint16& val) { serializer.read_object(val); return serializer; }
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, int32& val) { serializer.read_object(val); return serializer; }
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, uint32& val) { serializer.read_uint_vlc(val); return serializer; }
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, int64& val) { serializer.read_object(val); return serializer; }
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, uint64& val) { serializer.read_object(val); return serializer; }
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, long& val) { serializer.read_object(val); return serializer; }
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, unsigned long& val) { serializer.read_object(val); return serializer; }
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, float& val) { serializer.read_object(val); return serializer; }
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, double& val) { serializer.read_object(val); return serializer; }
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, dynamic_string& str)
{
serializer.read_string(str);
return serializer;
}
template<typename T>
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, crnlib::vector<T>& vec)
{
serializer.read_vector(vec);
return serializer;
}
template<typename T>
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, T* p)
{
serializer.read_object(*p);
return serializer;
}
} // namespace crnlib