// THIS CODE IS COPYRIGHT ACCESS SOFTWARE INC.  ALL RIGHTS RESERVED
// THE ORIGINAL CODE IS BY PAUL JOHNSTON, MODIFIED BY MATT DAWSON 8/4/97

#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#include <windef.h>
#include <winbase.h>
#include "lz.h"


ComDecEngine::ComDecEngine()
{
	input_code_size=8;
	bEncrypt = 0;

}
void ComDecEngine::ReInitLZW (void)
/* (Re)initialize LZW state; shared code for startup and Clear processing */
{
  code_size = input_code_size+1;
  limit_code = clear_code << 1; /* 2^code_size */
  max_code = clear_code + 2;    /* first unused code value */
  sp = symbol_stack;            /* init stack to empty */
}

void ComDecEngine::InitLZWCode (void)
/* Initialize for a series of LZWReadByte (and hence GetCode) calls */
{
  /* GetCode initialization */
  last_byte = 2;                /* make safe to "recopy last two bytes" */
  last_bit = 0;                 /* nothing in the buffer */
  cur_bit = 0;                  /* force buffer load on first call */
  out_of_blocks = FALSE;

  /* LZWReadByte initialization */
  clear_code = 1 << input_code_size; /* compute special code values */
  end_code = clear_code + 1;    /* note that these do not change */
  first_time = TRUE;
  ReInitLZW();
}


int ComDecEngine::GetDataBlock(void) 
{
	int i,count;

	count=min(SrcLeft,READ_MAX);
	//if (InputType) 
	//{
	//	Buffer=SrcPtr-2;
	//	SrcPtr+=count;
	//} 
	//else
		count=_lread(hInFile,Buffer+2,count);

	SrcLeft-=count;
	if (bEncrypt) 
	{
		//do unencryption
		for (i=0; i<count; i++)
			Buffer[i+2]^=5;
	}
	return count;
}

int ComDecEngine::GetCode (void)
/* Fetch the next code_size bits from the GIF data */
/* We assume code_size is less than 16 */
{
  register int accum;
  int offs, ret, count;

  if ( (cur_bit+code_size) > last_bit) 
	{
		/* Time to reload the buffer */
		/* preserve last two bytes of what we have -- assume code_size <= 16 */
		if (!InputType) 
		{
			Buffer[0] = Buffer[last_byte-2];
			Buffer[1] = Buffer[last_byte-1];
		}
		/* Load more bytes; set flag if we reach the terminator block */
		count = GetDataBlock();
		/* Reset counters */
		cur_bit = (cur_bit - last_bit) + 16;
		last_byte = 2 + count;
		last_bit = last_byte * 8;
  }

  /* Form up next 24 bits in accum */
  offs = cur_bit >> 3;          /* byte containing cur_bit */
  accum = Buffer[offs+2] & 0xFF;
  accum <<= 8;
  accum |= Buffer[offs+1] & 0xFF;
  accum <<= 8;
  accum |= Buffer[offs] & 0xFF;



  /* Right-align cur_bit in accum, then mask off desired number of bits */
  accum >>= (cur_bit & 7);
  ret = ((int) accum) & ((1 << code_size) - 1);

  cur_bit += code_size;
  return ret;
}


int ComDecEngine::LZWReadByte (void)
/* Read an LZW-compressed byte */
{
  int code;            /* current working code */
  int incode;                   /* saves actual input code */

  /* First time, just eat the expected Clear code(s) and return next code, */
  /* which is assumed to be a raw byte. */
  if (first_time) {
	 first_time = FALSE;
	 do {
		code = GetCode();
	 } while (code == clear_code);
	 firstcode = oldcode = code; /* make firstcode, oldcode valid! */
	 return code;
  }

  /* If any codes are stacked from a previously read symbol, return them */
  if (sp > symbol_stack)
	 return (int) *(--sp);

  code = GetCode();

  if (code == clear_code) {
	 /* Reinit static state, swallow any extra Clear codes, and return */
	 ReInitLZW();
	 do {
		code = GetCode();
	 } while (code == clear_code);
	 firstcode = oldcode = code; /* gotta reinit these too */
	 return code;
  }

  if (code == end_code)
	 return -1;

  /* Normal raw byte or LZW symbol */
  incode = code;                /* save for a moment */

  if (code >= max_code) {       /* special case for not-yet-defined symbol */
	 *sp++ = (UINT8) firstcode;  /* it will be defined as oldcode/firstcode */
	 code = oldcode;
  }

  /* If it's a symbol, expand it into the stack */
  while (code >= clear_code) {
	 *sp++ = symbol_tail[code];  /* tail of symbol: a simple byte value */
	 code = symbol_head[code];   /* head of symbol: another LZW symbol */
  }
  /* At this point code just represents a raw byte */
  firstcode = code;             /* save for possible future use */

  /* If there's room in table, */
  if ((code = max_code) < LZW_TABLE_SIZE) {
	 /* Define a new symbol = prev sym + head of this sym's expansion */
	 symbol_head[code] = oldcode;
	 symbol_tail[code] = (UINT8) firstcode;
	 max_code++;
	 /* Is it time to increase code_size? */
	 if ((max_code >= limit_code) && (code_size < MAX_LZW_BITS)) {
		code_size++;
		limit_code <<= 1;         /* keep equal to 2^code_size */
	 }
  }

  oldcode = incode;             /* save last input symbol for future use */
  return firstcode;             /* return first byte of symbol's expansion */
}



int ComDecEngine::DecompressLZW(HFILE hSrcFile,DWORD dwCompressedSize,BYTE* OutputBuffer) 
{
	int nextbyte;

	hInFile = hSrcFile; //input_file=SrcHandle;
	SrcLeft = dwCompressedSize;//(int)GetFileSize((void *)hInFile,NULL);
	InputType=0;//SrcType;

	DestPtr=OutputBuffer;
	
	symbol_head=(UINT16 *)hash_prefix;
	symbol_tail=(UINT8 *)hash_suffix;

	InitLZWCode();
	do {
		nextbyte=LZWReadByte();
		if (nextbyte>=0)
			*DestPtr++=nextbyte;
	} while (nextbyte!=-1);

	return DestPtr-OutputBuffer;
}


/******************************/
/* this is the LZW write code */
/******************************/







 



void ComDecEngine::flush_packet (void)
/* flush any accumulated data */
{
  if (bytesinpkt > 0) {         /* never write zero-length packet */
	 //packetbuf[0] = (char) bytesinpkt++;
	 if (_lwrite(hOutFile,packetbuf, bytesinpkt)
	!= (size_t) bytesinpkt) {
		printf("Output file write error");
		exit(1);
	}
	 bytesinpkt = 0;
  }
}


/* Add a character to current packet; flush to disk if necessary */
#define CHAR_OUT(c)  \
	{ packetbuf[bytesinpkt++] = (char) (c);  \
		 if (bytesinpkt >= 255)  \
			flush_packet();  \
	}

#define ENCR_CHAR_OUT(c)  \
	{ packetbuf[bytesinpkt++] = (char) ((c)^5);  \
		 if (bytesinpkt >= 255)  \
			flush_packet();  \
	}


/* Routine to convert variable-width codes into a byte stream */



void ComDecEngine::output (short code)
/* Emit a code of n_bits bits */
/* Uses cur_accum and cur_bits to reblock into 8-bit bytes */
{
  cur_accum |= ((int) code) << cur_bits;
  cur_bits += n_bits;

  if (bEncrypt)
	{
		while (cur_bits >= 8) {
		 ENCR_CHAR_OUT(cur_accum & 0xFF);
		 cur_accum >>= 8;
		 cur_bits -= 8;
		}
	}
	else
	{
		while (cur_bits >= 8) {
		 CHAR_OUT(cur_accum & 0xFF);
		 cur_accum >>= 8;
		 cur_bits -= 8;
		}
	}

  /*
	* If the next entry is going to be too big for the code size,
	* then increase it, if possible.  We do this here to ensure
	* that it's done in sync with the decoder's codesize increases.
	*/
  if (free_code > maxcode) {
	 n_bits++;
	 if (n_bits == MAX_LZW_BITS)
		maxcode = LZW_TABLE_SIZE; /* free_code will never exceed this */
	 else
		maxcode = MAXCODE(n_bits);
  }
}


/* The LZW algorithm proper */



void ComDecEngine::clear_hash (void)
/* Fill the hash table with empty entries */
{
  /* It's sufficient to zero hash_code[] */
  memset((void *) hash_code, 0, HSIZE * sizeof(short));
}


void ComDecEngine::clear_block (void)
/* Reset compressor and issue a Clear code */
{
  clear_hash();                 /* delete all the symbols */
  free_code = ClearCode + 2;
  output(ClearCode);            /* inform decoder */
  n_bits = init_bits;           /* reset code size */
  maxcode = MAXCODE(n_bits);
}


void ComDecEngine::compress_init (short i_bits)
/* Initialize LZW compressor */
{
  /* init all the static variables */
  n_bits = init_bits = i_bits;
  maxcode = MAXCODE(n_bits);
  ClearCode = ((int) 1 << (init_bits - 1));
  EOFCode = ClearCode + 1;
  free_code = ClearCode + 2;
  first_byte = 1;            /* no waiting symbol yet */
  /* init output buffering vars */
  bytesinpkt = 0;
  cur_accum = 0;
  cur_bits = 0;
  /* clear hash table */
  clear_hash();
  /* GIF specifies an initial Clear code */
  output(ClearCode);
}


void ComDecEngine::compress_byte (short c)
/* Accept and compress one 8-bit byte */
{
  register short i;
  register short disp;

  if (first_byte) {             /* need to initialize waiting_code */
	 waiting_code = c;
	 first_byte = 0;
	 return;
  }

  /* Probe hash table to see if a symbol exists for
	* waiting_code followed by c.
	* If so, replace waiting_code by that symbol and return.
	*/
  i = ((short) c << (MAX_LZW_BITS-8)) + waiting_code;
  /* i is less than twice 2**MAX_LZW_BITS, therefore less than twice HSIZE */
  if (i >= LZW_TABLE_SIZE)
	 i -= LZW_TABLE_SIZE;
  
  if (hash_code[i] != 0) 
	{      /* is first probed slot empty? */
		if (hash_prefix[i] == waiting_code && hash_suffix[i] == (UINT8) c) 
		{
			waiting_code = hash_code[i];
			return;
		}
		if (i == 0)                 /* secondary hash (after G. Knott) */
			disp = 1;
		else
			disp = HSIZE - i;
		while (1) 
		{
			i -= disp;
			if (i < 0)
				i += HSIZE;
			if (hash_code[i] == 0)
				break;                  /* hit empty slot */
			if (hash_prefix[i] == waiting_code && hash_suffix[i] == (UINT8) c) 
			{
				waiting_code = hash_code[i];
				return;
			}
		}
  }

  /* here when hashtable[i] is an empty slot; desired symbol not in table */
  output(waiting_code);
  if (free_code < LZW_TABLE_SIZE) {
	 hash_code[i] = free_code++; /* add symbol to hashtable */
	 hash_prefix[i] = waiting_code;
	 hash_suffix[i] = (UINT8) c;
  } else
	 clear_block();
  waiting_code = c;
}


void ComDecEngine::compress_term (void)
/* Clean up at end */
{
  /* Flush out the buffered code */
  if (! first_byte)
	 output(waiting_code);
  /* Send an EOF code */
  output(EOFCode);
  /* Flush the bit-packing buffer */
  if (bEncrypt)
	{
		if (cur_bits > 0) {
		 ENCR_CHAR_OUT(cur_accum & 0xFF);
		}
	}
	else
	{
		if (cur_bits > 0) {
		 CHAR_OUT(cur_accum & 0xFF);
		}
	}
  /* Flush the packet buffer */
  flush_packet();
}

#define MAX_DATA 4096
BOOL ComDecEngine::CompressFile(BYTE *pData,DWORD dwSize, HFILE hOut)
{
	DWORD dwPos = 0;
	hOutFile = hOut;
	
	compress_init(9);

	while (dwPos < dwSize)
	{
		compress_byte(pData[dwPos]);
		dwPos++;
	}

	compress_term();

	return TRUE;
}

