git » fp-git.git » commit 557dcac

* Coded the compression algorithm.

author dessaya
2005-03-13 05:11:50 UTC
committer dessaya
2005-03-13 05:11:50 UTC
parent 12e9c168c24f85a80d82a57e5d8640e6786d49e2

* Coded the compression algorithm.
* Created the 'lzg' tool which is able to compress and expand files of size
  less than ~64k.

PR/src/lib/compression/lzg_compress.c +204 -0
PR/src/lib/compression/lzg_decompress.c +95 -0
stuff/contest/lzg/Makefile +15 -0
stuff/contest/lzg/lzg.c +172 -0
stuff/contest/lzg/lzg_compress.c +204 -0
stuff/contest/lzg/lzg_compress.h +7 -0
stuff/contest/lzg/lzg_uncompress.c +95 -0
stuff/contest/lzg/lzg_uncompress.h +7 -0
stuff/contest/lzg/test +15 -1
stuff/contest/lzg/uncompress.c +0 -137

diff --git a/PR/src/lib/compression/lzg_compress.c b/PR/src/lib/compression/lzg_compress.c
new file mode 100644
index 0000000..b0a076a
--- /dev/null
+++ b/PR/src/lib/compression/lzg_compress.c
@@ -0,0 +1,204 @@
+/* 
+ * LZG compression
+ * 
+ * ---------------------------------------------------------------------------- 
+ * 
+ * Authors: 
+ *   Enrique Calot <ecalot.cod@princed.com.ar>
+ *   Diego Essaya <dessaya@fi.uba.ar>
+ * 
+ * Research: Tammo Jan Dijkemma, Anke Balderer, Enrique Calot
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2004, 2005 the Princed Team
+ * 
+ * This file is part of the Princed project.
+ * 
+ * Princed is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Princed is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modus operandi of the compression algorithm
+ * -------------------------------------------
+ * 
+ * For each input byte we take a window containing the 1023 previous bytes.
+ * If the window goes out of bounds (ie, when the current input byte is
+ * before position 1024), we consider it filled with zeros.
+ *
+ *     00000000000000000000********************************
+ *                         ^                  ^
+ *                    input start   current input byte
+ *           |--------------------------------|
+ *                    window size=1023
+ * 
+ * The algorithm works as follows:
+ *
+ * While there is unread input data:
+ *     Create a maskbyte.
+ *     For each bit in the maskbyte (and there is still unread input data):
+ *         Compare the following input bytes with the bytes in the window,
+ *         and search the longest pattern that is equal to the next bytes.
+ *         If we found a pattern of length n > 2:
+ *             Assign 0 to the current bit of the maskbyte.
+ *             In the next 2 bytes of the output, specify the relative
+ *             position and length of the pattern.
+ *             Advance output pointer by 2.
+ *             Advance input pointer by n.
+ * 	       Else:
+ *             Assign 1 to the current bit of the maskbyte.
+ * 	           Copy the current input byte in the next output byte.
+ *             Advance output pointer by 1.
+ *             Advance input pointer by 1.
+ */
+
+#include <string.h>  /* memchr() */
+#include <stdio.h>
+#include "lzg_compress.h"
+
+/* Window size */
+#define WIN_SIZE 1024
+
+/* A repetition pattern must have a length of at least MIN_PATTERN_SIZE 
+ * to be accepted (ie, to be worth for compressing) */
+#define MIN_PATTERN_SIZE 3
+#define MAX_PATTERN_SIZE 66
+
+/* search the longest pattern in the window that matches the first bytes
+ * of the input */
+void search_best_pattern(unsigned char *input, int inputSize, 
+                         unsigned char *window,
+                         unsigned char **best_pattern, 
+                         int *best_pattern_len)
+{
+	unsigned char *pattern;
+	int pattern_len;
+	int window_len = WIN_SIZE - 1;
+
+	*best_pattern_len = 0;
+
+	while ((pattern = (unsigned char *)memchr(window, *input, window_len)))
+	{
+		unsigned char *ic = input + 1;
+		unsigned char *wc = pattern + 1;
+		pattern_len = 1;
+
+		while ( (ic < (input + inputSize)) && 
+		        (wc < (window + window_len)) &&
+		        (*ic == *wc) &&
+				pattern_len < MAX_PATTERN_SIZE)
+		{
+			ic++; wc++; pattern_len++;
+		}
+
+		if (pattern_len > *best_pattern_len)
+		{
+			*best_pattern_len = pattern_len;
+			*best_pattern = pattern;
+		}
+
+		window_len -= wc - window;
+		window = wc;
+	}
+}
+
+/* Insert the specified bit in the current maskByte. If the maskByte is full,
+ * start a new one. */
+void pushMaskBit(int b, unsigned char **maskByte, int *maskBit,
+                 unsigned char *output, int *outputPos)
+{
+	if ( (!(*maskByte)) || (*maskBit == 8) )
+	{
+		/* start a new maskByte */
+		*maskByte = output + *outputPos;
+		(*outputPos)++;
+		**maskByte = 0;
+		*maskBit = 0;
+printf("maskbyte i=%d\n", *outputPos - 1);
+	}
+
+	**maskByte >>= 1;
+	**maskByte += b << 7;
+	(*maskBit)++;
+}
+
+/* Insert the two bytes describing the pattern repetition to the output. */
+void addPattern(unsigned char *input, int inputPos,
+                unsigned char *output, int outputPos,
+                unsigned char *pattern, int pattern_len)
+{
+	int loc = (pattern - input) + 1024 - 66;
+printf("pattern i=%d o=%d rep=%d loc=%d\n", outputPos, inputPos, pattern_len, inputPos-(pattern-input));
+	output[outputPos] = 
+		(((pattern_len - 3) << 2) & 0xfc) + ((loc & 0x0300) >> 8);
+	output[outputPos + 1] = (loc & 0x00FF);
+}
+
+/* Compress using the LZG algorithm */
+/* Assume output has been allocated and the size is very big */
+void compressLzg(unsigned char* input, int inputSize, 
+                 unsigned char* output, int *outputSize)
+{
+	int inputPos = 0, outputPos = 0;
+	unsigned char *maskByte = NULL;
+	int maskBit = 0;
+	int i;
+
+	/* Create ghost window filled with zeros before input data: */
+	for (i = inputSize - 1; i >= 0; i--)
+		input[i + WIN_SIZE] = input[i];
+	for (i = 0; i < WIN_SIZE; i++)
+		input[i] = 0;
+	input += WIN_SIZE;
+
+	while (inputPos < inputSize)
+	{
+		unsigned char *best_pattern;
+		int best_pattern_len;
+		unsigned char *window;
+
+		/* Determine window position: */
+		window = input + inputPos - (WIN_SIZE - 1);
+
+		search_best_pattern(input + inputPos, inputSize - inputPos,
+		                    window, 
+		                    &best_pattern, &best_pattern_len);
+
+		if (best_pattern_len < MIN_PATTERN_SIZE)
+		{
+			/* No suitable pattern found. Just copy the current byte. */
+			pushMaskBit(1, &maskByte, &maskBit, output, &outputPos);
+			output[outputPos] = input[inputPos];
+printf("copy i=%d o=%d data=%02x\n", outputPos, inputPos, output[outputPos]);
+			inputPos++;
+			outputPos++;
+		}
+		else
+		{
+			/* Can compress. Repeat the best pattern. */
+			pushMaskBit(0, &maskByte, &maskBit, output, &outputPos);
+			addPattern(input, inputPos, output, outputPos,
+			           best_pattern, best_pattern_len);
+			inputPos += best_pattern_len;
+			outputPos += 2;
+		}
+	}
+
+	/* finish last maskByte: */
+	*maskByte >>= (8 - maskBit);
+
+	*outputSize = outputPos;
+}
+
diff --git a/PR/src/lib/compression/lzg_decompress.c b/PR/src/lib/compression/lzg_decompress.c
new file mode 100644
index 0000000..bd84c86
--- /dev/null
+++ b/PR/src/lib/compression/lzg_decompress.c
@@ -0,0 +1,95 @@
+/* 
+ * LZG extraction
+ * 
+ * ---------------------------------------------------------------------------- 
+ * 
+ * Authors: 
+ *   Enrique Calot <ecalot.cod@princed.com.ar>
+ * 
+ * Research: Tammo Jan Dijkemma, Anke Balderer, Enrique Calot
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2004, 2005 the Princed Team
+ * 
+ * This file is part of the Princed project.
+ * 
+ * Princed is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Princed is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include "lzg_uncompress.h"
+
+/* modulus to be used in the 10 bits of the algorithm */
+#define LZG_WINDOW_SIZE    0x400 /* =1024=1<<10 */
+
+/* LZG expansion algorithm sub function */
+unsigned char popBit(unsigned char *byte) {
+	register unsigned char bit=(*byte)&1;
+	(*byte)>>=1;
+	return bit;
+}
+
+/* Expands LZ Groody algorithm. This is the core of PR */
+int expandLzg(const unsigned char* input, int inputSize, 
+               unsigned char* output, int *outputSize) {
+
+	int           loc, oCursor=0, iCursor=0;
+	unsigned char maskbyte=0, rep, k;
+
+	/* initialize the first 1024 bytes of the window with zeros */
+	for(oCursor=0;oCursor<LZG_WINDOW_SIZE;output[oCursor++]=0);
+
+	/* main loop */
+	while (iCursor<inputSize) {
+		maskbyte=input[iCursor++];
+printf("maskbyte i=%d\n", iCursor - 1);
+		for (k=8;k&&(iCursor<inputSize);k--) {
+			if (popBit(&maskbyte)) {
+				output[oCursor++]=input[iCursor++]; /* copy input to output */
+printf("copy i=%d o=%d data=%02x\n", iCursor - 1, oCursor - (LZG_WINDOW_SIZE + 1), output[oCursor-1]);
+			} else {
+				/*
+				 * loc:
+				 *  10 bits for the slide iCursorition (S). Add 66 to this number,
+				 *  substract the result to the current oCursor and take the last 10 bits.
+				 * rep:
+				 *  6 bits for the repetition number (R). Add 3 to this number.
+				 */
+				loc= 66 + ((input[iCursor] & 0x03 /*00000011*/) <<8) + input[iCursor+1];
+				rep= 3  + ((input[iCursor] & 0xfc /*11111100*/) >>2);
+			
+				iCursor+=2; /* move the cursor 2 bytes ahead */
+				
+				loc=(oCursor-loc)&0x3ff; /* this is the real loc number (allways positive!) */
+printf("pattern i=%d o=%d rep=%d loc=%d\n", iCursor - 2, oCursor-LZG_WINDOW_SIZE, rep, loc);
+				
+				while (rep--) { /* repeat pattern in output */
+					output[oCursor]=output[oCursor-loc];
+
+					oCursor++;
+				}
+			}
+		}
+	}
+	
+	/* ignore the first 1024 bytes */
+	for(iCursor=LZG_WINDOW_SIZE;iCursor<oCursor;iCursor++)
+		output[iCursor-LZG_WINDOW_SIZE]=output[iCursor];
+
+	*outputSize=oCursor-LZG_WINDOW_SIZE;
+	return maskbyte;
+}
+
diff --git a/stuff/contest/lzg/Makefile b/stuff/contest/lzg/Makefile
new file mode 100644
index 0000000..287a509
--- /dev/null
+++ b/stuff/contest/lzg/Makefile
@@ -0,0 +1,15 @@
+# Makefile for the lzg compressor/extractor
+
+CC=gcc
+CPPFLAGS=-Wall -ansi -pedantic -g
+
+all: lzg
+
+lzg: lzg.o lzg_compress.o lzg_uncompress.o
+
+lzg.o: lzg.c lzg_compress.h lzg_uncompress.h
+lzg_compress.o: lzg_compress.h
+lzg_uncompress.o: lzg_uncompress.h
+
+clean:
+	rm -fv *.o lzg
diff --git a/stuff/contest/lzg/lzg.c b/stuff/contest/lzg/lzg.c
new file mode 100644
index 0000000..fa3f2f1
--- /dev/null
+++ b/stuff/contest/lzg/lzg.c
@@ -0,0 +1,172 @@
+/* 
+ * LZG compressor/extractor
+ * 
+ * This sample code is to test the LZG algorithm
+ *
+ * Usage:
+ *  ./lzg [-x] (input file) (output file)
+ *
+ * Use -x to uncompress.
+ * 
+ * ---------------------------------------------------------------------------- 
+ * 
+ * Authors: 
+ *   Enrique Calot <ecalot.cod@princed.com.ar>
+ *   Diego Essaya <dessaya@fi.uba.ar>
+ * 
+ * Research: Tammo Jan Dijkemma, Anke Balderer, Enrique Calot
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2004, 2005 the Princed Team
+ * 
+ * This file is part of the Princed project.
+ * 
+ * Princed is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Princed is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "lzg_compress.h"
+#include "lzg_uncompress.h"
+
+typedef enum {COMPRESS, EXPAND, HELP, ERROR} action_t;
+
+struct t_options {
+	char *input_file;
+	char *output_file;
+};
+
+/* A big number (the input/output must be less that that) */
+#define LZG_MAX_MEMSIZE    65536
+
+void print_syntax()
+{
+	fprintf(stderr, "Syntax: lzg [-x] input [output]\n");
+}
+
+action_t process_args(int argc, char *argv[], struct t_options *opts)
+{
+	action_t action = COMPRESS;
+	int i;
+
+	opts->input_file = opts->output_file = NULL;
+
+	for(i = 1; i < argc; i++) {
+		if (!strcmp(argv[i], "-x")) {
+			action = EXPAND;
+		}
+		else { /* filename */
+			if (!opts->input_file || !strcmp(opts->input_file, "-"))
+				opts->input_file = argv[i];
+			else if (!opts->output_file || !strcmp(opts->output_file, "-"))
+				opts->output_file = argv[i];
+			else 
+			{
+				fprintf(stderr, "Invalid argument: %s\n", argv[i]);
+				return ERROR;
+			}
+		}
+	}
+
+	return action;
+}
+
+int main(int argc, char *argv[])
+{
+	action_t         action;
+	struct t_options opts;
+	unsigned char    input[LZG_MAX_MEMSIZE];
+	unsigned char    output[LZG_MAX_MEMSIZE];
+	int              inputSize, outputSize;
+	FILE*            fp;
+	int              result;
+
+	action = process_args(argc, argv, &opts);
+	if (action == ERROR)
+	{
+		print_syntax();
+		return 1;
+	}
+	if (action == HELP)
+	{
+		print_syntax();
+		return 0;
+	}
+	
+	if (!opts.input_file)
+	{
+		fprintf(stderr, "warning: Reading from stdin.\n");
+		fp = stdin;
+	}
+	else
+	{
+		fp = fopen(opts.input_file, "rb");
+		if (!fp) {
+			fprintf(stderr, "Error opening file '%s' for reading.\n", opts.input_file);
+			return 1;
+		}
+	}
+
+	inputSize = fread(input, 1, sizeof(input), fp);
+	if (inputSize <= 0)
+	{
+		fprintf(stderr, "Error reading input file.\n");
+		return 1;
+	}
+
+	fclose(fp);
+
+	if (!opts.output_file)
+	{
+		fprintf(stderr, "warning: Writing to stdout.\n");
+		fp = stdout;
+	}
+	else
+	{
+		fp = fopen(opts.output_file, "wb");
+		if (!fp) {
+			fprintf(stderr, "Error opening file '%s' for writing.\n", opts.output_file);
+			return 1;
+		}
+	}
+
+	if (action == EXPAND)
+	{
+		result=expandLzg(input, inputSize, output, &outputSize);
+		if (result)
+			fprintf(stderr,"Maskbyte not clean, possible data corruption\n");
+	}
+	else
+	{
+		compressLzg(input, inputSize, output, &outputSize);
+	}
+	
+	if (fwrite(output, outputSize, 1, fp) <= 0)
+	{
+		fprintf(stderr, "Error writing output.\n");
+		return 1;
+	}
+
+	fclose(fp);
+
+	/* show results on screen */
+	printf("Results:\n Input file: %s (%d)\n Output file: %s (%d)\n",
+	       opts.input_file ? opts.input_file : "stdin", inputSize,
+	       opts.output_file ? opts.output_file : "stdout", outputSize);
+
+	return 0;
+}
+
diff --git a/stuff/contest/lzg/lzg_compress.c b/stuff/contest/lzg/lzg_compress.c
new file mode 100644
index 0000000..b0a076a
--- /dev/null
+++ b/stuff/contest/lzg/lzg_compress.c
@@ -0,0 +1,204 @@
+/* 
+ * LZG compression
+ * 
+ * ---------------------------------------------------------------------------- 
+ * 
+ * Authors: 
+ *   Enrique Calot <ecalot.cod@princed.com.ar>
+ *   Diego Essaya <dessaya@fi.uba.ar>
+ * 
+ * Research: Tammo Jan Dijkemma, Anke Balderer, Enrique Calot
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2004, 2005 the Princed Team
+ * 
+ * This file is part of the Princed project.
+ * 
+ * Princed is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Princed is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modus operandi of the compression algorithm
+ * -------------------------------------------
+ * 
+ * For each input byte we take a window containing the 1023 previous bytes.
+ * If the window goes out of bounds (ie, when the current input byte is
+ * before position 1024), we consider it filled with zeros.
+ *
+ *     00000000000000000000********************************
+ *                         ^                  ^
+ *                    input start   current input byte
+ *           |--------------------------------|
+ *                    window size=1023
+ * 
+ * The algorithm works as follows:
+ *
+ * While there is unread input data:
+ *     Create a maskbyte.
+ *     For each bit in the maskbyte (and there is still unread input data):
+ *         Compare the following input bytes with the bytes in the window,
+ *         and search the longest pattern that is equal to the next bytes.
+ *         If we found a pattern of length n > 2:
+ *             Assign 0 to the current bit of the maskbyte.
+ *             In the next 2 bytes of the output, specify the relative
+ *             position and length of the pattern.
+ *             Advance output pointer by 2.
+ *             Advance input pointer by n.
+ * 	       Else:
+ *             Assign 1 to the current bit of the maskbyte.
+ * 	           Copy the current input byte in the next output byte.
+ *             Advance output pointer by 1.
+ *             Advance input pointer by 1.
+ */
+
+#include <string.h>  /* memchr() */
+#include <stdio.h>
+#include "lzg_compress.h"
+
+/* Window size */
+#define WIN_SIZE 1024
+
+/* A repetition pattern must have a length of at least MIN_PATTERN_SIZE 
+ * to be accepted (ie, to be worth for compressing) */
+#define MIN_PATTERN_SIZE 3
+#define MAX_PATTERN_SIZE 66
+
+/* search the longest pattern in the window that matches the first bytes
+ * of the input */
+void search_best_pattern(unsigned char *input, int inputSize, 
+                         unsigned char *window,
+                         unsigned char **best_pattern, 
+                         int *best_pattern_len)
+{
+	unsigned char *pattern;
+	int pattern_len;
+	int window_len = WIN_SIZE - 1;
+
+	*best_pattern_len = 0;
+
+	while ((pattern = (unsigned char *)memchr(window, *input, window_len)))
+	{
+		unsigned char *ic = input + 1;
+		unsigned char *wc = pattern + 1;
+		pattern_len = 1;
+
+		while ( (ic < (input + inputSize)) && 
+		        (wc < (window + window_len)) &&
+		        (*ic == *wc) &&
+				pattern_len < MAX_PATTERN_SIZE)
+		{
+			ic++; wc++; pattern_len++;
+		}
+
+		if (pattern_len > *best_pattern_len)
+		{
+			*best_pattern_len = pattern_len;
+			*best_pattern = pattern;
+		}
+
+		window_len -= wc - window;
+		window = wc;
+	}
+}
+
+/* Insert the specified bit in the current maskByte. If the maskByte is full,
+ * start a new one. */
+void pushMaskBit(int b, unsigned char **maskByte, int *maskBit,
+                 unsigned char *output, int *outputPos)
+{
+	if ( (!(*maskByte)) || (*maskBit == 8) )
+	{
+		/* start a new maskByte */
+		*maskByte = output + *outputPos;
+		(*outputPos)++;
+		**maskByte = 0;
+		*maskBit = 0;
+printf("maskbyte i=%d\n", *outputPos - 1);
+	}
+
+	**maskByte >>= 1;
+	**maskByte += b << 7;
+	(*maskBit)++;
+}
+
+/* Insert the two bytes describing the pattern repetition to the output. */
+void addPattern(unsigned char *input, int inputPos,
+                unsigned char *output, int outputPos,
+                unsigned char *pattern, int pattern_len)
+{
+	int loc = (pattern - input) + 1024 - 66;
+printf("pattern i=%d o=%d rep=%d loc=%d\n", outputPos, inputPos, pattern_len, inputPos-(pattern-input));
+	output[outputPos] = 
+		(((pattern_len - 3) << 2) & 0xfc) + ((loc & 0x0300) >> 8);
+	output[outputPos + 1] = (loc & 0x00FF);
+}
+
+/* Compress using the LZG algorithm */
+/* Assume output has been allocated and the size is very big */
+void compressLzg(unsigned char* input, int inputSize, 
+                 unsigned char* output, int *outputSize)
+{
+	int inputPos = 0, outputPos = 0;
+	unsigned char *maskByte = NULL;
+	int maskBit = 0;
+	int i;
+
+	/* Create ghost window filled with zeros before input data: */
+	for (i = inputSize - 1; i >= 0; i--)
+		input[i + WIN_SIZE] = input[i];
+	for (i = 0; i < WIN_SIZE; i++)
+		input[i] = 0;
+	input += WIN_SIZE;
+
+	while (inputPos < inputSize)
+	{
+		unsigned char *best_pattern;
+		int best_pattern_len;
+		unsigned char *window;
+
+		/* Determine window position: */
+		window = input + inputPos - (WIN_SIZE - 1);
+
+		search_best_pattern(input + inputPos, inputSize - inputPos,
+		                    window, 
+		                    &best_pattern, &best_pattern_len);
+
+		if (best_pattern_len < MIN_PATTERN_SIZE)
+		{
+			/* No suitable pattern found. Just copy the current byte. */
+			pushMaskBit(1, &maskByte, &maskBit, output, &outputPos);
+			output[outputPos] = input[inputPos];
+printf("copy i=%d o=%d data=%02x\n", outputPos, inputPos, output[outputPos]);
+			inputPos++;
+			outputPos++;
+		}
+		else
+		{
+			/* Can compress. Repeat the best pattern. */
+			pushMaskBit(0, &maskByte, &maskBit, output, &outputPos);
+			addPattern(input, inputPos, output, outputPos,
+			           best_pattern, best_pattern_len);
+			inputPos += best_pattern_len;
+			outputPos += 2;
+		}
+	}
+
+	/* finish last maskByte: */
+	*maskByte >>= (8 - maskBit);
+
+	*outputSize = outputPos;
+}
+
diff --git a/stuff/contest/lzg/lzg_compress.h b/stuff/contest/lzg/lzg_compress.h
new file mode 100644
index 0000000..252145d
--- /dev/null
+++ b/stuff/contest/lzg/lzg_compress.h
@@ -0,0 +1,7 @@
+#ifndef _LZG_COMPRESS_H_
+#define _LZG_COMPRESS_H_
+
+void compressLzg(unsigned char* input, int inputSize, 
+                 unsigned char* output, int *outputSize);
+
+#endif
diff --git a/stuff/contest/lzg/lzg_uncompress.c b/stuff/contest/lzg/lzg_uncompress.c
new file mode 100644
index 0000000..bd84c86
--- /dev/null
+++ b/stuff/contest/lzg/lzg_uncompress.c
@@ -0,0 +1,95 @@
+/* 
+ * LZG extraction
+ * 
+ * ---------------------------------------------------------------------------- 
+ * 
+ * Authors: 
+ *   Enrique Calot <ecalot.cod@princed.com.ar>
+ * 
+ * Research: Tammo Jan Dijkemma, Anke Balderer, Enrique Calot
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2004, 2005 the Princed Team
+ * 
+ * This file is part of the Princed project.
+ * 
+ * Princed is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Princed is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include "lzg_uncompress.h"
+
+/* modulus to be used in the 10 bits of the algorithm */
+#define LZG_WINDOW_SIZE    0x400 /* =1024=1<<10 */
+
+/* LZG expansion algorithm sub function */
+unsigned char popBit(unsigned char *byte) {
+	register unsigned char bit=(*byte)&1;
+	(*byte)>>=1;
+	return bit;
+}
+
+/* Expands LZ Groody algorithm. This is the core of PR */
+int expandLzg(const unsigned char* input, int inputSize, 
+               unsigned char* output, int *outputSize) {
+
+	int           loc, oCursor=0, iCursor=0;
+	unsigned char maskbyte=0, rep, k;
+
+	/* initialize the first 1024 bytes of the window with zeros */
+	for(oCursor=0;oCursor<LZG_WINDOW_SIZE;output[oCursor++]=0);
+
+	/* main loop */
+	while (iCursor<inputSize) {
+		maskbyte=input[iCursor++];
+printf("maskbyte i=%d\n", iCursor - 1);
+		for (k=8;k&&(iCursor<inputSize);k--) {
+			if (popBit(&maskbyte)) {
+				output[oCursor++]=input[iCursor++]; /* copy input to output */
+printf("copy i=%d o=%d data=%02x\n", iCursor - 1, oCursor - (LZG_WINDOW_SIZE + 1), output[oCursor-1]);
+			} else {
+				/*
+				 * loc:
+				 *  10 bits for the slide iCursorition (S). Add 66 to this number,
+				 *  substract the result to the current oCursor and take the last 10 bits.
+				 * rep:
+				 *  6 bits for the repetition number (R). Add 3 to this number.
+				 */
+				loc= 66 + ((input[iCursor] & 0x03 /*00000011*/) <<8) + input[iCursor+1];
+				rep= 3  + ((input[iCursor] & 0xfc /*11111100*/) >>2);
+			
+				iCursor+=2; /* move the cursor 2 bytes ahead */
+				
+				loc=(oCursor-loc)&0x3ff; /* this is the real loc number (allways positive!) */
+printf("pattern i=%d o=%d rep=%d loc=%d\n", iCursor - 2, oCursor-LZG_WINDOW_SIZE, rep, loc);
+				
+				while (rep--) { /* repeat pattern in output */
+					output[oCursor]=output[oCursor-loc];
+
+					oCursor++;
+				}
+			}
+		}
+	}
+	
+	/* ignore the first 1024 bytes */
+	for(iCursor=LZG_WINDOW_SIZE;iCursor<oCursor;iCursor++)
+		output[iCursor-LZG_WINDOW_SIZE]=output[iCursor];
+
+	*outputSize=oCursor-LZG_WINDOW_SIZE;
+	return maskbyte;
+}
+
diff --git a/stuff/contest/lzg/lzg_uncompress.h b/stuff/contest/lzg/lzg_uncompress.h
new file mode 100644
index 0000000..242894f
--- /dev/null
+++ b/stuff/contest/lzg/lzg_uncompress.h
@@ -0,0 +1,7 @@
+#ifndef _LZG_UNCOMPRESS_H_
+#define _LZG_UNCOMPRESS_H_
+
+int expandLzg(const unsigned char* input, int inputSize, 
+              unsigned char* output, int *outputSize);
+
+#endif
diff --git a/stuff/contest/lzg/test b/stuff/contest/lzg/test
index 17dcccb..8493c62 100755
--- a/stuff/contest/lzg/test
+++ b/stuff/contest/lzg/test
@@ -1 +1,15 @@
-ls cmp|sed -e 's/\([0-9]*\).cmp/\1/'|while read i; do ./uncompress cmp/$i.cmp roo/$i.roo>/dev/null; diff raw/$i.raw roo/$i.roo;done
+#!/bin/bash
+
+# test compress & uncompress functions
+
+[ -d samples ] || { echo "samples dir not found!"; exit 1; }
+
+if [ "x$1" = "xuncompress" ]; then
+	[ -d raw ] || mkdir raw
+
+	ls samples/*cmp | sed -e 's/[^0-9]*\([0-9]*\).cmp/\1/' | while read i; do ./lzg -x samples/$i.cmp raw/$i.raw >/dev/null; diff samples/$i.raw raw/$i.raw;done
+else
+	[ -d cmp ] || mkdir cmp
+
+	ls samples/*raw | sed -e 's/[^0-9]*\([0-9]*\).raw/\1/' | while read i; do ./lzg samples/$i.raw cmp/$i.cmp >/dev/null; ./lzg -x cmp/$i.cmp cmp/$i.raw >/dev/null; diff samples/$i.raw cmp/$i.raw;done
+fi
diff --git a/stuff/contest/lzg/uncompress.c b/stuff/contest/lzg/uncompress.c
deleted file mode 100644
index 828925d..0000000
--- a/stuff/contest/lzg/uncompress.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * This sample code is to test the LZG algorithm
- *
- * Compile with:
- *  gcc -o uncompress uncompress.c
- *
- * Usage:
- *  ./uncompress (input file) (output file)
- *
- * note that input file must be a valid LZG compressed file with
- * permission to be read and output file should be a nonexistent file
- * or it will be overwritten.
- *
- * This document is GPL
- * Source Author: Enrique Calot
- * Research: Tammo Jan Dijkemma, Anke Balderer, Enrique Calot
- */
-
-#include <stdio.h>
-
-/* BEGIN of page pasted part */
-
-/* A big number (the output must be less that that) */
-#define LZG_MAX_MEMSIZE    32001
-
-/* modulus to be used in the 10 bits of the algorithm */
-#define LZG_WINDOW_SIZE    0x400 /* =1024=1<<10 */
-
-/* LZG expansion algorithm sub function */
-unsigned char popBit(unsigned char *byte) {
-	register unsigned char bit=(*byte)&1;
-	(*byte)>>=1;
-	return bit;
-}
-
-/* Expands LZ Groody algorithm. This is the core of PR */
-int expandLzg(const unsigned char* input, int inputSize, 
-               unsigned char* output, int *outputSize) {
-
-	int           loc, oCursor=0, iCursor=0;
-	unsigned char maskbyte=0, rep, k;
-
-	/* initialize the first 1024 bytes of the window with zeros */
-	for(oCursor=0;oCursor<LZG_WINDOW_SIZE;output[oCursor++]=0);
-
-	/* main loop */
-	while (iCursor<inputSize) {
-		maskbyte=input[iCursor++];
-		for (k=8;k&&(iCursor<inputSize);k--) {
-			if (popBit(&maskbyte)) {
-				output[oCursor++]=input[iCursor++]; /* copy input to output */
-printf("print %02x@%d from input(%d)\n",output[oCursor-1],oCursor-1025,iCursor-1);
-			} else {
-				/*
-				 * loc:
-				 *  10 bits for the slide iCursorition (S). Add 66 to this number,
-				 *  substract the result to the current oCursor and take the last 10 bits.
-				 * rep:
-				 *  6 bits for the repetition number (R). Add 3 to this number.
-				 */
-				loc= 66 + ((input[iCursor] & 0x03 /*00000011*/) <<8) + input[iCursor+1];
-				rep= 3  + ((input[iCursor] & 0xfc /*11111100*/) >>2);
-			
-				iCursor+=2; /* move the cursor 2 bytes ahead */
-				
-				loc=(oCursor-loc)&0x3ff; /* this is the real loc number (allways positive!) */
-				
-				while (rep--) { /* repeat pattern in output */
-					output[oCursor]=output[oCursor-loc];
-
-					printf("print %02x@%d copied from %d (loc=%d)\n",output[oCursor],oCursor-LZG_WINDOW_SIZE,oCursor-loc-LZG_WINDOW_SIZE,loc);
-
-					oCursor++;
-				}
-			}
-		}
-	}
-	
-	/* ignore the first 1024 bytes */
-	for(iCursor=LZG_WINDOW_SIZE;iCursor<oCursor;iCursor++)
-		output[iCursor-LZG_WINDOW_SIZE]=output[iCursor];
-
-	*outputSize=oCursor-LZG_WINDOW_SIZE;
-	return maskbyte;
-}
-
-/* END of page pasted part */
-
-int main(int argc, char** argv) {
-	/* declare variables */
-	unsigned char uncompressed[LZG_MAX_MEMSIZE];
-	unsigned char compressed[LZG_MAX_MEMSIZE];
-	int           uncompressedSize, compressedSize;
-	FILE*         fp;
-	int           result;
-				
-	/* validate input */
-	if (argc!=3) {
-		fprintf(stderr,"Syntax: %s [cmp file] [target raw file]\n",*argv);
-		return 1;
-	}
-
-	/* open file */
-	fp=fopen(argv[1],"rb");
-	if (!fp) {
-		fprintf(stderr,"Error opening '%s'. Does it exist?\n",argv[1]);
-		return 2;
-	}
-
-	/* read file to array */
-	uncompressedSize=fread(uncompressed,1,sizeof(uncompressed),fp);
-	
-	/* close file */
-	fclose(fp);
-
-	/* compress file */
-	result=expandLzg(uncompressed,uncompressedSize,compressed,&compressedSize);
-
-	if (result) fprintf(stderr,"Maskbyte not clean, possible data corruption\n");
-	
-	/* save results */
-	fp=fopen(argv[2],"wb");	
-	if (!fp) {
-		fprintf(stderr,"Error opening '%s' for writting. Do you have permissions?\n",argv[2]);
-		return 4;
-	}
-	fwrite(compressed,compressedSize,1,fp);
-	fclose(fp);
-
-	/* show results on screen */
-	printf ("Results:\n Input file: %s (%d)\n Output file: %s (%d)\n",
-		argv[1],uncompressedSize,argv[2],compressedSize);
-
-	/* end */
-	return 0;
-}
-