/* * The Python Imaging Library. * $Id$ * * a fast, suspendable TIFF LZW decoder * * description: * This code is based on the GIF decoder. There are some * subtle differences between GIF and TIFF LZW, though: * - The fill order is different. In the TIFF file, you * must shift new bits in to the right, not to the left. * - There is no blocking in the input data stream. * - The code size is increased one step earlier than * for GIF * - Image data are seen as a byte stream, not a pixel * stream. This means that the code size will always * start at 9 bits. * * history: * 95-09-13 fl Created (derived from GifDecode.c) * 96-03-28 fl Revised API, integrated with PIL * 97-01-05 fl Added filter support, added extra consistency checks * * Copyright (c) Fredrik Lundh 1995-97. * Copyright (c) Secret Labs AB 1997. * * See the README file for information on usage and redistribution. */ #include "Imaging.h" #include #include /* memcpy() */ #include "Lzw.h" int ImagingLzwDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) { UINT8* p; int c, i; int thiscode; LZWSTATE* context = (LZWSTATE*) state->context; unsigned char *ptr = buf; if (!state->state) { /* Clear code */ context->clear = 1 << 8; /* End code */ context->end = context->clear + 1; state->state = 1; } for (;;) { if (state->state == 1) { /* First free entry in table */ context->next = context->clear + 2; /* Initial code size */ context->codesize = 8 + 1; context->codemask = (1 << context->codesize) - 1; /* Buffer pointer. We fill the buffer from right, which allows us to return all of it in one operation. */ context->bufferindex = LZWBUFFER; state->state = 2; } if (context->bufferindex < LZWBUFFER) { /* Return whole buffer in one chunk */ i = LZWBUFFER - context->bufferindex; p = &context->buffer[context->bufferindex]; context->bufferindex = LZWBUFFER; } else { /* Get current symbol */ while (context->bitcount < context->codesize) { if (bytes < 1) return ptr - buf;; /* Read next byte */ c = *ptr++; bytes--; /* New bits are shifted in from from the right. */ context->bitbuffer = (context->bitbuffer << 8) | c; context->bitcount += 8; } /* Extract current symbol from bit buffer. */ c = (context->bitbuffer >> (context->bitcount - context->codesize)) & context->codemask; /* Adjust buffer */ context->bitcount -= context->codesize; /* If c is less than clear, it's a data byte. Otherwise, it's either clear/end or a code symbol which should be expanded. */ if (c == context->clear) { if (state->state != 2) state->state = 1; continue; } if (c == context->end) break; i = 1; p = &context->lastdata; if (state->state == 2) { /* First valid symbol after clear; use as is */ if (c > context->clear) { state->errcode = IMAGING_CODEC_BROKEN; return -1; } context->lastdata = context->lastcode = c; state->state = 3; } else { thiscode = c; if (c > context->next) { state->errcode = IMAGING_CODEC_BROKEN; return -1; } if (c == context->next) { /* c == next is allowed, by some strange reason */ if (context->bufferindex <= 0) { state->errcode = IMAGING_CODEC_BROKEN; return -1; } context->buffer[--context->bufferindex] = context->lastdata; c = context->lastcode; } while (c >= context->clear) { /* Copy data string to buffer (beginning from right) */ if (context->bufferindex <= 0 || c >= LZWTABLE) { state->errcode = IMAGING_CODEC_BROKEN; return -1; } context->buffer[--context->bufferindex] = context->data[c]; c = context->link[c]; } context->lastdata = c; if (context->next < LZWTABLE) { /* While we still have room for it, add this symbol to the table. */ context->data[context->next] = c; context->link[context->next] = context->lastcode; context->next++; if (context->next == context->codemask && context->codesize < LZWBITS) { /* Expand code size */ context->codesize++; context->codemask = (1 << context->codesize) - 1; } } context->lastcode = thiscode; } } /* Update the output image */ for (c = 0; c < i; c++) { state->buffer[state->x] = p[c]; if (++state->x >= state->bytes) { int x, bpp; /* Apply filter */ switch (context->filter) { case 2: /* Horizontal differing ("prior") */ bpp = (state->bits + 7) / 8; for (x = bpp; x < state->bytes; x++) state->buffer[x] += state->buffer[x-bpp]; } /* Got a full line, unpack it */ state->shuffle((UINT8*) im->image[state->y + state->yoff] + state->xoff * im->pixelsize, state->buffer, state->xsize); state->x = 0; if (++state->y >= state->ysize) /* End of file (errcode = 0) */ return -1; } } } return ptr - buf; }