2007-09-29 08:39:35 +00:00
|
|
|
#include "fitz-base.h"
|
|
|
|
#include "fitz-stream.h"
|
|
|
|
|
|
|
|
#include "filt_faxd.h"
|
|
|
|
#include "filt_faxc.h"
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
SNORMAL, /* neutral state, waiting for any code */
|
|
|
|
SMAKEUP, /* got a 1d makeup code, waiting for terminating code */
|
|
|
|
SEOL, /* at eol, needs output buffer space */
|
|
|
|
SH1, SH2 /* in H part 1 and 2 (both makeup and terminating codes) */
|
|
|
|
};
|
|
|
|
|
|
|
|
/* TODO: uncompressed */
|
|
|
|
|
|
|
|
typedef struct fz_faxd_s fz_faxd;
|
|
|
|
|
|
|
|
struct fz_faxd_s
|
|
|
|
{
|
|
|
|
fz_filter super;
|
2007-10-19 23:05:02 +00:00
|
|
|
|
2007-09-29 08:39:35 +00:00
|
|
|
int k;
|
|
|
|
int endofline;
|
|
|
|
int encodedbytealign;
|
|
|
|
int columns;
|
|
|
|
int rows;
|
|
|
|
int endofblock;
|
|
|
|
int blackis1;
|
|
|
|
|
|
|
|
int stride;
|
|
|
|
int ridx;
|
|
|
|
|
|
|
|
int bidx;
|
|
|
|
unsigned int word;
|
|
|
|
|
|
|
|
int stage, a, c, dim, eolc;
|
|
|
|
unsigned char *ref;
|
|
|
|
unsigned char *dst;
|
|
|
|
};
|
|
|
|
|
|
|
|
fz_error *
|
|
|
|
fz_newfaxd(fz_filter **fp, fz_obj *params)
|
|
|
|
{
|
|
|
|
fz_obj *obj;
|
|
|
|
|
|
|
|
FZ_NEWFILTER(fz_faxd, fax, faxd);
|
|
|
|
|
|
|
|
fax->ref = nil;
|
|
|
|
fax->dst = nil;
|
|
|
|
|
|
|
|
fax->k = 0;
|
|
|
|
fax->endofline = 0;
|
|
|
|
fax->encodedbytealign = 0;
|
|
|
|
fax->columns = 1728;
|
|
|
|
fax->rows = 0;
|
|
|
|
fax->endofblock = 1;
|
|
|
|
fax->blackis1 = 0;
|
|
|
|
|
|
|
|
obj = fz_dictgets(params, "K");
|
|
|
|
if (obj) fax->k = fz_toint(obj);
|
|
|
|
|
|
|
|
obj = fz_dictgets(params, "EndOfLine");
|
|
|
|
if (obj) fax->endofline = fz_tobool(obj);
|
|
|
|
|
|
|
|
obj = fz_dictgets(params, "EncodedByteAlign");
|
|
|
|
if (obj) fax->encodedbytealign = fz_tobool(obj);
|
|
|
|
|
|
|
|
obj = fz_dictgets(params, "Columns");
|
|
|
|
if (obj) fax->columns = fz_toint(obj);
|
|
|
|
|
|
|
|
obj = fz_dictgets(params, "Rows");
|
|
|
|
if (obj) fax->rows = fz_toint(obj);
|
|
|
|
|
|
|
|
obj = fz_dictgets(params, "EndOfBlock");
|
|
|
|
if (obj) fax->endofblock = fz_tobool(obj);
|
|
|
|
|
|
|
|
obj = fz_dictgets(params, "BlackIs1");
|
|
|
|
if (obj) fax->blackis1 = fz_tobool(obj);
|
|
|
|
|
|
|
|
fax->stride = ((fax->columns - 1) >> 3) + 1;
|
|
|
|
fax->ridx = 0;
|
|
|
|
fax->bidx = 32;
|
|
|
|
fax->word = 0;
|
|
|
|
|
|
|
|
fax->stage = SNORMAL;
|
|
|
|
fax->a = -1;
|
|
|
|
fax->c = 0;
|
|
|
|
fax->dim = fax->k < 0 ? 2 : 1;
|
|
|
|
fax->eolc = 0;
|
|
|
|
|
|
|
|
fax->ref = fz_malloc(fax->stride);
|
|
|
|
if (!fax->ref) { fz_free(fax); return fz_outofmem; }
|
|
|
|
|
|
|
|
fax->dst = fz_malloc(fax->stride);
|
|
|
|
if (!fax->dst) { fz_free(fax); fz_free(fax->ref); return fz_outofmem; }
|
|
|
|
|
|
|
|
memset(fax->ref, 0, fax->stride);
|
|
|
|
memset(fax->dst, 0, fax->stride);
|
|
|
|
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
fz_dropfaxd(fz_filter *p)
|
|
|
|
{
|
|
|
|
fz_faxd *fax = (fz_faxd*) p;
|
|
|
|
fz_free(fax->ref);
|
|
|
|
fz_free(fax->dst);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void eatbits(fz_faxd *fax, int nbits)
|
|
|
|
{
|
|
|
|
fax->word <<= nbits;
|
|
|
|
fax->bidx += nbits;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline fz_error * fillbits(fz_faxd *fax, fz_buffer *in)
|
|
|
|
{
|
|
|
|
while (fax->bidx >= 8)
|
|
|
|
{
|
|
|
|
if (in->rp + 1 > in->wp)
|
|
|
|
return fz_ioneedin;
|
|
|
|
fax->bidx -= 8;
|
|
|
|
fax->word |= *in->rp << fax->bidx;
|
|
|
|
in->rp ++;
|
|
|
|
}
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
getcode(fz_faxd *fax, const cfd_node *table, int initialbits)
|
|
|
|
{
|
|
|
|
unsigned int word = fax->word;
|
|
|
|
int tidx = word >> (32 - initialbits);
|
|
|
|
int val = table[tidx].val;
|
|
|
|
int nbits = table[tidx].nbits;
|
|
|
|
|
|
|
|
if (nbits > initialbits)
|
|
|
|
{
|
|
|
|
int mask = (1 << (32 - initialbits)) - 1;
|
|
|
|
tidx = val + ((word & mask) >> (32 - nbits));
|
|
|
|
val = table[tidx].val;
|
|
|
|
nbits = initialbits + table[tidx].nbits;
|
|
|
|
}
|
|
|
|
|
|
|
|
eatbits(fax, nbits);
|
|
|
|
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* decode one 1d code */
|
|
|
|
static fz_error *
|
|
|
|
dec1d(fz_faxd *fax)
|
|
|
|
{
|
|
|
|
int code;
|
|
|
|
|
|
|
|
if (fax->a == -1)
|
|
|
|
fax->a = 0;
|
|
|
|
|
|
|
|
if (fax->c)
|
|
|
|
code = getcode(fax, cf_black_decode, cfd_black_initial_bits);
|
|
|
|
else
|
|
|
|
code = getcode(fax, cf_white_decode, cfd_white_initial_bits);
|
|
|
|
|
|
|
|
if (code == UNCOMPRESSED)
|
|
|
|
return fz_throw("ioerror: uncompressed data in faxd");
|
|
|
|
|
|
|
|
if (code < 0)
|
|
|
|
return fz_throw("ioerror: negative code in 1d faxd");
|
|
|
|
|
|
|
|
if (fax->a + code > fax->columns)
|
|
|
|
return fz_throw("ioerror: overflow in 1d faxd");
|
|
|
|
|
|
|
|
if (fax->c)
|
|
|
|
setbits(fax->dst, fax->a, fax->a + code);
|
|
|
|
|
|
|
|
fax->a += code;
|
|
|
|
|
|
|
|
if (code < 64)
|
|
|
|
{
|
|
|
|
fax->c = !fax->c;
|
|
|
|
fax->stage = SNORMAL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
fax->stage = SMAKEUP;
|
|
|
|
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* decode one 2d code */
|
|
|
|
static fz_error *
|
|
|
|
dec2d(fz_faxd *fax)
|
|
|
|
{
|
|
|
|
int code, b1, b2;
|
|
|
|
|
|
|
|
if (fax->stage == SH1 || fax->stage == SH2)
|
|
|
|
{
|
|
|
|
if (fax->a == -1)
|
|
|
|
fax->a = 0;
|
|
|
|
|
|
|
|
if (fax->c)
|
|
|
|
code = getcode(fax, cf_black_decode, cfd_black_initial_bits);
|
|
|
|
else
|
|
|
|
code = getcode(fax, cf_white_decode, cfd_white_initial_bits);
|
|
|
|
|
|
|
|
if (code == UNCOMPRESSED)
|
|
|
|
return fz_throw("ioerror: uncompressed data in faxd");
|
|
|
|
|
|
|
|
if (code < 0)
|
|
|
|
return fz_throw("ioerror: negative code in 2d faxd");
|
|
|
|
|
|
|
|
if (fax->a + code > fax->columns)
|
|
|
|
return fz_throw("ioerror: overflow in 2d faxd");
|
|
|
|
|
|
|
|
if (fax->c)
|
|
|
|
setbits(fax->dst, fax->a, fax->a + code);
|
|
|
|
|
|
|
|
fax->a += code;
|
|
|
|
|
|
|
|
if (code < 64)
|
|
|
|
{
|
|
|
|
fax->c = !fax->c;
|
|
|
|
if (fax->stage == SH1)
|
|
|
|
fax->stage = SH2;
|
|
|
|
else if (fax->stage == SH2)
|
|
|
|
fax->stage = SNORMAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
code = getcode(fax, cf_2d_decode, cfd_2d_initial_bits);
|
|
|
|
|
|
|
|
switch (code)
|
|
|
|
{
|
|
|
|
case H:
|
|
|
|
fax->stage = SH1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case P:
|
|
|
|
b1 = findchangingcolor(fax->ref, fax->a, fax->columns, !fax->c);
|
|
|
|
b2 = findchanging(fax->ref, b1, fax->columns);
|
|
|
|
if (fax->c) setbits(fax->dst, fax->a, b2);
|
|
|
|
fax->a = b2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case V0:
|
|
|
|
b1 = findchangingcolor(fax->ref, fax->a, fax->columns, !fax->c);
|
|
|
|
if (fax->c) setbits(fax->dst, fax->a, b1);
|
|
|
|
fax->a = b1;
|
|
|
|
fax->c = !fax->c;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VR1:
|
|
|
|
b1 = findchangingcolor(fax->ref, fax->a, fax->columns, !fax->c);
|
|
|
|
if (fax->c) setbits(fax->dst, fax->a, b1 + 1);
|
|
|
|
fax->a = b1 + 1;
|
|
|
|
fax->c = !fax->c;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VR2:
|
|
|
|
b1 = findchangingcolor(fax->ref, fax->a, fax->columns, !fax->c);
|
|
|
|
if (fax->c) setbits(fax->dst, fax->a, b1 + 2);
|
|
|
|
fax->a = b1 + 2;
|
|
|
|
fax->c = !fax->c;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VR3:
|
|
|
|
b1 = findchangingcolor(fax->ref, fax->a, fax->columns, !fax->c);
|
|
|
|
if (fax->c) setbits(fax->dst, fax->a, b1 + 3);
|
|
|
|
fax->a = b1 + 3;
|
|
|
|
fax->c = !fax->c;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VL1:
|
|
|
|
b1 = findchangingcolor(fax->ref, fax->a, fax->columns, !fax->c);
|
|
|
|
if (fax->c) setbits(fax->dst, fax->a, b1 - 1);
|
|
|
|
fax->a = b1 - 1;
|
|
|
|
fax->c = !fax->c;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VL2:
|
|
|
|
b1 = findchangingcolor(fax->ref, fax->a, fax->columns, !fax->c);
|
|
|
|
if (fax->c) setbits(fax->dst, fax->a, b1 - 2);
|
|
|
|
fax->a = b1 - 2;
|
|
|
|
fax->c = !fax->c;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VL3:
|
|
|
|
b1 = findchangingcolor(fax->ref, fax->a, fax->columns, !fax->c);
|
|
|
|
if (fax->c) setbits(fax->dst, fax->a, b1 - 3);
|
|
|
|
fax->a = b1 - 3;
|
|
|
|
fax->c = !fax->c;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case UNCOMPRESSED:
|
|
|
|
return fz_throw("ioerror: uncompressed data in faxd");
|
|
|
|
|
|
|
|
case ERROR:
|
|
|
|
return fz_throw("ioerror: invalid code in 2d faxd");
|
|
|
|
|
|
|
|
default:
|
|
|
|
return fz_throw("ioerror: invalid code in 2d faxd (%d)", code);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
fz_error *
|
|
|
|
fz_processfaxd(fz_filter *f, fz_buffer *in, fz_buffer *out)
|
|
|
|
{
|
|
|
|
fz_faxd *fax = (fz_faxd*)f;
|
|
|
|
fz_error *error;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (fax->stage == SEOL)
|
|
|
|
goto eol;
|
|
|
|
|
|
|
|
loop:
|
|
|
|
|
|
|
|
if (fillbits(fax, in))
|
|
|
|
{
|
|
|
|
if (in->eof)
|
|
|
|
{
|
|
|
|
if (fax->bidx > 31)
|
|
|
|
{
|
|
|
|
if (fax->a > 0)
|
|
|
|
goto eol;
|
|
|
|
goto rtc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return fz_ioneedin;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((fax->word >> (32 - 12)) == 0)
|
|
|
|
{
|
|
|
|
eatbits(fax, 1);
|
|
|
|
goto loop;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((fax->word >> (32 - 12)) == 1)
|
|
|
|
{
|
|
|
|
eatbits(fax, 12);
|
|
|
|
fax->eolc ++;
|
|
|
|
|
|
|
|
if (fax->k > 0)
|
|
|
|
{
|
|
|
|
if ((fax->word >> (32 - 1)) == 1)
|
|
|
|
fax->dim = 1;
|
|
|
|
else
|
|
|
|
fax->dim = 2;
|
|
|
|
eatbits(fax, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (fax->dim == 1)
|
|
|
|
{
|
|
|
|
fax->eolc = 0;
|
|
|
|
error = dec1d(fax);
|
|
|
|
if (error) return error;
|
|
|
|
|
|
|
|
}
|
|
|
|
else if (fax->dim == 2)
|
|
|
|
{
|
|
|
|
fax->eolc = 0;
|
|
|
|
error = dec2d(fax);
|
|
|
|
if (error) return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no eol check after makeup codes nor in the middle of an H code */
|
|
|
|
if (fax->stage == SMAKEUP || fax->stage == SH1 || fax->stage == SH2)
|
|
|
|
goto loop;
|
|
|
|
|
|
|
|
/* check for eol conditions */
|
|
|
|
if (fax->eolc || fax->a >= fax->columns)
|
|
|
|
{
|
|
|
|
if (fax->a > 0)
|
|
|
|
goto eol;
|
|
|
|
if (fax->eolc == (fax->k < 0 ? 2 : 6))
|
|
|
|
goto rtc;
|
|
|
|
}
|
|
|
|
|
|
|
|
goto loop;
|
|
|
|
|
|
|
|
eol:
|
|
|
|
fax->stage = SEOL;
|
|
|
|
if (out->wp + fax->stride > out->ep)
|
|
|
|
return fz_ioneedout;
|
|
|
|
|
|
|
|
if (fax->blackis1)
|
|
|
|
memcpy(out->wp, fax->dst, fax->stride);
|
|
|
|
else
|
|
|
|
for (i = 0; i < fax->stride; i++)
|
|
|
|
out->wp[i] = ~fax->dst[i];
|
|
|
|
|
|
|
|
memcpy(fax->ref, fax->dst, fax->stride);
|
|
|
|
memset(fax->dst, 0, fax->stride);
|
|
|
|
out->wp += fax->stride;
|
|
|
|
|
|
|
|
fax->stage = SNORMAL;
|
|
|
|
fax->c = 0;
|
|
|
|
fax->a = -1;
|
|
|
|
fax->ridx ++;
|
|
|
|
|
|
|
|
if (!fax->endofblock && fax->rows)
|
|
|
|
{
|
|
|
|
if (fax->ridx >= fax->rows)
|
|
|
|
goto rtc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* we have not read dim from eol, make a guess */
|
|
|
|
if (fax->k > 0 && !fax->eolc)
|
|
|
|
{
|
|
|
|
if (fax->ridx % fax->k == 0)
|
|
|
|
fax->dim = 1;
|
|
|
|
else
|
|
|
|
fax->dim = 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if endofline & encodedbytealign, EOLs are *not* optional */
|
|
|
|
if (fax->encodedbytealign)
|
|
|
|
{
|
|
|
|
if (fax->endofline)
|
|
|
|
eatbits(fax, (12 - fax->bidx) & 7);
|
|
|
|
else
|
|
|
|
eatbits(fax, (8 - fax->bidx) & 7);
|
|
|
|
}
|
|
|
|
|
|
|
|
goto loop;
|
|
|
|
|
|
|
|
rtc:
|
|
|
|
i = (32 - fax->bidx) / 8;
|
|
|
|
while (i-- && in->rp > in->bp)
|
|
|
|
in->rp --;
|
|
|
|
|
|
|
|
out->eof = 1;
|
|
|
|
return fz_iodone;
|
|
|
|
}
|
|
|
|
|