metaforce/Runtime/Streams/CInputStream.cpp

284 lines
6.6 KiB
C++

#include "CInputStream.hpp"
#if METAFORCE_TARGET_BYTE_ORDER == __ORDER_LITTLE_ENDIAN__
#include "Runtime/CBasics.hpp"
#endif
#include <cstring>
#include <logvisor/logvisor.hpp>
namespace metaforce {
static logvisor::Module Log("metaforce::CInputStream");
static u32 min_containing_bytes(u32 v) {
v = 32 - v;
v = (v >> 3) - (static_cast<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<u8*>(const_cast<void*>(ptr))), x14_owned(owned) {}
CInputStream::~CInputStream() {
if (x14_owned) {
delete[] x10_ptr;
}
}
bool CInputStream::InternalReadNext() {
x8_blockLen = Read(x10_ptr, xc_len);
x4_blockOffset = 0;
return x8_blockLen != 0;
}
bool CInputStream::GrabAnotherBlock() { return InternalReadNext(); }
void CInputStream::Get(u8* dest, u32 len) {
s32 readCount = 0;
x20_bitOffset = 0;
while (len != 0) {
s32 blockLen = x8_blockLen - x4_blockOffset;
if (len < blockLen) {
blockLen = len;
}
if (blockLen != 0) {
memcpy(dest + readCount, x10_ptr + x4_blockOffset, blockLen);
len -= blockLen;
readCount += blockLen;
x4_blockOffset += blockLen;
} else if (len > 256) {
u32 readLen = Read(dest + readCount, len);
#ifndef NDEBUG
if (readLen == 0) {
Log.report(logvisor::Fatal, FMT_STRING("Invalid read size!"));
break;
}
#endif
len -= readLen;
readCount += readLen;
} else {
GrabAnotherBlock();
};
}
x18_readPosition += readCount;
}
u32 CInputStream::ReadBytes(void* dest, u32 len) {
if (len == 0) {
return 0;
}
if (x4_blockOffset == x8_blockLen) {
GrabAnotherBlock();
}
u32 curLen = len;
u32 curReadLen = 0;
while (curReadLen < len) {
if ((x8_blockLen - x4_blockOffset) == 0 && !InternalReadNext()) {
break;
}
u32 readCount = x8_blockLen - x4_blockOffset;
if (curLen < (x8_blockLen - x4_blockOffset)) {
readCount = curLen;
}
memcpy(reinterpret_cast<u8*>(dest) + curReadLen, x10_ptr + x4_blockOffset, readCount);
curReadLen += readCount;
curLen -= readCount;
x4_blockOffset += readCount;
}
x18_readPosition += curReadLen;
return curReadLen;
}
u32 CInputStream::ReadBits(u32 bitCount) {
u32 ret = 0;
const s32 shiftAmt = x20_bitOffset - s32(bitCount);
if (shiftAmt < 0) {
/* OR in remaining bits of cached value */
u32 mask = bitCount == 32 ? UINT32_MAX : ((1U << bitCount) - 1);
ret |= (x1c_bitWord << u32(-shiftAmt)) & mask;
/* Load in exact number of bytes remaining */
auto loadDiv = std::div(-shiftAmt, 8);
if (loadDiv.rem != 0) {
++loadDiv.quot;
}
Get(reinterpret_cast<u8*>(&x1c_bitWord) + 4 - loadDiv.quot, loadDiv.quot);
#if METAFORCE_TARGET_BYTE_ORDER == __ORDER_LITTLE_ENDIAN__
x1c_bitWord = CBasics::SwapBytes(x1c_bitWord);
#endif
/* New bit offset */
x20_bitOffset = loadDiv.quot * 8 + shiftAmt;
/* OR in next bits */
mask = (1U << u32(-shiftAmt)) - 1;
ret |= (x1c_bitWord >> x20_bitOffset) & mask;
} else {
/* OR in bits of cached value */
const u32 mask = bitCount == 32 ? UINT32_MAX : ((1U << bitCount) - 1);
ret |= (x1c_bitWord >> u32(shiftAmt)) & mask;
/* New bit offset */
x20_bitOffset -= bitCount;
}
return ret;
}
char CInputStream::ReadChar() {
u8 tmp = 0;
Get(&tmp, sizeof(tmp));
return static_cast<char>(tmp);
}
bool CInputStream::ReadBool() { return Get<bool>(); }
s16 CInputStream::ReadInt16() {
s16 tmp = 0;
Get(reinterpret_cast<u8*>(&tmp), sizeof(tmp));
#if METAFORCE_TARGET_BYTE_ORDER == __ORDER_LITTLE_ENDIAN__
CBasics::Swap2Bytes(reinterpret_cast<u8*>(&tmp));
#endif
return tmp;
}
u16 CInputStream::ReadUint16() {
u16 tmp = 0;
Get(reinterpret_cast<u8*>(&tmp), sizeof(tmp));
#if METAFORCE_TARGET_BYTE_ORDER == __ORDER_LITTLE_ENDIAN__
CBasics::Swap2Bytes(reinterpret_cast<u8*>(&tmp));
#endif
return tmp;
}
s32 CInputStream::ReadInt32() {
s32 tmp = 0;
Get(reinterpret_cast<u8*>(&tmp), sizeof(tmp));
#if METAFORCE_TARGET_BYTE_ORDER == __ORDER_LITTLE_ENDIAN__
CBasics::Swap4Bytes(reinterpret_cast<u8*>(&tmp));
#endif
return tmp;
}
u32 CInputStream::ReadUint32() {
u32 tmp = 0;
Get(reinterpret_cast<u8*>(&tmp), sizeof(tmp));
#if METAFORCE_TARGET_BYTE_ORDER == __ORDER_LITTLE_ENDIAN__
CBasics::Swap4Bytes(reinterpret_cast<u8*>(&tmp));
#endif
return tmp;
}
s64 CInputStream::ReadInt64() {
s64 tmp = 0;
Get(reinterpret_cast<u8*>(&tmp), sizeof(tmp));
#if METAFORCE_TARGET_BYTE_ORDER == __ORDER_LITTLE_ENDIAN__
CBasics::Swap8Bytes(reinterpret_cast<u8*>(&tmp));
#endif
return tmp;
}
u64 CInputStream::ReadUint64() {
u64 tmp = 0;
Get(reinterpret_cast<u8*>(&tmp), sizeof(tmp));
#if METAFORCE_TARGET_BYTE_ORDER == __ORDER_LITTLE_ENDIAN__
CBasics::Swap8Bytes(reinterpret_cast<u8*>(&tmp));
#endif
return tmp;
}
float CInputStream::ReadFloat() {
float tmp = 0.f;
Get(reinterpret_cast<u8*>(&tmp), sizeof(tmp));
#if METAFORCE_TARGET_BYTE_ORDER == __ORDER_LITTLE_ENDIAN__
CBasics::Swap4Bytes(reinterpret_cast<u8*>(&tmp));
#endif
return tmp;
}
float CInputStream::ReadReal32() { return Get<float>(); }
double CInputStream::ReadDouble() {
double tmp = 0.0;
Get(reinterpret_cast<u8*>(&tmp), sizeof(tmp));
#if METAFORCE_TARGET_BYTE_ORDER == __ORDER_LITTLE_ENDIAN__
CBasics::Swap8Bytes(reinterpret_cast<u8*>(&tmp));
#endif
return tmp;
}
double CInputStream::ReadReal64() { return Get<double>(); }
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