metaforce/Runtime/IOStreams.cpp

163 lines
3.9 KiB
C++
Raw Normal View History

2015-08-23 23:58:07 +00:00
#include "IOStreams.hpp"
2017-02-06 03:21:58 +00:00
#include "hecl/hecl.hpp"
2015-08-23 23:58:07 +00:00
2016-03-04 23:04:53 +00:00
namespace urde
2015-08-23 23:58:07 +00:00
{
2017-02-06 03:21:58 +00:00
#define DUMP_BITS 0
#if DUMP_BITS
static void PrintBinary(u32 val, u32 count)
{
for (int i=0 ; i<count ; ++i)
{
printf("%d", (val >> (count-i-1)) & 0x1);
}
}
#endif
2016-03-19 19:19:43 +00: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
*/
s32 CBitStreamReader::ReadEncoded(u32 bitCount)
{
2017-02-06 03:21:58 +00:00
#if DUMP_BITS
auto pos = position();
auto boff = x20_bitOffset;
#endif
u32 ret = 0;
s32 shiftAmt = x20_bitOffset - s32(bitCount);
if (shiftAmt < 0)
{
2017-02-06 03:21:58 +00:00
/* OR in remaining bits of cached value */
2017-02-07 02:25:58 +00:00
u32 mask = bitCount == 32 ? 0xffffffff : ((1 << bitCount) - 1);
ret |= (x1c_val << u32(-shiftAmt)) & mask;
2017-02-06 03:21:58 +00: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);
/* New bit offset */
x20_bitOffset = loadDiv.quot * 8 + shiftAmt;
/* OR in next bits */
2017-02-07 02:25:58 +00:00
mask = (1 << u32(-shiftAmt)) - 1;
2017-02-06 03:21:58 +00:00
ret |= (x1c_val >> x20_bitOffset) & mask;
}
else
{
2017-02-06 03:21:58 +00:00
/* OR in bits of cached value */
2017-02-07 02:25:58 +00:00
u32 mask = bitCount == 32 ? 0xffffffff : ((1 << bitCount) - 1);
ret |= (x1c_val >> u32(shiftAmt)) & mask;
2017-02-06 03:21:58 +00:00
/* New bit offset */
x20_bitOffset -= bitCount;
}
2017-02-06 03:21:58 +00:00
#if DUMP_BITS
printf("READ ");
PrintBinary(ret, bitCount);
printf(" %d %d\n", int(pos), int(boff));
#endif
return ret;
}
2016-03-20 04:10:29 +00:00
void CBitStreamWriter::WriteEncoded(u32 val, u32 bitCount)
{
2017-02-06 03:21:58 +00:00
#if DUMP_BITS
printf("WRITE ");
PrintBinary(val, bitCount);
printf(" %d %d\n", int(position()), int(x18_bitOffset));
#endif
s32 shiftAmt = x18_bitOffset - s32(bitCount);
if (shiftAmt < 0)
2016-03-20 04:10:29 +00:00
{
2017-02-06 03:21:58 +00:00
/* OR remaining bits to cached value */
u32 mask = (1 << x18_bitOffset) - 1;
2017-02-07 02:25:58 +00:00
x14_val |= (val >> u32(-shiftAmt)) & mask;
2017-02-06 03:21:58 +00:00
/* Write out 32-bits */
x14_val = hecl::SBig(x14_val);
writeUBytes(reinterpret_cast<u8*>(&x14_val), 4);
/* Cache remaining bits */
x18_bitOffset = 0x20 + shiftAmt;
x14_val = val << x18_bitOffset;
2016-03-20 04:10:29 +00:00
}
else
{
2017-02-06 03:21:58 +00:00
/* OR bits to cached value */
2017-02-07 02:25:58 +00:00
u32 mask = bitCount == 32 ? 0xffffffff : ((1 << bitCount) - 1);
x14_val |= (val & mask) << u32(shiftAmt);
2016-03-20 04:10:29 +00:00
2017-02-06 03:21:58 +00:00
/* New bit offset */
x18_bitOffset -= bitCount;
2016-03-20 04:10:29 +00:00
}
}
2017-02-04 03:46:12 +00:00
void CBitStreamWriter::Flush()
{
2017-02-06 03:21:58 +00:00
if (x18_bitOffset < 0x20)
2017-02-04 03:46:12 +00:00
{
2017-02-06 03:21:58 +00:00
auto pos = std::div(0x20 - x18_bitOffset, 8);
2017-02-04 03:46:12 +00:00
if (pos.rem) ++pos.quot;
2017-02-06 03:21:58 +00:00
x14_val = hecl::SBig(x14_val);
writeUBytes(reinterpret_cast<u8*>(&x14_val), pos.quot);
x18_bitOffset = 0x20;
2017-02-04 03:46:12 +00:00
x14_val = 0;
}
}
2015-08-23 23:58:07 +00:00
class CZipSupport
{
public:
static void* Alloc(void*, u32 c, u32 n)
{
return new u8[c*n];
2015-08-23 23:58:07 +00:00
}
static void Free(void*, void* buf)
{
delete[] static_cast<u8*>(buf);
}
};
CZipInputStream::CZipInputStream(std::unique_ptr<CInputStream>&& strm)
: x24_compBuf(new u8[4096]), x28_strm(std::move(strm))
2015-08-23 23:58:07 +00:00
{
x30_zstrm.next_in = x24_compBuf.get();
x30_zstrm.avail_in = 0;
x30_zstrm.zalloc = CZipSupport::Alloc;
x30_zstrm.zfree = CZipSupport::Free;
inflateInit(&x30_zstrm);
}
CZipInputStream::~CZipInputStream()
{
inflateEnd(&x30_zstrm);
}
atUint64 CZipInputStream::readUBytesToBuf(void *buf, atUint64 len)
{
x30_zstrm.next_out = (Bytef*)buf;
x30_zstrm.avail_out = len;
if (!x30_zstrm.avail_in)
{
atUint64 readSz = x28_strm->readUBytesToBuf(x24_compBuf.get(), 4096);
x30_zstrm.avail_in = readSz;
x30_zstrm.next_in = x24_compBuf.get();
}
inflate(&x30_zstrm, Z_NO_FLUSH);
return x30_zstrm.total_out;
}
}