Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/Imaging/libImaging/LzwDecode.c
diff options
context:
space:
mode:
Diffstat (limited to 'Imaging/libImaging/LzwDecode.c')
-rw-r--r--Imaging/libImaging/LzwDecode.c230
1 files changed, 230 insertions, 0 deletions
diff --git a/Imaging/libImaging/LzwDecode.c b/Imaging/libImaging/LzwDecode.c
new file mode 100644
index 0000000..adbaf46
--- /dev/null
+++ b/Imaging/libImaging/LzwDecode.c
@@ -0,0 +1,230 @@
+/*
+ * The Python Imaging Library.
+ * $Id: LzwDecode.c 2134 2004-10-06 08:55:20Z fredrik $
+ *
+ * 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;
+}