ref: f4ba52e6835e5935ad294b7dbbfbce3fc36d40c1
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; }