Pillow/libImaging/LzwDecode.c
2010-07-30 22:52:47 -04:00

231 lines
5.0 KiB
C

/*
* 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 <stdio.h>
#include <stdlib.h> /* 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;
}