about summary refs log tree commit diff
path: root/src/engine/compression.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine/compression.cpp')
-rw-r--r--src/engine/compression.cpp370
1 files changed, 370 insertions, 0 deletions
diff --git a/src/engine/compression.cpp b/src/engine/compression.cpp
new file mode 100644
index 00000000..c878b15b
--- /dev/null
+++ b/src/engine/compression.cpp
@@ -0,0 +1,370 @@
+#include <baselib/system.h>
+#include <string.h>
+
+// LZW Compressor
+struct SYM
+{
+	unsigned char *data;
+	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;
+	symbols.syms[i].data = sym;
+	symbols.syms[i].size = len;
+	symbols.currentsym = (symbols.currentsym+1)%255;
+	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;
+}
+
+static void sym_init()
+{
+	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;
+}
+
+static int sym_find(unsigned char *data, int size, int avoid)
+{
+	int best = data[0];
+	int bestlen = 1;
+	int current = symbols.jumptable[data[0]];
+
+	while(current != -1)
+	{
+		if(current != avoid && symbols.syms[current].size <= size && memcmp(data, symbols.syms[current].data, symbols.syms[current].size) == 0)
+		{
+			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);
+	int lastsym = -1;
+
+	// 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;
+			}
+
+ 			int sym = sym_find(src, left, lastsym);
+			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
+				lastsym = sym_add_and_index(src, symsize+1);
+			
+			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_;
+	unsigned char *prevdst = 0;
+	int prevsize = -1;
+	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_);
+
+			if(prevdst) // this one could be removed
+				sym_add(prevdst, prevsize+1);
+				
+			memcpy(dst, sym_data(item), sym_size(item));
+			prevdst = dst;
+			prevsize = sym_size(item);
+			dst += sym_size(item);
+		}
+
+	}
+
+	return 0;
+}
+
+// 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;
+}
+