/*************************************************************
 *                                                           *
 *    ths  Filesystem                  04.08.94      V0.1    *
 *                                                           *
 *    Thomas Scheuermann     ths@ai-lab.fh-furtwangen.de     *
 *                                                           *
 *************************************************************/

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/mm.h>
#include <linux/locks.h>
#include <linux/fs.h>
#include <linux/malloc.h>

#include <asm/system.h>
#include <asm/segment.h>
#include <asm/bitops.h>

#include "ths.h"
#include "ths_i.h"

/*
 * Dekompressionsalgorithmus
 * funktioniert nur mit Komprimierung 2
 */

void decompress(struct super_block *s, struct ths_buffer *tbf, int mdfat)
{
	unsigned char zc,zu,flag,*data=NULL;
	unsigned long sektor;
	struct buffer_head *bh;
	int i,k,rb,rl,hz,m,sek,sekmax;

#ifdef DEBUG
	printk("decompress %d\n",mdfat);
#endif

	sektor = (mdfat & 0x1fffff) +1;
	sekmax = ((mdfat & 0x3c000000)>>26) +1;

/*
 * i	: Bitzaehler
 * k	: Zeichenzaehler dekomprimiert
 * hz	: Hilfszaehler fuer Bits;
 * rb	: Rueckwaertsbezug rb Bytes
 * rl	: Laenge des Rueckwaertsbezugs
 * m	: Laengenhilfsspeicher
 * flag	: Status
 * zc	: komprimiertes Zeichen
 * zu	: unkomprimiertes Zeichen
 * sek	: Sektorzaehler
 */
	k=0;
	zu=0;
	zc=0;
	rb=0;
	rl=0;
	hz=0;
	m=0;
	sek = 0;
	flag = 'n';

	for(i=0;sek<sekmax;)
	{
		if(!(i%8))
		{
			if(!(i%4096))
			{
				data = ths_uread(s,sektor+i/4096,&bh);
			}
			if(!i)
			{
				if(data[0]!=0x44 && data[1]!=0x53 && data[2]!=0x00 && data[3]!=0x02)
				{
					printk("Komprimierung nicht erkannt!!\n");
					return;
				}
				i=32;
			}
			zc = data[(i/8)%512];
		}
		switch(flag)
		{
			case 'n':		/* neu */
				if(zc&1)
					flag = 'I';
				else
					flag = 'O';
				zc >>= 1;
				break;
			case 'I':		/* erstes Bit 1 */
				if(zc&1)
					flag = 'r';
				else
				{
					flag = 'L';
					hz = 7;
				}
				zc >>= 1;
				break;
			case 'O':		/* erstes Bit 0 */
				if(zc&1)
				{
					flag = 'l';
					hz=7;
				}
				else
				{
					flag = 'A';
					hz = 6;
					rb = 0;
				}
				zc >>= 1;
				break;
			case 'l':		/* Zeichen 0 - 127 */
				if(zc&1)
					zu |=0x80;
				zu >>= 1;
				zc >>= 1;
				if(!(--hz))
				{
					flag ='n';
					(tbf->data[k/512])[k%512] = zu;
					k++;
					zu=0;
				}
				break;
			case 'L':		/* Zeichen 128 - 255 */
				if(zc&1)
					zu |=0x80;
				zu >>= 1;
				zc >>= 1;
				if(!(--hz))
				{
					zu |=0x80;
					flag ='n';
					(tbf->data[k/512])[k%512] = zu;
					k++;
					zu=0;
				}
				break;
			case 'r':		/* Rueck ? */
				if(zc&1)
				{
					flag = 'C';
					hz = 12;
					rb = 0;
				}
				else
				{
					flag = 'B';
					hz = 8;
					rb = 0;
				}
				zc >>= 1;
				break;
			case 'A':		/* 6 Bit rueckwarts */
				if(zc&1)
					rb |=0x40;
				rb >>= 1;
				zc >>= 1;
				if(!(--hz))
				{
					flag ='X';
				}
				break;
			case 'B':		/* 8 Bit rueckwarts */
				if(zc&1)
					rb |=0x100;
				rb >>= 1;
				zc >>= 1;
				if(!(--hz))
				{
					flag ='X';
					rb += 64;
				}
				break;
			case 'C':		/* 12 Bit rueckwarts */
				if(zc&1)
					rb |=0x1000;
				rb >>= 1;
				zc >>= 1;
				if(!(--hz))
				{
					if(rb==0xfff)
					{
						sek++;
						flag = 'n';
						break;
					}
					flag ='X';
					rb +=320;
				}
				break;
			case 'X':		/* Trefferlaenge, 0 zaehlen */
				if(zc&1)
				{
					flag = 'Y';
					rl =0;
					m = 1;
					m <<=hz;
					if(m==1)
					{
						flag = 'n';
						(tbf->data[k/512])[k%512] = (tbf->data[(k-rb)/512])[(k-rb)%512];
						k++;
						(tbf->data[k/512])[k%512] = (tbf->data[(k-rb)/512])[(k-rb)%512];
						k++;
					}
				}
				else
				{
					hz++;
				}
				zc >>= 1;
				break;
			case 'Y':		/* Trefferlaenge berechnen */
				if(!(--hz))
				{
					if(zc&1)
						rl |= m;
					rl >>= 1;
					rl = rl + m + 1;
					for(hz=0;hz<rl;hz++)
					{
						(tbf->data[k/512])[k%512] = (tbf->data[(k-rb)/512])[(k-rb)%512];
						k++;
					}
					flag = 'n';
				}
				else
				{
					if(zc&1)
						rl |= m;
					rl >>= 1;
				}
				zc >>= 1;
				break;
		}
		i++;
		if(!(i%4096))
		{
			brelse(bh);
		}
	}
	if((i%4096))
	{
		brelse(bh);
	}
	return;
}




