Skip to content

Commit

Permalink
Implement general structure for Pbg3Archive::ReadDecompressEntry
Browse files Browse the repository at this point in the history
  • Loading branch information
toadster172 committed Nov 14, 2024
1 parent 09eee19 commit e325953
Showing 1 changed file with 99 additions and 76 deletions.
175 changes: 99 additions & 76 deletions src/pbg3/Pbg3Archive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,72 +197,52 @@ i32 Pbg3Archive::Load(char *path)
#define LZSS_DICTSIZE_MASK 0x1fff
#define LZSS_MIN_MATCH 3

class BitStream
{
public:
BitStream(u8 *data, u32 size) : data(data), size(size), curByte(0), curByteIdx(0), curBitIdx(0x80), m_checksum(0)
{
}
u32 Read(u32 numBits)
{
u32 ret = 0;
while (numBits != 0)
{
if (this->curBitIdx == 0x80)
{
this->curByte = *this->data;
if (this->curByteIdx < this->size)
{
this->data += 1;
this->curByteIdx += 1;
}
else
{
this->curByte = 0;
}
this->m_checksum += this->curByte;
}
if ((this->curByte & this->curBitIdx) != 0)
{
ret |= (1 << (numBits - 1));
}
numBits--;
this->curBitIdx >>= 1;
if (this->curBitIdx == 0)
{
this->curBitIdx = 0x80;
}
}
return ret;
}

u32 checksum()
{
return this->m_checksum;
}

private:
u8 *data;
u8 curByte;
u32 curByteIdx;
u32 curBitIdx;
u32 size;
u32 m_checksum;
};
#define BITFIELD_NEW_BYTE(byte, currDataPtr, baseDataPtr, size, checksum) \
byte = *dataCursor; \
if ((i32) (currDataPtr - baseDataPtr) >= (i32) size) \
{ \
currByte = 0; \
} \
else \
{ \
dataCursor++; \
} \
checksum += byte;

#define BITFIELD_READ_BITS(bitsCount, outBitMask, bitfieldReturn, inBitMask, byte, currDataPtr, baseDataPtr, size, checksum) \
outBitMask = 0x01 << (bitsCount - 1); \
bitfieldReturn = 0; \
while (outBitMask != 0) \
{ \
if (inBitMask == 0x80) \
{ \
BITFIELD_NEW_BYTE(byte, currDataPtr, baseDataPtr, size, checksum) \
} \
if ((byte & inBitMask) != 0) \
{ \
bitfieldReturn |= outBitMask; \
} \
\
outBitMask >>= 1; \
inBitMask >>= 1; \
if (inBitMask == 0) \
{ \
inBitMask = 0x80; \
} \
} \

u8 *Pbg3Archive::ReadDecompressEntry(u32 entryIdx, char *filename)
{
if (entryIdx >= this->numOfEntries)
return NULL;

if (this->parser == NULL)
if (entryIdx >= this->numOfEntries || this->parser == NULL)
return NULL;

u32 size = this->entries[entryIdx].uncompressedSize;
u32 size = this->GetEntrySize(entryIdx);
u8 *out = (u8 *)malloc(size);
if (out == NULL)
return NULL;

u8 *outCursor = out;

u32 expectedCsum;
u8 *rawData = this->ReadEntryRaw(&size, &expectedCsum, entryIdx);

Expand All @@ -272,49 +252,92 @@ u8 *Pbg3Archive::ReadDecompressEntry(u32 entryIdx, char *filename)
return NULL;
}

u8 dict[LZSS_DICTSIZE];
memset(dict, 0, sizeof(dict));
u8 *dataCursor = rawData;
u8 inBitMask = 0x80;
u32 checksum = 0;
u32 dictHead = 1;

u32 bytesWritten = 0;

u8 dict[LZSS_DICTSIZE];

// Memset doesn't produce matching assembly
for (i32 i = 0; i < LZSS_DICTSIZE; i++)
{
dict[i] = 0;
}

u32 currByte;
u32 bitfieldReturn;
u32 outBitMask;
u32 matchOffset;

BitStream bs = BitStream(rawData, size);
while (TRUE)
{
if (bs.Read(1) != 0)
if (inBitMask == 0x80)
{
BITFIELD_NEW_BYTE(currByte, dataCursor, rawData, size, checksum)
}

u32 opcode = currByte & inBitMask;
inBitMask >>= 1;
if (inBitMask == 0x00)
{
inBitMask = 0x80;
}

// Read literal byte from next 8 bits
if (opcode != 0)
{
u8 c = bs.Read(8);
out[bytesWritten] = c;
bytesWritten += 1;
dict[dictHead] = c;
BITFIELD_READ_BITS(8, outBitMask, bitfieldReturn, inBitMask, currByte, dataCursor, rawData, size, checksum)
*outCursor = bitfieldReturn;
outCursor++;
dict[dictHead] = bitfieldReturn;
dictHead = (dictHead + 1) & LZSS_DICTSIZE_MASK;
}
// Copy from dictionary, 13 bit offset, then 4 bit length
else
{
u32 matchOffset = bs.Read(13);
if (!matchOffset)
BITFIELD_READ_BITS(13, outBitMask, bitfieldReturn, inBitMask, currByte, dataCursor, rawData, size, checksum)
matchOffset = bitfieldReturn;

if (matchOffset == 0)
break;

u32 matchLen = bs.Read(4) + LZSS_MIN_MATCH;
BITFIELD_READ_BITS(4, outBitMask, bitfieldReturn, inBitMask, currByte, dataCursor, rawData, size, checksum)

for (u32 i = 0; i < matchLen; ++i)
for (i32 i = 0; i <= (i32) bitfieldReturn + 2; i++)
{
u8 c = dict[(matchOffset + i) & LZSS_DICTSIZE_MASK];
out[bytesWritten] = c;
bytesWritten += 1;
u32 c = dict[(matchOffset + i) & LZSS_DICTSIZE_MASK];
*outCursor = c;
outCursor++;
dict[dictHead] = c;
dictHead = (dictHead + 1) & LZSS_DICTSIZE_MASK;
}
}
}
// ???? No clue what this was supposed to be
while (inBitMask != 0x80)
{
if (inBitMask == 0x80 && (i32) (dataCursor - rawData) < (i32) size)
{
dataCursor++;
}

if (this->entries[entryIdx].checksum != bs.checksum())
inBitMask >>= 1;
if (inBitMask == 0)
{
inBitMask = 0x80;
}
}

free(rawData);

if (expectedCsum != checksum)
{
free(out);
out = NULL;
return NULL;
}

free(rawData);
return out;
}
}; // namespace th06

0 comments on commit e325953

Please sign in to comment.