pdf-devel
[Top][All Lists]
Advanced

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

[pdf-devel] Patch for Flate filter


From: gerel
Subject: [pdf-devel] Patch for Flate filter
Date: Sat, 04 Oct 2008 13:56:31 -0700 (PDT)

Hi guys,

Finally we have a block based filter working with cache size = 1. :-)

Here is a patch (tests included).

##
# Bazaar merge directive format 2 (Bazaar 0.90)
# revision_id: address@hidden
# target_branch: file:///home/gerel/PROJECTS/libgnupdf/trunk/
# testament_sha1: 1d0173be6a538ca8a55480ec4179e1cc93002343
# timestamp: 2008-10-04 17:46:50 -0300
# base_revision_id: address@hidden
# 
# Begin patch
=== modified file 'ChangeLog'
--- ChangeLog   2008-10-04 18:44:47 +0000
+++ ChangeLog   2008-10-04 20:36:54 +0000
@@ -1,11 +1,32 @@
 2008-10-04  Gerardo E. Gidoni  <address@hidden>
 
+       * doc/gnupdf-tsd.texi: added flate filter tests.
+
+       * torture/unit/base/stm/pdf-stm-read.c: same.
+
+       * torture/unit/base/stm/pdf-stm-write.c: same.
+
+       * src/Makefile.am: added flate filter source files.
+
+       * src/base/pdf-stm-f-flate.c: adapted for new stream API.
+
+       * src/base/pdf-stm-f-flate.h: same.
+
+       * src/base/pdf-stm-filter.c: added flate filter.
+
+       * src/base/pdf-stm-filter.h: same.
+
+       * utils/pdf-filter.c: same.
+
+2008-10-04  Gerardo E. Gidoni  <address@hidden>
+
        * src/base/pdf-stm-f-rl.c: adapted to new filter API.
 
        * torture/unit/base/stm/pdf-stm-read.c: same.
 
        * torture/unit/base/stm/pdf-stm-write.c: same.
 
+
 2008-10-04  Jose E. Marchesi  <address@hidden>
 
        * doc/pdf-filter.1: Generated.

=== modified file 'doc/gnupdf-tsd.texi'
--- doc/gnupdf-tsd.texi 2008-09-28 14:00:42 +0000
+++ doc/gnupdf-tsd.texi 2008-10-01 02:14:52 +0000
@@ -277,6 +277,16 @@
 @end table
 @end deffn
 
address@hidden Test pdf_stm_read_009
+Create a memory-based reading stream and attach a flate filter
+decoder to it.
address@hidden @strong
address@hidden Success condition
+The decoded data should be correct.
address@hidden table
address@hidden deffn
+
+
 @node pdf_stm_read_char
 @subsubsection pdf_stm_read_char
 
@@ -405,6 +415,15 @@
 @end deffn
 
 
address@hidden Test pdf_stm_write_007
+Create a memory-based writing stream and attach a flate filter
+encoder to it.
address@hidden @strong
address@hidden Success condition
+The encoded data should be correct.
address@hidden table
address@hidden deffn
+
 @node Text Module
 @subsection Text Module
 

=== modified file 'src/Makefile.am'
--- src/Makefile.am     2008-09-27 22:28:27 +0000
+++ src/Makefile.am     2008-10-01 21:19:40 +0000
@@ -44,11 +44,11 @@
                      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 
 
-# if ZLIB
-#  STM_MODULE_SOURCES += base/pdf-stm-f-flate.c base/pdf-stm-f-flate.h
-#endif
+if ZLIB
+  STM_MODULE_SOURCES += base/pdf-stm-f-flate.c base/pdf-stm-f-flate.h
+endif
 
 TEXT_MODULE_SOURCES = base/pdf-text-context.c base/pdf-text-context.h \
                       base/pdf-text-encoding.c base/pdf-text-encoding.h \

=== modified file 'src/base/pdf-stm-f-flate.c'
--- src/base/pdf-stm-f-flate.c  2008-03-05 12:32:04 +0000
+++ src/base/pdf-stm-f-flate.c  2008-10-04 20:46:45 +0000
@@ -1,4 +1,4 @@
-/* -*- mode: C -*- Time-stamp: "08/03/05 12:24:36 jemarch"
+/* -*- mode: C -*- Time-stamp: "2008-10-04 17:46:35 gerel"
  *
  *       File:         pdf-stm-f-flate.c
  *       Date:         Tue Jul 10 23:44:00 2007
@@ -26,172 +26,331 @@
 
 #include <stdio.h>
 #include <string.h>
-#include <zlib.h>
 #include <pdf-alloc.h>
-#include <pdf-base.h>
+#include <pdf-hash.h>
 #include <pdf-stm-f-flate.h>
 
 
-static int pdf_stm_f_flate_encode (pdf_char_t *in, pdf_stm_pos_t in_size,
-                                   pdf_char_t **out, pdf_stm_pos_t *out_size);
-static int pdf_stm_f_flate_decode (pdf_char_t *in, pdf_stm_pos_t in_size,
-                                   pdf_char_t **out, pdf_stm_pos_t *out_size);
-
-int
-pdf_stm_f_flate_init (void **filter_data,
-                     void *conf_data)
-{
-  pdf_stm_f_flate_data_t *data;
-  pdf_stm_f_flate_conf_t conf;
-
-  data = (pdf_stm_f_flate_data_t *) filter_data;
-  conf = (pdf_stm_f_flate_conf_t) conf_data;
-
-  /* Create the private data storage */
-  *data =
-    (pdf_stm_f_flate_data_t) pdf_alloc (sizeof(struct pdf_stm_f_flate_data_s));
-  (*data)->mode = conf->mode;
-
-  return PDF_OK;
-}
-
-int
-pdf_stm_f_flate_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_flate_data_t data;
-
-  data = (pdf_stm_f_flate_data_t) filter_data;
-  switch (data->mode)
-    {
-    case PDF_STM_F_FLATE_MODE_ENCODE:
-      {
-        return pdf_stm_f_flate_encode (in, in_size, out, out_size);
-      }
-    case PDF_STM_F_FLATE_MODE_DECODE:
-      {
-        return pdf_stm_f_flate_decode (in, in_size, out, out_size);
-      }
-    default:
-      {
+static int deflate_inbuf (pdf_stm_f_flate_t st, pdf_stm_buffer_t out,
+                          int flush);
+static pdf_status_t deflate_inbuf_return (pdf_stm_f_flate_t st,
+                                          pdf_stm_buffer_t out,
+                                          pdf_bool_t finish_p);
+
+pdf_status_t
+pdf_stm_f_flateenc_init (pdf_hash_t params, void **state)
+{
+  pdf_status_t ret;
+  pdf_stm_f_flate_t filter_state;
+
+  filter_state = pdf_alloc (sizeof (struct pdf_stm_f_flate_s));
+
+  if (state == NULL)
+    {
+      ret = PDF_EBADDATA;
+    }
+  else if (filter_state == NULL)
+    {
+      ret = PDF_ENOMEM;
+    }
+  else
+    {
+      /* Initialize fields */
+      filter_state->stream.zalloc = Z_NULL;
+      filter_state->stream.zfree = Z_NULL;
+      filter_state->stream.opaque = Z_NULL;
+      filter_state->writing_p = PDF_FALSE;
+      filter_state->to_write = 0;
+      filter_state->incnt = 0;
+      filter_state->outcnt = 0;
+      filter_state->zret = Z_OK;
+
+      if (deflateInit (&(filter_state->stream), Z_DEFAULT_COMPRESSION) != Z_OK)
+        {
+          ret = PDF_ERROR;
+        }
+      else
+        {
+          *state = (void *) filter_state;
+          ret = PDF_OK;
+        }
+    }
+
+  return ret;
+}
+
+
+pdf_status_t
+pdf_stm_f_flatedec_init (pdf_hash_t params, void **state)
+{
+  pdf_status_t ret;
+  pdf_stm_f_flate_t filter_state;
+
+  filter_state = pdf_alloc (sizeof (struct pdf_stm_f_flate_s));
+
+  if (state == NULL)
+    {
+      ret = PDF_EBADDATA;
+    }
+  else if (filter_state == NULL)
+    {
+      ret = PDF_ENOMEM;
+    }
+  else
+    {
+      /* Initialize fields */
+      filter_state->stream.zalloc = Z_NULL;
+      filter_state->stream.zfree = Z_NULL;
+      filter_state->stream.opaque = Z_NULL;
+      filter_state->stream.avail_in = 0;
+      filter_state->stream.next_in = Z_NULL;
+      filter_state->writing_p = PDF_FALSE;
+      filter_state->to_write = 0;
+      filter_state->incnt = 0;
+      filter_state->outcnt = 0;
+      filter_state->zret = Z_OK;
+
+      if (inflateInit (&(filter_state->stream)) != Z_OK)
+        {
+          ret = PDF_ERROR;
+        }
+      else
+        {
+          *state = (void *) filter_state;
+          ret = PDF_OK;
+        }
+    }
+
+  return ret;
+
+}
+
+
+pdf_status_t
+pdf_stm_f_flateenc_apply (pdf_hash_t params, void *state, pdf_stm_buffer_t in,
+                          pdf_stm_buffer_t out, pdf_bool_t finish_p)
+{
+  pdf_stm_f_flate_t st;
+  int flush;
+
+  st = (pdf_stm_f_flate_t) state;
+
+
+  /* Fill the input CHUNK  */
+  if (!st->writing_p)
+    {
+      while (st->incnt < PDF_STM_F_FLATE_CHUNK && !pdf_stm_buffer_eob_p(in))
+        {
+          st->inbuf[st->incnt] = in->data[in->rp];
+          st->incnt++;
+          in->rp++;
+        }
+    }
+  else
+    {
+      return (deflate_inbuf_return (st, out, finish_p));
+    }
+
+    
+  /* If more data may come and the input CHUNK has space, ask for it. */
+  if (!finish_p && st->incnt < PDF_STM_F_FLATE_CHUNK)
+    {
+      return PDF_ENINPUT;
+    }
+
+  /* 
+   * Now we have the input CHUNK full or finish_p is set,
+   * we deflate and write to out.
+   */ 
+  return (deflate_inbuf_return (st, out, finish_p));
+}
+
+
+pdf_status_t
+pdf_stm_f_flatedec_apply (pdf_hash_t params, void *state, pdf_stm_buffer_t in,
+                          pdf_stm_buffer_t out, pdf_bool_t finish_p)
+{
+  pdf_stm_f_flate_t st;
+
+  st = (pdf_stm_f_flate_t) state;
+
+  /* Fill the input CHUNK */
+  if (!st->writing_p)
+    {
+      while (st->incnt < PDF_STM_F_FLATE_CHUNK && !pdf_stm_buffer_eob_p(in))
+        {
+          st->inbuf[st->incnt] = in->data[in->rp];
+          st->incnt++;
+          in->rp++;
+        }
+    }
+  else
+    {
+      /* 
+       * Not nice, but keeps the writing process code clear.
+       * Notice that the labeled code is inside a while loop,
+       * so I feel that avoiding this goto won't bring us better code.
+       */
+      goto writing;
+    }
+
+  if (st->incnt == 0)
+    {
+      return PDF_ENINPUT;
+    }
+
+  /* we inflate and write to out */
+  st->stream.avail_in = st->incnt;
+  st->stream.next_in = st->inbuf;
+  do {
+    st->stream.avail_out = PDF_STM_F_FLATE_CHUNK;
+    st->stream.next_out = st->outbuf;
+    st->outcnt = 0;
+
+    st->zret = inflate(&(st->stream), Z_NO_FLUSH);
+    if (st->zret == Z_STREAM_ERROR || st->zret == Z_NEED_DICT ||
+        st->zret == Z_DATA_ERROR || st->zret == Z_MEM_ERROR)
+      {
+        /* should not be reached */
+        inflateEnd(&(st->stream));
         return PDF_ERROR;
       }
-    }
-  
-  /* Not reached */
-}
-
-int
-pdf_stm_f_flate_dealloc (void **filter_data)
-{
-  pdf_stm_f_flate_data_t *data;
-
-  data = (pdf_stm_f_flate_data_t *) filter_data;
-  pdf_dealloc (*data);
-
-  return PDF_OK;
-}
+
+    st->to_write = PDF_STM_F_FLATE_CHUNK - st->stream.avail_out;
+
+  writing:
+    while (st->outcnt < st->to_write && !pdf_stm_buffer_full_p(out))
+      {
+        out->data[out->wp] = st->outbuf[st->outcnt];
+        out->wp++;
+        st->outcnt++;
+      }
+    if (pdf_stm_buffer_full_p(out))
+      {
+        st->writing_p = PDF_TRUE;
+        return PDF_ENOUTPUT;
+      }
+  } while (st->stream.avail_out == 0);
+
+  if (st->zret == Z_STREAM_END)
+    {
+      return PDF_EEOF;
+    }
+  /* the input CHUNK now is empty, if needed, ask for input */
+  st->writing_p = PDF_FALSE;
+  st->incnt = 0;
+  if (pdf_stm_buffer_eob_p(in))
+    {
+      return PDF_ENINPUT;
+    }
+
+  return PDF_OK;
+}
+
+
+
+pdf_status_t
+pdf_stm_f_flatedec_dealloc_state (void *state)
+{
+  pdf_stm_f_flate_t st = state;
+  inflateEnd(&(st->stream));
+  pdf_dealloc (state);
+  return PDF_OK;
+}
+
+pdf_status_t
+pdf_stm_f_flateenc_dealloc_state (void *state)
+{
+  pdf_dealloc (state);
+  return PDF_OK;
+}
+
 
 /* Private functions */
 
 static int
-pdf_stm_f_flate_encode (pdf_char_t *in, 
-                        pdf_stm_pos_t in_size,
-                        pdf_char_t **out,
-                        pdf_stm_pos_t *out_size)
-{
-  unsigned long compressed_bound;
+deflate_inbuf (pdf_stm_f_flate_t st, pdf_stm_buffer_t out, int flush)
+{
+  if (st->writing_p)
+    {
+      /* 
+       * Not nice, but keeps the writing process code clear.
+       * Notice that the labeled code is inside a while loop,
+       * so I feel that avoiding this goto won't bring us better code.
+       */
+      goto writing;
+    }
+
+  st->stream.avail_in = st->incnt;
+  st->stream.next_in = st->inbuf;
+  do {
+    st->stream.avail_out = PDF_STM_F_FLATE_CHUNK;
+    st->stream.next_out = st->outbuf;
+    st->outcnt = 0;
+
+    st->zret = deflate(&(st->stream), flush);
+    if (st->zret == Z_STREAM_ERROR)
+      {
+        /* should not be reached */
+        deflateEnd (&(st->stream));
+        return -1;
+      }
+
+    st->to_write = PDF_STM_F_FLATE_CHUNK - st->stream.avail_out;
+
+  writing:
+
+    while (st->outcnt < st->to_write && !pdf_stm_buffer_full_p(out))
+      {
+        out->data[out->wp++] = st->outbuf[st->outcnt];
+        st->outcnt++;
+      }
+    if (pdf_stm_buffer_full_p(out))
+      {
+        st->writing_p = PDF_TRUE;
+        return 1;
+      }
+  } while (st->stream.avail_out == 0);
+
+  st->writing_p = PDF_FALSE;
+  return 0;
+}
+
+
+static pdf_status_t
+deflate_inbuf_return (pdf_stm_f_flate_t st, pdf_stm_buffer_t out,
+                      pdf_bool_t finish_p)
+{
   int ret;
 
-  /* Allocate memory for destination buffer */
-  compressed_bound = compressBound (in_size);
-  *out_size = compressed_bound;
-  *out = (pdf_char_t *) pdf_alloc (*out_size);
-
-  /* Compress input */
-  ret = compress (*out, 
-                  (unsigned long *) out_size,
-                  in,
-                  in_size);
-
-  if (ret == Z_OK)
-    {
-      /* Adjust memory to really used  and return */
-      *out = (pdf_char_t *) pdf_realloc (*out,
-                                         *out_size);
+  if (finish_p)
+    {
+      ret = deflate_inbuf(st, out, Z_FINISH);
+    }
+  else
+    {
+      ret = deflate_inbuf(st, out, Z_NO_FLUSH);
+    }
+
+  if (ret < 0)
+    {
+      return PDF_ERROR;
+    }
+  else if (ret > 0)
+    {
+      return PDF_ENOUTPUT;
+    }
+  else if (finish_p)
+    {
+      deflateEnd (&(st->stream));
+      return PDF_EEOF;
+    }
+  else
+    {
+      /* the input CHUNK now is empty */
+      st->incnt = 0;
       return PDF_OK;
     }
-  else
-    {
-      /* Z_MEM_ERROR or Z_BUF_ERROR happened.  In any case, return
-         reporting that the filter application failed. */
-      return PDF_FALSE;
-    }
-
-  /* Not reached */
-}
-
-#define CHUNK 16384
-
-static int
-pdf_stm_f_flate_decode (pdf_char_t *in,
-                        pdf_stm_pos_t in_size,
-                        pdf_char_t **out,
-                        pdf_stm_pos_t *out_size)
-{
-  z_stream zstm;
-  int ret;
-  pdf_char_t out_aux[16384];
-  pdf_stm_pos_t nchunks;
-
-  zstm.zalloc = Z_NULL;
-  zstm.zfree = Z_NULL;
-  zstm.opaque = Z_NULL;
-  zstm.avail_in = in_size;
-  zstm.next_in = in;
-
-  inflateInit (&zstm);
-
-  *out_size = 0;
-  *out = NULL;
-  nchunks = 0;
-  do
-    {
-      zstm.avail_out = CHUNK;
-      zstm.next_out = out_aux;
-      
-      ret = inflate (&zstm, Z_NO_FLUSH);
-
-      switch (ret)
-        {
-        case Z_NEED_DICT:
-        case Z_DATA_ERROR:
-        case Z_MEM_ERROR:
-          {
-            goto error;
-          }
-        }
-          
-      *out_size =  *out_size + (CHUNK - zstm.avail_out);
-      *out = (pdf_char_t *) pdf_realloc (*out,
-                                         *out_size);
-
-      memcpy (*out + (nchunks * CHUNK),
-              out_aux,
-              CHUNK - zstm.avail_out);
-
-      nchunks++;
-
-    } while (ret != Z_STREAM_END);
-
-  ret = inflateEnd (&zstm);
-  
-  return PDF_OK;
-
- error:
-  (void) inflateEnd (&zstm);
-  return PDF_ERROR;
 }
 
 

=== modified file 'src/base/pdf-stm-f-flate.h'
--- src/base/pdf-stm-f-flate.h  2008-02-11 01:11:25 +0000
+++ src/base/pdf-stm-f-flate.h  2008-10-01 21:19:40 +0000
@@ -1,4 +1,4 @@
-/* -*- mode: C -*- Time-stamp: "08/02/11 01:04:11 jemarch"
+/* -*- mode: C -*- Time-stamp: "2008-10-01 18:16:15 gerel"
  *
  *       File:         pdf-stm-f-flate.h
  *       Date:         Tue Jul 10 23:39:27 2007
@@ -27,43 +27,53 @@
 #define PDF_STM_F_FLATE_H
 
 #include <config.h>
-#include <pdf-base.h>
-
-/* Filter configuration */
-
-/* BEGIN PUBLIC */
-
-enum pdf_stm_f_flate_mode_t
-{
-  PDF_STM_F_FLATE_MODE_ENCODE,
-  PDF_STM_F_FLATE_MODE_DECODE
-};
-
-/* END PUBLIC */
-
-struct pdf_stm_f_flate_conf_s
-{
-  int mode;
-};
-
-typedef struct pdf_stm_f_flate_conf_s *pdf_stm_f_flate_conf_t;
-
-/* Private data */
-
-struct pdf_stm_f_flate_data_s
-{
-  int mode;
-};
-
-typedef struct pdf_stm_f_flate_data_s *pdf_stm_f_flate_data_t;
+#include <pdf-hash.h>
+#include <pdf-stm-buffer.h>
+#include <zlib.h>
+
+
+
+ /* 
+  * As read in the zlib documentation, our cache size must be at least 0.1%
+  * larger than the CHUNK size, plus 12 bytes.
+  * We assume that our cache size is of 4096 bytes.
+  */
+#define PDF_STM_F_FLATE_CHUNK 1024
+
+struct pdf_stm_f_flate_s
+{
+  z_stream stream;
+  int zret;
+  pdf_size_t incnt, outcnt, to_write;
+  pdf_bool_t writing_p;
+  pdf_char_t inbuf[PDF_STM_F_FLATE_CHUNK], outbuf[PDF_STM_F_FLATE_CHUNK];
+};
+
+typedef struct pdf_stm_f_flate_s * pdf_stm_f_flate_t;
+
 
 /* Filter API implementation */
 
-int pdf_stm_f_flate_init (void **filter_data, void *conf_data);
-int pdf_stm_f_flate_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_flate_dealloc (void **filter_data);
+pdf_status_t pdf_stm_f_flatedec_init (pdf_hash_t params,
+                                   void **state);
+
+pdf_status_t pdf_stm_f_flatedec_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_flateenc_init (pdf_hash_t params,
+                                   void **state);
+
+pdf_status_t pdf_stm_f_flateenc_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_flatedec_dealloc_state (void *state);
+pdf_status_t pdf_stm_f_flateenc_dealloc_state (void *state);
 
 
 #endif /* pdf_stm_f_flate.h */

=== modified file 'src/base/pdf-stm-filter.c'
--- src/base/pdf-stm-filter.c   2008-10-04 12:31:11 +0000
+++ src/base/pdf-stm-filter.c   2008-10-04 19:29:59 +0000
@@ -1,4 +1,4 @@
-/* -*- mode: C -*- Time-stamp: "08/10/04 04:35:11 jemarch"
+/* -*- mode: C -*- Time-stamp: "2008-10-04 16:25:56 gerel"
  *
  *       File:         pdf-stm-filter.c
  *       Date:         Thu Jun 12 22:13:31 2008
@@ -97,6 +97,20 @@
         new->impl.dealloc_state_fn = pdf_stm_f_rldec_dealloc_state;
         break;
       }
+    case PDF_STM_FILTER_FLATE_ENC:
+      {
+        new->impl.init_fn = pdf_stm_f_flateenc_init;
+        new->impl.apply_fn = pdf_stm_f_flateenc_apply;
+        new->impl.dealloc_state_fn = pdf_stm_f_flateenc_dealloc_state;
+        break;
+      }
+    case PDF_STM_FILTER_FLATE_DEC:
+      {
+        new->impl.init_fn = pdf_stm_f_flatedec_init;
+        new->impl.apply_fn = pdf_stm_f_flatedec_apply;
+        new->impl.dealloc_state_fn = pdf_stm_f_flatedec_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-04 12:31:11 +0000
+++ src/base/pdf-stm-filter.h   2008-10-04 19:29:59 +0000
@@ -1,4 +1,4 @@
-/* -*- mode: C -*- Time-stamp: "08/10/04 04:34:08 jemarch"
+/* -*- mode: C -*- Time-stamp: "2008-10-04 16:26:39 gerel"
  *
  *       File:         pdf-stm-filter.h
  *       Date:         Thu Jun 12 22:05:06 2008
@@ -35,6 +35,7 @@
 #include <pdf-stm-f-null.h>
 #include <pdf-stm-f-ahex.h>
 #include <pdf-stm-f-rl.h>
+#include <pdf-stm-f-flate.h>
 
 /* BEGIN PUBLIC */
 
@@ -45,7 +46,10 @@
   PDF_STM_FILTER_AHEX_ENC,
   PDF_STM_FILTER_AHEX_DEC,
   PDF_STM_FILTER_RL_ENC,
-  PDF_STM_FILTER_RL_DEC
+  PDF_STM_FILTER_RL_DEC,
+  PDF_STM_FILTER_FLATE_ENC,
+  PDF_STM_FILTER_FLATE_DEC
+
 };
 
 /* Filter implementation */

=== modified file 'torture/unit/base/stm/pdf-stm-read.c'
--- torture/unit/base/stm/pdf-stm-read.c        2008-10-04 18:44:47 +0000
+++ torture/unit/base/stm/pdf-stm-read.c        2008-10-04 20:36:54 +0000
@@ -1,4 +1,4 @@
-/* -*- mode: C -*- Time-stamp: "2008-10-04 15:42:24 gerel"
+/* -*- mode: C -*- Time-stamp: "2008-10-04 16:38:06 gerel"
  *
  *       File:         pdf-stm-read.c
  *       Date:         Sat Sep 20 15:20:17 2008
@@ -289,6 +289,9 @@
 }
 END_TEST
 
+
+
+
 /*
  * Test: pdf_stm_read_005
  * Description:
@@ -538,6 +541,84 @@
 
 
 /*
+ * Test: pdf_stm_read_009
+ * Description:
+ *   Create a memory-based reading stream and attach a flate filter
+ *   decoder to it.
+ * Success condition:
+ *   The decoded data should be correct.
+ */
+START_TEST (pdf_stm_read_009)
+{
+  pdf_status_t ret;
+  pdf_hash_t params;
+  pdf_stm_t stm;
+  pdf_size_t buf_size, total=1059,read;
+  pdf_char_t *buf, *decoded=
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990";
+  pdf_char_t *dataux, *encoded =
+    "\x78\x9c\x33\x34\x32\x32\x36\x36\x36\x01\x02\x53\x10\x30\x03\x03"
+    "\x73\x08\xb0\x80\x02\x4b\x18\x30\x30\x1c\x55\x3d\xaa\x7a\x54\xf5"
+    "\x88\x52\xcd\x00\x00\xe1\x0b\xdf\xfc";
+
+  /* Writing stream */
+  /* Create a memory buffer */
+  buf_size = 2000;
+  buf = pdf_alloc (buf_size);
+  fail_if(buf == NULL);
+  /* Create the stream */
+  ret = pdf_stm_mem_new (encoded,
+                         41,
+                         1,
+                         PDF_STM_READ,
+                         &stm);
+  fail_if(ret != PDF_OK);
+  /* Create the filter */
+  fail_if (pdf_stm_install_filter (stm, PDF_STM_FILTER_FLATE_DEC, params) !=
+           PDF_OK);
+
+  read = 0;
+  total = 1059;
+  dataux = buf;
+  while (total > 0)
+    {
+      read = pdf_stm_read (stm, dataux, total);
+      dataux = dataux + read;
+      total -= read;
+    }
+
+  fail_if (memcmp (buf, decoded, 1059) != 0);
+  /* Destroy the stream */
+  pdf_stm_destroy (stm);
+  pdf_dealloc (buf);
+
+}
+END_TEST
+
+
+/*
  * Test case creation function
  */
 TCase *
@@ -553,6 +634,8 @@
   tcase_add_test(tc, pdf_stm_read_006);
   tcase_add_test(tc, pdf_stm_read_007);
   tcase_add_test(tc, pdf_stm_read_008);
+  tcase_add_test(tc, pdf_stm_read_009);
+
 
   return tc;
 }

=== modified file 'torture/unit/base/stm/pdf-stm-write.c'
--- torture/unit/base/stm/pdf-stm-write.c       2008-10-04 18:44:47 +0000
+++ torture/unit/base/stm/pdf-stm-write.c       2008-10-04 20:36:54 +0000
@@ -1,4 +1,4 @@
-/* -*- mode: C -*- Time-stamp: "2008-10-04 15:38:46 gerel"
+/* -*- mode: C -*- Time-stamp: "2008-10-04 17:29:25 gerel"
  *
  *       File:         pdf-stm-write.c
  *       Date:         Sun Sep 21 16:37:27 2008
@@ -347,6 +347,86 @@
 }
 END_TEST
 
+
+/*
+ * Test: pdf_stm_write_007
+ * Description:
+ *   Create a memory-based reading stream and attach a flate filter
+ *   encoder to it.
+ * Success condition:
+ *   The decoded data should be correct.
+ */
+START_TEST (pdf_stm_write_007)
+{
+  pdf_status_t ret;
+  pdf_hash_t params;
+  pdf_stm_t stm;
+  pdf_size_t buf_size, total,written;
+  pdf_char_t *buf, *decoded=
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990" \
+    "1223334444555556666667777777888888889999999990";
+  pdf_char_t *dataux, *encoded =
+    "\x78\x9c\x33\x34\x32\x32\x36\x36\x36\x01\x02\x53\x10\x30\x03\x03"
+    "\x73\x08\xb0\x80\x02\x4b\x18\x30\x30\x1c\x55\x3d\xaa\x7a\x54\xf5"
+    "\x88\x52\xcd\x00\x00\xe1\x0b\xdf\xfc";
+
+  /* Writing stream */
+  /* Create a memory buffer */
+  buf_size = 100;
+  buf = pdf_alloc (buf_size);
+  fail_if(buf == NULL);
+  /* Create the stream */
+  ret = pdf_stm_mem_new (buf,
+                         buf_size,
+                         1,
+                         PDF_STM_WRITE,
+                         &stm);
+  fail_if(ret != PDF_OK);
+  /* Create the filter */
+  fail_if (pdf_stm_install_filter (stm, PDF_STM_FILTER_FLATE_ENC, params) !=
+           PDF_OK);
+
+  written = 0;
+  total = 1059;
+  dataux = decoded;
+  while (total > 0)
+    {
+      written = pdf_stm_write (stm, dataux, total);
+      dataux = dataux + written;
+      total -= written;
+    }
+  pdf_stm_flush (stm, PDF_TRUE);
+
+  fail_if (memcmp (buf, encoded, 41) != 0);
+  /* Destroy the stream */
+  pdf_stm_destroy (stm);
+  pdf_dealloc (buf);
+
+}
+END_TEST
+
+
 /*
  * Test case creation function
  */
@@ -361,6 +441,7 @@
   tcase_add_test(tc, pdf_stm_write_004);
   tcase_add_test(tc, pdf_stm_write_005);
   tcase_add_test(tc, pdf_stm_write_006);
+  tcase_add_test(tc, pdf_stm_write_007);
   
   return tc;
 }

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


###


-gerel




reply via email to

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