mirror of
https://github.com/reactos/reactos.git
synced 2024-11-20 14:30:57 +00:00
a7fddf9c07
svn path=/trunk/; revision=29689
262 lines
4.2 KiB
C
262 lines
4.2 KiB
C
#include "fitz-base.h"
|
|
#include "fitz-stream.h"
|
|
|
|
#define noDEBUG 1
|
|
|
|
enum
|
|
{
|
|
MINBITS = 9,
|
|
MAXBITS = 12,
|
|
MAXBYTES = 2,
|
|
NUMCODES = (1 << MAXBITS),
|
|
LZW_CLEAR = 256,
|
|
LZW_EOD = 257,
|
|
LZW_FIRST = 258,
|
|
HSIZE = 9001, /* 91% occupancy (???) */
|
|
HSHIFT = (13 - 8)
|
|
};
|
|
|
|
typedef struct lzw_hash_s lzw_hash;
|
|
|
|
struct lzw_hash_s
|
|
{
|
|
int hash;
|
|
int code;
|
|
};
|
|
|
|
typedef struct fz_lzwe_s fz_lzwe;
|
|
|
|
struct fz_lzwe_s
|
|
{
|
|
fz_filter super;
|
|
|
|
int earlychange;
|
|
|
|
int bidx; /* partial bits used in out->wp */
|
|
unsigned char bsave; /* partial byte saved between process() calls */
|
|
|
|
int resume;
|
|
int code;
|
|
int fcode;
|
|
int hcode;
|
|
|
|
int codebits;
|
|
int oldcode;
|
|
int nextcode;
|
|
|
|
lzw_hash table[HSIZE];
|
|
};
|
|
|
|
static void
|
|
clearhash(fz_lzwe *lzw)
|
|
{
|
|
int i;
|
|
for (i = 0; i < HSIZE; i++)
|
|
lzw->table[i].hash = -1;
|
|
}
|
|
|
|
fz_error *
|
|
fz_newlzwe(fz_filter **fp, fz_obj *params)
|
|
{
|
|
FZ_NEWFILTER(fz_lzwe, lzw, lzwe);
|
|
|
|
lzw->earlychange = 0;
|
|
|
|
if (params)
|
|
{
|
|
fz_obj *obj;
|
|
obj = fz_dictgets(params, "EarlyChange");
|
|
if (obj) lzw->earlychange = fz_toint(obj) != 0;
|
|
}
|
|
|
|
lzw->bidx = 0;
|
|
lzw->bsave = 0;
|
|
|
|
lzw->resume = 0;
|
|
lzw->code = -1;
|
|
lzw->hcode = -1;
|
|
lzw->fcode = -1;
|
|
|
|
lzw->codebits = MINBITS;
|
|
lzw->nextcode = LZW_FIRST;
|
|
lzw->oldcode = -1; /* generates LZW_CLEAR */
|
|
|
|
clearhash(lzw);
|
|
|
|
return nil;
|
|
}
|
|
|
|
void
|
|
fz_droplzwe(fz_filter *filter)
|
|
{
|
|
}
|
|
|
|
static void
|
|
putcode(fz_lzwe *lzw, fz_buffer *out, int code)
|
|
{
|
|
int nbits = lzw->codebits;
|
|
|
|
while (nbits > 0)
|
|
{
|
|
if (lzw->bidx == 0)
|
|
{
|
|
*out->wp = 0;
|
|
}
|
|
|
|
/* code does not fit: shift right */
|
|
if (nbits > (8 - lzw->bidx))
|
|
{
|
|
*out->wp |= code >> (nbits - (8 - lzw->bidx));
|
|
nbits = nbits - (8 - lzw->bidx);
|
|
lzw->bidx = 0;
|
|
out->wp ++;
|
|
}
|
|
|
|
/* shift left */
|
|
else
|
|
{
|
|
*out->wp |= code << ((8 - lzw->bidx) - nbits);
|
|
lzw->bidx += nbits;
|
|
if (lzw->bidx == 8)
|
|
{
|
|
lzw->bidx = 0;
|
|
out->wp ++;
|
|
}
|
|
nbits = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static fz_error *
|
|
compress(fz_lzwe *lzw, fz_buffer *in, fz_buffer *out)
|
|
{
|
|
if (lzw->resume)
|
|
{
|
|
lzw->resume = 0;
|
|
goto resume;
|
|
}
|
|
|
|
/* at start of data, output a clear code */
|
|
if (lzw->oldcode == -1)
|
|
{
|
|
if (out->wp + 3 > out->ep)
|
|
return fz_ioneedout;
|
|
|
|
if (in->rp + 1 > in->wp)
|
|
{
|
|
if (in->eof)
|
|
goto eof;
|
|
return fz_ioneedin;
|
|
}
|
|
|
|
putcode(lzw, out, LZW_CLEAR);
|
|
|
|
lzw->oldcode = *in->rp++;
|
|
}
|
|
|
|
begin:
|
|
while (1)
|
|
{
|
|
if (in->rp + 1 > in->wp)
|
|
{
|
|
if (in->eof)
|
|
goto eof;
|
|
return fz_ioneedin;
|
|
}
|
|
|
|
/* read character */
|
|
lzw->code = *in->rp++;
|
|
|
|
/* hash string + character */
|
|
lzw->fcode = (lzw->code << MAXBITS) + lzw->oldcode;
|
|
lzw->hcode = (lzw->code << HSHIFT) ^ lzw->oldcode;
|
|
|
|
/* primary hash */
|
|
if (lzw->table[lzw->hcode].hash == lzw->fcode)
|
|
{
|
|
lzw->oldcode = lzw->table[lzw->hcode].code;
|
|
continue;
|
|
}
|
|
|
|
/* secondary hash */
|
|
if (lzw->table[lzw->hcode].hash != -1)
|
|
{
|
|
int disp = HSIZE - lzw->hcode;
|
|
if (lzw->hcode == 0)
|
|
disp = 1;
|
|
do
|
|
{
|
|
lzw->hcode = lzw->hcode - disp;
|
|
if (lzw->hcode < 0)
|
|
lzw->hcode += HSIZE;
|
|
if (lzw->table[lzw->hcode].hash == lzw->fcode)
|
|
{
|
|
lzw->oldcode = lzw->table[lzw->hcode].code;
|
|
goto begin;
|
|
}
|
|
} while (lzw->table[lzw->hcode].hash != -1);
|
|
}
|
|
|
|
resume:
|
|
/* new entry: emit code and add to table */
|
|
|
|
/* reserve space for this code and an eventual CLEAR code */
|
|
if (out->wp + 5 > out->ep)
|
|
{
|
|
lzw->resume = 1;
|
|
return fz_ioneedout;
|
|
}
|
|
|
|
putcode(lzw, out, lzw->oldcode);
|
|
|
|
lzw->oldcode = lzw->code;
|
|
lzw->table[lzw->hcode].code = lzw->nextcode;
|
|
lzw->table[lzw->hcode].hash = lzw->fcode;
|
|
|
|
lzw->nextcode ++;
|
|
|
|
/* table is full: emit clear code and reset */
|
|
if (lzw->nextcode == NUMCODES - 1)
|
|
{
|
|
putcode(lzw, out, LZW_CLEAR);
|
|
clearhash(lzw);
|
|
lzw->nextcode = LZW_FIRST;
|
|
lzw->codebits = MINBITS;
|
|
}
|
|
|
|
/* check if next entry will be too big for the code size */
|
|
else if (lzw->nextcode >= (1 << lzw->codebits) - lzw->earlychange)
|
|
{
|
|
lzw->codebits ++;
|
|
}
|
|
}
|
|
|
|
eof:
|
|
if (out->wp + 5 > out->ep)
|
|
return fz_ioneedout;
|
|
|
|
putcode(lzw, out, lzw->oldcode);
|
|
putcode(lzw, out, LZW_EOD);
|
|
|
|
out->eof = 1;
|
|
return fz_iodone;
|
|
}
|
|
|
|
fz_error *
|
|
fz_processlzwe(fz_filter *filter, fz_buffer *in, fz_buffer *out)
|
|
{
|
|
fz_lzwe *lzw = (fz_lzwe*)filter;
|
|
fz_error *error;
|
|
|
|
/* restore partial bits */
|
|
*out->wp = lzw->bsave;
|
|
|
|
error = compress(lzw, in, out);
|
|
|
|
/* save partial bits */
|
|
lzw->bsave = *out->wp;
|
|
|
|
return error;
|
|
}
|
|
|