fz_error fz_processlzwd(fz_filter *filter, fz_buffer *in, fz_buffer *out) { fz_lzwd *lzw = (fz_lzwd*)filter; unsigned char *s; int len; if (lzw->resume) { lzw->resume = 0; goto output; } while (1) { if (fillbits(lzw, in)) { if (in->eof) { if (lzw->bidx > 32 - lzw->codebits) { unstuff(lzw, in); return fz_iodone; } } else { return fz_ioneedin; } } lzw->code = lzw->word >> (32 - lzw->codebits); if (lzw->code == LZW_EOD) { eatbits(lzw, lzw->codebits); unstuff(lzw, in); return fz_iodone; } if (lzw->code == LZW_CLEAR) { int oldcodebits = lzw->codebits; lzw->codebits = MINBITS; lzw->nextcode = LZW_FIRST; lzw->code = lzw->word >> (32 - oldcodebits - MINBITS) & ((1 << MINBITS) - 1); if (lzw->code == LZW_EOD) { eatbits(lzw, oldcodebits + MINBITS); unstuff(lzw, in); return fz_iodone; } eatbits(lzw, oldcodebits + MINBITS); lzw->oldcode = lzw->code; if (out->wp + 1 > out->ep) { lzw->resume = 1; return fz_ioneedout; } *out->wp++ = lzw->code; continue; } eatbits(lzw, lzw->codebits); /* if stream starts without a clear code, oldcode is undefined... */ if (lzw->oldcode == -1) { lzw->oldcode = lzw->code; goto output; } /* add new entry to the code table */ lzw->table[lzw->nextcode].prev = lzw->oldcode; lzw->table[lzw->nextcode].firstchar = lzw->table[lzw->oldcode].firstchar; lzw->table[lzw->nextcode].length = lzw->table[lzw->oldcode].length + 1; if (lzw->code < lzw->nextcode) lzw->table[lzw->nextcode].value = lzw->table[lzw->code].firstchar; else lzw->table[lzw->nextcode].value = lzw->table[lzw->nextcode].firstchar; lzw->nextcode ++; if (lzw->nextcode >= (1 << lzw->codebits) - lzw->earlychange - 1) { lzw->codebits ++; if (lzw->codebits > MAXBITS) lzw->codebits = MAXBITS; /* FIXME */ } lzw->oldcode = lzw->code; output: /* code maps to a string, copy to output (in reverse...) */ if (lzw->code > 255) { if (out->wp + lzw->table[lzw->code].length > out->ep) { lzw->resume = 1; return fz_ioneedout; } len = lzw->table[lzw->code].length; s = out->wp + len; do { *(--s) = lzw->table[lzw->code].value; lzw->code = lzw->table[lzw->code].prev; } while (lzw->code >= 0 && s > out->wp); out->wp += len; } /* ... or just a single character */ else { if (out->wp + 1 > out->ep) { lzw->resume = 1; return fz_ioneedout; } *out->wp++ = lzw->code; } }
static int readlzwd(fz_stream *stm, unsigned char *buf, int len) { fz_lzwd *lzw = stm->state; unsigned char *p = buf; unsigned char *ep = buf + len; unsigned char *s; int codelen; while (lzw->rp < lzw->wp && p < ep) *p++ = *lzw->rp++; while (p < ep) { if (lzw->eod) return 0; if (fillbits(lzw)) { if (lzw->bidx > 32 - lzw->codebits) { lzw->eod = 1; return p - buf; } } lzw->code = lzw->word >> (32 - lzw->codebits); lzw->code &= (1 << lzw->codebits) - 1; eatbits(lzw, lzw->codebits); if (lzw->code == LZW_EOD) { lzw->eod = 1; return p - buf; } if (lzw->code == LZW_CLEAR) { lzw->codebits = MINBITS; lzw->nextcode = LZW_FIRST; lzw->oldcode = -1; continue; } /* if stream starts without a clear code, oldcode is undefined... */ if (lzw->oldcode == -1) { lzw->oldcode = lzw->code; goto output; } /* add new entry to the code table */ lzw->table[lzw->nextcode].prev = lzw->oldcode; lzw->table[lzw->nextcode].firstchar = lzw->table[lzw->oldcode].firstchar; lzw->table[lzw->nextcode].length = lzw->table[lzw->oldcode].length + 1; if (lzw->code < lzw->nextcode) lzw->table[lzw->nextcode].value = lzw->table[lzw->code].firstchar; else if (lzw->code == lzw->nextcode) lzw->table[lzw->nextcode].value = lzw->table[lzw->nextcode].firstchar; else fz_warn("out of range code encountered in lzw decode"); lzw->nextcode ++; if (lzw->nextcode > (1 << lzw->codebits) - lzw->earlychange - 1) { lzw->codebits ++; if (lzw->codebits > MAXBITS) lzw->codebits = MAXBITS; /* FIXME */ } lzw->oldcode = lzw->code; output: /* code maps to a string, copy to output (in reverse...) */ if (lzw->code > 255) { codelen = lzw->table[lzw->code].length; lzw->rp = lzw->bp; lzw->wp = lzw->bp + codelen; assert(codelen < MAXLENGTH); s = lzw->wp; do { *(--s) = lzw->table[lzw->code].value; lzw->code = lzw->table[lzw->code].prev; } while (lzw->code >= 0 && s > lzw->bp); } /* ... or just a single character */ else { lzw->bp[0] = lzw->code; lzw->rp = lzw->bp; lzw->wp = lzw->bp + 1; } /* copy to output */ while (lzw->rp < lzw->wp && p < ep) *p++ = *lzw->rp++; } return p - buf; }