psxsdk/libhuff/huff.c

120 lines
2.5 KiB
C

// Huffman decompression library for PSXSDK
// Huffman decompression code adapted from huff program
// by Joe Wingbermuehle
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <psx.h>
#include "huff.h"
#define BUFFER_SIZE 1024
unsigned char libhuff_inBuffer[BUFFER_SIZE];
unsigned char libhuff_outBuffer[BUFFER_SIZE];
struct CodeNode {
unsigned char value;
unsigned long code;
unsigned int codeSize;
};
struct CodeNode libhuff_codes[256];
unsigned int libhuff_codesUsed;
// Decompress_Mem returns size of uncompressed data if SizeLimit >= UncompressedDataSize,
// otherwise if UncompressedDataSize > SizeLimit, 0 is returned
// SizeLimit is the maximum space available for decompressed data
unsigned int huff_decompress(void *dst, void *src, int sizeLimit) {
int x, y;
unsigned int dataSize;
unsigned long mask, maskSize;
unsigned char ch;
int offset;
// int last;
int ib, ob;
int src_pos = 8;
int dst_pos = 0;
unsigned char *srcc = (unsigned char*)src;
unsigned char *dstc = (unsigned char*)dst;
libhuff_codesUsed = *((unsigned int*)src);
dataSize = *((unsigned int*)src + 1);
if(dataSize > sizeLimit)
return 0;
for(x = 0; x < libhuff_codesUsed; x++) {
libhuff_codes[x].value = srcc[src_pos++];
libhuff_codes[x].codeSize = srcc[src_pos++] + 1;
}
offset = 7;
ch = 0;
for(x = 0; x < libhuff_codesUsed; x++) {
libhuff_codes[x].code = 0;
for(y = libhuff_codes[x].codeSize - 1; y >= 0; y--) {
if(offset == 7) {
ch = srcc[src_pos++];
}
libhuff_codes[x].code |= ((ch >> offset) & 1) << y;
offset = (offset - 1) & 7;
}
}
maskSize = 0;
mask = 0;
offset = 7;
//last = 0;
y = 0;
x = 0;
ib = BUFFER_SIZE;
ob = 0;
for(;;) {
if(offset == 7) {
if(ib >= BUFFER_SIZE) {
memcpy(libhuff_inBuffer, &srcc[src_pos], BUFFER_SIZE);
src_pos += BUFFER_SIZE;
ib = 0;
}
ch = libhuff_inBuffer[ib++];
}
mask <<= 1;
mask |= (ch >> offset) & 1;
++maskSize;
offset = (offset - 1) & 7;
while(libhuff_codes[y].codeSize < maskSize) ++y;
while(libhuff_codes[y].codeSize == maskSize) {
if(libhuff_codes[y].code == mask) {
if(ob >= BUFFER_SIZE) {
memcpy(&dstc[dst_pos], libhuff_outBuffer, BUFFER_SIZE);
dst_pos += BUFFER_SIZE;
ob = 0;
}
libhuff_outBuffer[ob++] = libhuff_codes[y].value;
++x;
if(x >= dataSize) {
memcpy(&dstc[dst_pos], libhuff_outBuffer, ob);
dst_pos += ob;
return dataSize;
}
mask = 0;
maskSize = 0;
y = 0;
break;
}
++y;
}
}
return dataSize;
}