Files

141 lines
3.8 KiB
C++
Raw Permalink Normal View History

2019-11-08 18:45:31 -05:00
#include "Runtime/IOStreams.hpp"
#include <hecl/hecl.hpp>
2015-08-23 13:58:07 -10:00
2021-04-10 01:42:06 -07:00
namespace metaforce {
2017-02-05 17:21:58 -10:00
#define DUMP_BITS 0
#if DUMP_BITS
2018-12-07 19:30:43 -10:00
static void PrintBinary(u32 val, u32 count) {
2019-11-08 18:49:37 -05:00
for (u32 i = 0; i < count; ++i) {
2020-04-11 12:51:39 -10:00
fmt::print(FMT_STRING("{}"), (val >> (count - i - 1)) & 0x1);
2018-12-07 19:30:43 -10:00
}
2017-02-05 17:21:58 -10:00
}
#endif
2016-03-19 12:19:43 -07:00
/*!
* \brief CBitStreamReader::ReadBit
* Reads and decodes an encoded value from a bitstream.
* \param bitCount How many bits to read
* \return s32 The encoded value
*/
2018-12-07 19:30:43 -10:00
s32 CBitStreamReader::ReadEncoded(u32 bitCount) {
2017-02-05 17:21:58 -10:00
#if DUMP_BITS
2019-11-08 18:49:37 -05:00
const auto pos = position();
const auto boff = x20_bitOffset;
2017-02-05 17:21:58 -10:00
#endif
2018-12-07 19:30:43 -10:00
u32 ret = 0;
2019-11-08 19:05:42 -05:00
const s32 shiftAmt = x20_bitOffset - s32(bitCount);
2018-12-07 19:30:43 -10:00
if (shiftAmt < 0) {
/* OR in remaining bits of cached value */
2019-11-08 19:05:42 -05:00
u32 mask = bitCount == 32 ? UINT32_MAX : ((1U << bitCount) - 1);
2018-12-07 19:30:43 -10:00
ret |= (x1c_val << u32(-shiftAmt)) & mask;
2017-02-05 17:21:58 -10:00
2018-12-07 19:30:43 -10:00
/* Load in exact number of bytes remaining */
auto loadDiv = std::div(-shiftAmt, 8);
if (loadDiv.rem)
++loadDiv.quot;
readUBytesToBuf(reinterpret_cast<u8*>(&x1c_val) + 4 - loadDiv.quot, loadDiv.quot);
x1c_val = hecl::SBig(x1c_val);
2017-02-05 17:21:58 -10:00
2018-12-07 19:30:43 -10:00
/* New bit offset */
x20_bitOffset = loadDiv.quot * 8 + shiftAmt;
2017-02-05 17:21:58 -10:00
2018-12-07 19:30:43 -10:00
/* OR in next bits */
2019-11-08 19:05:42 -05:00
mask = (1U << u32(-shiftAmt)) - 1;
2018-12-07 19:30:43 -10:00
ret |= (x1c_val >> x20_bitOffset) & mask;
} else {
/* OR in bits of cached value */
2019-11-08 19:05:42 -05:00
const u32 mask = bitCount == 32 ? UINT32_MAX : ((1U << bitCount) - 1);
2018-12-07 19:30:43 -10:00
ret |= (x1c_val >> u32(shiftAmt)) & mask;
2018-12-07 19:30:43 -10:00
/* New bit offset */
x20_bitOffset -= bitCount;
}
2017-02-05 17:21:58 -10:00
#if DUMP_BITS
2019-11-08 18:49:37 -05:00
std::fputs("READ ", stdout);
2018-12-07 19:30:43 -10:00
PrintBinary(ret, bitCount);
2020-04-11 12:51:39 -10:00
fmt::print(FMT_STRING(" {} {}\n"), pos, boff);
2017-02-05 17:21:58 -10:00
#endif
2018-12-07 19:30:43 -10:00
return ret;
}
2018-12-07 19:30:43 -10:00
void CBitStreamWriter::WriteEncoded(u32 val, u32 bitCount) {
2017-02-05 17:21:58 -10:00
#if DUMP_BITS
2019-11-08 18:49:37 -05:00
std::fputs("WRITE ", stdout);
2018-12-07 19:30:43 -10:00
PrintBinary(val, bitCount);
2020-04-11 12:51:39 -10:00
fmt::print(FMT_STRING(" {} {}\n"), position(), x18_bitOffset);
2017-02-05 17:21:58 -10:00
#endif
2019-11-08 19:05:42 -05:00
const s32 shiftAmt = x18_bitOffset - s32(bitCount);
2018-12-07 19:30:43 -10:00
if (shiftAmt < 0) {
/* OR remaining bits to cached value */
2019-11-08 19:05:42 -05:00
const u32 mask = (1U << x18_bitOffset) - 1;
2018-12-07 19:30:43 -10:00
x14_val |= (val >> u32(-shiftAmt)) & mask;
2017-02-05 17:21:58 -10:00
2018-12-07 19:30:43 -10:00
/* Write out 32-bits */
x14_val = hecl::SBig(x14_val);
writeBytes(&x14_val, sizeof(x14_val));
2017-02-05 17:21:58 -10:00
2018-12-07 19:30:43 -10:00
/* Cache remaining bits */
x18_bitOffset = 0x20 + shiftAmt;
x14_val = val << x18_bitOffset;
} else {
/* OR bits to cached value */
2019-11-08 19:05:42 -05:00
const u32 mask = bitCount == 32 ? UINT32_MAX : ((1U << bitCount) - 1);
2018-12-07 19:30:43 -10:00
x14_val |= (val & mask) << u32(shiftAmt);
2016-03-19 21:10:29 -07:00
2018-12-07 19:30:43 -10:00
/* New bit offset */
x18_bitOffset -= bitCount;
}
2016-03-19 21:10:29 -07:00
}
2018-12-07 19:30:43 -10:00
void CBitStreamWriter::Flush() {
if (x18_bitOffset >= 0x20) {
return;
2018-12-07 19:30:43 -10:00
}
auto pos = std::div(0x20 - s32(x18_bitOffset), 8);
if (pos.rem != 0) {
++pos.quot;
}
x14_val = hecl::SBig(x14_val);
writeBytes(&x14_val, pos.quot);
x18_bitOffset = 0x20;
x14_val = 0;
2017-02-03 17:46:12 -10:00
}
2015-08-23 13:58:07 -10:00
CZipInputStream::CZipInputStream(std::unique_ptr<CInputStream>&& strm)
2018-12-07 19:30:43 -10:00
: x24_compBuf(new u8[4096]), x28_strm(std::move(strm)) {
x30_zstrm.next_in = x24_compBuf.get();
x30_zstrm.avail_in = 0;
x30_zstrm.zalloc = [](void*, u32 c, u32 n) -> void* { return new u8[size_t{c} * size_t{n}]; };
x30_zstrm.zfree = [](void*, void* buf) { delete[] static_cast<u8*>(buf); };
2018-12-07 19:30:43 -10:00
inflateInit(&x30_zstrm);
2015-08-23 13:58:07 -10:00
}
2018-12-07 19:30:43 -10:00
CZipInputStream::~CZipInputStream() { inflateEnd(&x30_zstrm); }
2015-08-23 13:58:07 -10:00
2018-12-07 19:30:43 -10:00
atUint64 CZipInputStream::readUBytesToBuf(void* buf, atUint64 len) {
x30_zstrm.next_out = static_cast<Bytef*>(buf);
2018-12-07 19:30:43 -10:00
x30_zstrm.avail_out = len;
x30_zstrm.total_out = 0;
while (x30_zstrm.avail_out != 0) {
if (x30_zstrm.avail_in == 0) {
atUint64 readSz = x28_strm->readUBytesToBuf(x24_compBuf.get(), 4096);
x30_zstrm.avail_in = readSz;
x30_zstrm.next_in = x24_compBuf.get();
2015-08-23 13:58:07 -10:00
}
2018-12-07 19:30:43 -10:00
int inflateRet = inflate(&x30_zstrm, Z_NO_FLUSH);
if (inflateRet != Z_OK)
break;
}
return x30_zstrm.total_out;
2015-08-23 13:58:07 -10:00
}
2021-04-10 01:42:06 -07:00
} // namespace metaforce