pdf-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[pdf-devel] LZW filter implementation


From: Juan Pedro Bolivar Puente
Subject: [pdf-devel] LZW filter implementation
Date: Sun, 12 Oct 2008 14:49:33 +0200
User-agent: Mozilla-Thunderbird 2.0.0.16 (X11/20080724)

Hi,

I have finished the LZW implementation. Two notes:
  - With cache < 5 we cannot assure that some characters are missed in a
compression-decompression cycle (footer sequence sequence takes several
chars).
  - It seems that with cache = 1 the decoder gets a point (the first
bitsize change of the LZW codes) from which it stops producing sensible
output. I would have fixed this but with the previous issue (which is an
architecture problem, not implementation) it does not make sense.
  - Also, the decompression apply function might seem ugly with those 6
goto's (Dijkstra's nightmare :p) but it is actually much cleaner than
when it was goto-less. Actually, that trick makes the algorithm very
similar to the old-stateless implementation, and a such much easier to
debug.

File attached.

BTW, I am very busy for the rest of October. Is it too much to wait for
the predictor's reimplementation till the first week of November?

Regards,
JP


# Bazaar merge directive format 2 (Bazaar 0.90)
# revision_id: address@hidden
# target_branch: http://bzr.savannah.gnu.org/r/pdf/libgnupdf/branches\
#   /trunk/
# testament_sha1: 426b2081ac672f50e885635475c74f31a894c9ac
# timestamp: 2008-10-12 14:35:06 +0200
# base_revision_id: address@hidden
# 
# Begin patch
=== modified file 'src/Makefile.am'
--- src/Makefile.am     2008-10-05 15:08:05 +0000
+++ src/Makefile.am     2008-10-12 12:34:46 +0000
@@ -44,7 +44,8 @@
                      base/pdf-stm-filter.h base/pdf-stm-filter.c \
                      base/pdf-stm-f-null.h base/pdf-stm-f-null.c \
                      base/pdf-stm-f-ahex.h base/pdf-stm-f-ahex.c \
-                     base/pdf-stm-f-rl.h base/pdf-stm-f-rl.c
+                     base/pdf-stm-f-rl.h base/pdf-stm-f-rl.c \
+                    base/pdf-stm-f-lzw.h base/pdf-stm-f-lzw.c
 
 if ZLIB
   STM_MODULE_SOURCES += base/pdf-stm-f-flate.c base/pdf-stm-f-flate.h

=== modified file 'src/base/pdf-stm-f-lzw.c'
--- src/base/pdf-stm-f-lzw.c    2008-08-28 22:46:53 +0000
+++ src/base/pdf-stm-f-lzw.c    2008-10-12 12:34:46 +0000
@@ -27,21 +27,20 @@
 #include <pdf-alloc.h>
 #include <pdf-stm-f-lzw.h>
 
-#define MIN_BITSIZE 9
-#define MAX_BITSIZE 12
-#define MAX_DICTSIZE (1 << MAX_BITSIZE)
-
-#define MAX_COMPRESSION_FACTOR 1.5
-
-#define NULL_INDEX ~0U
-
-enum {
-  LZW_RESET_CODE = 256,
-  LZW_EOD_CODE,
-  LZW_FIRST_CODE
-} lzw_special_codes;
-
-
+#define LZW_DEFAULT_EARLY_CHANGE  0
+
+#define LZW_CACHE_SIZE    16
+#define LZW_MIN_BITSIZE   9
+#define LZW_MAX_BITSIZE   12
+#define LZW_MAX_DICTSIZE  (1 << LZW_MAX_BITSIZE)
+#define LZW_NULL_INDEX    ~0U
+
+enum lzw_special_codes_e
+  {
+    LZW_RESET_CODE = 256,
+    LZW_EOD_CODE,
+    LZW_FIRST_CODE
+  };
 
 /* -- LZW code output/input -- */
 
@@ -49,54 +48,68 @@
  * Object to read and write codes of variable bitsize in a buffer.
  * Warning: using both get and put functions may break the buffer.
  */
-typedef struct lzw_buffer_s
+struct lzw_buffer_s
 {
-  pdf_char_t* curp;
-  pdf_char_t* endp;
+  pdf_stm_buffer_t buf;
+  pdf_char_t cache [LZW_CACHE_SIZE];
+  pdf_size_t cache_size;
   unsigned long valbuf;
   unsigned valbits;
   unsigned bitsize;
   unsigned maxval;
-} lzw_buffer_t;
+};
+typedef struct lzw_buffer_s* lzw_buffer_t;
 
 static void
-lzw_buffer_init (lzw_buffer_t* b, 
-                pdf_char_t* ptr,
-                int size,
+lzw_buffer_init (lzw_buffer_t b,
                 int bitsize)
 {
-  b->curp = ptr;
-  b->endp = ptr + size;
+  b->buf = NULL;
+  b->cache_size = 0;
   b->valbuf = 0;
   b->valbits = 0;
   b->bitsize = bitsize;
   b->maxval = (1 << bitsize) - 1;
 }
 
-static unsigned int
-lzw_buffer_get_code (lzw_buffer_t* b)
+static void
+lzw_buffer_set (lzw_buffer_t b,
+               pdf_stm_buffer_t buf)
+{
+  b->buf = buf;
+}
+
+static pdf_status_t
+lzw_buffer_get_code (lzw_buffer_t b,
+                    unsigned int* code)
 {
   unsigned long r;
   
   while (b->valbits <= 24)
-  {
-    if (b->curp > b->endp)
-      return NULL_INDEX;
-    
-    b->valbuf |= (unsigned long) *b->curp++ << (24 - b->valbits);
-    b->valbits += 8;
-  }
+    {
+      if (pdf_stm_buffer_eob_p (b->buf))
+       {
+         return PDF_ENINPUT;
+       }
+      
+      b->valbuf |=
+       (unsigned long) b->buf->data [b->buf->rp++] <<
+       (24 - b->valbits);
+      b->valbits += 8;
+    }
 
   r = b->valbuf >> (32 - b->bitsize);
   b->valbuf <<= b->bitsize;
   b->valbits -= b->bitsize;
   
-  return r;
+  *code = r;
+
+  return PDF_OK;
 }
 
 /* Once finished, call with 0 as code value to flush the buffer. */
 static void
-lzw_buffer_put_code (lzw_buffer_t* b,
+lzw_buffer_put_code (lzw_buffer_t b,
                     unsigned int code)
 {
   b->valbuf |= (unsigned long) code << (32 - b->bitsize - b->valbits);
@@ -104,17 +117,47 @@
 
   while (b->valbits >= 8)
     {
-      *b->curp++ = b->valbuf >> 24;
+      if (pdf_stm_buffer_full_p (b->buf))
+       {
+         b->cache [b->cache_size++] = b->valbuf >> 24;
+       }
+      else
+       {
+         b->buf->data [b->buf->wp++] = b->valbuf >> 24;
+       }
       b->valbuf <<= 8;
       b->valbits -= 8;
     }
 }
 
+static pdf_status_t
+lzw_buffer_flush (lzw_buffer_t b)
+{
+  int i;
+
+  i = 0;
+  while (b->cache_size &&
+        !pdf_stm_buffer_full_p (b->buf))
+    {
+      b->buf->data [b->buf->wp++] = b->cache [i++];
+      b->cache_size--;
+    }
+
+  if (pdf_stm_buffer_full_p (b->buf))
+    {
+      return PDF_ENOUTPUT;
+    }
+
+  return PDF_OK;
+}
+
 static int
-lzw_buffer_inc_bitsize (lzw_buffer_t* b)
+lzw_buffer_inc_bitsize (lzw_buffer_t b)
 {
-  if (b->bitsize == MAX_BITSIZE)
-    return PDF_ERROR;
+  if (b->bitsize == LZW_MAX_BITSIZE)
+    {
+      return PDF_ERROR;
+    }
   
   ++b->bitsize;
   b->maxval = (1 << b->bitsize) - 1;
@@ -123,20 +166,19 @@
 }
 
 static void
-lzw_buffer_set_bitsize (lzw_buffer_t* b,
+lzw_buffer_set_bitsize (lzw_buffer_t b,
                        int newsize)
 {
   b->bitsize = newsize;
   b->maxval = (1 << newsize) - 1;
 }
 
-
 /* -- LZW dictionary handler -- */
 
 /*
  * The strings are stored in a non balanced ordered binary tree.
  */
-typedef struct lzw_string_s
+struct lzw_string_s
 {
   unsigned prefix;   /* Prefix string code */
   pdf_char_t suffix; /* Appended character */
@@ -144,27 +186,31 @@
   unsigned first; /* First string with the same prefix.  */
   unsigned left;  /* Next string with smaller suffix and same prefix. */
   unsigned right; /* Next string with greater suffix and same prefix. */
-} lzw_string_t;
+};
+
+typedef struct lzw_string_s* lzw_string_t;
 
 static void
-lzw_string_init (lzw_string_t* s)
+lzw_string_init (lzw_string_t s)
 {
-  memset(s, 0xFF, sizeof(lzw_string_t));
+  memset (s, 0xFF, sizeof (struct lzw_string_s));
 }
 
-
-typedef struct lzw_dict_s
+struct lzw_dict_s
 {
-  lzw_string_t table[MAX_DICTSIZE];
+  struct lzw_string_s table [LZW_MAX_DICTSIZE];
   unsigned size;
-} lzw_dict_t;
+};
+typedef struct lzw_dict_s* lzw_dict_t;
 
 static void
-lzw_dict_init (lzw_dict_t* d)
+lzw_dict_init (lzw_dict_t d)
 {
   int i;
   
-  memset(d->table, 0xFF, sizeof(lzw_string_t) * MAX_DICTSIZE);
+  memset (d->table,
+         LZW_NULL_INDEX,
+         sizeof (struct lzw_string_s) * LZW_MAX_DICTSIZE);
 
   for (i = 0; i < LZW_FIRST_CODE; i++)
     {
@@ -174,14 +220,14 @@
   d->size = LZW_FIRST_CODE;
 }
 
-static int
-lzw_dict_add (lzw_dict_t* d,
-             lzw_string_t* s)
+static pdf_bool_t
+lzw_dict_add (lzw_dict_t d,
+             lzw_string_t s)
 {
   unsigned index;
   int must_add;
   
-  if (s->prefix == NULL_INDEX)
+  if (s->prefix == LZW_NULL_INDEX)
     {
       s->prefix = s->suffix;
       return PDF_FALSE; /* The string is a basic character, found! */
@@ -189,7 +235,7 @@
   
   index = d->table[s->prefix].first;
 
-  if (index == NULL_INDEX)
+  if (index == LZW_NULL_INDEX)
     {
       d->table[s->prefix].first = d->size;
     }
@@ -205,7 +251,7 @@
            }
          else if (s->suffix < d->table[index].suffix)
            {
-             if (d->table[index].left == NULL_INDEX)
+             if (d->table[index].left == LZW_NULL_INDEX)
                {
                  d->table[index].left = d->size;
                  must_add = PDF_TRUE;
@@ -217,7 +263,7 @@
            }
          else
            {
-             if (d->table[index].right == NULL_INDEX)
+             if (d->table[index].right == LZW_NULL_INDEX)
                {
                  d->table[index].right = d->size;
                  must_add = PDF_TRUE;
@@ -235,10 +281,14 @@
   return PDF_TRUE;
 }
 
-#define lzw_dict_reset lzw_dict_init
+static void
+lzw_dict_reset (lzw_dict_t dict)
+{
+  lzw_dict_init (dict);
+}
 
 static void
-lzw_dict_fast_add (lzw_dict_t* d,
+lzw_dict_fast_add (lzw_dict_t d,
                   unsigned prefix,
                   pdf_char_t suffix)
 {
@@ -248,7 +298,7 @@
 }
 
 static void
-lzw_dict_decode (lzw_dict_t* d,
+lzw_dict_decode (lzw_dict_t d,
                 unsigned code,
                 pdf_char_t** decode,
                 unsigned* size)
@@ -256,301 +306,365 @@
   *size = 0;
 
   do {
+    //fprintf (stderr, "code: %d\n", code);
     *(*decode)-- = d->table[code].suffix;
     ++(*size);
     code = d->table[code].prefix;
-  } while (code != NULL_INDEX);
+  } while (code != LZW_NULL_INDEX);
+
   (*decode)++;
-  
 }
 
-/* -- The encoder -- */
-
-static int
-pdf_stm_f_lzw_encode (pdf_stm_f_lzw_data_t data,
-                      pdf_char_t *in,
-                      pdf_stm_pos_t in_size,
-                      pdf_char_t **out,
-                      pdf_stm_pos_t *out_size)
-{
-  lzw_buffer_t buffer;
-  lzw_dict_t dict;
-  lzw_string_t string;
-  
-  /* Allocate buffer with enough space. */
-  *out_size = in_size * MAX_COMPRESSION_FACTOR;
-  if ((*out = (pdf_char_t *) pdf_alloc (*out_size)) == NULL)
+/* -- THE ENCODER -- */
+
+struct lzwenc_state_s
+{
+  /* cached params */
+  pdf_i32_t early_change;
+
+  /* encoding state */
+  pdf_bool_t           must_reset_p;
+  struct lzw_buffer_s  buffer;
+  struct lzw_dict_s    dict;
+  struct lzw_string_s  string;
+};
+typedef struct lzwenc_state_s* lzwenc_state_t;
+
+pdf_status_t
+pdf_stm_f_lzwenc_init (pdf_hash_t params,
+                      void **ext_state)
+{
+  pdf_i32_t* early_change_ptr;
+  lzwenc_state_t state;
+
+  state = pdf_alloc (sizeof (struct lzwenc_state_s));
+  if (!state)
     {
-      *out_size = 0;
       return PDF_ERROR;
     }
-
-  /* Do the actual encoding. */
-  lzw_buffer_init(&buffer, *out, *out_size, MIN_BITSIZE);
-  lzw_dict_init(&dict);
-  lzw_string_init(&string);
-
-  lzw_buffer_put_code(&buffer, LZW_RESET_CODE);
-
-  while (--in_size >= 0)
-    {
-      string.suffix = *in++;
-
-      if (lzw_dict_add(&dict, &string))
+  
+  if (pdf_hash_search (params, "EarlyChange", (void **) &early_change_ptr)
+      != PDF_OK)
+    {
+      state->early_change = LZW_DEFAULT_EARLY_CHANGE;
+    }
+  else
+    {
+      state->early_change = *early_change_ptr;
+    }
+
+  lzw_buffer_init (&state->buffer, LZW_MIN_BITSIZE);
+  lzw_dict_init (&state->dict);
+  lzw_string_init (&state->string);
+  state->must_reset_p = PDF_TRUE;
+  
+  *ext_state = state;
+  return PDF_OK;
+}
+
+pdf_status_t
+pdf_stm_f_lzwenc_apply (pdf_hash_t params,
+                       void *ext_state,
+                       pdf_stm_buffer_t in,
+                       pdf_stm_buffer_t out,
+                       pdf_bool_t finish_p)
+{
+  pdf_status_t ret;
+  lzwenc_state_t st;
+
+  ret = PDF_OK;
+  st  = ext_state;
+  lzw_buffer_set (&st->buffer, out);
+
+  ret = lzw_buffer_flush (&st->buffer);
+  if (ret != PDF_OK)
+    {
+      return ret;
+    }
+  
+  if (st->must_reset_p)
+    {
+      lzw_buffer_put_code (&st->buffer, LZW_RESET_CODE);
+      st->must_reset_p = PDF_FALSE;
+    }
+  
+  while (!pdf_stm_buffer_eob_p (in) &&
+        !pdf_stm_buffer_full_p (out))
+    {
+      st->string.suffix = in->data [in->rp++];
+      if (lzw_dict_add (&st->dict, &st->string))
        {
-         lzw_buffer_put_code(&buffer, string.prefix);
-         string.prefix = string.suffix;
+         lzw_buffer_put_code (&st->buffer, st->string.prefix);
+         st->string.prefix = st->string.suffix;
 
-         if (buffer.maxval - data->early_change == dict.size)
+         if (st->buffer.maxval - st->early_change == st->dict.size)
            {
-             if (!lzw_buffer_inc_bitsize(&buffer))
+             if (!lzw_buffer_inc_bitsize(&st->buffer))
                {
-                 lzw_buffer_put_code(&buffer, LZW_RESET_CODE);
-                 lzw_buffer_set_bitsize(&buffer, MIN_BITSIZE);
-                 lzw_dict_reset(&dict);
+                 lzw_buffer_put_code (&st->buffer, LZW_RESET_CODE);
+                 lzw_buffer_set_bitsize (&st->buffer, LZW_MIN_BITSIZE);
+                 lzw_dict_reset (&st->dict);
                }
            }
        }
     }
-  
-  lzw_buffer_put_code(&buffer, string.prefix);
-  if (buffer.maxval - data->early_change == dict.size)
-    lzw_buffer_inc_bitsize(&buffer);
-  lzw_buffer_put_code(&buffer, LZW_EOD_CODE);
-  lzw_buffer_put_code(&buffer, 0);
-
-  /* Resize buffer to fit the data. */
-  *out_size = (buffer.curp - *out);
-  if ((*out = pdf_realloc(*out, *out_size)) == NULL)
-    {
-      *out_size = 0;
-      return PDF_ERROR;
-    }
-
-  return PDF_OK;
-}
-
-/* -- The decoder -- */
-
-/* Utility to write to the output. */
-
-typedef struct lzw_writer_s
-{
-  pdf_char_t* buf;
-  pdf_char_t* cur;
-  int writen;
-  int allocated;
-} lzw_writer_t;
-
-static int
-lzw_writer_init (lzw_writer_t* s,
-                int size)
-{
-  if ((s->buf = pdf_alloc(size)) == NULL)
-    {
-      return PDF_ERROR;
-    }
-
-  s->cur = s->buf;
-  s->writen = 0;
-  s->allocated = size;
-  
-  return PDF_OK;
-}
-
-static int
-lzw_writer_fit (lzw_writer_t* s)
-{
-  if ((s->buf = pdf_realloc(s->buf, s->writen)) == NULL)
-    {
-      return PDF_ERROR;
-    }
-
-  s->cur = s->buf + s->writen;
-  s->allocated = s->writen;
-  
-  return PDF_OK;
-}
-
-static int
-lzw_writer_put (lzw_writer_t* s,
-               pdf_char_t* data,
-               unsigned size)
-{
-  if (s->allocated < s->writen + size)
-    {
-      s->allocated = s->allocated * 2 + 1;
-      if ((s->buf = pdf_realloc(s->buf, s->allocated)) == NULL)
+
+  if (finish_p)
+    {
+      lzw_buffer_put_code (&st->buffer, st->string.prefix);
+      if ((st->buffer.maxval - st->early_change) == st->dict.size)
        {
-         return PDF_ERROR;
+         lzw_buffer_inc_bitsize(&st->buffer);
        }
-      s->cur = s->buf + s->writen;
-    }
-
-  memcpy(s->cur, data, size);
-  s->cur += size;
-  s->writen += size;
+      
+      lzw_buffer_put_code (&st->buffer, LZW_EOD_CODE);
+      lzw_buffer_put_code (&st->buffer, 0);
+      lzw_buffer_put_code (&st->buffer, 0);
+      
+      ret = PDF_EEOF;
+    }
+  else if (pdf_stm_buffer_full_p (out))
+    {
+      ret = PDF_ENOUTPUT;
+    }
+  else if (pdf_stm_buffer_eob_p (in))
+    {
+      ret = PDF_ENINPUT;
+    }
   
+  return ret;
+}
+
+pdf_status_t
+pdf_stm_f_lzwenc_dealloc_state (void *state)
+{
+  pdf_dealloc (state);
   return PDF_OK;
 }
 
-static void
-lzw_writer_destroy (lzw_writer_t* s)
-{
-  pdf_dealloc (s->buf);
-}
-
-static int
-pdf_stm_f_lzw_decode (pdf_stm_f_lzw_data_t data,
-                      pdf_char_t *in,
-                      pdf_stm_pos_t in_size,
-                      pdf_char_t **out,
-                      pdf_stm_pos_t *out_size)
-{
-  pdf_char_t dec_buf[MAX_DICTSIZE];
+/* -- THE DECODER -- */
+
+
+#define LZWDEC_CHECK(st, pos, what)                            \
+  do { (st)->state_pos = (pos);                                        \
+       if (((st)->tmp_ret = (what)) != PDF_OK)                 \
+        { return ((st)->tmp_ret); }                            \
+  } while (0);
+
+enum lzwdec_state
+  {
+    LZWDEC_STATE_START,
+    LZWDEC_STATE_CLEAN,
+    LZWDEC_STATE_WRITE,
+    LZWDEC_STATE_READ,
+    LZWDEC_STATE_LOOP_WRITE,
+    LZWDEC_STATE_LOOP_READ
+  };
+
+struct lzwdec_state_s
+{
+  /* cached params */
+  pdf_i32_t early_change;
+
+  /* state */
+  pdf_char_t  dec_buf [LZW_MAX_DICTSIZE];
   pdf_char_t* decoded;
-  unsigned dec_size;
+  unsigned    dec_size;
   
   unsigned new_code;
   unsigned old_code;
-   
-  lzw_buffer_t buffer;
-  lzw_dict_t dict;
-  lzw_writer_t writer;
-
-  *out = NULL;
-  *out_size = 0;
-
-  if (lzw_writer_init(&writer, in_size) == PDF_ERROR)
-    return PDF_ERROR;
-  
-  lzw_buffer_init(&buffer, in, in_size,  MIN_BITSIZE);
-  lzw_dict_init(&dict);
-  old_code = NULL_INDEX;
-  
-  do {
-    lzw_buffer_set_bitsize(&buffer, MIN_BITSIZE);
-    lzw_dict_reset(&dict);
-
-    do {
-      new_code = lzw_buffer_get_code(&buffer);
-    } while(new_code == LZW_RESET_CODE);
-    
-    if (new_code == NULL_INDEX)
-      {
-       lzw_writer_destroy(&writer);
-       return PDF_ERROR;
-      }
-    
-    if (new_code != LZW_EOD_CODE)
-      {
-       if (lzw_writer_put(&writer, (pdf_char_t*)&new_code, 1) == PDF_ERROR)
-         return PDF_ERROR;
-       
-       old_code = new_code;
-       new_code = lzw_buffer_get_code(&buffer);
-      }
-    
-    while (new_code != LZW_EOD_CODE && new_code != LZW_RESET_CODE)
-      {
-       decoded = &(dec_buf[MAX_DICTSIZE-2]);
-       
-       if (new_code < dict.size) /* Is new code in the dict? */
-         {
-           lzw_dict_decode(&dict, new_code, &decoded, &dec_size);
-           lzw_dict_fast_add(&dict, old_code, decoded[0]);
-         }
-       else
-         {
-           lzw_dict_decode(&dict, old_code, &decoded, &dec_size);
-           lzw_dict_fast_add(&dict, old_code, decoded[0]);
-           decoded[dec_size++] = decoded[0];
-         }
-
-       if (lzw_writer_put(&writer, decoded, dec_size) == PDF_ERROR)
-           return PDF_ERROR;
-
-       if (dict.size == buffer.maxval - 1 - data->early_change)
-         if (!lzw_buffer_inc_bitsize(&buffer));
-           /* break; We must wait for the reset code, don't reset yet. */
-       
-       old_code = new_code;
-       new_code = lzw_buffer_get_code(&buffer);
-       
-       if (new_code == NULL_INDEX)
-         {
-           lzw_writer_destroy(&writer);
-           return PDF_ERROR;
-         }
-      }
-  } while (new_code != LZW_EOD_CODE);
-  
-  if (lzw_writer_fit(&writer) == PDF_ERROR)
-    return PDF_ERROR;
-  
-  *out = writer.buf;
-  *out_size = writer.writen;
-
-  return PDF_OK;  
-}
-
-
-/* -- PDF Filter functions --*/
-
-int 
-pdf_stm_f_lzw_init (void **filter_data,
-                    void *conf_data)
-{
-  pdf_stm_f_lzw_data_t *data;
-  pdf_stm_f_lzw_conf_t conf;
-
-  data = (pdf_stm_f_lzw_data_t *) filter_data;
-  conf = (pdf_stm_f_lzw_conf_t) conf_data;
-
-  /* Create the private data storage */
-  *data =
-    (pdf_stm_f_lzw_data_t) pdf_alloc (sizeof(struct pdf_stm_f_lzw_data_s));
-  (*data)->mode = conf->mode;
-  (*data)->early_change = conf->early_change;
-
-  return PDF_OK;
-}
-
-int
-pdf_stm_f_lzw_apply (void *filter_data,
-                     pdf_char_t *in, pdf_stm_pos_t in_size,
-                     pdf_char_t **out, pdf_stm_pos_t *out_size)
-{
-  pdf_stm_f_lzw_data_t data;
-
-  data = (pdf_stm_f_lzw_data_t) filter_data;
-  switch (data->mode)
-    {
-    case PDF_STM_F_LZW_MODE_ENCODE:
-      {
-        return pdf_stm_f_lzw_encode (data, in, in_size, out, out_size);
-      }
-    case PDF_STM_F_LZW_MODE_DECODE:
-      {
-        return pdf_stm_f_lzw_decode (data, in, in_size, out, out_size);
-      }
+
+  /* flow managment */
+  enum lzwdec_state state_pos;
+  pdf_status_t tmp_ret;
+  
+  struct lzw_buffer_s buffer;
+  struct lzw_dict_s   dict;
+};
+typedef struct lzwdec_state_s* lzwdec_state_t;
+
+
+pdf_status_t
+pdf_stm_f_lzwdec_init (pdf_hash_t params,
+                      void **ext_state)
+{
+  pdf_i32_t* early_change;
+  lzwdec_state_t state;
+
+  state = pdf_alloc (sizeof (struct lzwdec_state_s));
+  if (!state)
+    {
+      return PDF_ERROR;
+    }
+  
+  if (pdf_hash_search (params, "EarlyChange", (void**) &early_change) != 
PDF_OK)
+    {
+      state->early_change = LZW_DEFAULT_EARLY_CHANGE;
+    }
+  else
+    {
+      state->early_change = *early_change;
+    }
+  
+  lzw_buffer_init (&state->buffer, LZW_MIN_BITSIZE);
+  lzw_dict_init (&state->dict);
+  state->old_code = LZW_NULL_INDEX;
+  state->decoded = state->dec_buf + (LZW_MAX_DICTSIZE-2);
+  state->dec_size = 0;
+  state->state_pos = LZWDEC_STATE_START;
+  state->tmp_ret = 0;
+    
+  *ext_state = state;
+  return PDF_OK;
+}
+
+pdf_status_t
+lzwdec_put_decoded (lzwdec_state_t st, pdf_stm_buffer_t out)
+{
+  pdf_status_t ret;
+  pdf_size_t to_write;
+  
+  ret = PDF_OK;
+
+  if (st->dec_size)
+    {
+      /* output the decoded string */
+      to_write = st->dec_size;
+      if (st->dec_size > (out->size - out->wp))
+       {
+         to_write = out->size - out->wp;
+         ret = PDF_ENOUTPUT;
+       }
+
+      memcpy (out->data + out->wp, st->decoded, to_write);
+      out->wp += to_write;
+      st->decoded += to_write;
+      st->dec_size -= to_write;
+    }
+
+  return ret;
+}
+
+pdf_status_t
+lzwdec_put_code (lzwdec_state_t st,
+                pdf_stm_buffer_t out,
+                unsigned long  code)
+{
+  if (pdf_stm_buffer_full_p (out))
+    {
+      return PDF_ENOUTPUT;
+    }
+  
+  out->data [out->wp++] = code & 0xFF;
+  
+  return PDF_OK;
+}
+
+pdf_status_t
+pdf_stm_f_lzwdec_apply (pdf_hash_t params,
+                       void *ext_state,
+                       pdf_stm_buffer_t in,
+                       pdf_stm_buffer_t out,
+                       pdf_bool_t finish_p)
+{
+  lzwdec_state_t st;
+
+  st = ext_state;
+  lzw_buffer_set (&st->buffer, in);
+
+  switch (st->state_pos)
+    {
+    case LZWDEC_STATE_START:
+      break;
+    case LZWDEC_STATE_CLEAN:
+      goto lzwdec_state_clean;
+    case LZWDEC_STATE_WRITE:
+      goto lzwdec_state_write;
+    case LZWDEC_STATE_READ:
+      goto lzwdec_state_read;
+    case LZWDEC_STATE_LOOP_WRITE:
+      goto lzwdec_state_loop_write;
+    case LZWDEC_STATE_LOOP_READ:
+      goto lzwdec_state_loop_read;
     default:
-      {
-        return PDF_ERROR;
-      }
+      break;
     }
   
-  /* Not reached */
+  do
+    {
+      /* need a reset */
+      lzw_buffer_set_bitsize (&st->buffer, LZW_MIN_BITSIZE);
+      lzw_dict_reset (&st->dict);
+      
+      do 
+       {
+       lzwdec_state_clean:
+         LZWDEC_CHECK (st, LZWDEC_STATE_CLEAN,
+                       lzw_buffer_get_code (&st->buffer, &st->new_code));
+       }
+      while (st->new_code == LZW_RESET_CODE);
+    
+      if (st->new_code != LZW_EOD_CODE)
+       {
+       lzwdec_state_write:
+         LZWDEC_CHECK (st, LZWDEC_STATE_WRITE,
+                       lzwdec_put_code (st, out, st->new_code));
+
+         st->old_code = st->new_code;
+       lzwdec_state_read:
+         LZWDEC_CHECK (st, LZWDEC_STATE_READ,
+                       lzw_buffer_get_code (&st->buffer, &st->new_code));  
+       }
+
+      while (st->new_code != LZW_EOD_CODE &&
+            st->new_code != LZW_RESET_CODE)
+       {
+         st->decoded = st->dec_buf + (LZW_MAX_DICTSIZE-2);
+
+         /* Is new code in the dict? */
+         if (st->new_code < st->dict.size)
+           {
+             lzw_dict_decode (&st->dict, st->new_code,
+                              &st->decoded, &st->dec_size);
+             lzw_dict_fast_add (&st->dict, st->old_code, st->decoded[0]);
+           }
+         else
+           {
+             lzw_dict_decode (&st->dict, st->old_code,
+                              &st->decoded, &st->dec_size);
+             lzw_dict_fast_add (&st->dict, st->old_code, st->decoded[0]);
+             st->decoded [st->dec_size++] = st->decoded [0];
+           }
+
+         /* output the decoded string */
+       lzwdec_state_loop_write:
+         LZWDEC_CHECK (st, LZWDEC_STATE_LOOP_WRITE,
+                       lzwdec_put_decoded (st, out));
+         
+         if (st->dict.size == st->buffer.maxval - 1 - st->early_change)
+           {
+             if (!lzw_buffer_inc_bitsize (&st->buffer));
+             /* break; We must wait for the reset code, don't reset yet. */
+           }
+         
+         /* get next code */
+         st->old_code = st->new_code;
+       lzwdec_state_loop_read:
+         LZWDEC_CHECK (st, LZWDEC_STATE_LOOP_READ,
+                       lzw_buffer_get_code (&st->buffer, &st->new_code));
+           
+       }
+    }
+  while (st->new_code != LZW_EOD_CODE);
+
+  st->state_pos = LZWDEC_STATE_START;
+  return PDF_EEOF;
 }
 
-int
-pdf_stm_f_lzw_dealloc (void **filter_data)
+pdf_status_t
+pdf_stm_f_lzwdec_dealloc_state (void *state)
 {
-  pdf_stm_f_lzw_data_t *data;
-
-  data = (pdf_stm_f_lzw_data_t *) filter_data;
-  pdf_dealloc (*data);
-
+  pdf_dealloc (state);
   return PDF_OK;
 }
 

=== modified file 'src/base/pdf-stm-f-lzw.h'
--- src/base/pdf-stm-f-lzw.h    2008-02-11 01:11:25 +0000
+++ src/base/pdf-stm-f-lzw.h    2008-10-12 12:34:46 +0000
@@ -27,54 +27,34 @@
 #define PDF_STM_F_LZW_H
 
 #include <config.h>
-#include <pdf-base.h>
-
-/* Configuration data */
-
-/* BEGIN PUBLIC */
-
-enum pdf_stm_f_lzw_mode_t
-{
-  PDF_STM_F_LZW_MODE_ENCODE,
-  PDF_STM_F_LZW_MODE_DECODE
-};
-
-/* END PUBLIC */
-
-struct pdf_stm_f_lzw_conf_s
-{
-  int mode;
-  int early_change;   /* An indication of when to increase the code
-                         length. If the value of this entry is 0, code
-                         length increases are postponed as long as
-                         possible. If the value is 1, code length
-                         increases occur one code early. This
-                         parameter is included because LZW sample code
-                         distributed by some vendors increases the
-                         code length one code earlier than necessary.
-                         
-                         Default value: 1 */
-};
-
-typedef struct pdf_stm_f_lzw_conf_s *pdf_stm_f_lzw_conf_t;
-
-/* Private data */
-
-struct pdf_stm_f_lzw_data_s
-{
-  int mode;
-  int early_change;
-};
-
-typedef struct pdf_stm_f_lzw_data_s *pdf_stm_f_lzw_data_t;
-
-/* Filter API implementation */
-
-int pdf_stm_f_lzw_init (void **filter_data, void *conf_data);
-int pdf_stm_f_lzw_apply (void *filter_data,
-                         pdf_char_t *in, pdf_stm_pos_t in_size,
-                         pdf_char_t **out, pdf_stm_pos_t *out_size);
-int pdf_stm_f_lzw_dealloc (void **filter_data);
+#include <pdf-types.h>
+#include <pdf-hash.h>
+#include <pdf-stm-buffer.h>
+
+/* Filter implementation API */
+
+pdf_status_t pdf_stm_f_lzwenc_init (pdf_hash_t params,
+                                   void **state);
+
+pdf_status_t pdf_stm_f_lzwenc_apply (pdf_hash_t params,
+                                    void *state,
+                                    pdf_stm_buffer_t in,
+                                    pdf_stm_buffer_t out,
+                                    pdf_bool_t finish_p);
+
+pdf_status_t pdf_stm_f_lzwenc_dealloc_state (void *state);
+
+pdf_status_t pdf_stm_f_lzwdec_init (pdf_hash_t params,
+                                   void **state);
+
+pdf_status_t pdf_stm_f_lzwdec_apply (pdf_hash_t params,
+                                    void *state,
+                                    pdf_stm_buffer_t in,
+                                    pdf_stm_buffer_t out,
+                                    pdf_bool_t finish_p);
+
+pdf_status_t pdf_stm_f_lzwdec_dealloc_state (void *state);
+
 
 #endif /* pdf_stm_f_lzw.h */
 

=== modified file 'src/base/pdf-stm-filter.c'
--- src/base/pdf-stm-filter.c   2008-10-05 15:08:05 +0000
+++ src/base/pdf-stm-filter.c   2008-10-12 12:34:46 +0000
@@ -111,6 +111,20 @@
         new->impl.dealloc_state_fn = pdf_stm_f_flatedec_dealloc_state;
         break;
       }
+    case PDF_STM_FILTER_LZW_ENC:
+      {
+        new->impl.init_fn = pdf_stm_f_lzwenc_init;
+        new->impl.apply_fn = pdf_stm_f_lzwenc_apply;
+        new->impl.dealloc_state_fn = pdf_stm_f_lzwenc_dealloc_state;
+        break;
+      }
+    case PDF_STM_FILTER_LZW_DEC:
+      {
+        new->impl.init_fn = pdf_stm_f_lzwdec_init;
+        new->impl.apply_fn = pdf_stm_f_lzwdec_apply;
+        new->impl.dealloc_state_fn = pdf_stm_f_lzwdec_dealloc_state;
+        break;
+      }
     default:
       {
         /* Shall not be reached, but makes the compiler happy */

=== modified file 'src/base/pdf-stm-filter.h'
--- src/base/pdf-stm-filter.h   2008-10-05 15:08:05 +0000
+++ src/base/pdf-stm-filter.h   2008-10-12 12:34:46 +0000
@@ -36,6 +36,7 @@
 #include <pdf-stm-f-ahex.h>
 #include <pdf-stm-f-rl.h>
 #include <pdf-stm-f-flate.h>
+#include <pdf-stm-f-lzw.h>
 
 /* BEGIN PUBLIC */
 
@@ -48,8 +49,9 @@
   PDF_STM_FILTER_RL_ENC,
   PDF_STM_FILTER_RL_DEC,
   PDF_STM_FILTER_FLATE_ENC,
-  PDF_STM_FILTER_FLATE_DEC
-
+  PDF_STM_FILTER_FLATE_DEC,
+  PDF_STM_FILTER_LZW_ENC,
+  PDF_STM_FILTER_LZW_DEC
 };
 
 /* Filter implementation */

=== modified file 'utils/pdf-filter.c'
--- utils/pdf-filter.c  2008-10-05 15:08:05 +0000
+++ utils/pdf-filter.c  2008-10-12 12:34:46 +0000
@@ -247,10 +247,10 @@
   *last_ret = ret;
 
   ret = pdf_stm_cfile_new (*read_mode ? stdin : stdout,
-                              0,
-                              cache_size, 
-                              *read_mode ? PDF_STM_READ : PDF_STM_WRITE,
-                              &stm);
+                          0,
+                          cache_size, 
+                          *read_mode ? PDF_STM_READ : PDF_STM_WRITE,
+                          &stm);
     
   if (ret != PDF_OK)
     {
@@ -326,10 +326,32 @@
           }
        case LZWENC_FILTER_ARG:
           {
+           ret = pdf_hash_new (NULL, &filter_params);
+            if (ret != PDF_OK)
+              {
+                pdf_error (ret, stderr, "while creating the ahexdec filter 
parameters hash table");
+                exit (1);
+              }
+
+            pdf_stm_install_filter (stm,
+                                    PDF_STM_FILTER_LZW_ENC,
+                                    filter_params);
+
             break;
           }
         case LZWDEC_FILTER_ARG:
           {
+            ret = pdf_hash_new (NULL, &filter_params);
+            if (ret != PDF_OK)
+              {
+                pdf_error (ret, stderr, "while creating the ahexdec filter 
parameters hash table");
+                exit (1);
+              }
+
+            pdf_stm_install_filter (stm,
+                                    PDF_STM_FILTER_LZW_DEC,
+                                    filter_params);
+
             break;
           }
 #ifdef HAVE_LIBZ

# Begin bundle
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
DA==

reply via email to

[Prev in Thread] Current Thread [Next in Thread]