pdf-devel
[Top][All Lists]
Advanced

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

[pdf-devel] Streams solution proposal


From: Juan Pedro Bolivar Puente
Subject: [pdf-devel] Streams solution proposal
Date: Fri, 03 Oct 2008 00:05:48 +0200
User-agent: Mozilla-Thunderbird 2.0.0.16 (X11/20080724)

Hi,

I attach my proposal of streams problems solution. It does not contain
the promised self-testing bash script, as I'm a bit tired and have to
weak up early, but will do it tomorrow :)


The main problem with the old implementation was that it didn't take
into account that a filter can generate less data than it consumes and
vice-versa. My approach to solve this is to use circular buffers as
cache between buffers.

With a circular buffer, a filter can just "take as much data as it can"
and write "as much data as it can". Appart from the change of the kind
of buffers, this has some small consequences on the filters
implementation: they must not return PDF_EEOF when the input buffer is
empty withouth having filled the output buffer, it can simply mean that
the filter chain reduces the amount of data.

There are many fixes all around the code. I have added comments tagged
as [FIX], [NOTE] and [BUG] commenting these things. If you need more
explanations please ask.


As I said on another email, I have created a new backend that takes a
FILE*. It can not seek well, but can be easily solved probably. The
pdf-filter utility has been rewrited so it is more versatile and makes a
sensible use of the new STM API, as it's incorrect use of the stm api
was one of the bugs that lead the tests to fail.


I think that this implementation still needs quite some polishing, but
it is still much more stable than the old one. I still have to try the
new jemarch implementation, but it seems quite good.


As I said, I don't worry if this never ever gets to trunk, but well, I
still think that you should take a look at it :-)

Best,
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: 844003ae49758029e5f0d379ac048436b6cbb215
# timestamp: 2008-10-02 23:52:17 +0200
# base_revision_id: address@hidden
# 
# Begin patch
=== modified file 'AUTHORS'
--- AUTHORS     2008-09-28 10:39:11 +0000
+++ AUTHORS     2008-10-02 21:51:49 +0000
@@ -118,8 +118,16 @@
 
 Juan Pedro Bolívar Puente: wrote src/base/pdf-stm-f-pred.c
   src/base/pdf-stm-f-pred.h src/base/pdf-stm-f-lzw.c
-  src/base/pdf-stm-f-lzw.h 
+  src/base/pdf-stm-f-lzw.h stc/base/pdf-ring-buffer.h
+  src/base/pdf-ring-buffer.c
 and changed utils/pdf-filter.c utils/pdf-filter.h
+  src/base/pdf-stm-f-null.h src/base/pdf-stm-f-null.c
+  src/base/pdf-stm-buffer.h src/base/pdf-stm-buffer.c
+  src/base/pdf-stm-filter.h src/base/pdf-stm-filter.c
+  src/base/pdf-stm-be.h src/base/pdf-stm-be.c
+  src/base/pdf-stm-f-ahex.h src/base/pdf-stm-ahex.c
+  src/base/pdf-stm-f-rl.h src/base/pdf-stm-rl.c
+  src/Makefile.am
 
 Karl Berry: changed doc/gnupdf.texi doc/gnupdf-utils.texi
   doc/Makefile.am 

=== modified file 'src/Makefile.am'
--- src/Makefile.am     2008-09-27 22:28:27 +0000
+++ src/Makefile.am     2008-10-02 21:51:49 +0000
@@ -70,6 +70,8 @@
                        base/pdf-crypt-c-aesv2.c base/pdf-crypt-c-aesv2.h \
                        base/pdf-crypt-c-v2.c base/pdf-crypt-c-v2.h
 
+RING_BUFFER_SOURCES = base/pdf-ring-buffer.c base/pdf-ring-buffer.h
+
 BASE_LAYER_SOURCES = base/pdf-base.c base/pdf-base.h \
                      $(ALLOC_MODULE_SOURCES) \
                      $(TYPES_MODULE_SOURCES) \
@@ -80,7 +82,8 @@
                      $(TEXT_MODULE_SOURCES) \
                      $(HASH_MODULE_SOURCES) \
                      $(TIME_MODULE_SOURCES) \
-                     $(CRYPT_MODULE_SOURCES)
+                     $(CRYPT_MODULE_SOURCES) \
+                    $(RING_BUFFER_SOURCES)
 
 
 # Library sources
@@ -118,6 +121,7 @@
               base/pdf-time.h \
               base/pdf-text.h \
               base/pdf-fsys.h \
+             base/pdf-ring-buffer.h \
               base/pdf-stm-buffer.h \
               base/pdf-stm-be.h \
               base/pdf-stm-filter.h \

=== added file 'src/base/pdf-ring-buffer.c'
--- src/base/pdf-ring-buffer.c  1970-01-01 00:00:00 +0000
+++ src/base/pdf-ring-buffer.c  2008-10-02 21:51:49 +0000
@@ -0,0 +1,280 @@
+/* -*- mode: C -*- Time-stamp: "08/09/21 21:16:40 jemarch"
+ *
+ *       File:         pdf-ring-buffer.c
+ *       Date:         Thu Oct  2 12:31:15 2008
+ *
+ *       GNU PDF Library - Streams
+ *
+ */
+
+/* Copyright (C) 2008 Free Software Foundation, Inc. */
+
+/* This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+
+#include <pdf-alloc.h>
+#include <pdf-ring-buffer.h>
+
+/* Private data. */
+struct pdf_ring_buffer_s
+{
+  pdf_char_t* data;
+  pdf_size_t  size;
+  pdf_size_t  read_avail;
+  pdf_size_t  write_pos;
+  pdf_size_t  read_pos;
+};
+
+/* Creation and destruction. */
+
+pdf_ring_buffer_t
+pdf_ring_buffer_new (pdf_size_t size)
+{
+  pdf_ring_buffer_t buf;
+
+  buf = pdf_alloc (sizeof (struct pdf_ring_buffer_s));
+  if (!buf)
+    {
+      return NULL;
+    }
+    
+  buf->data = pdf_alloc (size);
+  if (!buf->data)
+    {
+      pdf_dealloc (buf);
+      return NULL;
+    }
+
+  buf->size = size;
+  buf->read_avail = 0;
+  buf->write_pos = 0;
+  buf->read_pos = 0;
+
+  return buf;
+}
+
+pdf_status_t
+pdf_ring_buffer_destroy (pdf_ring_buffer_t buf)
+{
+  pdf_dealloc (buf->data);
+  pdf_dealloc (buf);
+  
+  return PDF_OK;
+}
+
+/* Reseting. */
+
+pdf_status_t
+pdf_ring_buffer_reset (pdf_ring_buffer_t buf)
+{
+  buf->read_pos = 0;
+  buf->write_pos = 0;
+  buf->read_avail = 0;
+
+  return PDF_OK;
+}
+
+pdf_status_t
+pdf_ring_buffer_skip (pdf_ring_buffer_t buf, int nskip)
+{
+  buf->read_pos = (buf->read_pos + nskip) % buf->size;
+  buf->read_avail -= nskip;
+
+  return PDF_OK;
+}
+
+pdf_status_t
+pdf_ring_buffer_skip_one (pdf_ring_buffer_t buf)
+{
+  buf->read_pos++;
+  if (buf->read_pos >= buf->size)
+    {
+      buf->read_pos = 0;
+    }
+  
+  buf->read_avail--;
+
+  return PDF_OK;
+}
+
+/* Testing. */
+
+pdf_bool_t
+pdf_ring_buffer_full_p (pdf_ring_buffer_t buf)
+{
+  return (buf->read_avail == buf->size);
+}
+
+pdf_bool_t
+pdf_ring_buffer_empty_p (pdf_ring_buffer_t buf)
+{
+  return (buf->read_avail == 0);
+}
+
+pdf_size_t
+pdf_ring_buffer_size (pdf_ring_buffer_t buf)
+{
+  return buf->size;
+}
+
+pdf_size_t
+pdf_ring_buffer_read_avail (pdf_ring_buffer_t buf)
+{
+  return buf->read_avail;
+}
+
+pdf_size_t
+pdf_ring_buffer_write_avail (pdf_ring_buffer_t buf)
+{
+  return (buf->size - buf->read_avail);
+}
+
+pdf_ring_buffer_check_t
+pdf_ring_buffer_check (pdf_ring_buffer_t buf)
+{
+  if (buf->read_avail < 0)
+    {
+      return PDF_RING_BUFFER_UNDERRUN;
+    }
+
+  if (buf->read_avail > buf->size)
+    {
+      return PDF_RING_BUFFER_OVERRUN;
+    }
+  
+  return PDF_RING_BUFFER_OK;
+}
+
+/* Read and write. */
+
+pdf_status_t
+pdf_ring_buffer_write (pdf_ring_buffer_t buf,
+                      const pdf_char_t* data, pdf_size_t nwrite)
+{
+  if (buf->write_pos + nwrite > buf->size)
+    {
+      memcpy (buf->data + buf->write_pos,
+             data,
+             buf->size - buf->write_pos);
+      memcpy (buf->data,
+             data + buf->size - buf->write_pos, 
+             buf->write_pos + nwrite - buf->size);
+    }
+  else
+    {
+      memcpy (buf->data + buf->write_pos,
+             data,
+             nwrite);
+    }
+
+  buf->write_pos = (buf->write_pos + nwrite) % buf->size;
+  buf->read_avail += nwrite;
+  
+  return PDF_OK;
+}
+
+pdf_status_t
+pdf_ring_buffer_read (pdf_ring_buffer_t buf,
+                     pdf_char_t* dest, pdf_size_t nread)
+{
+  if (buf->read_pos + nread > buf->size)
+    {
+      memcpy (dest,
+             buf->data + buf->read_pos,
+             buf->size - buf->read_pos);
+      memcpy (dest + buf->size - buf->read_pos,
+             buf->data,
+             buf->read_pos + nread - buf->size);
+    }
+  else
+    {
+      memcpy (dest, buf->data + buf->read_pos, nread);
+    }
+  
+  buf->read_pos = (buf->read_pos + nread) % buf->size;
+  buf->read_avail -= nread;
+
+  return PDF_OK;
+}
+
+pdf_size_t
+pdf_ring_buffer_safe_write (pdf_ring_buffer_t buf,
+                           const pdf_char_t* data, pdf_size_t nwrite)
+{
+  int write_avail;
+
+  write_avail = buf->size - buf->read_avail;
+  if (write_avail < nwrite)
+    {
+      nwrite = write_avail;
+    }
+
+  pdf_ring_buffer_write (buf, data, nwrite);
+  
+  return nwrite;
+}
+
+pdf_size_t
+pdf_ring_buffer_safe_read (pdf_ring_buffer_t buf,
+                          pdf_char_t* dest, pdf_size_t nread)
+{
+  if (buf->read_avail < nread)
+    {
+      nread = buf->read_avail;
+    }
+
+  pdf_ring_buffer_read (buf, dest, nread);
+
+  return nread;
+}
+
+pdf_status_t
+pdf_ring_buffer_write_one (pdf_ring_buffer_t buf, pdf_char_t val)
+{
+  buf->data [buf->write_pos++] = val;
+
+  if (buf->write_pos >= buf->size)
+    {
+      buf->write_pos = 0;
+    }
+
+  buf->read_avail++;
+  
+  return PDF_OK;
+}
+
+pdf_char_t
+pdf_ring_buffer_read_one (pdf_ring_buffer_t buf)
+{
+  pdf_char_t val;
+
+  val = buf->data [buf->read_pos++];
+
+  if (buf->read_pos >= buf->size)
+    {
+      buf->read_pos = 0;
+    }
+
+  buf->read_avail--;
+
+  return val;
+}
+
+pdf_char_t
+pdf_ring_buffer_peek (pdf_ring_buffer_t buf)
+{
+  return buf->data [buf->read_pos];
+}

=== added file 'src/base/pdf-ring-buffer.h'
--- src/base/pdf-ring-buffer.h  1970-01-01 00:00:00 +0000
+++ src/base/pdf-ring-buffer.h  2008-10-02 21:51:49 +0000
@@ -0,0 +1,115 @@
+/* -*- mode: C -*- Time-stamp: "08/09/21 21:16:40 jemarch"
+ *
+ *       File:         pdf-ring-buffer.h
+ *       Date:         Thu Oct  2 12:30:00 2008
+ *
+ *       GNU PDF Library - Streams
+ *
+ */
+
+/* Copyright (C) 2008 Free Software Foundation, Inc. */
+
+/* This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PDF_RING_BUFFER_H
+#define PDF_RING_BUFFER_H
+
+#include <pdf-types.h>
+
+/* BEGIN PUBLIC */
+
+/* Ring buffer possible states. */
+typedef enum
+  {
+    PDF_RING_BUFFER_OK,
+    PDF_RING_BUFFER_UNDERRUN,
+    PDF_RING_BUFFER_OVERRUN
+  } pdf_ring_buffer_check_t;
+
+/* Hidden structure */
+
+struct pdf_ring_buffer_s;
+typedef struct pdf_ring_buffer_s* pdf_ring_buffer_t;
+
+/* Construction and destruction */
+
+pdf_ring_buffer_t
+pdf_ring_buffer_new (pdf_size_t size);
+
+pdf_status_t
+pdf_ring_buffer_destroy (pdf_ring_buffer_t buf);
+
+/* Reseting. */
+
+pdf_status_t
+pdf_ring_buffer_reset (pdf_ring_buffer_t buf);
+
+pdf_status_t
+pdf_ring_buffer_skip (pdf_ring_buffer_t buf, int nskip);
+
+pdf_status_t
+pdf_ring_buffer_skip_one (pdf_ring_buffer_t buf);
+
+/* Testing. */
+
+pdf_size_t
+pdf_ring_buffer_size (pdf_ring_buffer_t buf);
+
+pdf_size_t
+pdf_ring_buffer_read_avail (pdf_ring_buffer_t buf);
+
+pdf_size_t
+pdf_ring_buffer_write_avail (pdf_ring_buffer_t buf);
+
+pdf_bool_t
+pdf_ring_buffer_full_p (pdf_ring_buffer_t buf);
+
+pdf_bool_t
+pdf_ring_buffer_empty_p (pdf_ring_buffer_t buf);
+
+pdf_ring_buffer_check_t
+pdf_ring_buffer_check (pdf_ring_buffer_t buf);
+
+/* Read and write. */
+
+pdf_status_t
+pdf_ring_buffer_write (pdf_ring_buffer_t buf,
+                      const pdf_char_t* data, pdf_size_t nwrite);
+
+pdf_status_t
+pdf_ring_buffer_read (pdf_ring_buffer_t buf,
+                     pdf_char_t* dest, pdf_size_t nread);
+
+pdf_size_t
+pdf_ring_buffer_safe_write (pdf_ring_buffer_t buf,
+                           const pdf_char_t* data, pdf_size_t nwrite);
+
+pdf_size_t
+pdf_ring_buffer_safe_read (pdf_ring_buffer_t buf,
+                          pdf_char_t* dest, pdf_size_t nread);
+
+pdf_status_t
+pdf_ring_buffer_write_one (pdf_ring_buffer_t buf, pdf_char_t val);
+
+pdf_char_t
+pdf_ring_buffer_read_one (pdf_ring_buffer_t buf);
+
+pdf_char_t
+pdf_ring_buffer_peek (pdf_ring_buffer_t buf);
+
+/* END PUBLIC */
+
+#endif /* PDF_RING_BUFFER_H */
+

=== modified file 'src/base/pdf-stm-be.c'
--- src/base/pdf-stm-be.c       2008-09-24 21:46:44 +0000
+++ src/base/pdf-stm-be.c       2008-10-02 21:51:49 +0000
@@ -31,12 +31,38 @@
 static pdf_off_t pdf_stm_be_file_seek (pdf_stm_be_t be,
                                        pdf_off_t pos);
 static pdf_off_t pdf_stm_be_file_tell (pdf_stm_be_t be);
+static pdf_size_t pdf_stm_be_cfile_read (pdf_stm_be_t be,
+                                        pdf_char_t *buffer,
+                                        pdf_size_t bytes);
+static pdf_size_t pdf_stm_be_cfile_write (pdf_stm_be_t be,
+                                         pdf_char_t *buffer,
+                                         pdf_size_t bytes);
+static pdf_off_t pdf_stm_be_cfile_seek (pdf_stm_be_t be,
+                                       pdf_off_t pos);
+static pdf_off_t pdf_stm_be_cfile_tell (pdf_stm_be_t be);
 
 /*
  * Public functions
  */
 
 pdf_stm_be_t
+pdf_stm_be_new_cfile (FILE* file,
+                     pdf_off_t pos)
+{
+  pdf_stm_be_t new;
+
+  /* Allocate a new structure */
+  new = (pdf_stm_be_t) pdf_alloc(sizeof(struct pdf_stm_be_s));
+
+  /* Initialization */
+  new->type = PDF_STM_BE_CFILE;
+  new->data.cfile.file = file;
+  new->data.cfile.pos = pos;
+
+  return new;
+}
+
+pdf_stm_be_t
 pdf_stm_be_new_file (pdf_fsys_file_t file,
                      pdf_off_t pos)
 {
@@ -105,6 +131,13 @@
                                              bytes);
         break;
       }
+    case PDF_STM_BE_CFILE:
+      {
+        readed_bytes = pdf_stm_be_cfile_read (be,
+                                             buffer,
+                                             bytes);
+        break;
+      }
     default:
       {
         /* Uh oh */
@@ -139,6 +172,13 @@
                                                bytes);
         break;
       }
+    case PDF_STM_BE_CFILE:
+      {
+        written_bytes = pdf_stm_be_cfile_write (be,
+                                               buffer,
+                                               bytes);
+        break;
+      }
     default:
       {
         /* Uh oh */
@@ -168,6 +208,11 @@
         result = pdf_stm_be_file_seek (be, pos);
         break;
       }
+    case PDF_STM_BE_CFILE:
+      {
+        result = pdf_stm_be_cfile_seek (be, pos);
+        break;
+      }
     default:
       {
         /* Uh oh */
@@ -195,6 +240,11 @@
         result = pdf_stm_be_file_tell (be);
         break;
       }
+    case PDF_STM_BE_CFILE:
+      {
+        result = pdf_stm_be_cfile_tell (be);
+        break;
+      }
     default:
       {
         /* Uh oh */
@@ -413,4 +463,105 @@
   return be->data.file.pos;
 }
 
+/* cfile backend implementation */
+
+static pdf_off_t
+pdf_stm_be_cfile_seek (pdf_stm_be_t be,
+                      pdf_off_t pos)
+{
+  pdf_off_t max_pos;
+  
+  fseek (be->data.cfile.file, 0, SEEK_END);
+  max_pos = ftell (be->data.cfile.file);
+
+  /* Check the requested position */
+  if (pos < 0)
+    {
+      pos = 0;
+    }
+  if (pos > max_pos)
+    {
+      pos = max_pos - 1;
+    }
+
+  be->data.cfile.pos = pos;
+
+  return pos;
+}
+
+static pdf_off_t
+pdf_stm_be_cfile_tell (pdf_stm_be_t be)
+{
+  return be->data.cfile.pos;
+}
+
+static pdf_size_t
+pdf_stm_be_cfile_read (pdf_stm_be_t be,
+                      pdf_char_t *buffer,
+                      pdf_size_t bytes)
+{
+  pdf_size_t readed_bytes;
+  /* pdf_off_t current_pos; */
+
+  /* Seek in the file */
+  /*
+    [TODO] This is not working.
+    
+  current_pos = ftell (be->data.cfile.file);
+  if (fseek (be->data.cfile.file, be->data.cfile.pos, SEEK_SET))
+    {
+      return 0;
+    }
+  */
+  /* Read the requested number of bytes */
+  readed_bytes = fread (buffer, 
+                       1, bytes,
+                       be->data.cfile.file);
+
+  /* Restore the file position and update the position of the
+     stream */
+  /*
+    be->data.cfile.pos = be->data.cfile.pos + readed_bytes;
+  if (fseek (be->data.cfile.file, current_pos, SEEK_SET))
+    {
+      return 0;
+    }
+  */
+
+  return readed_bytes;
+}
+
+static pdf_size_t
+pdf_stm_be_cfile_write (pdf_stm_be_t be,
+                       pdf_char_t *buffer,
+                       pdf_size_t bytes)
+{
+  pdf_size_t written_bytes;
+  /* pdf_off_t current_pos; */
+  
+  /* Seek in the file */
+  /*
+    [TODO] This is not working.
+  current_pos = ftell (be->data.cfile.file);
+  if (fseek (be->data.cfile.file, be->data.cfile.pos, SEEK_SET))
+    {
+      return 0;
+    }
+  */
+  /* Write the requested number of bytes */
+  written_bytes = fwrite (buffer,
+                         1, bytes,
+                         be->data.cfile.file);
+  
+  /* Restore the file position and update the position of the
+     stream */
+  /*be->data.cfile.pos = be->data.file.pos + written_bytes;
+  if (fseek (be->data.cfile.file, current_pos, SEEK_SET))
+    {
+      return 0;
+    }
+  */                                   
+  return written_bytes;
+}
+
 /* End of pdf-stm-be.c */

=== modified file 'src/base/pdf-stm-be.h'
--- src/base/pdf-stm-be.h       2008-09-20 17:14:04 +0000
+++ src/base/pdf-stm-be.h       2008-10-02 21:51:49 +0000
@@ -13,6 +13,7 @@
 #include <config.h>
 #include <pdf-types.h>
 #include <pdf-fsys.h>
+#include <stdio.h>
 
 /* BEGIN PUBLIC */
 
@@ -20,7 +21,8 @@
 enum pdf_stm_be_type_e
 {
   PDF_STM_BE_MEM = 0,
-  PDF_STM_BE_FILE
+  PDF_STM_BE_FILE,
+  PDF_STM_BE_CFILE
 };
 
 /* Backend data type */
@@ -30,6 +32,12 @@
   pdf_off_t pos; /* Current position */
 };
 
+struct pdf_stm_be_cfile_s
+{
+  FILE*      file;
+  pdf_off_t  pos;
+};
+
 struct pdf_stm_be_mem_s
 {
   pdf_char_t *buffer;  /* Buffer contents */
@@ -45,6 +53,7 @@
   {
     struct pdf_stm_be_mem_s mem;
     struct pdf_stm_be_file_s file;
+    struct pdf_stm_be_cfile_s cfile;
   } data;
 };
 
@@ -56,6 +65,8 @@
  * Public API
  */
 
+pdf_stm_be_t pdf_stm_be_new_cfile (FILE* file,
+                                  pdf_off_t pos);
 pdf_stm_be_t pdf_stm_be_new_file (pdf_fsys_file_t file,
                                   pdf_off_t pos);
 pdf_stm_be_t pdf_stm_be_new_mem (pdf_char_t *buffer,

=== modified file 'src/base/pdf-stm-f-ahex.c'
--- src/base/pdf-stm-f-ahex.c   2008-09-26 22:52:29 +0000
+++ src/base/pdf-stm-f-ahex.c   2008-10-02 21:51:49 +0000
@@ -61,8 +61,8 @@
 pdf_status_t
 pdf_stm_f_ahexenc_apply (pdf_hash_t params,
                          void *state,
-                         pdf_stm_buffer_t in,
-                         pdf_stm_buffer_t out,
+                         pdf_ring_buffer_t in,
+                         pdf_ring_buffer_t out,
                          pdf_bool_t finish_p)
 {
   pdf_status_t ret;
@@ -74,18 +74,20 @@
   
   filter_state = (pdf_stm_f_ahexenc_t) state;
   wrote_newline = PDF_FALSE;
-  while ((!pdf_stm_buffer_eob_p (in)) &&
-         (!pdf_stm_buffer_full_p (out)))
+  while ((!pdf_ring_buffer_empty_p (in)) &&
+         (!pdf_ring_buffer_full_p (out)))
     {
       if ((!wrote_newline) &&
           (filter_state->written_bytes != 0) &&
           ((filter_state->written_bytes % PDF_STM_F_AHEX_LINE_WIDTH) == 0))
         {
           /* Insert a new line character */
-          out->data[out->wp] = '\n';
-          out->wp++;
+          pdf_ring_buffer_write_one (out, '\n');
           wrote_newline = PDF_TRUE;
 
+         /* [FIX] Without this an overrun can happen when processing
+            a lot of data. */
+         filter_state->written_bytes = 0;
           continue;
         }
       else
@@ -95,7 +97,7 @@
 
       /* For each byte in the input we should generate two bytes in the
          output. */
-      in_char = in->data[in->rp];
+      in_char = pdf_ring_buffer_read_one (in);
 
       /* Determine the hex digits to write for this input character */
       if (filter_state->last_nibble != -1)
@@ -108,24 +110,21 @@
           first_nibble = pdf_stm_f_ahex_int2hex (in_char >> 4);
           second_nibble = pdf_stm_f_ahex_int2hex (in_char);
         }
-      in->rp++;
 
       /* Write the hex digits to the output buffer, if possible */
 
       /* First nibble */
-      out->data[out->wp] = first_nibble;
-      out->wp++;
+      pdf_ring_buffer_write_one (out, first_nibble);
       filter_state->written_bytes++;
 
       /* Maybe write the second nibble */
-      if (pdf_stm_buffer_full_p (out))
+      if (pdf_ring_buffer_full_p (out))
         {
           filter_state->last_nibble = second_nibble;
         }
       else
         {
-          out->data[out->wp] = second_nibble;
-          out->wp++;
+          pdf_ring_buffer_write_one (out, second_nibble);
           filter_state->written_bytes++;
         }
     }
@@ -133,10 +132,9 @@
   if (finish_p)
     {
       /* The end of the encoded data is a 3E '>' ASCII character */
-      if (!pdf_stm_buffer_full_p (out))
+      if (!pdf_ring_buffer_full_p (out))
         {
-          out->data[out->wp] = '>';
-          out->wp++;
+         pdf_ring_buffer_write_one (out, '>');
         }
       else
         {
@@ -145,7 +143,13 @@
         }
     }
 
-  if ((in->wp - in->rp) == 0)
+  /* [FIX]
+     I think that this kind of test is dangerous in the actual
+     filters. Think of a compression filter that makes less data
+     than it gets... The solution is to propagate the EOF only
+     if the backend returned EOF.
+  
+  if (pdf_ring_buffer_empty_p (in))
     {
       ret = PDF_EEOF;
     }
@@ -153,7 +157,9 @@
     {
       ret = PDF_OK;
     }
-
+  */
+  ret = PDF_OK;
+  
   return ret;
 }
 
@@ -197,37 +203,37 @@
 pdf_status_t
 pdf_stm_f_ahexdec_apply (pdf_hash_t params,
                          void *state,
-                         pdf_stm_buffer_t in,
-                         pdf_stm_buffer_t out,
+                         pdf_ring_buffer_t in,
+                         pdf_ring_buffer_t out,
                          pdf_bool_t finish_p)
 {
   pdf_status_t ret;
   pdf_stm_f_ahexdec_t filter_state;
   pdf_i32_t first_nibble;
   pdf_i32_t second_nibble;
-
+  pdf_char_t in_char;
+  
   ret = PDF_OK;
   first_nibble = PDF_EOF;
   second_nibble = PDF_EOF;
   filter_state = (pdf_stm_f_ahexdec_t) state;
 
-  while ((!pdf_stm_buffer_eob_p (in)) &&
-         (!pdf_stm_buffer_full_p (out)))
+  while ((!pdf_ring_buffer_empty_p (in)) &&
+         (!pdf_ring_buffer_full_p (out)))
     {
       /* Skip white characters */
-      if (pdf_stm_f_ahex_white_p ((pdf_u32_t) in->data[in->rp]))
+      in_char = pdf_ring_buffer_read_one (in);
+      if (pdf_stm_f_ahex_white_p ((pdf_u32_t) in_char))
         {
-          in->rp++;
           continue;
         }
 
       /* Detect the end of the hex data */
-      if (in->data[in->rp] == '>')
+      if (in_char == '>')
         {
           if (filter_state->last_nibble == PDF_EOF)
             {
               /* We are done :'D */
-              in->rp++;
               ret = PDF_EEOF;
               break;
             }
@@ -236,9 +242,9 @@
               /* Found an even number of hex digits. We assume that
                  the second nibble is 0, so generate a byte of data
                  and finish */
-              out->data[out->wp] =
-                pdf_stm_f_ahex_hex2int (filter_state->last_nibble) << 4;
-              out->wp++;
+              pdf_ring_buffer_write_one
+               (out,
+                pdf_stm_f_ahex_hex2int (filter_state->last_nibble) << 4);
               filter_state->last_nibble = PDF_EOF;
               ret = PDF_EEOF;
               break;
@@ -246,7 +252,7 @@
         }
 
       /* Detect an invalid character */
-      if (!pdf_stm_f_ahex_hex_p ((pdf_u32_t) in->data[in->rp]))
+      if (!pdf_stm_f_ahex_hex_p ((pdf_u32_t) in_char))
         {
           ret = PDF_ERROR;
           break;
@@ -257,32 +263,33 @@
       if (filter_state->last_nibble == PDF_EOF)
         {
           /* Get the first nibble */
-          first_nibble = (pdf_u32_t) in->data[in->rp];
-          in->rp++;
+          first_nibble = (pdf_u32_t) in_char;
 
           filter_state->last_nibble = first_nibble;
         }
       else
         {
           /* Get the second nibble */
-          second_nibble = (pdf_u32_t) in->data[in->rp];
-          in->rp++;
+          second_nibble = (pdf_u32_t) in_char;
 
           /* Generate one byte of data */
-          out->data[out->wp] = (pdf_stm_f_ahex_hex2int (first_nibble) << 4)
-            + pdf_stm_f_ahex_hex2int (second_nibble);
-          out->wp++;
+          pdf_ring_buffer_write_one (out,
+                                    (pdf_stm_f_ahex_hex2int (first_nibble) <<4)
+                                    + pdf_stm_f_ahex_hex2int (second_nibble));
 
           filter_state->last_nibble = PDF_EOF;
         }
     }
-  
+
+  /*
+    [FIX] Read above.
   if ((ret == PDF_OK) &&
-      (pdf_stm_buffer_eob_p (in)))
+      (pdf_ring_buffer_eob_p (in)))
     {
       ret = PDF_EEOF;
     }
-
+  */
+      
   return ret;
 }
 

=== modified file 'src/base/pdf-stm-f-ahex.h'
--- src/base/pdf-stm-f-ahex.h   2008-09-26 20:49:09 +0000
+++ src/base/pdf-stm-f-ahex.h   2008-10-02 21:51:49 +0000
@@ -29,7 +29,7 @@
 #include <config.h>
 #include <pdf-types.h>
 #include <pdf-hash.h>
-#include <pdf-stm-buffer.h>
+#include <pdf-ring-buffer.h>
 
 /* Internal state */
 struct pdf_stm_f_ahexenc_s
@@ -54,8 +54,8 @@
                                      void **state);
 pdf_status_t pdf_stm_f_ahexdec_apply (pdf_hash_t params,
                                       void *state,
-                                      pdf_stm_buffer_t in,
-                                      pdf_stm_buffer_t out,
+                                      pdf_ring_buffer_t in,
+                                      pdf_ring_buffer_t out,
                                       pdf_bool_t finish_p);
 pdf_status_t pdf_stm_f_ahexdec_dealloc_state (void *state);
 
@@ -63,8 +63,8 @@
                                      void **state);
 pdf_status_t pdf_stm_f_ahexenc_apply (pdf_hash_t params,
                                       void *state,
-                                      pdf_stm_buffer_t in,
-                                      pdf_stm_buffer_t out,
+                                      pdf_ring_buffer_t in,
+                                      pdf_ring_buffer_t out,
                                       pdf_bool_t finish_p);
 pdf_status_t pdf_stm_f_ahexenc_dealloc_state (void *state);
 

=== modified file 'src/base/pdf-stm-f-null.c'
--- src/base/pdf-stm-f-null.c   2008-09-27 20:55:07 +0000
+++ src/base/pdf-stm-f-null.c   2008-10-02 21:51:49 +0000
@@ -46,32 +46,23 @@
 pdf_status_t
 pdf_stm_f_null_apply (pdf_hash_t params,
                       void *state,
-                      pdf_stm_buffer_t in,
-                      pdf_stm_buffer_t out,
+                      pdf_ring_buffer_t in,
+                      pdf_ring_buffer_t out,
                       pdf_bool_t finish_p)
 {
   pdf_status_t ret;
-  pdf_size_t in_size;
-  pdf_size_t out_size;
-  pdf_size_t bytes_to_copy;
 
   /* Fill the output buffer with the contents of the input buffer, but
      note that the second may be bigger than the former */
-  in_size = in->wp - in->rp;
-  out_size = out->size - out->wp;
-
-  bytes_to_copy = PDF_MIN(out_size, in_size);
-
-  if (bytes_to_copy != 0)
+  while (!pdf_ring_buffer_full_p (out) &&
+        !pdf_ring_buffer_empty_p (in))
     {
-      memcpy ((char *) out->data,
-              (char *) in->data,
-              bytes_to_copy);
-
-      in->rp = in->rp + bytes_to_copy;
-      out->wp = out->wp + bytes_to_copy;
+      pdf_ring_buffer_write_one (out,
+                                pdf_ring_buffer_read_one (in));
     }
 
+  /*
+    [FIX] Explanation in pdf-stm-ahex.c
   if (bytes_to_copy < out_size)
     {
       ret = PDF_EEOF;
@@ -80,7 +71,9 @@
     {
       ret = PDF_OK;
     }
-
+  */
+  ret = PDF_OK;
+  
   return ret;
 }
 

=== modified file 'src/base/pdf-stm-f-null.h'
--- src/base/pdf-stm-f-null.h   2008-09-26 18:56:50 +0000
+++ src/base/pdf-stm-f-null.h   2008-10-02 21:51:49 +0000
@@ -29,7 +29,7 @@
 #include <config.h>
 #include <pdf-types.h>
 #include <pdf-hash.h>
-#include <pdf-stm-buffer.h>
+#include <pdf-ring-buffer.h>
 
 /* Filter implementation API */
 
@@ -38,8 +38,8 @@
 
 pdf_status_t pdf_stm_f_null_apply (pdf_hash_t params,
                                    void *state,
-                                   pdf_stm_buffer_t in,
-                                   pdf_stm_buffer_t out,
+                                   pdf_ring_buffer_t in,
+                                   pdf_ring_buffer_t out,
                                    pdf_bool_t finish_p);
 pdf_status_t pdf_stm_f_null_dealloc_state (void *state);
 

=== modified file 'src/base/pdf-stm-f-rl.c'
--- src/base/pdf-stm-f-rl.c     2008-09-28 23:21:24 +0000
+++ src/base/pdf-stm-f-rl.c     2008-10-02 21:51:49 +0000
@@ -30,10 +30,10 @@
 #include <pdf-stm-f-rl.h>
 
 
-static int encode_rl_char (pdf_stm_f_rl_t st, pdf_stm_buffer_t out);
-static int decode_rl_char (pdf_stm_f_rl_t st, pdf_stm_buffer_t out);
-static int copy_next_bytes (pdf_stm_f_rl_t st, pdf_stm_buffer_t in,
-                            pdf_stm_buffer_t out);
+static int encode_rl_char (pdf_stm_f_rl_t st, pdf_ring_buffer_t out);
+static int decode_rl_char (pdf_stm_f_rl_t st, pdf_ring_buffer_t out);
+static int copy_next_bytes (pdf_stm_f_rl_t st, pdf_ring_buffer_t in,
+                            pdf_ring_buffer_t out);
 
 
 pdf_status_t
@@ -79,44 +79,45 @@
 
 
 pdf_status_t
-pdf_stm_f_rlenc_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_rlenc_apply (pdf_hash_t params, void * state, pdf_ring_buffer_t in,
+                       pdf_ring_buffer_t out, pdf_bool_t finish_p)
 {
   pdf_stm_f_rl_t st;
 
   st = (pdf_stm_f_rl_t) state;
-
-  while (!pdf_stm_buffer_eob_p (in))
+    
+  while (!pdf_ring_buffer_empty_p (in) &&
+        !pdf_ring_buffer_full_p (out))
     {
-      st->curchar = in->data[in->rp];
-
+      st->curchar = pdf_ring_buffer_peek (in);
+      
       /* we're not encoding any character yet */
       if (!st->run_p)
-        {
-          st->rlchar = st->curchar;
-          st->run_p = PDF_TRUE;
-          st->rl++; 
-          in->rp++;
-        }
+       {
+         st->rlchar = st->curchar;
+         st->run_p = PDF_TRUE;
+         st->rl++;
+         pdf_ring_buffer_skip_one (in);
+       }
       /* we're encoding some character now */
       else if (st->curchar == st->rlchar && st->rl < 127)
-        {
-          st->rl++;
-          in->rp++;
-        }
+       {
+         st->rl++;
+         pdf_ring_buffer_skip_one (in);
+       }
       /* 
        * the rl code is too long or the rl char is different,
        * so we write what we encoded so far.
        */
       else
-        {
-          if (encode_rl_char (st, out) < 0)
-            {
-              return PDF_OK;
-            }
-          st->rl=-1;
-          st->run_p = PDF_FALSE;
-        }
+       {
+         if (encode_rl_char (st, out) < 0)
+           {
+             return PDF_OK;
+           }
+         st->rl = -1;
+         st->run_p = PDF_FALSE;
+       }
     }
 
   /* 
@@ -126,28 +127,31 @@
   if (finish_p)
     {
       if (st->run_p)
-        {
-          if (encode_rl_char (st, out) < 0)
-            {
-              /* Should not be reached */
-              return PDF_ERROR;
-            }
-          st->rl=-1;
-          st->run_p = PDF_FALSE;
-        }
-      if (pdf_stm_buffer_full_p (out))
-        {
-          /* Should not be reached */
-          return PDF_ERROR;
-        }
+       {
+         if (encode_rl_char (st, out) < 0)
+           {
+             /* Should not be reached */
+             return PDF_ERROR;
+           }
+         st->rl=-1;
+         st->run_p = PDF_FALSE;
+       }
+      if (pdf_ring_buffer_full_p (out))
+       {
+         /* Should not be reached */
+         return PDF_ERROR;
+       }
       /* Insert EOD marker */
-      out->data[out->wp++] = 128;
+      pdf_ring_buffer_write_one (out, 128);
     }
 
-  if (pdf_stm_buffer_eob_p (in))
-    {
-      return PDF_EEOF;
-    }
+  /* [FIX] Explained on pdf-ahex.c
+     if (pdf_ring_buffer_empty_p (in))
+     {
+     return PDF_EEOF;
+     }
+  */
+  
   return PDF_OK;
 }
 
@@ -160,24 +164,24 @@
 }
 
 pdf_status_t
-pdf_stm_f_rldec_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_rldec_apply (pdf_hash_t params, void *state, pdf_ring_buffer_t in,
+                       pdf_ring_buffer_t out, pdf_bool_t finish_p)
 {
   pdf_stm_f_rl_t st;
   pdf_status_t copied;
 
   st = (pdf_stm_f_rl_t) state;
 
-  while (!pdf_stm_buffer_eob_p (in))
+  while (!pdf_ring_buffer_empty_p (in))
     {
-      st->curchar = in->data[in->rp];
+      st->curchar = pdf_ring_buffer_peek (in);
 
       /* we're not decoding any character yet */
       if (!st->run_p)
         {
           st->rlchar = st->curchar;
           st->run_p = PDF_TRUE;
-          in->rp++;
+          pdf_ring_buffer_skip_one (in);
         }
       /* copy the following 1 to 128 bytes literally */
       else if (st->rlchar < 128)
@@ -201,7 +205,7 @@
               return PDF_OK;
             }
           st->run_p = PDF_FALSE;
-          in->rp++;
+          pdf_ring_buffer_skip_one (in);
         }
       /* EOD mark */
       else
@@ -210,11 +214,13 @@
         }
     }
 
-  if (pdf_stm_buffer_eob_p (in))
-    {
-      return PDF_EEOF;
-    }
-
+  /* [FIX]
+     if (pdf_ring_buffer_eob_p (in))
+     {
+     return PDF_EEOF;
+     }
+  */
+  
   return PDF_OK;
 }
 
@@ -228,25 +234,26 @@
 /* Private functions */
 
 static int
-encode_rl_char (pdf_stm_f_rl_t st, pdf_stm_buffer_t out)
+encode_rl_char (pdf_stm_f_rl_t st, pdf_ring_buffer_t out)
 {
   if (st->enc_p == PDF_STM_F_RL_NONE)
     {
-      if (pdf_stm_buffer_full_p (out))
+      if (pdf_ring_buffer_full_p (out))
         {
           return -1;
         }
-      out->data[out->wp++] = (st->rl == 0) ? 0 : 256 - st->rl;    
+      pdf_ring_buffer_write_one (out,
+                                (st->rl == 0) ? 0 : 256 - st->rl);    
       st->enc_p = PDF_STM_F_RL_WRL;
     }
 
   if (st->enc_p == PDF_STM_F_RL_WRL)
     {
-      if (pdf_stm_buffer_full_p (out))
+      if (pdf_ring_buffer_full_p (out))
         {
           return -1;
         }
-      out->data[out->wp++] = st->rlchar;
+      pdf_ring_buffer_write_one (out, st->rlchar);
       st->enc_p = PDF_STM_F_RL_NONE;
     }
 
@@ -255,7 +262,7 @@
 
 
 static int
-decode_rl_char (pdf_stm_f_rl_t st, pdf_stm_buffer_t out)
+decode_rl_char (pdf_stm_f_rl_t st, pdf_ring_buffer_t out)
 {
   if (!st->dec_p)
     {
@@ -265,11 +272,11 @@
 
   while (st->dec_count > 0)
     {
-      if (pdf_stm_buffer_full_p (out))
+      if (pdf_ring_buffer_full_p (out))
         {
           return -1;
         }
-      out->data[out->wp++] = st->curchar;
+      pdf_ring_buffer_write_one (out, st->curchar);
       st->dec_count--;
     }
 
@@ -279,30 +286,29 @@
 
 
 static int
-copy_next_bytes (pdf_stm_f_rl_t st, pdf_stm_buffer_t in, pdf_stm_buffer_t out)
+copy_next_bytes (pdf_stm_f_rl_t st, pdf_ring_buffer_t in, pdf_ring_buffer_t 
out)
 {
   if (!st->dec_p)
     {
       st->dec_count = st->rlchar + 1;
       st->dec_p = PDF_TRUE;
-      out->data[out->wp++] = st->curchar;
-      in->rp++;
+      pdf_ring_buffer_write_one (out, st->curchar);
+      pdf_ring_buffer_skip_one (in);
       st->dec_count--;
     }
 
   while (st->dec_count > 0)
     {
-      if (pdf_stm_buffer_eob_p (in))
+      if (pdf_ring_buffer_empty_p (in))
         {
           return 1;
         }
-      else if (pdf_stm_buffer_full_p (out))
+      else if (pdf_ring_buffer_full_p (out))
         {
           return -1;
         }
-      out->data[out->wp] = in->data[in->rp];
-      out->wp++;
-      in->rp++;
+      pdf_ring_buffer_write_one (out,
+                                pdf_ring_buffer_read_one (in));
       st->dec_count--;
     }
 

=== modified file 'src/base/pdf-stm-f-rl.h'
--- src/base/pdf-stm-f-rl.h     2008-09-28 13:51:52 +0000
+++ src/base/pdf-stm-f-rl.h     2008-10-02 21:51:49 +0000
@@ -29,14 +29,14 @@
 #include <config.h>
 #include <pdf-types.h>
 #include <pdf-hash.h>
-#include <pdf-stm-buffer.h>
+#include <pdf-ring-buffer.h>
 
 
 typedef enum
-{
-        PDF_STM_F_RL_WRL=0,
-        PDF_STM_F_RL_NONE
-} pdf_stm_f_rl_enc_e;
+  {
+    PDF_STM_F_RL_WRL=0,
+    PDF_STM_F_RL_NONE
+  } pdf_stm_f_rl_enc_e;
 
 struct pdf_stm_f_rl_s
 {
@@ -56,8 +56,8 @@
 
 pdf_status_t pdf_stm_f_rldec_apply (pdf_hash_t params,
                                     void *state,
-                                    pdf_stm_buffer_t in,
-                                    pdf_stm_buffer_t out,
+                                    pdf_ring_buffer_t in,
+                                    pdf_ring_buffer_t out,
                                     pdf_bool_t finish_p);
 pdf_status_t pdf_stm_f_rldec_dealloc_state (void *state);
 
@@ -66,8 +66,8 @@
 
 pdf_status_t pdf_stm_f_rlenc_apply (pdf_hash_t params,
                                     void *state,
-                                    pdf_stm_buffer_t in,
-                                    pdf_stm_buffer_t out,
+                                    pdf_ring_buffer_t in,
+                                    pdf_ring_buffer_t out,
                                     pdf_bool_t finish_p);
 pdf_status_t pdf_stm_f_rlenc_dealloc_state (void *state);
 

=== modified file 'src/base/pdf-stm-filter.c'
--- src/base/pdf-stm-filter.c   2008-09-28 13:51:52 +0000
+++ src/base/pdf-stm-filter.c   2008-10-02 21:51:49 +0000
@@ -52,9 +52,10 @@
   /* Data sources */
   new->next = NULL;
   new->backend = NULL;
-
+  new->be_buf = NULL;
+  
   /* Input buffer */
-  new->in = pdf_stm_buffer_new (buffer_size);
+  new->in = pdf_ring_buffer_new (buffer_size);
 
   /* Output buffer */
   new->out = NULL;
@@ -116,10 +117,16 @@
 pdf_status_t
 pdf_stm_filter_destroy (pdf_stm_filter_t filter)
 {
-  pdf_stm_buffer_destroy (filter->in);
+  pdf_ring_buffer_destroy (filter->in);
   filter->impl.dealloc_state_fn (filter->state);
   pdf_dealloc (filter);
 
+  /* Dealloc backend buffer if necessary. */
+  if (filter->be_buf)
+    {
+      pdf_dealloc (filter->be_buf);
+    }
+  
   /* Note that the memory used by the output buffer and by the params
      hash is NOT managed by the filter */
 
@@ -139,18 +146,23 @@
                        pdf_stm_be_t be)
 {
   filter->backend = be;
+  if (filter->be_buf == NULL)
+    {
+      filter->be_buf = pdf_alloc (pdf_ring_buffer_size (filter->in));
+    }
+  
   return PDF_OK;
 }
 
 inline pdf_status_t
 pdf_stm_filter_set_out (pdf_stm_filter_t filter,
-                        pdf_stm_buffer_t buffer)
+                        pdf_ring_buffer_t buffer)
 {
   filter->out = buffer;
   return PDF_OK;
 }
 
-inline pdf_stm_buffer_t
+inline pdf_ring_buffer_t
 pdf_stm_filter_get_in (pdf_stm_filter_t filter)
 {
   return filter->in;
@@ -161,15 +173,16 @@
                       pdf_bool_t finish_p)
 {
   pdf_status_t ret;
+  pdf_status_t ret2 = PDF_OK;
 
-  pdf_stm_buffer_rewind (filter->out);
   ret = PDF_OK;
 
-  while ((!pdf_stm_buffer_full_p (filter->out)) 
-         && (ret == PDF_OK))
+  while (!pdf_ring_buffer_full_p (filter->out) 
+         && (ret == PDF_OK)
+        && (ret2 == PDF_OK))
     {
       /* If the input buffer is empty, refill it */
-      if (pdf_stm_buffer_eob_p (filter->in))
+      if (pdf_ring_buffer_empty_p (filter->in))
         {
           ret = pdf_stm_filter_get_input (filter, finish_p);
         }
@@ -177,15 +190,15 @@
       if (ret != PDF_ERROR)
         {
           /* Generate output */
-          ret = filter->impl.apply_fn (filter->params,
-                                       filter->state,
-                                       filter->in,
-                                       filter->out,
-                                       finish_p);
+          ret2 = filter->impl.apply_fn (filter->params,
+                                       filter->state,
+                                       filter->in,
+                                       filter->out,
+                                       finish_p);
         }
     }
 
-  return ret;
+  return (ret2 == PDF_OK ? ret : ret2);
 }
 
 pdf_status_t
@@ -219,8 +232,6 @@
   pdf_status_t ret;
   pdf_size_t read_bytes;
 
-  pdf_stm_buffer_rewind (filter->in);
-
   if (filter->next != NULL)
     {
       ret = pdf_stm_filter_apply (filter->next, finish_p);
@@ -228,15 +239,17 @@
   else if (filter->backend != NULL)
     {
       read_bytes = pdf_stm_be_read (filter->backend,
-                                    filter->in->data,
-                                    filter->in->size);
-      filter->in->wp = read_bytes;
+                                    filter->be_buf,
+                                    pdf_ring_buffer_size (filter->in));
       if (read_bytes == 0)
         {
           ret = PDF_EEOF;
         }
       else
         {
+         pdf_ring_buffer_write (filter->in,
+                                filter->be_buf,
+                                read_bytes);
           ret = PDF_OK;
         }
     }
@@ -249,4 +262,22 @@
   return ret;
 }
 
+/* [FIX] This function is very important. Before this function was written, we
+   checked that there is no remaining data in the filter chain just looking at
+   the tail. That causes problem, as some combinations of filters with 
different
+   consumption/production ratios can cause both the tail and head to be empty
+   but still have some remaining data in the middle of the chain. */
+pdf_bool_t
+pdf_stm_filter_has_data_p (pdf_stm_filter_t filter)
+{
+  if (filter)
+    {
+      return
+       !pdf_ring_buffer_empty_p (filter->in) ||
+       pdf_stm_filter_has_data_p (filter->next);
+    }
+
+  return PDF_FALSE;
+}
+
 /* End of pdf-stm-filter.c */

=== modified file 'src/base/pdf-stm-filter.h'
--- src/base/pdf-stm-filter.h   2008-09-28 13:51:52 +0000
+++ src/base/pdf-stm-filter.h   2008-10-02 21:51:49 +0000
@@ -29,7 +29,7 @@
 #include <config.h>
 #include <pdf-types.h>
 #include <pdf-hash.h>
-#include <pdf-stm-buffer.h>
+#include <pdf-ring-buffer.h>
 #include <pdf-stm-be.h>
 
 #include <pdf-stm-f-null.h>
@@ -56,8 +56,8 @@
 
   pdf_status_t (*apply_fn) (pdf_hash_t params,
                             void *state,
-                            pdf_stm_buffer_t in,
-                            pdf_stm_buffer_t out,
+                            pdf_ring_buffer_t in,
+                            pdf_ring_buffer_t out,
                             pdf_bool_t finish_p);
   pdf_status_t (*dealloc_state_fn) (void *state);
 };
@@ -70,10 +70,12 @@
   struct pdf_stm_filter_s *next; /* Next filter in the chain, or
                                     NULL */
   pdf_stm_be_t backend;          /* Backend, or NULL */
-
+  pdf_char_t*  be_buf;           /* Serialization buffer. NULL if backend
+                                   is null. */
+  
   /* Input and output buffers */
-  pdf_stm_buffer_t in;
-  pdf_stm_buffer_t out;
+  pdf_ring_buffer_t in;
+  pdf_ring_buffer_t out;
 
   /* Filter-specific information */
   pdf_hash_t params;
@@ -100,12 +102,13 @@
 inline pdf_status_t pdf_stm_filter_set_be (pdf_stm_filter_t filter,
                                            pdf_stm_be_t be);
 inline pdf_status_t pdf_stm_filter_set_out (pdf_stm_filter_t filter,
-                                            pdf_stm_buffer_t buffer);
+                                            pdf_ring_buffer_t buffer);
 pdf_stm_filter_t pdf_stm_filter_get_tail (pdf_stm_filter_t filter);
-inline pdf_stm_buffer_t pdf_stm_filter_get_in (pdf_stm_filter_t filter);
+inline pdf_ring_buffer_t pdf_stm_filter_get_in (pdf_stm_filter_t filter);
 
 pdf_status_t pdf_stm_filter_apply (pdf_stm_filter_t filter, pdf_bool_t 
finish_p);
 pdf_status_t pdf_stm_filter_reset (pdf_stm_filter_t filter);
+pdf_bool_t pdf_stm_filter_has_data_p (pdf_stm_filter_t filter);
 
 #endif /* ! PDF_STM_FILTER_H */
 

=== modified file 'src/base/pdf-stm.c'
--- src/base/pdf-stm.c  2008-09-27 20:55:07 +0000
+++ src/base/pdf-stm.c  2008-10-02 21:51:49 +0000
@@ -42,6 +42,26 @@
 /*
  * Public functions
  */
+pdf_status_t
+pdf_stm_cfile_new (FILE* file,
+                  pdf_off_t offset,
+                  pdf_size_t cache_size,
+                  enum pdf_stm_mode_e mode,
+                  pdf_stm_t *stm)
+{
+  /* Allocate memory for the new stream */
+  *stm = pdf_stm_alloc ();
+
+  /* Initialize a file stream */
+  (*stm)->type = PDF_STM_CFILE;
+  (*stm)->backend = pdf_stm_be_new_cfile (file,
+                                         offset);
+  
+  /* Initialize the common parts */
+  return pdf_stm_init (cache_size,
+                       mode,
+                       *stm);
+}
 
 pdf_status_t
 pdf_stm_file_new (pdf_fsys_file_t file,
@@ -57,9 +77,11 @@
   (*stm)->type = PDF_STM_FILE;
   (*stm)->backend = pdf_stm_be_new_file (file,
                                          offset);
-  pdf_stm_filter_set_be ((*stm)->filter,
-                         (*stm)->backend);
-
+  /* [FIX]
+     pdf_stm_filter_set_be ((*stm)->filter,
+     (*stm)->backend);
+  */
+  
   /* Initialize the common parts */
   return pdf_stm_init (cache_size,
                        mode,
@@ -100,15 +122,20 @@
       pdf_stm_flush (stm);
 
       /* Finish the filters */
-      pdf_stm_finish (stm);
+      /* [FIX]
+        This caused the ending character to be printed twice!
+       pdf_stm_finish (stm); */
     }
 
   /* Destroy the backend */
   pdf_stm_be_destroy (stm->backend);
 
   /* Destroy the cache */
-  pdf_stm_buffer_destroy (stm->cache);
+  pdf_ring_buffer_destroy (stm->cache);
 
+  /* Dealloc the serialization buffer */
+  pdf_dealloc (stm->tmp_buf);
+  
   /* Destroy the filter chain */
   filter = stm->filter;
   while (filter != NULL)
@@ -130,9 +157,6 @@
               pdf_size_t bytes)
 {
   pdf_size_t read_bytes;
-  pdf_size_t pending_bytes;
-  pdf_size_t cache_size;
-  pdf_size_t to_copy_bytes;
   pdf_status_t ret;
 
   if (stm->mode != PDF_STM_READ)
@@ -143,32 +167,25 @@
 
   ret = PDF_OK;
   read_bytes = 0;
-  while ((read_bytes < bytes) &&
-         (ret == PDF_OK))
-    {
-      pending_bytes = bytes - read_bytes;
-
-      /* If the cache is empty, refill it with filtered data */
-      if (pdf_stm_buffer_eob_p (stm->cache))
-        {
-          ret = pdf_stm_filter_apply (stm->filter, PDF_FALSE);
-        }
-
-      if (ret != PDF_ERROR)
-        {
-          /* Read data from the cache */
-          pending_bytes = bytes - read_bytes;
-          cache_size = stm->cache->wp - stm->cache->rp;
-          to_copy_bytes = PDF_MIN(pending_bytes, cache_size);
-
-          memcpy ((char *) (buf + read_bytes),
-                  (char *) stm->cache->data + stm->cache->rp,
-                  to_copy_bytes);
-          
-          read_bytes += to_copy_bytes;
-          stm->cache->rp += to_copy_bytes;
-        }
-    }
+  do {
+    /* If we need more data refill the cache with filtered data */
+    if (pdf_ring_buffer_write_avail (stm->cache))
+      {
+       ret = pdf_stm_filter_apply (stm->filter, PDF_FALSE);
+      }
+
+    if (ret != PDF_ERROR)
+      {
+       read_bytes +=
+         pdf_ring_buffer_safe_read (stm->cache,
+                                    buf + read_bytes,
+                                    bytes - read_bytes);
+      }
+  } while ((read_bytes < bytes) &&
+          (ret != PDF_EEOF ||
+           pdf_stm_filter_has_data_p (stm->filter)) &&
+          (ret != PDF_ERROR));
+
 
   if (ret == PDF_ERROR)
     {
@@ -186,11 +203,8 @@
 {
   pdf_status_t ret;
   pdf_size_t written_bytes;
-  pdf_size_t pending_bytes;
-  pdf_size_t to_write_bytes;
   pdf_stm_filter_t tail_filter;
-  pdf_stm_buffer_t tail_buffer;
-  pdf_size_t tail_buffer_size;
+  pdf_ring_buffer_t tail_buffer;
 
   if (stm->mode != PDF_STM_WRITE)
     {
@@ -206,34 +220,26 @@
   while ((written_bytes < bytes) &&
          (ret == PDF_OK))
     {
-      if (pdf_stm_buffer_full_p (tail_buffer))
+      if (pdf_ring_buffer_full_p (tail_buffer))
         {
-          /* Flush the cache */
-          tail_buffer_size = tail_buffer->wp - tail_buffer->rp;
-          if (pdf_stm_flush (stm) < tail_buffer_size)
-            {
-              ret = PDF_EEOF;
-            }
+          /* Flush the cache
+            [FIX] The test for EOF was not correct.
+         */
+          pdf_stm_flush (stm);
+         
+         if (!pdf_ring_buffer_empty_p (tail_buffer))
+           {
+             return PDF_EOF;
+           }
         }
 
       if (ret == PDF_OK)
         {
-          /* Write the data into the tail buffer. Note that at this
-             point the tail buffer should be empty */
-          tail_buffer_size = tail_buffer->size - tail_buffer->wp;
-          pending_bytes = bytes - written_bytes;
-
-          to_write_bytes = PDF_MIN(pending_bytes, tail_buffer_size);
-
-          if (to_write_bytes != 0)
-            {
-              memcpy ((char *) tail_buffer->data + tail_buffer->wp,
-                      (char *) buf + written_bytes,
-                      to_write_bytes);
-
-              written_bytes += to_write_bytes;
-              tail_buffer->wp += to_write_bytes;
-            }
+          /* Write the data into the tail buffer. */
+          written_bytes +=
+           pdf_ring_buffer_safe_write (tail_buffer,
+                                       buf + written_bytes,
+                                       bytes - written_bytes);
         }
     }
   
@@ -244,9 +250,9 @@
 pdf_stm_flush (pdf_stm_t stm)
 {
   pdf_stm_filter_t tail_filter;
-  pdf_stm_buffer_t tail_buffer;
+  pdf_ring_buffer_t tail_buffer;
   pdf_status_t ret;
-  pdf_size_t cache_size;
+  pdf_size_t read_bytes;
   pdf_size_t written_bytes;
   pdf_size_t flushed_bytes;
 
@@ -263,21 +269,24 @@
      tail filter gets empty */
   flushed_bytes = 0;
   ret = PDF_OK;
-  while ((!pdf_stm_buffer_eob_p (tail_buffer)) &&
-         (ret == PDF_OK))
+  while ((pdf_stm_filter_has_data_p (stm->filter)) &&
+         (ret != PDF_ERROR))
     {
       ret = pdf_stm_filter_apply (stm->filter, PDF_FALSE);
-      
+
       if (ret != PDF_ERROR)
         {
+         read_bytes = pdf_ring_buffer_safe_read (stm->cache,
+                                                 stm->tmp_buf,
+                                                 stm->cache_size);
+         
           /* Write the data from the buffer cache into the backend */
-          cache_size = stm->cache->wp - stm->cache->rp;
           written_bytes = pdf_stm_be_write (stm->backend,
-                                            stm->cache->data + stm->cache->rp, 
 
-                                            cache_size);
+                                            stm->tmp_buf,  
+                                            read_bytes);
           flushed_bytes += written_bytes;
 
-          if (written_bytes < cache_size)
+          if (written_bytes < read_bytes)
             {
               /* There is no room in the backend */
               ret = PDF_EEOF;
@@ -285,11 +294,6 @@
         }
     }
 
-  if (pdf_stm_buffer_eob_p (tail_buffer))
-    {
-      pdf_stm_buffer_rewind (tail_buffer);
-    }
-
   return flushed_bytes;
 }
 
@@ -303,7 +307,7 @@
   /* Create the new filter */
   filter = pdf_stm_filter_new (filter_type,
                                filter_params,
-                               stm->cache->size);
+                               stm->cache_size);
 
   /* Set the new filter as the new head of the filter chain */
   pdf_stm_filter_set_next (filter, stm->filter);
@@ -332,12 +336,12 @@
 {
   pdf_off_t new_pos;
   pdf_stm_filter_t tail_filter;
-  pdf_stm_buffer_t tail_buffer;
+  pdf_ring_buffer_t tail_buffer;
 
   if (stm->mode == PDF_STM_READ)
     {
       /* Discard the cache contents */
-      pdf_stm_buffer_rewind (stm->cache);
+      pdf_ring_buffer_reset (stm->cache);
 
       /* Seek the backend */
       new_pos = pdf_stm_be_seek (stm->backend, pos);
@@ -353,7 +357,7 @@
 
       /* Note that if there is an EOF condition in the backend we are
          going to lose data */
-      pdf_stm_buffer_rewind (tail_buffer);
+      pdf_ring_buffer_reset (tail_buffer);
 
       /* Seek the backend */
       new_pos = pdf_stm_be_seek (stm->backend, pos);
@@ -366,14 +370,13 @@
 pdf_stm_tell (pdf_stm_t stm)
 {
   pdf_off_t pos;
-  pdf_size_t cache_size;
   pdf_stm_filter_t tail_filter;
-  pdf_stm_buffer_t tail_buffer;
+  pdf_ring_buffer_t tail_buffer;
 
   if (stm->mode == PDF_STM_READ)
     {
-      cache_size = stm->cache->wp - stm->cache->rp;
-      pos = pdf_stm_be_tell (stm->backend) + cache_size;
+      pos = pdf_stm_be_tell (stm->backend)
+       + pdf_ring_buffer_read_avail (stm->cache);
     }
   else
     {
@@ -382,8 +385,8 @@
       tail_filter = pdf_stm_filter_get_tail (stm->filter);
       tail_buffer = pdf_stm_filter_get_in (tail_filter);
 
-      cache_size = tail_buffer->wp - tail_buffer->rp;
-      pos = pdf_stm_be_tell (stm->backend) + cache_size;
+      pos = pdf_stm_be_tell (stm->backend)
+       + pdf_ring_buffer_read_avail (tail_buffer);
     }
 
   return pos;
@@ -392,40 +395,51 @@
 pdf_size_t
 pdf_stm_finish (pdf_stm_t stm)
 {
-  pdf_stm_filter_t tail_filter;
-  pdf_stm_buffer_t tail_buffer;
   pdf_status_t ret;
   pdf_size_t written_bytes;
-  pdf_size_t cache_size;
+  pdf_size_t read_bytes;
 
   if (stm->mode != PDF_STM_WRITE)
     {
-      /* Invalid operation */
+      /* Invalid operation
+
+        [NOTE] Why? I think that we must be able to finish read streams.
+        I think that this can be achieved by finishing the filters when
+        a read operation results in the filters returning EOF. If we
+        don't finish read filters, they will often return invalid data.
+      */
       return 0;
     }
 
   written_bytes = 0;
-  tail_filter = pdf_stm_filter_get_tail (stm->filter);
-  tail_buffer = pdf_stm_filter_get_in (tail_filter);
-
-  /* Rewind the tail buffer */
-  pdf_stm_buffer_rewind (tail_buffer);
   
   /* Finish the filters */
+  pdf_stm_flush (stm);
+
+  /* Cache the finish symbols. */
   ret = pdf_stm_filter_apply (stm->filter, PDF_TRUE);
-      
-  if (ret != PDF_ERROR)
+  
+  /* Not needed. */
+  /*
+    if (ret == PDF_EOF)
     {
-      /* Write the data from the buffer cache into the backend. 
+  */
+  /* Write the data from the buffer cache into the backend. 
          
-         Note that we have a design flaw here: the data generated by
-         the finalization of the filters should not exceed the size of
-         the stream cache. */
-      cache_size = stm->cache->wp - stm->cache->rp;
-      written_bytes = pdf_stm_be_write (stm->backend,
-                                        stm->cache->data + stm->cache->rp,  
-                                        cache_size);
-    }
+     Note that we have a design flaw here: the data generated by
+     the finalization of the filters should not exceed the size of
+     the stream cache.
+
+     [NOTE] This can be fixed leting the filter suggest a minimum
+     cache size.
+  */
+  read_bytes = pdf_ring_buffer_safe_read (stm->cache,
+                                         stm->tmp_buf,
+                                         stm->cache_size);
+  written_bytes = pdf_stm_be_write (stm->backend,
+                                   stm->tmp_buf,  
+                                   read_bytes);
+  /*}*/
 
   return written_bytes;
 }
@@ -447,15 +461,26 @@
       cache_size = PDF_STM_DEFAULT_CACHE_SIZE;
     } 
 
-  /* Initialize the null filter */
+  /* Initialize the null filter
+
+     [NOTE] I suggest not using a NULL filter. The code
+     can be easily changed to avoid it.
+  */
   pdf_hash_new (NULL, &null_filter_params);
   stm->filter = pdf_stm_filter_new (PDF_STM_FILTER_NULL,
                                     null_filter_params,
                                     cache_size);
 
   /* Initialize the filter cache */
-  stm->cache = pdf_stm_buffer_new (cache_size);
-
+  stm->cache = pdf_ring_buffer_new (cache_size);
+
+  /* Allocate a temporal buffer for serialization from
+     the ring buffer. */
+  stm->tmp_buf = pdf_alloc (cache_size);
+
+  /* Remember the cache size for convenience. */
+  stm->cache_size = cache_size;
+  
   /* Configure the filter */
   stm->mode = mode;
   if (stm->mode == PDF_STM_READ)
@@ -493,26 +518,28 @@
   pdf_u32_t ret_char;
 
   /* Is the cache empty? */
+  
   ret = PDF_OK;
-  if (pdf_stm_buffer_eob_p (stm->cache))
+  if (pdf_ring_buffer_empty_p (stm->cache))
     {
       ret = pdf_stm_filter_apply (stm->filter, PDF_FALSE);
     }
 
-  if (pdf_stm_buffer_eob_p (stm->cache))
+  if (pdf_ring_buffer_empty_p (stm->cache))
     {
       ret_char = PDF_EOF;
     }
   else
     {
       /* Read a character from the cache */
-      ret_char = 
-        (pdf_u32_t) stm->cache->data[stm->cache->rp];
-
-      if (!peek_p)
+      if (peek_p)
         {
-          stm->cache->rp++;
+          ret_char = pdf_ring_buffer_peek (stm->cache);
         }
+      else
+       {
+         ret_char = pdf_ring_buffer_read_one (stm->cache);
+       }
     }
   
   return ret_char;

=== modified file 'src/base/pdf-stm.h'
--- src/base/pdf-stm.h  2008-09-21 19:29:09 +0000
+++ src/base/pdf-stm.h  2008-10-02 21:51:49 +0000
@@ -53,7 +53,7 @@
 #include <pdf-types.h>
 #include <pdf-hash.h>
 #include <pdf-fsys.h>
-#include <pdf-stm-buffer.h>
+#include <pdf-ring-buffer.h>
 #include <pdf-stm-filter.h>
 #include <pdf-stm-be.h>
 
@@ -75,7 +75,8 @@
 enum pdf_stm_type_e
 {
   PDF_STM_FILE,
-  PDF_STM_MEM
+  PDF_STM_MEM,
+  PDF_STM_CFILE
 };
 
 /* Stream data type */
@@ -84,9 +85,11 @@
   enum pdf_stm_type_e type;
   enum pdf_stm_mode_e mode;
 
-  pdf_stm_be_t backend;     /* Stream backend */
-  pdf_stm_filter_t filter;  /* Filter chain */
-  pdf_stm_buffer_t cache;   /* Stream cache */
+  pdf_stm_be_t      backend;    /* Stream backend */
+  pdf_stm_filter_t  filter;     /* Filter chain */
+  pdf_ring_buffer_t cache;      /* Stream cache */
+  pdf_char_t*       tmp_buf;    /* Serialization buffer */
+  pdf_size_t        cache_size; /* Size of the cache */
 };
 
 typedef struct pdf_stm_s *pdf_stm_t;
@@ -96,6 +99,11 @@
  */
 
 /* Creation and destruction */
+pdf_status_t pdf_stm_cfile_new (FILE* file,
+                               pdf_off_t offset,
+                               pdf_size_t cache_size,
+                               enum pdf_stm_mode_e mode,
+                               pdf_stm_t *stm);
 pdf_status_t pdf_stm_file_new (pdf_fsys_file_t file,
                                pdf_off_t offset,
                                pdf_size_t cache_size,

=== modified file 'utils/pdf-filter.c'
--- utils/pdf-filter.c  2008-09-28 10:56:49 +0000
+++ utils/pdf-filter.c  2008-10-02 21:51:49 +0000
@@ -30,9 +30,9 @@
 #include <getopt.h>
 
 #ifdef HAVE_MALLOC_H
- #include <malloc.h>
+#include <malloc.h>
 #else
- #include <stdlib.h>
+#include <stdlib.h>
 #endif /* HAVE_MALLOC_H */
 
 #include <xalloc.h>
@@ -55,47 +55,53 @@
  */
 
 static struct option GNU_longOptions[] =
-{
-  {"help", no_argument, NULL, HELP_ARG},
-  {"usage", no_argument, NULL, USAGE_ARG},
-  {"version", no_argument, NULL, VERSION_ARG},
-  {"null", no_argument, NULL, NULL_FILTER_ARG},
-  {"ahexdec", no_argument, NULL, ASCIIHEXDEC_FILTER_ARG},
-  {"ahexenc", no_argument, NULL, ASCIIHEXENC_FILTER_ARG},
-  {"a85dec", no_argument, NULL, ASCII85DEC_FILTER_ARG},
-  {"a85enc", no_argument, NULL, ASCII85ENC_FILTER_ARG},
-  {"lzwenc", no_argument, NULL, LZWENC_FILTER_ARG},
-  {"lzwdec", no_argument, NULL, LZWDEC_FILTER_ARG},
+  {
+    {"help", no_argument, NULL, HELP_ARG},
+    {"usage", no_argument, NULL, USAGE_ARG},
+    {"version", no_argument, NULL, VERSION_ARG},
+    {"readmode", no_argument, NULL, READ_ARG},
+    {"cache", required_argument, NULL, CACHE_ARG},
+    {"null", no_argument, NULL, NULL_FILTER_ARG},
+    {"ahexdec", no_argument, NULL, ASCIIHEXDEC_FILTER_ARG},
+    {"ahexenc", no_argument, NULL, ASCIIHEXENC_FILTER_ARG},
+    {"a85dec", no_argument, NULL, ASCII85DEC_FILTER_ARG},
+    {"a85enc", no_argument, NULL, ASCII85ENC_FILTER_ARG},
+    {"lzwenc", no_argument, NULL, LZWENC_FILTER_ARG},
+    {"lzwdec", no_argument, NULL, LZWDEC_FILTER_ARG},
 #ifdef HAVE_LIBZ
-  {"flatedec", no_argument, NULL, FLATEDEC_FILTER_ARG},
-  {"flateenc", no_argument, NULL, FLATEENC_FILTER_ARG},
+    {"flatedec", no_argument, NULL, FLATEDEC_FILTER_ARG},
+    {"flateenc", no_argument, NULL, FLATEENC_FILTER_ARG},
 #endif /* HAVE_LIBZ */
-  {"rldec", no_argument, NULL, RUNLENGTHDEC_FILTER_ARG},
-  {"rlenc", no_argument, NULL, RUNLENGTHENC_FILTER_ARG},
-  {"cfaxdec", no_argument, NULL, CCITTFAXDEC_FILTER_ARG},
-  {"jbig2dec", no_argument, NULL, JBIG2DEC_FILTER_ARG},
-  {"dctdec", no_argument, NULL, DCTDEC_FILTER_ARG},
-  {"jxpdec", no_argument, NULL, JXPDEC_FILTER_ARG},
-  {"predenc", no_argument, NULL, PREDENC_FILTER_ARG},
-  {"preddec", no_argument, NULL, PREDDEC_FILTER_ARG},
-  {"lzw-earlychange", no_argument, NULL, LZW_EARLY_CHANGE_ARG},
-  {"predenc-type", required_argument, NULL, PREDENC_TYPE_ARG},
-  {"preddec-type", required_argument, NULL, PREDDEC_TYPE_ARG},
-  {"pred-colors", required_argument, NULL, PRED_COLORS_ARG},
-  {"pred-bpc", required_argument, NULL, PRED_BPC_ARG},
-  {"pred-columns", required_argument, NULL, PRED_COLUMNS_ARG},
-  {NULL, 0, NULL, 0}
-};
+    {"rldec", no_argument, NULL, RUNLENGTHDEC_FILTER_ARG},
+    {"rlenc", no_argument, NULL, RUNLENGTHENC_FILTER_ARG},
+    {"cfaxdec", no_argument, NULL, CCITTFAXDEC_FILTER_ARG},
+    {"jbig2dec", no_argument, NULL, JBIG2DEC_FILTER_ARG},
+    {"dctdec", no_argument, NULL, DCTDEC_FILTER_ARG},
+    {"jxpdec", no_argument, NULL, JXPDEC_FILTER_ARG},
+    {"predenc", no_argument, NULL, PREDENC_FILTER_ARG},
+    {"preddec", no_argument, NULL, PREDDEC_FILTER_ARG},
+    {"lzw-earlychange", no_argument, NULL, LZW_EARLY_CHANGE_ARG},
+    {"predenc-type", required_argument, NULL, PREDENC_TYPE_ARG},
+    {"preddec-type", required_argument, NULL, PREDDEC_TYPE_ARG},
+    {"pred-colors", required_argument, NULL, PRED_COLORS_ARG},
+    {"pred-bpc", required_argument, NULL, PRED_BPC_ARG},
+    {"pred-columns", required_argument, NULL, PRED_COLUMNS_ARG},
+    {NULL, 0, NULL, 0}
+  };
 
 /* Messages */
 
 char *pdf_filter_version_msg = "pdf_filter 0.1";
 
 char *pdf_filter_usage_msg = "\
-Usage: pdf_filter [[FILTER FILTER_ARGS]...]\n\
+Usage: pdf_filter [[OPTIONS] [FILTER FILTER_ARGS]...]\n\
 Filter the standard input with the specified PDF standard filters and \n\
 write the result in the standard output.\n\
 \n\
+availible options\
+  --readmode                          test the stream in read mode instead\
+                                       of write mode.\n\
+  --cache=NUM                         set the stream cache size.\n\n\
 available filters\n\
   --null                              use the NULL filter\n\
   --ahexdec                           use the ASCII Hex decoder filter\n\
@@ -105,10 +111,10 @@
   --lzwenc                            use the LZW encoder filter\n\
   --lzwdec                            use the LZW decoder filter\n"
 #ifdef HAVE_LIBZ
-"  --flatedec                          use the Flate decoder filter\n\
+  "  --flatedec                          use the Flate decoder filter\n\
   --flateenc                          use the Flate encoder filter\n"
 #endif /* HAVE_LIBZ */
-"  --rldec                             use the Run Length decoder filter\n\
+  "  --rldec                             use the Run Length decoder filter\n\
   --rlenc                             use the Run Length encoder filter\n\
   --cfaxdec                           use the CCITT Fax decoder filter\n\
   --jbig2dec                          use the JBIG2 decoder filter\n\
@@ -130,69 +136,88 @@
 
 char *pdf_filter_help_msg = "";
 
-typedef struct filter_args_s
-{
-  int lzw_early_change;
-  int pred_enc_type;
-  int pred_dec_type;
-  int pred_colors;
-  int pred_bpc;
-  int pred_columns;
-} filter_args_t;
-
-static void
-filter_args_init(filter_args_t* a)
-{
-  /*  a->lzw_early_change = DEF_LZW_EARLY_CHANGE;
-  a->pred_enc_type = DEF_PRED_ENC_TYPE;
-  a->pred_dec_type = DEF_PRED_DEC_TYPE;
-  a->pred_colors = DEF_PRED_COLORS;
-  a->pred_bpc = DEF_PRED_BPC;
-  a->pred_columns = DEF_PRED_COLUMS; */
-}
+static pdf_stm_t
+create_stream (int argc, char* argv[], pdf_bool_t* mode, pdf_status_t* 
last_ret);
+
+static void
+install_filters (int argc, char* argv[], pdf_stm_t stm, pdf_status_t ret);
+
+static void
+process_stream (pdf_stm_t, pdf_bool_t mode);
 
 int
 main (int argc, char *argv[])
 {
+  pdf_stm_t stm;
+  pdf_bool_t read_mode;
+  pdf_status_t last_ret;
+  
+  stm = create_stream (argc, argv, &read_mode, &last_ret);
+  install_filters (argc, argv, stm, last_ret);
+  process_stream (stm, read_mode);
+  pdf_stm_destroy (stm);
+ 
+  return 0;
+}
+
+static void
+process_stream (pdf_stm_t stm, pdf_bool_t read_mode)
+{
+#define BUF_SIZE 256
+  
+  pdf_size_t read_bytes;
+  pdf_char_t buf [BUF_SIZE];
+  
+  if (read_mode)
+    {
+      /* Read from the buffer which will process anything on stdin
+        and push to stdout */
+      do
+       {
+         read_bytes = pdf_stm_read (stm, buf, BUF_SIZE);
+         fwrite (buf, 1, read_bytes, stdout);
+       }
+      while (read_bytes == BUF_SIZE);
+
+      /* [NOTE] We should add a pdf_stm_finish. Read pdf_stm_finish note. */
+    }
+  else
+    {
+      /* Write stdin into the write stream,
+        which will be transparently writting the output to stdout. */
+      do
+       {
+         read_bytes = fread (buf, 1, BUF_SIZE, stdin);
+         pdf_stm_write (stm, buf, read_bytes);
+       }
+      while (read_bytes == BUF_SIZE);
+
+      pdf_stm_finish (stm);
+    }
+  
+#undef BUF_SIZE
+}
+
+static pdf_stm_t
+create_stream (int argc, char* argv[], pdf_bool_t* read_mode,
+              pdf_status_t* last_ret)
+{
   char c;
-  pdf_stm_t stm;
-  pdf_char_t *buf;
-  pdf_size_t buf_size;
   pdf_status_t ret;
-  pdf_hash_t null_filter_params;
-  pdf_hash_t ahexenc_filter_params;
-  pdf_hash_t ahexdec_filter_params;
-  pdf_hash_t rlenc_filter_params;
-  pdf_hash_t rldec_filter_params;
-  pdf_char_t *line;
-  pdf_size_t line_bytes;
-  pdf_size_t read_bytes;
-  pdf_size_t written_bytes;
-
-  /* Create the output buffer */
-  buf_size = 4096;
-  buf = pdf_alloc (buf_size);
-
-  /* Create a writing memory stream */
-  ret = pdf_stm_mem_new (buf,
-                         buf_size,
-                         0, /* Use the default cache size */
-                         PDF_STM_WRITE,
-                         &stm);
-  if (ret != PDF_OK)
-    {
-      pdf_error (ret, stderr, "while creating the write stream");
-      exit (1);
-    }
-
-  /*  filter_args_init(&args); */
-
-  /* Manage command line arguments */
-  while ((ret = getopt_long (argc,
-                           argv,
-                           "",
-                           GNU_longOptions, 
-                           NULL)) != -1)
+  pdf_size_t cache_size;
+  pdf_stm_t stm;
+  pdf_bool_t finish;
+
+  finish = PDF_FALSE;
+  cache_size = 0;
+  *read_mode = PDF_FALSE; 
+    
+  while (!finish &&
+        (ret = getopt_long (argc,
+                            argv,
+                            "",
+                            GNU_longOptions, 
+                            NULL)) != -1)
     {
       c = ret;
       switch (c)
@@ -216,6 +241,69 @@
             exit (0);
             break;
           }
+       case READ_ARG:
+         {
+           *read_mode = PDF_TRUE;
+           break;
+         }
+       case CACHE_ARG:
+         {
+           cache_size = atoi (optarg);
+           break;
+         }
+       case '?':
+       default:
+         {
+           finish = PDF_TRUE;
+           break;
+         }
+       }
+    }
+  *last_ret = ret;
+
+  /* Create a stream */
+  if (*read_mode)
+    {
+      ret = pdf_stm_cfile_new (stdin,
+                              0,
+                              cache_size, 
+                              PDF_STM_READ,
+                              &stm);
+    }
+  else
+    {
+      ret = pdf_stm_cfile_new (stdout,
+                              0,
+                              cache_size,
+                              PDF_STM_WRITE,
+                              &stm);
+    }
+  
+  if (ret != PDF_OK)
+    {
+      pdf_error (ret, stderr, "while creating the write stream");
+      exit (1);
+    }
+
+  return stm;
+}
+
+static void
+install_filters (int argc, char* argv[], pdf_stm_t stm, pdf_status_t ret)
+{
+  char c;
+  pdf_hash_t null_filter_params;
+  pdf_hash_t ahexenc_filter_params;
+  pdf_hash_t ahexdec_filter_params;
+  pdf_hash_t rlenc_filter_params;
+  pdf_hash_t rldec_filter_params;
+
+  /* Install filters */
+  do
+    {
+      c = ret;
+      switch (c)
+       {
          /* FILTER INSTALLERS */
         case NULL_FILTER_ARG:
           {
@@ -321,7 +409,6 @@
                 pdf_error (ret, stderr, "while creating the rlenc filter 
parameters hash table");
                 exit (1);
               }
-
             pdf_stm_install_filter (stm,
                                     PDF_STM_FILTER_RL_ENC,
                                     rlenc_filter_params);
@@ -404,41 +491,12 @@
           }
         }
     }
-
-  /* Write stdin into the write stream */
-  line = NULL;
-  line_bytes = 0;
-  while ((read_bytes = getline ((char **) &line, &line_bytes, stdin)) != EOF)
-    {
-      pdf_stm_seek (stm, 0);
-      pdf_stm_write (stm,
-                     line,
-                     read_bytes);
-
-      written_bytes = pdf_stm_flush (stm);
-      fwrite ((char *) buf,
-              written_bytes,
-              1,
-              stdout);
-
-      pdf_dealloc (line);
-      line = NULL;
-      line_bytes = 0;
-    }
-
-  pdf_stm_seek (stm, 0);
-  written_bytes = pdf_stm_finish (stm);
-  fwrite ((char *) buf,
-          written_bytes,
-          1,
-          stdout);
-
-  /* Cleanup */
-  free (buf);
-  pdf_stm_destroy (stm);
-  
-  return 0;
+  while ((ret = getopt_long (argc,
+                            argv,
+                            "",
+                            GNU_longOptions, 
+                            NULL)) != -1);
+
 }
 
-
 /* End of pdf_filter.c */

=== modified file 'utils/pdf-filter.h'
--- utils/pdf-filter.h  2008-02-11 01:11:25 +0000
+++ utils/pdf-filter.h  2008-10-02 21:51:49 +0000
@@ -36,6 +36,8 @@
   HELP_ARG,
   USAGE_ARG,
   VERSION_ARG,
+  READ_ARG,
+  CACHE_ARG,
   NULL_FILTER_ARG,
   ASCIIHEXDEC_FILTER_ARG,
   ASCIIHEXENC_FILTER_ARG,

# Begin bundle
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
Az9rWfP9gSbmP/uj/8XckU4UJDe/ItQA

reply via email to

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