#include "fontmisc.h"
#include <bufio.h>
#define BITS 16
#if BITS > 15
typedef long int code_int;
#else
typedef int code_int;
#endif
typedef long int count_int;
#ifdef NO_UCHAR
typedef char char_type;
#else
typedef unsigned char char_type;
#endif
static char_type magic_header[] = { "\037\235" };
#define BIT_MASK 0x1f
#define BLOCK_MASK 0x80
#define INIT_BITS 9
#ifdef COMPATIBLE
# define MAXCODE(n_bits) (1 << (n_bits) - 1)
#else
# define MAXCODE(n_bits) ((1 << (n_bits)) - 1)
#endif
#define FIRST 257
#define CLEAR 256
#define STACK_SIZE 8192
typedef struct _compressedFILE {
BufFilePtr file;
char_type *stackp;
code_int oldcode;
char_type finchar;
int block_compress;
int maxbits;
code_int maxcode, maxmaxcode;
code_int free_ent;
int clear_flg;
int n_bits;
int offset, size;
char_type buf[BITS];
char_type de_stack[STACK_SIZE];
char_type *tab_suffix;
unsigned short *tab_prefix;
} CompressedFile;
static int hsize_table[] = {
5003,
9001,
18013,
35023,
69001
};
static int BufCompressedClose ( BufFilePtr f, int doClose );
static int BufCompressedFill ( BufFilePtr f );
static code_int getcode ( CompressedFile *file );
static int BufCompressedSkip ( BufFilePtr f, int bytes );
BufFilePtr
BufFilePushCompressed (BufFilePtr f)
{
int code;
int maxbits;
int hsize;
CompressedFile *file;
int extra;
if ((BufFileGet(f) != (magic_header[0] & 0xFF)) ||
(BufFileGet(f) != (magic_header[1] & 0xFF)))
{
return 0;
}
code = BufFileGet (f);
if (code == BUFFILEEOF) return 0;
maxbits = code & BIT_MASK;
if (maxbits > BITS || maxbits < 12)
return 0;
hsize = hsize_table[maxbits - 12];
extra = (1 << maxbits) * sizeof (char_type) +
hsize * sizeof (unsigned short);
file = (CompressedFile *) xalloc (sizeof (CompressedFile) + extra);
if (!file)
return 0;
file->file = f;
file->maxbits = maxbits;
file->block_compress = code & BLOCK_MASK;
file->maxmaxcode = 1 << file->maxbits;
file->tab_suffix = (char_type *) &file[1];
file->tab_prefix = (unsigned short *) (file->tab_suffix + file->maxmaxcode);
file->maxcode = MAXCODE(file->n_bits = INIT_BITS);
for ( code = 255; code >= 0; code-- ) {
file->tab_prefix[code] = 0;
file->tab_suffix[code] = (char_type) code;
}
file->free_ent = ((file->block_compress) ? FIRST : 256 );
file->clear_flg = 0;
file->offset = 0;
file->size = 0;
file->stackp = file->de_stack;
bzero(file->buf, BITS);
file->finchar = file->oldcode = getcode (file);
if (file->oldcode != -1)
*file->stackp++ = file->finchar;
return BufFileCreate ((char *) file,
BufCompressedFill,
0,
BufCompressedSkip,
BufCompressedClose);
}
static int
BufCompressedClose (BufFilePtr f, int doClose)
{
CompressedFile *file;
BufFilePtr raw;
file = (CompressedFile *) f->private;
raw = file->file;
xfree (file);
BufFileClose (raw, doClose);
return 1;
}
static int
BufCompressedFill (BufFilePtr f)
{
CompressedFile *file;
register char_type *stackp, *de_stack;
register char_type finchar;
register code_int code, oldcode, incode;
BufChar *buf, *bufend;
file = (CompressedFile *) f->private;
buf = f->buffer;
bufend = buf + BUFFILESIZE;
stackp = file->stackp;
de_stack = file->de_stack;
finchar = file->finchar;
oldcode = file->oldcode;
while (buf < bufend) {
while (stackp > de_stack && buf < bufend)
*buf++ = *--stackp;
if (buf == bufend)
break;
if (oldcode == -1)
break;
code = getcode (file);
if (code == -1)
break;
if ( (code == CLEAR) && file->block_compress ) {
for ( code = 255; code >= 0; code-- )
file->tab_prefix[code] = 0;
file->clear_flg = 1;
file->free_ent = FIRST - 1;
if ( (code = getcode (file)) == -1 )
break;
}
incode = code;
if ( code >= file->free_ent ) {
*stackp++ = finchar;
code = oldcode;
}
while ( code >= 256 )
{
*stackp++ = file->tab_suffix[code];
code = file->tab_prefix[code];
}
finchar = file->tab_suffix[code];
*stackp++ = finchar;
if ( (code=file->free_ent) < file->maxmaxcode ) {
file->tab_prefix[code] = (unsigned short)oldcode;
file->tab_suffix[code] = finchar;
file->free_ent = code+1;
}
oldcode = incode;
}
file->oldcode = oldcode;
file->stackp = stackp;
file->finchar = finchar;
if (buf == f->buffer) {
f->left = 0;
return BUFFILEEOF;
}
f->bufp = f->buffer + 1;
f->left = (buf - f->buffer) - 1;
return f->buffer[0];
}
static char_type rmask[9] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
static code_int
getcode(CompressedFile *file)
{
register code_int code;
register int r_off, bits;
register char_type *bp = file->buf;
register BufFilePtr raw;
if ( file->clear_flg > 0 || file->offset >= file->size ||
file->free_ent > file->maxcode )
{
if ( file->free_ent > file->maxcode ) {
file->n_bits++;
if ( file->n_bits == file->maxbits )
file->maxcode = file->maxmaxcode;
else
file->maxcode = MAXCODE(file->n_bits);
}
if ( file->clear_flg > 0) {
file->maxcode = MAXCODE (file->n_bits = INIT_BITS);
file->clear_flg = 0;
}
bits = file->n_bits;
raw = file->file;
while (bits > 0 && (code = BufFileGet (raw)) != BUFFILEEOF)
{
*bp++ = code;
--bits;
}
bp = file->buf;
if (bits == file->n_bits)
return -1;
file->size = file->n_bits - bits;
file->offset = 0;
file->size = (file->size << 3) - (file->n_bits - 1);
}
r_off = file->offset;
bits = file->n_bits;
bp += (r_off >> 3);
r_off &= 7;
#ifdef NO_UCHAR
code = ((*bp++ >> r_off) & rmask[8 - r_off]) & 0xff;
#else
code = (*bp++ >> r_off);
#endif
bits -= (8 - r_off);
r_off = 8 - r_off;
if ( bits >= 8 ) {
#ifdef NO_UCHAR
code |= (*bp++ & 0xff) << r_off;
#else
code |= *bp++ << r_off;
#endif
r_off += 8;
bits -= 8;
}
code |= (*bp & rmask[bits]) << r_off;
file->offset += file->n_bits;
return code;
}
static int
BufCompressedSkip (BufFilePtr f, int bytes)
{
int c;
while (bytes--)
{
c = BufFileGet(f);
if (c == BUFFILEEOF)
return BUFFILEEOF;
}
return 0;
}
#ifdef TEST
int
main (int argc, char *argv[])
{
BufFilePtr inputraw, input, output;
int c;
inputraw = BufFileOpenRead (0);
input = BufFilePushCompressed (inputraw);
output = BufFileOpenWrite (1);
while ((c = BufFileGet (input)) != BUFFILEEOF)
BufFilePut (c, output);
BufFileClose (input, FALSE);
BufFileClose (output, FALSE);
return 0;
}
#endif