120 lines
2.5 KiB
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;
|
|
}
|
|
|