#include "CInputStream.hpp" #if METAFORCE_TARGET_BYTE_ORDER == __ORDER_LITTLE_ENDIAN__ #include "Runtime/CBasics.hpp" #endif #include namespace metaforce { static u32 min_containing_bytes(u32 v) { v = 32 - v; v = (v >> 3) - ((s32) - (v & 7) >> 31); return v; } CInputStream::CInputStream(s32 len) : xc_len(len), x10_ptr(new u8[len]), x14_owned(true) {} CInputStream::CInputStream(const void* ptr, u32 len, bool owned) : x8_blockLen(len), xc_len(len), x10_ptr(reinterpret_cast(ptr)), x14_owned(owned) {} CInputStream::~CInputStream() { if (x14_owned) { delete[] x10_ptr; } } bool CInputStream::InternalReadNext() { x8_blockLen = Read(const_cast(x10_ptr), xc_len); x4_blockOffset = 0; return x8_blockLen != 0; } bool CInputStream::GrabAnotherBlock() { return InternalReadNext(); } void CInputStream::Get(u8* dest, u32 len) { x20_bitOffset = 0; u32 offset = 0; while (len != 0) { u32 blockLen = x8_blockLen - x4_blockOffset; if (len < blockLen) { blockLen = len; } if (blockLen == 0) { if (len <= 256) { GrabAnotherBlock(); } else { u32 readLen = Read(dest + offset, len); len -= readLen; offset += readLen; } } else { memcpy(dest + offset, x10_ptr + x4_blockOffset, blockLen); len -= blockLen; x4_blockOffset += blockLen; } } x18_readPosition += offset; } u32 CInputStream::ReadBytes(void* dest, u32 len) { if (len == 0) { return 0; } if (x4_blockOffset == x8_blockLen) { GrabAnotherBlock(); } u32 curReadLen = 0; u32 curLen = len; do { while (true) { if (len <= curReadLen) { x18_readPosition += curReadLen; return curReadLen; } u32 readCount = x8_blockLen - x4_blockOffset; if (readCount == 0) { break; } if (curLen < readCount) { readCount = curLen; } memcpy(reinterpret_cast(dest) + curReadLen, x10_ptr + x4_blockOffset, readCount); curReadLen += readCount; curLen -= readCount; } } while (InternalReadNext()); return curReadLen; } u32 CInputStream::ReadBits(u32 bitCount) { u32 ret = x20_bitOffset; if (ret < bitCount) { const u32 shiftAmt = bitCount - x20_bitOffset; const u32 mask = ret == 32 ? -1 : (1 << x20_bitOffset) - 1; u32 uVar2 = x1c_bitWord; x20_bitOffset = 0; u32 len = min_containing_bytes(shiftAmt); Get(reinterpret_cast(&x1c_bitWord), len); #if METAFORCE_TARGET_BYTE_ORDER == __ORDER_LITTLE_ENDIAN__ x1c_bitWord = CBasics::SwapBytes(x1c_bitWord); #endif const u32 retMask = shiftAmt == 32 ? -1 : (1 << shiftAmt) - 1; const u32 tmpOffset = x20_bitOffset; x20_bitOffset = len * 8; ret = ((mask & uVar2) >> (32 - ret) << shiftAmt) | (retMask & (x1c_bitWord >> (32 - shiftAmt))) << tmpOffset; x20_bitOffset -= shiftAmt; x1c_bitWord <<= shiftAmt; } else { x20_bitOffset -= bitCount; ret = bitCount == 32 ? -1 : (1 << bitCount) - 1; ret &= x1c_bitWord >> (32 - bitCount); x1c_bitWord <<= bitCount; } return ret; } char CInputStream::ReadChar() { u8 tmp = 0; Get(&tmp, sizeof(tmp)); return static_cast(tmp); } bool CInputStream::ReadBool() { return Get(); } s16 CInputStream::ReadInt16() { s16 tmp = 0; Get(reinterpret_cast(&tmp), sizeof(tmp)); #if METAFORCE_TARGET_BYTE_ORDER == __ORDER_LITTLE_ENDIAN__ CBasics::Swap2Bytes(reinterpret_cast(&tmp)); #endif return tmp; } u16 CInputStream::ReadUint16() { u16 tmp = 0; Get(reinterpret_cast(&tmp), sizeof(tmp)); #if METAFORCE_TARGET_BYTE_ORDER == __ORDER_LITTLE_ENDIAN__ CBasics::Swap2Bytes(reinterpret_cast(&tmp)); #endif return tmp; } s32 CInputStream::ReadInt32() { s32 tmp = 0; Get(reinterpret_cast(&tmp), sizeof(tmp)); #if METAFORCE_TARGET_BYTE_ORDER == __ORDER_LITTLE_ENDIAN__ CBasics::Swap4Bytes(reinterpret_cast(&tmp)); #endif return tmp; } u32 CInputStream::ReadUint32() { u32 tmp = 0; Get(reinterpret_cast(&tmp), sizeof(tmp)); #if METAFORCE_TARGET_BYTE_ORDER == __ORDER_LITTLE_ENDIAN__ CBasics::Swap4Bytes(reinterpret_cast(&tmp)); #endif return tmp; } s64 CInputStream::ReadInt64() { s64 tmp = 0; Get(reinterpret_cast(&tmp), sizeof(tmp)); #if METAFORCE_TARGET_BYTE_ORDER == __ORDER_LITTLE_ENDIAN__ CBasics::Swap8Bytes(reinterpret_cast(&tmp)); #endif return tmp; } u64 CInputStream::ReadUint64() { u64 tmp = 0; Get(reinterpret_cast(&tmp), sizeof(tmp)); #if METAFORCE_TARGET_BYTE_ORDER == __ORDER_LITTLE_ENDIAN__ CBasics::Swap8Bytes(reinterpret_cast(&tmp)); #endif return tmp; } float CInputStream::ReadFloat() { float tmp = 0.f; Get(reinterpret_cast(&tmp), sizeof(tmp)); #if METAFORCE_TARGET_BYTE_ORDER == __ORDER_LITTLE_ENDIAN__ CBasics::Swap4Bytes(reinterpret_cast(&tmp)); #endif return tmp; } float CInputStream::ReadReal32() { return Get(); } double CInputStream::ReadDouble() { double tmp = 0.0; Get(reinterpret_cast(&tmp), sizeof(tmp)); #if METAFORCE_TARGET_BYTE_ORDER == __ORDER_LITTLE_ENDIAN__ CBasics::Swap8Bytes(reinterpret_cast(&tmp)); #endif return tmp; } double CInputStream::ReadReal64() { return Get(); } template <> bool cinput_stream_helper(CInputStream& in) { return in.ReadChar() != 0; } template <> s8 cinput_stream_helper(CInputStream& in) { return in.ReadChar(); } template <> u8 cinput_stream_helper(CInputStream& in) { return in.ReadChar(); } template <> s16 cinput_stream_helper(CInputStream& in) { return in.ReadInt16(); } template <> s32 cinput_stream_helper(CInputStream& in) { return in.ReadInt32(); } template <> u32 cinput_stream_helper(CInputStream& in) { return in.ReadUint32(); } template <> s64 cinput_stream_helper(CInputStream& in) { return in.ReadInt64(); } template <> u64 cinput_stream_helper(CInputStream& in) { return in.ReadUint64(); } template <> float cinput_stream_helper(CInputStream& in) { return in.ReadFloat(); } template <> double cinput_stream_helper(CInputStream& in) { return in.ReadDouble(); } template <> std::string cinput_stream_helper(CInputStream& in) { std::string ret; auto chr = in.ReadChar(); while (chr != '\0') { ret += chr; chr = in.ReadChar(); } return ret; } u32 CInputStream::GetBitCount(u32 val) { int bits = 0; for (; val != 0; val >>= 1) { bits += 1; } return bits; } } // namespace metaforce