home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Hacker Chronicles 2
/
HACKER2.BIN
/
1215.LZH.C
< prev
next >
Wrap
Text File
|
1991-02-24
|
35KB
|
973 lines
/*--------------------------------------------------------------------------*/
/* lzh.c - file compression subroutines for lzss + Huffman encoding */
/* */
/* Source code history: */
/* */
/* The original lzhuf.c source was written by Haruyasu Yoshizaki on */
/* 11/20/1988 with some minor changes 4/6/1989. Comments were */
/* translated by Haruhiko Okumura on 4/7/1989. */
/* */
/* The original lzss compression was written by Haruhiko Okumura, */
/* 12-2-404 Green Heights, 580 Nagasawa, Yokosuka 239, Japan. The */
/* Adaptive Huffman algorithm was added by Yoshizaki to increase */
/* speed and compression and developed it into the LHarc archiver. */
/* */
/* Modifications were made by Allan Hoeltje P.O. Box 18045 Boulder, */
/* Colorado, USA 80308-8045, during the month of June 1989. These */
/* modifications include: More comments; better file error handling; */
/* run-length encoding input and output to increase the compression */
/* ratio. Note: the run length encoding gives you about 2 to 5 per */
/* cent better compression but more importantly it speeds up the */
/* compression process on text files by about 60 per cent. */
/* */
/* Additional modifications made on February 17, 1991 to make the */
/* routines more usable as subroutines for a parent application. */
/* The two routines, lzhEncode and lzhDecode are the main entry */
/* points. Everything else is static. */
/* */
/* It is my understanding that the lzHuff algorithm and source code */
/* is in the public domain and it's use is free and unrestricted. */
/*--------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "rsalib.h"
#include "rsaio.h"
/*
** Convert to or from external byte order.
** Note that hilo_swap does nothing if this is a LSB-first CPU.
*/
#define convert2(x,lx) hilo_swap( (byteptr)&(x), (lx) )
#define convert(x) convert2( (x), sizeof(x) )
#define EXIT_FAILURE 1
#define EXIT_SUCCESS 0
typedef unsigned char uchar;
static FILE *inFile; /* clear text input */
static FILE *outFile; /* compressed output */
static unsigned long int codesize = 0;
static unsigned long int inCount = 0;
static unsigned long int outCount = 0;
void Error( char *message )
{
printf( "\n%s\n", message );
exit( EXIT_FAILURE );
}
/*--------------------------------------------------------------------------*/
/* Run length encoded getc and putc routines. */
/*--------------------------------------------------------------------------*/
/* getCHR
This does a simple getc and count.
*/
static int getCHR( FILE *f )
{
int c;
if ((c = getc( f )) != EOF)
inCount++;
return( c );
}
/* putCHR
This does a simple putc and count with a write error check.
*/
void putCHR( int c, FILE *f )
{
if (putc( c, f ) == EOF)
{
Error( "lzh putCHR: can't write output file!" );
}
outCount++;
}
#define NOHIST 0 /* don't consider previous input */
#define INREP 1 /* sending a repeated value */
#define SENTCHAR 1 /* lastchar set, no lookahead yet */
#define SENDNEWC 2 /* run over, send new char next */
#define SENDCNT 3 /* newchar set, send count next */
#define DLE 0x90 /* repeat sequence marker */
static unsigned char state = NOHIST; /* current packing state */
/*--------------------------------------------------------------------------*/
/* getRLC */
/* Non-repeat compression - text is read from file "f" and passed */
/* through normally except that a run of more than two characters is */
/* encoded as: <char> <DLE> <count>. Special case: a count of zero */
/* indicates that the DLE is really a DLE, not a repeat marker. */
/*--------------------------------------------------------------------------*/
static int
getRLC( FILE *f )
{
static int lastc; /* value returned on last call */
static int repcnt; /* repetition counter */
static int c; /* latest value seen */
static char *badstate = "lzh getRLC: Bad packing state!";
switch (state) /* depends on our state */
{
case NOHIST: /* no relevant history */
state = SENTCHAR;
return (lastc = getCHR(f)); /* remember the value next time */
break;
case SENTCHAR: /* char was sent. look ahead */
switch (lastc) /* action depends on char */
{
case DLE: /* if we sent a real DLE */
state = NOHIST; /* then start over again */
return (0); /* but note that the DLE was real */
break;
case EOF: /* EOF is always a special case */
return (EOF);
break;
default: /* else test for a repeat */
for (repcnt = 1 ;
((c = getCHR(f)) == lastc) && (repcnt < 255) ;
repcnt++); /* find end of run */
switch(repcnt) /* action depends on run size */
{
case 1: /* not a repeat */
return (lastc = c); /* but remember value next time */
break;
case 2: /* a repeat, but too short */
state = SENDNEWC; /* send the second one next time */
return (lastc);
break;
default: /* a run - compress it */
state = SENDCNT; /* send repeat count next time */
return (DLE); /* send repeat marker this time */
break;
}
}
case SENDNEWC: /* send second char of short run */
state = SENTCHAR;
return (lastc = c);
break;
case SENDCNT: /* sent DLE, now send count */
state = SENDNEWC;
return (repcnt);
break;
default:
{
Error( badstate );
}
}
}
/*--------------------------------------------------------------------------*/
/* putRLC */
/* This routine is used to decode non-repeat compression bytes and */
/* write them to file "t". Bytes are passed one at a time in coded */
/* format, and are written out uncoded. The data is stored normally, */
/* except that runs of more than two characters are represented as: */
/* */
/* <char> <DLE> <count> */
/* with a special case that a count of zero indicates a DLE as data, */
/* not as a repeat marker. */
/*--------------------------------------------------------------------------*/
static int
putRLC( int c, FILE *t )
{
static int lastc; /* last character seen */
static char *badstate = "lzh putRLC: Bad unpacking state!";
switch (state) /* action depends on our state */
{
case NOHIST: /* no previous history */
if (c == DLE) /* if starting a series */
state = INREP; /* then remember it next time */
else
putCHR( (lastc = c), t ); /* else nothing unusual */
break;
case INREP: /* in a repeat */
if (c) /* if count is nonzero */
while(--c) /* then repeatedly ... */
putCHR( lastc, t ); /* ... output the byte */
else
putCHR( DLE, t ); /* else output DLE as data */
state = NOHIST; /* back to no history */
break;
default:
{
Error( badstate );
}
}
return(0);
}
/*--------------------------------------------------------------------------*/
/* LZSS Compression */
/*--------------------------------------------------------------------------*/
#define buffSize 2048 /* size of ring buffer */
#define lookSize 60 /* lookahead buffer size */
#define THRESHOLD 2 /* if matchLen is greater than Threshold */
/* then code string into position & length */
#define treeRoot buffSize /* index for root of binary search tree */
/*
ring buffer with extra bytes to facilitate string comparison of
longest match. This is set by the InsertNode() procedure.
*/
static unsigned char textBuf[ buffSize + lookSize - 1 ];
static int matchPos, matchLen;
static int lson[ buffSize + 1 ];
static int rson[ buffSize + 257 ];
static int dad [ buffSize + 1 ];
/*--------------------------------------------------------------------------*/
/* InitTree */
/* Initialize the LZSS trees. */
/*--------------------------------------------------------------------------*/
static void InitTree( void )
{
register int i;
/*
For i = 0 to buffSize, rson[i] and lson[i] will be the right and
left children of node i. These nodes need not be initialized. Also,
dad[i] is the parent of node i. These are initialized to "treeRoot"
which means 'not used.'
For i = buffSize+1 to buffSize+256, rson[i] is the root of the tree
for strings that begin with character i. These are initialized
to "treeRoot". Note there are 256 trees.
*/
for (i = buffSize + 1 ; i <= (buffSize + 256) ; i++)
rson[i] = treeRoot; /* root */
for (i = 0 ; i < buffSize ; i++)
dad[i] = treeRoot; /* node */
}
/*--------------------------------------------------------------------------*/
/* InsertNode */
/* Inserts string of length lookSize, textBuf[r..r+lookSize-1], into */
/* one of the trees (textBuf[r]'th tree) and returns the longest-match */
/* position and length via the global variables matchPos and matchLen. */
/* If matchLen = lookSize, then remove the old node in favor of the new */
/* one, because the old one will be deleted sooner. Note r plays double */
/* role, as tree node and position in buffer. */
/*--------------------------------------------------------------------------*/
static void InsertNode(int r)
{
int i, p, cmp;
unsigned char *key;
unsigned c;
cmp = 1;
key = &textBuf[r];
p = buffSize + 1 + key[0];
rson[r] = lson[r] = treeRoot;
matchLen = 0;
for ( ; ; )
{
if (cmp >= 0)
{
if (rson[p] != treeRoot)
p = rson[p];
else
{
rson[p] = r;
dad [r] = p;
return;
}
}
else
{
if (lson[p] != treeRoot)
p = lson[p];
else
{
lson[p] = r;
dad [r] = p;
return;
}
}
for (i = 1; i < lookSize; i++)
if ((cmp = key[i] - textBuf[p + i]) != 0)
break;
if (i > THRESHOLD)
{
if (i > matchLen)
{
matchPos = ((r - p) & (buffSize - 1)) - 1;
if ((matchLen = i) >= lookSize)
break;
}
if (i == matchLen)
{
if ((c = ((r - p) & (buffSize - 1)) - 1) < matchPos)
{
matchPos = c;
}
}
}
}
dad[r] = dad[p];
lson[r] = lson[p];
rson[r] = rson[p];
dad[lson[p]] = r;
dad[rson[p]] = r;
if (rson[dad[p]] == p)
rson[dad[p]] = r;
else
lson[dad[p]] = r;
dad[p] = treeRoot; /* remove p */
}
/*--------------------------------------------------------------------------*/
/* DeleteNode */
/* Delete node p from the tree. */
/*--------------------------------------------------------------------------*/
static void DeleteNode( register int p )
{
register int q;
if (dad[p] == treeRoot)
return; /* not registered */
if (rson[p] == treeRoot)
q = lson[p];
else
if (lson[p] == treeRoot)
q = rson[p];
else
{
q = lson[p];
if (rson[q] != treeRoot)
{
do {
q = rson[q];
}
while (rson[q] != treeRoot);
rson[dad[q]] = lson[q];
dad[lson[q]] = dad[q];
lson[q] = lson[p];
dad[lson[p]] = q;
}
rson[q] = rson[p];
dad[rson[p]] = q;
}
dad[q] = dad[p];
if (rson[dad[p]] == p)
rson[dad[p]] = q;
else
lson[dad[p]] = q;
dad[p] = treeRoot;
}
/*--------------------------------------------------------------------------*/
/* Huffman Coding */
/*--------------------------------------------------------------------------*/
/* kinds of characters (character code = 0..N_CHAR-1) */
#define N_CHAR (256 - THRESHOLD + lookSize)
#define tableSize (N_CHAR * 2 - 1) /* size of table */
#define rootSize (tableSize - 1) /* position of root */
#define MAX_FREQ 0x8000 /* update the tree when the root */
/* frequency comes to this value. */
/*--------------------------------------------------------------------------*/
/* Tables for encoding the upper 6 bits of position */
/*--------------------------------------------------------------------------*/
static uchar p_len[64] =
{
0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
};
static uchar p_code[64] =
{
0x00, 0x20, 0x30, 0x40, 0x50, 0x58, 0x60, 0x68,
0x70, 0x78, 0x80, 0x88, 0x90, 0x94, 0x98, 0x9C,
0xA0, 0xA4, 0xA8, 0xAC, 0xB0, 0xB4, 0xB8, 0xBC,
0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE,
0xD0, 0xD2, 0xD4, 0xD6, 0xD8, 0xDA, 0xDC, 0xDE,
0xE0, 0xE2, 0xE4, 0xE6, 0xE8, 0xEA, 0xEC, 0xEE,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
};
/*--------------------------------------------------------------------------*/
/* Tables for decoding the upper 6 bits of position */
/*--------------------------------------------------------------------------*/
static uchar d_code[256] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B,
0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D,
0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F,
0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11,
0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15,
0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
0x18, 0x18, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B,
0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F,
0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23,
0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27,
0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B,
0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
};
static uchar d_len[256] =
{
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
};
static unsigned freq[tableSize + 1]; /* frequency table */
static int prnt[ tableSize + N_CHAR ];
/* pointers to parent nodes, except for the elements */
/* [tableSize..tableSize + N_CHAR - 1] which are used */
/* to get the positions of leaves corresponding to the */
/* codes. */
static int son[ tableSize ]; /* pointers to child nodes (son[], son[] + 1) */
static unsigned getbuf = 0;
static uchar getlen = 0;
/*--------------------------------------------------------------------------*/
/* GetBit */
/* Get one bit. */
/*--------------------------------------------------------------------------*/
static int GetBit( void )
{
int i;
while (getlen <= 8)
{
if ((i = getc( inFile )) < 0)
i = 0;
getbuf |= i << (8 - getlen);
getlen += 8;
}
i = getbuf;
getbuf <<= 1;
getlen--;
return (i < 0);
}
/*--------------------------------------------------------------------------*/
/* GetByte */
/* Get one byte. */
/*--------------------------------------------------------------------------*/
static int GetByte( void )
{
unsigned i;
while (getlen <= 8)
{
if ((i = getc( inFile )) < 0)
i = 0;
getbuf |= i << (8 - getlen);
getlen += 8;
}
i = getbuf;
getbuf <<= 8;
getlen -= 8;
return i >> 8;
}
/*--------------------------------------------------------------------------*/
/* Putcode */
/* Write c bits of code. */
/*--------------------------------------------------------------------------*/
static unsigned putbuf = 0;
static uchar putlen = 0;
static void Putcode(int l, unsigned c)
{
static char *werr = "lzh Putcode: can't write output file!";
putbuf |= (c >> putlen);
if ((putlen += l) >= 8)
{
if (putc( putbuf >> 8, outFile ) == EOF)
{
Error( werr );
}
if ((putlen -= 8) >= 8)
{
if (putc( putbuf, outFile ) == EOF)
{
Error( werr );
}
codesize += 2;
putlen -= 8;
putbuf = c << (l - putlen);
}
else
{
putbuf <<= 8;
codesize++;
}
}
}
/*--------------------------------------------------------------------------*/
/* StartHuff */
/* initialize the Huffman trees. */
/*--------------------------------------------------------------------------*/
static void StartHuff( void )
{
register int i, j;
for (i = 0; i < N_CHAR; i++)
{
freq[i] = 1;
son[i] = i + tableSize;
prnt[i + tableSize] = i;
}
i = 0;
j = N_CHAR;
while (j <= rootSize)
{
freq[j] = freq[i] + freq[i + 1];
son[j] = i;
prnt[i] = prnt[i + 1] = j;
i += 2;
j++;
}
freq[tableSize] = 0xffff;
prnt[rootSize] = 0;
}
/*--------------------------------------------------------------------------*/
/* reconst */
/* Reconstruction of tree. */
/*--------------------------------------------------------------------------*/
static void reconst( void )
{
register int i, j, k;
unsigned int f, l;
/* Collect leaf nodes in the first half of the table and replace the */
/* freq by (freq + 1) / 2. */
j = 0;
for (i = 0; i < tableSize; i++)
{
if (son[i] >= tableSize)
{
freq[j] = (freq[i] + 1) / 2;
son[j] = son[i];
j++;
}
}
/* begin constructing tree by connecting sons */
for (i = 0, j = N_CHAR; j < tableSize; i += 2, j++)
{
k = i + 1;
f = freq[j] = freq[i] + freq[k];
for (k = j - 1; f < freq[k]; k--);
k++;
l = (j - k) * 2;
memmove( &freq[k + 1], &freq[k], l );
freq[k] = f;
memmove( &son[k + 1], &son[k], l );
son[k] = i;
}
/* connect prnt */
for (i = 0; i < tableSize; i++)
if ((k = son[i]) >= tableSize)
prnt[k] = i;
else
prnt[k] = prnt[k + 1] = i;
}
/*--------------------------------------------------------------------------*/
/* update */
/* Increment frequency of given code by one, and update tree. */
/*--------------------------------------------------------------------------*/
static void update(int c)
{
int i, j, k, l;
if (freq[rootSize] == MAX_FREQ)
reconst();
c = prnt[c + tableSize];
do {
k = ++freq[c];
/* if the order is disturbed, exchange nodes */
if (k > freq[l = c + 1])
{
while (k > freq[++l]);
l--;
freq[c] = freq[l];
freq[l] = k;
i = son[c];
prnt[i] = l;
if (i < tableSize)
prnt[i + 1] = l;
j = son[l];
son[l] = i;
prnt[j] = c;
if (j < tableSize)
prnt[j + 1] = c;
son[c] = j;
c = l;
}
}
while ((c = prnt[c]) != 0); /* repeat up to root */
}
/*--------------------------------------------------------------------------*/
/* EncodeChar */
/*--------------------------------------------------------------------------*/
static void EncodeChar(unsigned c)
{
unsigned i;
int j, k;
i = j = 0;
k = prnt[c + tableSize];
/* travel from leaf to root */
do {
i >>= 1;
/* if node's address is odd-numbered, choose bigger brother node */
if (k & 1) i += 0x8000;
j++;
}
while ((k = prnt[k]) != rootSize);
Putcode(j, i);
update(c);
}
/*--------------------------------------------------------------------------*/
/* EncodePosition */
/*--------------------------------------------------------------------------*/
static void EncodePosition(unsigned c)
{
unsigned i;
/* output upper 6 bits by table lookup */
i = c >> 6;
Putcode( p_len[i], (unsigned)p_code[i] << 8 );
/* output lower 6 bits verbatim */
Putcode( 6, (c & 0x3f) << 10 );
}
/*--------------------------------------------------------------------------*/
/* EncodeEnd */
/*--------------------------------------------------------------------------*/
static void EncodeEnd( void )
{
static char *werr = "lzh EncodeEnd: can't write output file!";
if (putlen)
{
if (putc(putbuf >> 8, outFile) == EOF)
Error( werr );
codesize++;
}
}
/*--------------------------------------------------------------------------*/
/* DecodeChar */
/*--------------------------------------------------------------------------*/
static int DecodeChar( void )
{
register unsigned c;
/* Travel from root to leaf choosing the smaller child node (son[]) if */
/* the read bit is 0, the bigger (son[]+1} if 1. */
c = son[rootSize];
while (c < tableSize)
{
c += GetBit();
c = son[c];
}
c -= tableSize;
update(c);
return c;
}
/*--------------------------------------------------------------------------*/
/* DecodePosition */
/*--------------------------------------------------------------------------*/
static int DecodePosition( void )
{
register unsigned i, j, c;
/* recover upper 6 bits from table */
i = GetByte();
c = (unsigned)d_code[i] << 6;
j = d_len[i];
/* read lower 6 bits verbatim */
j -= 2;
while (j--)
i = (i << 1) + GetBit();
return (c | (i & 0x3f));
}
/* lzhEncode
Compress the input file and write to the output file.
Return the ratio of output to input size.
*/
int lzhEncode( FILE *in, FILE *out )
{
int i, c, len, r, s, last_matchLen;
unsigned long int textsize, beginByte;
static char *werr = "lzhEncode: can't write output file!";
inFile = in; /* set the global file pointers */
outFile = out;
/* Skip to the end of file and get the byte length. Write the length
as the first word in the compressed output file.
*/
beginByte = ftell( inFile ); /* just in case we were prepositioned */
fseek( inFile, 0L, SEEK_END );
textsize = ftell( inFile ) - beginByte;
fseek( inFile, beginByte, SEEK_SET ); /* go back to the beginning of the file */
if (textsize == 0)
return( -1 ); /* empty files are easy - signal an error */
convert( textsize ); /* convert to little endian if necessary */
if (fwrite( &textsize, sizeof textsize, 1, outFile ) < 1)
Error( werr );
StartHuff(); /* init the Huffman trees */
InitTree(); /* init the LZSS trees */
inCount = 0; /* init the input character count */
s = 0;
r = buffSize - lookSize;
for (i = 0; i < r; i++)
textBuf[i] = ' ';
/* fill the look ahead buffer */
for (len = 0; (len < lookSize) && ((c = getRLC( inFile )) != EOF); len++)
textBuf[r + len] = c;
for (i = 1; i <= lookSize; i++)
InsertNode( r - i );
InsertNode( r );
do {
if (matchLen > len)
matchLen = len;
if (matchLen <= THRESHOLD)
{
matchLen = 1;
EncodeChar( textBuf[r] );
}
else
{
EncodeChar( 255 - THRESHOLD + matchLen );
EncodePosition( matchPos );
}
last_matchLen = matchLen;
for (i = 0; (i < last_matchLen) && ((c = getRLC( inFile )) != EOF); i++)
{
DeleteNode( s );
textBuf[s] = c;
if (s < lookSize - 1)
textBuf[s + buffSize] = c;
s = (s + 1) & (buffSize - 1);
r = (r + 1) & (buffSize - 1);
InsertNode( r );
}
while (i++ < last_matchLen)
{
DeleteNode( s );
s = (s + 1) & (buffSize - 1);
r = (r + 1) & (buffSize - 1);
if (--len)
InsertNode( r );
}
}
while (len > 0);
EncodeEnd();
return( (int)((codesize * 10) / inCount ));
}
/*--------------------------------------------------------------------------*/
/* lzhDecode */
/*--------------------------------------------------------------------------*/
void lzhDecode( FILE *in, FILE *out )
{
int i, j, k, r, c;
unsigned long int textsize;
static char *werr = "lzhDecode: can't write output file!";
inFile = in; /* set the global file pointers */
outFile = out;
/* get the size of the input file in the first word */
if (fread( &textsize, sizeof textsize, 1, inFile ) < 1)
Error( "lzhDecode: Can't read the input file" );
convert( textsize ); /* convert to little endian if necessary */
if (textsize == 0)
return; /* nothing to decode, empty file */
StartHuff();
for (i = 0; i < (buffSize - lookSize); i++)
textBuf[i] = ' ';
r = buffSize - lookSize;
outCount = 0; /* init the output character count */
while (outCount < textsize )
{
c = DecodeChar();
if (c < 256)
{
if (putRLC( c, outFile ) == EOF)
Error( werr );
textBuf[r++] = c;
r &= (buffSize - 1);
}
else
{
i = (r - DecodePosition() - 1) & (buffSize - 1);
j = c - 255 + THRESHOLD;
for (k = 0; k < j; k++)
{
c = textBuf[(i + k) & (buffSize - 1)];
if (putRLC( c, outFile ) == EOF)
Error( werr );
textBuf[r++] = c;
r &= (buffSize - 1);
}
}
}
}
/* ---- end of lzh.c */