ref: 4f4c60b34d48ac94175de4939c2fe07e73c348c5
dir: /src/modloaders/pt2_pp_unpack.c/
/* PowerPacker unpack code taken from Heikki Orsila's amigadepack. Seems to have no license,
** so I'll assume it fits into BSD 3-Clause. If not, feel free to contact me at my email
** address found at the bottom of 16-bits.org.
**
** Edited by me (8bitbubsy).
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#define READ_BITS(nbits, var) \
bitCnt = (nbits); \
while (bitsLeft < bitCnt) \
{ \
if (bufSrc < src) \
return false; \
bitBuffer |= ((*--bufSrc) << bitsLeft); \
bitsLeft += 8; \
} \
(var) = 0; \
bitsLeft -= bitCnt; \
while (bitCnt--) \
{ \
(var) = ((var) << 1) | (bitBuffer & 1); \
bitBuffer >>= 1; \
}
static bool decrunch(uint8_t *src, uint8_t *dst, uint8_t *offsetLens, uint32_t srcLen, uint32_t dstLen, uint8_t skipBits)
{
uint8_t bitCnt;
uint32_t x, todo, offset;
if (src == NULL || dst == NULL || offsetLens == NULL)
return false;
uint8_t bitsLeft = 0;
uint32_t bitBuffer = 0;
uint32_t written = 0;
uint8_t *bufSrc = src + srcLen;
uint8_t *out = dst + dstLen;
uint8_t *dstEnd = out;
READ_BITS(skipBits, x);
while (written < dstLen)
{
READ_BITS(1, x);
if (x == 0)
{
todo = 1;
do
{
READ_BITS(2, x);
todo += x;
}
while (x == 3);
while (todo--)
{
READ_BITS(8, x);
if (out <= dst)
return false;
*--out = (uint8_t)x;
written++;
}
if (written == dstLen)
break;
}
READ_BITS(2, x);
uint32_t offBits = offsetLens[x];
todo = x + 2;
if (x == 3)
{
READ_BITS(1, x);
if (x == 0) offBits = 7;
READ_BITS((uint8_t)offBits, offset);
do
{
READ_BITS(3, x);
todo += x;
}
while (x == 7);
}
else
{
READ_BITS((uint8_t)offBits, offset);
}
if (out+offset >= dstEnd)
return false;
while (todo--)
{
x = out[offset];
if (out <= dst)
return false;
*--out = (uint8_t)x;
written++;
}
}
return true;
}
uint8_t *unpackPP(FILE *f, uint32_t *filesize)
{
uint8_t *outBuffer, ppCrunchData[4], *ppBuffer;
uint32_t ppPackLen, ppUnpackLen;
ppPackLen = *filesize;
if ((ppPackLen & 3) != 0 || ppPackLen <= 12)
return NULL;
ppBuffer = (uint8_t *)malloc(ppPackLen);
if (ppBuffer == NULL)
return NULL;
fseek(f, ppPackLen-4, SEEK_SET);
fread(ppCrunchData, 1, 4, f);
ppUnpackLen = (ppCrunchData[0] << 16) | (ppCrunchData[1] << 8) | ppCrunchData[2];
outBuffer = (uint8_t *)malloc(ppUnpackLen);
if (outBuffer == NULL)
{
free(ppBuffer);
return NULL;
}
rewind(f);
fread(ppBuffer, 1, ppPackLen, f);
fclose(f);
if (!decrunch(ppBuffer+8, outBuffer, ppBuffer+4, ppPackLen-12, ppUnpackLen, ppCrunchData[3]))
{
free(ppBuffer);
return NULL;
}
free(ppBuffer);
*filesize = ppUnpackLen;
return outBuffer;
}