2007-07-13 13:40:04 +00:00
|
|
|
#include <baselib/system.h>
|
2007-05-22 15:03:32 +00:00
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
// LZW Compressor
|
|
|
|
struct SYM
|
|
|
|
{
|
2007-05-24 10:57:18 +00:00
|
|
|
unsigned char *data;
|
2007-05-22 15:03:32 +00:00
|
|
|
int size;
|
|
|
|
int next;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct SYMBOLS
|
|
|
|
{
|
|
|
|
SYM syms[512];
|
|
|
|
int jumptable[256];
|
|
|
|
int currentsym;
|
|
|
|
};
|
|
|
|
|
|
|
|
static SYMBOLS symbols;
|
|
|
|
|
|
|
|
// symbol info
|
|
|
|
inline int sym_size(int i) { return symbols.syms[i].size; }
|
|
|
|
inline unsigned char *sym_data(int i) { return symbols.syms[i].data; }
|
|
|
|
|
|
|
|
static void sym_index(int sym)
|
|
|
|
{
|
|
|
|
int table = symbols.syms[sym].data[0];
|
|
|
|
symbols.syms[sym].next = symbols.jumptable[table];
|
|
|
|
symbols.jumptable[table] = sym;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void sym_unindex(int sym)
|
|
|
|
{
|
|
|
|
int table = symbols.syms[sym].data[0];
|
|
|
|
int prev = -1;
|
|
|
|
int current = symbols.jumptable[table];
|
|
|
|
|
|
|
|
while(current != -1)
|
|
|
|
{
|
|
|
|
if(current == sym)
|
|
|
|
{
|
|
|
|
if(prev != -1)
|
|
|
|
symbols.syms[prev].next = symbols.syms[current].next;
|
|
|
|
else
|
|
|
|
symbols.jumptable[table] = symbols.syms[current].next;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
prev = current;
|
|
|
|
current = symbols.syms[current].next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sym_add(unsigned char *sym, long len)
|
|
|
|
{
|
|
|
|
int i = 256+symbols.currentsym;
|
2007-05-24 10:57:18 +00:00
|
|
|
symbols.syms[i].data = sym;
|
2007-05-22 15:03:32 +00:00
|
|
|
symbols.syms[i].size = len;
|
2007-05-24 10:57:18 +00:00
|
|
|
symbols.currentsym = (symbols.currentsym+1)%255;
|
2007-05-22 15:03:32 +00:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sym_add_and_index(unsigned char *sym, long len)
|
|
|
|
{
|
|
|
|
if(symbols.syms[256+symbols.currentsym].size)
|
|
|
|
sym_unindex(256+symbols.currentsym);
|
|
|
|
int s = sym_add(sym, len);
|
|
|
|
sym_index( s);
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2007-05-24 10:57:18 +00:00
|
|
|
static void sym_init()
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-05-24 10:57:18 +00:00
|
|
|
static unsigned char table[256];
|
|
|
|
for(int i = 0; i < 256; i++)
|
|
|
|
{
|
|
|
|
table[i] = i;
|
|
|
|
symbols.syms[i].data = &table[i];
|
|
|
|
symbols.syms[i].size = 1;
|
|
|
|
symbols.jumptable[i] = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(int i = 0; i < 512; i++)
|
|
|
|
symbols.syms[i].next = -1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
// insert some symbols to start with
|
|
|
|
static unsigned char zeros[8] = {0,0,0,0,0,0,0,0};
|
|
|
|
//static unsigned char one1[4] = {0,0,0,1};
|
|
|
|
//static unsigned char one2[4] = {1,0,0,0};
|
|
|
|
sym_add_and_index(zeros, 2);
|
|
|
|
sym_add_and_index(zeros, 3);
|
|
|
|
sym_add_and_index(zeros, 4);
|
|
|
|
sym_add_and_index(zeros, 5);
|
|
|
|
sym_add_and_index(zeros, 6);
|
|
|
|
sym_add_and_index(zeros, 7);
|
|
|
|
sym_add_and_index(zeros, 8);
|
|
|
|
|
|
|
|
//sym_add_and_index(one1, 4);
|
|
|
|
//sym_add_and_index(one2, 4);*/
|
|
|
|
|
|
|
|
symbols.currentsym = 0;
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
|
|
|
|
2007-05-24 10:57:18 +00:00
|
|
|
static int sym_find(unsigned char *data, int size, int avoid)
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
|
|
|
int best = data[0];
|
|
|
|
int bestlen = 1;
|
|
|
|
int current = symbols.jumptable[data[0]];
|
|
|
|
|
|
|
|
while(current != -1)
|
|
|
|
{
|
2007-05-24 10:57:18 +00:00
|
|
|
if(current != avoid && symbols.syms[current].size <= size && memcmp(data, symbols.syms[current].data, symbols.syms[current].size) == 0)
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
|
|
|
if(bestlen < symbols.syms[current].size)
|
|
|
|
{
|
|
|
|
bestlen = symbols.syms[current].size;
|
|
|
|
best = current;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
current = symbols.syms[current].next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return best;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// compress
|
|
|
|
//
|
|
|
|
long lzw_compress(const void *src_, int size, void *dst_)
|
|
|
|
{
|
|
|
|
unsigned char *src = (unsigned char *)src_;
|
|
|
|
unsigned char *end = (unsigned char *)src_+size;
|
|
|
|
unsigned char *dst = (unsigned char *)dst_;
|
|
|
|
long left = (end-src);
|
2007-05-24 10:57:18 +00:00
|
|
|
int lastsym = -1;
|
2007-05-22 15:03:32 +00:00
|
|
|
|
|
|
|
// init symboltable
|
|
|
|
sym_init();
|
|
|
|
|
|
|
|
bool done = false;
|
|
|
|
while(!done)
|
|
|
|
{
|
|
|
|
unsigned char *flagptr = dst;
|
|
|
|
unsigned char flagbits = 0;
|
|
|
|
int b = 0;
|
|
|
|
|
|
|
|
dst++; // skip a byte where the flags are
|
|
|
|
|
|
|
|
for(; b < 8; b++)
|
|
|
|
{
|
|
|
|
if(left <= 0) // check for EOF
|
|
|
|
{
|
|
|
|
// write EOF symbol
|
|
|
|
flagbits |= 1<<b;
|
|
|
|
*dst++ = 255;
|
|
|
|
done = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-05-24 10:57:18 +00:00
|
|
|
int sym = sym_find(src, left, lastsym);
|
2007-05-22 15:03:32 +00:00
|
|
|
int symsize = sym_size( sym);
|
|
|
|
|
|
|
|
if(sym&0x100)
|
|
|
|
flagbits |= 1<<b; // add bit that says that its a symbol
|
|
|
|
|
|
|
|
*dst++ = sym&0xff; // set symbol
|
|
|
|
|
|
|
|
if(left > symsize+1) // create new symbol
|
2007-05-24 10:57:18 +00:00
|
|
|
lastsym = sym_add_and_index(src, symsize+1);
|
2007-05-22 15:03:32 +00:00
|
|
|
|
|
|
|
src += symsize; // advance src
|
|
|
|
left -= symsize;
|
|
|
|
}
|
|
|
|
|
|
|
|
// write the flags
|
|
|
|
*flagptr = flagbits;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (long)(dst-(unsigned char*)dst_);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// decompress
|
|
|
|
//
|
|
|
|
long lzw_decompress(const void *src_, void *dst_)
|
|
|
|
{
|
|
|
|
unsigned char *src = (unsigned char *)src_;
|
|
|
|
unsigned char *dst = (unsigned char *)dst_;
|
2007-05-24 10:57:18 +00:00
|
|
|
unsigned char *prevdst = 0;
|
|
|
|
int prevsize = -1;
|
2007-05-22 15:03:32 +00:00
|
|
|
int item;
|
|
|
|
|
|
|
|
sym_init();
|
|
|
|
|
|
|
|
while(1)
|
|
|
|
{
|
|
|
|
unsigned char flagbits = 0;
|
|
|
|
flagbits = *src++; // read flags
|
|
|
|
|
|
|
|
int b = 0;
|
|
|
|
for(; b < 8; b++)
|
|
|
|
{
|
|
|
|
item = *src++;
|
|
|
|
if(flagbits&(1<<b))
|
|
|
|
item |= 256;
|
|
|
|
|
|
|
|
if(item == 0x1ff) // EOF symbol
|
|
|
|
return (dst-(unsigned char *)dst_);
|
|
|
|
|
2007-05-24 10:57:18 +00:00
|
|
|
if(prevdst) // this one could be removed
|
|
|
|
sym_add(prevdst, prevsize+1);
|
2007-05-22 15:03:32 +00:00
|
|
|
|
2007-05-24 10:57:18 +00:00
|
|
|
memcpy(dst, sym_data(item), sym_size(item));
|
|
|
|
prevdst = dst;
|
|
|
|
prevsize = sym_size(item);
|
|
|
|
dst += sym_size(item);
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2007-07-13 13:40:04 +00:00
|
|
|
|
|
|
|
// Format: ESDDDDDD EDDDDDDD EDD... Extended, Data, Sign
|
|
|
|
unsigned char *vint_pack(unsigned char *dst, int i)
|
|
|
|
{
|
|
|
|
*dst = (i>>25)&0x40; // set sign bit if i<0
|
|
|
|
i = i^(i>>31); // if(i<0) i = ~i
|
|
|
|
|
|
|
|
*dst |= i&0x3F; // pack 6bit into dst
|
|
|
|
i >>= 6; // discard 6 bits
|
|
|
|
if(i)
|
|
|
|
{
|
|
|
|
*dst |= 0x80; // set extend bit
|
|
|
|
while(1)
|
|
|
|
{
|
|
|
|
dst++;
|
|
|
|
*dst = i&(0x7F); // pack 7bit
|
|
|
|
i >>= 7; // discard 7 bits
|
|
|
|
*dst |= (i!=0)<<7; // set extend bit (may branch)
|
|
|
|
if(!i)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
dst++;
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
|
|
|
const unsigned char *vint_unpack(const unsigned char *src, int *i)
|
|
|
|
{
|
|
|
|
int sign = (*src>>6)&1;
|
|
|
|
*i = *src&0x3F;
|
|
|
|
|
|
|
|
while(1)
|
|
|
|
{
|
|
|
|
if(!(*src&0x80)) break;
|
|
|
|
src++;
|
|
|
|
*i |= (*src&(0x7F))<<(6);
|
|
|
|
|
|
|
|
if(!(*src&0x80)) break;
|
|
|
|
src++;
|
|
|
|
*i |= (*src&(0x7F))<<(6+7);
|
|
|
|
|
|
|
|
if(!(*src&0x80)) break;
|
|
|
|
src++;
|
|
|
|
*i |= (*src&(0x7F))<<(6+7+7);
|
|
|
|
|
|
|
|
if(!(*src&0x80)) break;
|
|
|
|
src++;
|
|
|
|
*i |= (*src&(0x7F))<<(6+7+7+7);
|
|
|
|
}
|
|
|
|
|
|
|
|
src++;
|
|
|
|
*i ^= -sign; // if(sign) *i = ~(*i)
|
|
|
|
return src;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
long intpack_decompress(const void *src_, int size, void *dst_)
|
|
|
|
{
|
|
|
|
const unsigned char *src = (unsigned char *)src_;
|
|
|
|
const unsigned char *end = src + size;
|
|
|
|
int *dst = (int *)dst_;
|
|
|
|
while(src < end)
|
|
|
|
{
|
|
|
|
src = vint_unpack(src, dst);
|
|
|
|
dst++;
|
|
|
|
}
|
|
|
|
return (long)((unsigned char *)dst-(unsigned char *)dst_);
|
|
|
|
}
|
|
|
|
|
|
|
|
long intpack_compress(const void *src_, int size, void *dst_)
|
|
|
|
{
|
|
|
|
int *src = (int *)src_;
|
|
|
|
unsigned char *dst = (unsigned char *)dst_;
|
|
|
|
size /= 4;
|
|
|
|
while(size)
|
|
|
|
{
|
|
|
|
dst = vint_pack(dst, *src);
|
|
|
|
size--;
|
|
|
|
src++;
|
|
|
|
}
|
|
|
|
return (long)(dst-(unsigned char *)dst_);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
long zerobit_compress(const void *src_, int size, void *dst_)
|
|
|
|
{
|
|
|
|
unsigned char *src = (unsigned char *)src_;
|
|
|
|
unsigned char *dst = (unsigned char *)dst_;
|
|
|
|
|
|
|
|
//int zerocount = 0 ;
|
|
|
|
while(size)
|
|
|
|
{
|
|
|
|
unsigned char bit = 0x80;
|
|
|
|
unsigned char mask = 0;
|
|
|
|
int dst_move = 1;
|
|
|
|
int chunk = size < 8 ? size : 8;
|
|
|
|
size -= chunk;
|
|
|
|
|
|
|
|
for(int b = 0; b < chunk; b++, bit>>=1)
|
|
|
|
{
|
|
|
|
if(*src)
|
|
|
|
{
|
|
|
|
dst[dst_move] = *src;
|
|
|
|
mask |= bit;
|
|
|
|
dst_move++;
|
|
|
|
}
|
|
|
|
|
|
|
|
src++;
|
|
|
|
}
|
|
|
|
|
|
|
|
*dst = mask;
|
|
|
|
dst += dst_move;
|
|
|
|
}
|
|
|
|
|
|
|
|
long l = (long)(dst-(unsigned char *)dst_);
|
|
|
|
//dbg_msg("zerobit", "%d", (int)l);
|
|
|
|
return l;
|
|
|
|
}
|
|
|
|
|
|
|
|
long zerobit_decompress(const void *src_, int size, void *dst_)
|
|
|
|
{
|
|
|
|
unsigned char *src = (unsigned char *)src_;
|
|
|
|
unsigned char *dst = (unsigned char *)dst_;
|
|
|
|
unsigned char *end = src + size;
|
|
|
|
|
|
|
|
//int zerocount = 0 ;
|
|
|
|
while(src != end)
|
|
|
|
{
|
|
|
|
unsigned char bit = 0x80;
|
|
|
|
unsigned char mask = *src++;
|
|
|
|
|
|
|
|
for(int b = 0; b < 8; b++, bit>>=1)
|
|
|
|
{
|
|
|
|
if(mask&bit)
|
|
|
|
*dst++ = *src++;
|
|
|
|
else
|
|
|
|
*dst++ = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
long l = (long)(dst-(unsigned char *)dst_);
|
|
|
|
//dbg_msg("zerobit", "%d", (int)l);
|
|
|
|
return l;
|
|
|
|
}
|
|
|
|
|