Here's the current version of my token writer code for review.  It's
basically complete, but I'll need to read over it again and do some more
testing before submitting a final version.

Anyone wanting to test it could use the new --token-writer flag (and
possibly the --reader-flags and --writer-flags parameters) for
utils/pdf-tokeniser to read in a file (with no streams) and write it out
again.

-- Michael
# Bazaar merge directive format 2 (Bazaar 0.90)
# revision_id: [email protected]
# target_branch: file:///home/michael/src/%2Blocal/gnupdf/trunk/
# testament_sha1: d98ca6749064824f21ca16ce1514bb1ee207ed02
# timestamp: 2009-10-25 14:07:18 -0400
# base_revision_id: jema...@termi-20091021125920-kkzb61bh82cu8gew
# 
# Begin patch
=== modified file 'src/Makefile.am'
--- src/Makefile.am	2009-06-27 23:19:51 +0000
+++ src/Makefile.am	2009-10-25 18:06:21 +0000
@@ -84,7 +84,8 @@
                     base/pdf-fp-func.h base/pdf-fp-func.c
 
 TOKEN_MODULE_SOURCES = base/pdf-token.c base/pdf-token.h \
-                       base/pdf-token-reader.c base/pdf-token-reader.h
+                       base/pdf-token-reader.c base/pdf-token-reader.h \
+                       base/pdf-token-writer.c base/pdf-token-writer.h
 
 BASE_LAYER_SOURCES = base/pdf-base.c base/pdf-base.h \
                      $(ALLOC_MODULE_SOURCES) \
@@ -143,7 +144,8 @@
               base/pdf-crypt.h \
               base/pdf-fp-func.h \
               base/pdf-token.h \
-              base/pdf-token-reader.h
+              base/pdf-token-reader.h \
+              base/pdf-token-writer.h
 
 pdf.h : $(PUBLIC_HDRS)
 	chmod +x $(top_builddir)/src/extract-public-hdr

=== modified file 'src/base/pdf-stm.c'
--- src/base/pdf-stm.c	2009-10-21 07:08:09 +0000
+++ src/base/pdf-stm.c	2009-10-25 18:06:21 +0000
@@ -1,4 +1,4 @@
-/* -*- mode: C -*- Time-stamp: "2009-10-21 04:48:36 mgold"
+/* -*- mode: C -*- Time-stamp: "2009-10-22 08:14:33 mgold"
  *
  *       File:         pdf-stm.c
  *       Date:         Fri Jul  6 18:43:15 2007
@@ -206,7 +206,7 @@
 
 pdf_status_t
 pdf_stm_write (pdf_stm_t stm,
-               pdf_char_t *buf,
+               const pdf_char_t *buf,
                pdf_size_t bytes,
                pdf_size_t *written_bytes)
 {

=== modified file 'src/base/pdf-stm.h'
--- src/base/pdf-stm.h	2009-06-16 20:22:17 +0000
+++ src/base/pdf-stm.h	2009-10-25 18:06:21 +0000
@@ -107,7 +107,7 @@
                            pdf_size_t bytes,
                            pdf_size_t *read_bytes);
 pdf_status_t pdf_stm_write (pdf_stm_t stm,
-                            pdf_char_t *buf,
+                            const pdf_char_t *buf,
                             pdf_size_t bytes,
                             pdf_size_t *written_bytes);
 pdf_status_t pdf_stm_read_char (pdf_stm_t stm, pdf_char_t *c);

=== added file 'src/base/pdf-token-writer.c'
--- src/base/pdf-token-writer.c	1970-01-01 00:00:00 +0000
+++ src/base/pdf-token-writer.c	2009-10-25 18:06:21 +0000
@@ -0,0 +1,869 @@
+/* -*- mode: C -*- Time-stamp: "2009-10-25 06:56:00 mgold"
+ *
+ *       File:         pdf-token-writer.c
+ *       Date:         Wed Sep 23 04:37:51 2009
+ *
+ *       GNU PDF Library - Stream token writer
+ *
+ */
+
+/* Copyright (C) 2009 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 <config.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+#include <inttypes.h>
+#include <math.h>
+
+#include <pdf-token-writer.h>
+
+pdf_status_t
+pdf_token_writer_new (pdf_stm_t stm, pdf_token_writer_t *writer)
+{
+  pdf_status_t err;
+  pdf_token_writer_t new_tokw;
+
+  err = PDF_ENOMEM;
+  new_tokw = pdf_alloc (sizeof (*new_tokw));
+  if (!new_tokw)
+    goto fail;
+
+  /* determine the current locale's decimal point
+   * (avoid using localeconv since it may not be thread-safe) */
+  new_tokw->decimal_point = NULL;
+  {
+    int len;
+    char decpt[16];
+
+    err = PDF_ERROR;
+    len = snprintf (decpt, sizeof (decpt), "%#.0f", 1.0);
+    if (len <= 0 || (pdf_size_t)len >= sizeof (decpt))  /* shouldn't happen */
+      goto fail;
+
+    err = PDF_ENOMEM;
+    new_tokw->decimal_point = pdf_alloc (len);
+    if (!new_tokw->decimal_point)
+      goto fail;
+
+    /* this copies the trailing '\0' due to the starting offset */
+    memcpy (new_tokw->decimal_point, &decpt[1], len);
+  }
+
+  /* PDF32000 7.5.1: "lines that are not part of stream object data
+   * are limited to no more than 255 characters"... */
+  new_tokw->max_line_length = 255;  /* set to 0 to disable */
+
+  new_tokw->buffer = pdf_buffer_new (32768);
+  if (!new_tokw->buffer)
+    goto fail;
+
+  new_tokw->stream = stm;
+  pdf_token_writer_reset (new_tokw);
+
+  *writer = new_tokw;
+  return PDF_OK;
+
+fail:
+  if (new_tokw)
+    pdf_dealloc (new_tokw->decimal_point);
+  pdf_dealloc (new_tokw);
+
+  return err;
+}
+
+pdf_status_t
+pdf_token_writer_reset (pdf_token_writer_t writer)
+{
+  writer->pos = 0;
+  writer->stage = 0;
+  writer->in_keyword = PDF_FALSE;
+  writer->line_length = 0;
+  return PDF_OK;
+}
+
+pdf_status_t
+pdf_token_writer_destroy (pdf_token_writer_t writer)
+{
+  if (!writer) return PDF_EBADDATA;
+
+  assert (writer->buffer);
+  if (writer->buffer)
+    pdf_buffer_destroy (writer->buffer);
+  pdf_dealloc (writer->decimal_point);
+  pdf_dealloc (writer);
+
+  return PDF_OK;
+}
+
+
+/***** Unbuffered output *****/
+
+/* Write data to the stream.  All output passes through this function. */
+static pdf_status_t
+write_data (pdf_token_writer_t writer, const pdf_char_t *data,
+            pdf_size_t len, pdf_size_t *written)
+{
+  pdf_size_t i;
+  pdf_status_t rv;
+
+  rv = pdf_stm_write (writer->stream, data, len, written);
+  if (rv != PDF_OK)
+    return rv;
+
+  for (i = 0; i < *written; ++i)
+    {
+      pdf_char_t ch = data[i];
+      ++writer->line_length;
+      if (pdf_is_eol_char (ch))
+        writer->line_length = 0;
+
+      writer->in_keyword = pdf_is_regular_char (ch);
+    }
+  return PDF_OK;
+}
+
+/* Write a single character. */
+static INLINE pdf_status_t
+write_char (pdf_token_writer_t writer, pdf_char_t ch)
+{
+  pdf_size_t written;
+  return write_data (writer, &ch, 1, &written);
+}
+
+/* Write data starting at writer->pos, incrementing writer->pos as needed. */
+static INLINE pdf_status_t
+write_data_using_pos (pdf_token_writer_t writer,
+                      const pdf_char_t *data, pdf_size_t len)
+{
+  pdf_status_t rv;
+  pdf_size_t written;
+  if (writer->pos > len)
+    return PDF_EBADDATA;
+
+  while (writer->pos < len)
+    {
+      rv = write_data (writer, data + writer->pos, len - writer->pos,
+                       &written);
+      if (rv != PDF_OK)
+        return rv;
+
+      writer->pos += written;
+    }
+  return PDF_OK;
+}
+
+
+/***** Buffered output, buffer management *****/
+
+/* Write all buffered data to the stream. */
+static pdf_status_t
+flush_buffer (pdf_token_writer_t writer)
+{
+  pdf_buffer_t buf = writer->buffer;
+  pdf_size_t len;
+  while ( (len = buf->wp - buf->rp) > 0 )
+    {
+      pdf_size_t written;
+      pdf_status_t rv = write_data (writer,
+                                    buf->data + buf->rp,
+                                    len, &written);
+      if (rv != PDF_OK)
+        return rv;
+
+      buf->rp += written;
+    }
+  return pdf_buffer_rewind (buf);
+}
+
+/* Flush the buffer if there are less than 'len' bytes free. */
+static INLINE pdf_status_t
+reserve_buffer_space (pdf_token_writer_t writer, pdf_size_t len)
+{
+  if (writer->buffer->wp + len > writer->buffer->size)
+    {
+      pdf_status_t rv = flush_buffer (writer);
+      if (rv != PDF_OK)
+        return rv;
+
+      assert (len < writer->buffer->size);
+      assert (writer->buffer->wp == 0);
+    }
+  return PDF_OK;
+}
+
+/* Write a character into the buffer; this assumes it will fit. */
+static INLINE void
+write_buffered_char_nocheck (pdf_token_writer_t writer, pdf_char_t ch)
+{
+  writer->buffer->data[writer->buffer->wp++] = ch;
+  if (pdf_is_eol_char(ch))
+    writer->buffered_line_length = 0;
+  else
+    ++writer->buffered_line_length;
+}
+
+/* Write a character into the buffer.  The buffer is flushed only if
+ * there's no room to write the character. */
+static INLINE pdf_status_t
+write_buffered_char (pdf_token_writer_t writer, pdf_char_t ch)
+{
+  pdf_status_t rv = reserve_buffer_space (writer, 1);
+  if (rv == PDF_OK)
+    write_buffered_char_nocheck (writer, ch);
+  return rv;
+}
+
+
+/***** Misc. utility functions *****/
+
+/* Takes a number from 0 to 15 and returns the ASCII code for the
+ * corresponding hexadecimal digit. */
+static INLINE pdf_char_t
+hexchar (pdf_char_t ch)
+{
+  if (ch < 10)
+    return 48 + ch;       /* '0'--'9' */
+  else if (ch < 16)
+    return 65 + ch - 10;  /* 'A'--'F' */
+  return 255;
+}
+
+static pdf_status_t
+start_token (pdf_token_writer_t writer, pdf_bool_t need_wspace,
+             pdf_size_t len)
+{
+  pdf_bool_t add_wspace = (need_wspace && writer->in_keyword);
+  pdf_char_t wspace_char = 32;  /*space*/
+
+  if (add_wspace)
+    ++len;
+
+  if (writer->line_length + len > writer->max_line_length
+       && writer->max_line_length > 0)
+    {
+      add_wspace = PDF_TRUE;
+      wspace_char = 10;  /* newline */
+    }
+
+  if (add_wspace)
+    {
+      pdf_status_t rv = write_char (writer, wspace_char);
+      if (rv != PDF_OK) return rv;
+    }
+
+  return PDF_OK;
+}
+
+
+/***** Numeric tokens *****/
+
+/* Encode snprintf output for PDF.  'len' is the return value of snprint.
+ * Re-encodes bytes 0 to 'len' of writer->buffer and resets buffer->rp/wp. */
+static pdf_bool_t
+encode_buffer_number (pdf_token_writer_t writer, int len)
+{
+  pdf_buffer_t buf = writer->buffer;
+  if (len < 0 || len >= buf->size)
+    return PDF_FALSE;  /* snprint failed, or truncated its output. */
+
+  buf->wp = buf->rp = 0;
+  while (buf->wp < len)
+    {
+      char ch = (char)buf->data[buf->rp];
+      if (ch == '-')
+        {
+          ++buf->rp;
+          buf->data[buf->wp++] = 45;  /* '-' */
+        }
+      else if (ch >= '0' && ch <= '9')
+        {
+          ++buf->rp;
+          buf->data[buf->wp++] = 48 + (ch - '0');
+        }
+      else
+        {
+          /* This should be a decimal point; check it. */
+          pdf_size_t declen = strlen (writer->decimal_point);
+          int cmp = memcmp (buf->data + buf->rp,
+                            writer->decimal_point, declen);
+          if (cmp != 0)
+            return PDF_FALSE;  /* unexpected char */
+
+          buf->rp += declen;
+          buf->data[buf->wp++] = 46;  /* '.' */
+        }
+    }
+  buf->rp = 0;
+  return PDF_TRUE;  /* success */
+}
+
+static INLINE pdf_status_t
+write_integer_token (pdf_token_writer_t writer, pdf_token_t token)
+{
+  pdf_status_t rv;
+  switch (writer->stage)
+    {
+      case 0:
+        {
+          pdf_i32_t value = pdf_token_get_integer_value (token);
+          int len = snprintf ((char*)writer->buffer->data,
+                              writer->buffer->size, "%"PRId32, value);
+          if (!encode_buffer_number (writer, len)) return PDF_ERROR;
+        }
+        ++writer->stage;  /* fall through */
+      case 1:
+        rv = start_token (writer, PDF_TRUE /*need_wspace*/,
+                          writer->buffer->wp);
+        if (rv != PDF_OK) return rv;
+        ++writer->stage;  /* fall through */
+      case 2:
+        return flush_buffer (writer);
+      default:
+        return PDF_EBADDATA;
+    }
+}
+
+static INLINE pdf_status_t
+write_real_token (pdf_token_writer_t writer, pdf_token_t token)
+{
+  pdf_status_t rv;
+  switch (writer->stage)
+    {
+      case 0:
+        {
+          pdf_buffer_t buf = writer->buffer;
+          pdf_real_t value = pdf_token_get_real_value (token);
+          if (isnan(value) || isinf(value))
+            return PDF_EBADDATA;
+
+          /* The '#' flag forces snprintf to write a decimal point. */
+          int len = snprintf ((char*)buf->data,
+                              buf->size, "%#f", (double)value);
+          if (!encode_buffer_number (writer, len)) return PDF_ERROR;
+
+          /* strip trailing zeroes */
+          while (buf->wp && buf->data[buf->wp-1] == 48 /* '0' */)
+            --buf->wp;
+        }
+        ++writer->stage;  /* fall through */
+      case 1:
+        rv = start_token (writer, PDF_TRUE /*need_wspace*/,
+                          writer->buffer->wp);
+        if (rv != PDF_OK) return rv;
+        ++writer->stage;  /* fall through */
+      case 2:
+        return flush_buffer (writer);
+      default:
+        return PDF_EBADDATA;
+    }
+}
+
+
+/***** String tokens *****/
+
+static INLINE pdf_bool_t
+should_escape_strchar (pdf_u32_t flags, pdf_char_t ch,
+                       pdf_bool_t quote_parens)
+{
+  if (ch == 92 /* '\\' */ || ch == 13 /* CR */)
+    return PDF_TRUE;
+  if (ch == 40 /* '(' */ || ch == 41 /* ')' */)
+    return quote_parens;
+
+  if (flags & PDF_TOKEN_READABLE_STRINGS)
+    {
+      if (ch == 127 || (ch < 32 && ch != 10))
+        return PDF_TRUE;
+    }
+
+  return PDF_FALSE;
+}
+
+static INLINE int
+str_escape_len (const pdf_char_t *data, pdf_size_t len, pdf_size_t pos)
+{
+  switch (data[pos])
+    {
+      /* characters with two-character escape codes */
+      case  8:
+      case  9:
+      case 10:
+      case 12:
+      case 13:
+      case 40:
+      case 41:
+      case 92:
+        return 2;
+    }
+
+  if (data[pos] >= 0100)
+    return 4;  /* escaped using a backslash and 3 octal characters */
+
+  if (pos+1 < len)
+    {
+      if (data[pos+1] >= 48 && data[pos+1] <= 57)  /* '0'..'9' */
+        return 4;  /* need to write a 3-character octal number */
+    }
+
+  return (data[pos] >= 010) ? 3 : 2;
+}
+
+static void
+scan_string (pdf_token_writer_t writer, pdf_u32_t flags,
+             const pdf_char_t *data, pdf_size_t len, pdf_bool_t *use_hex)
+{
+  /* Match parentheses, and determine the portion of the string
+   * in which they should be quoted. */
+  writer->paren_quoting_start = 0;
+  writer->paren_quoting_end = len;
+  pdf_size_t i, j;
+  for (i = 0; i < len; ++i)
+    {
+      if (data[i] == 40)       /* '(' */
+        {
+          for (j = writer->paren_quoting_end - 1; j > i; --j)
+            {
+              /* find a matching ')' */
+              if (data[j] == 41)
+                {
+                  writer->paren_quoting_end = j;
+                  writer->paren_quoting_start = i + 1;
+                  break;
+                }
+            }
+        }
+    }
+
+  /* Determine the size of the escaped string. */
+  pdf_size_t enc_bytes = 0;
+  for (i = 0; i < len; ++i)
+    {
+      pdf_bool_t quote_parens = (i >= writer->paren_quoting_start
+                                  && i < writer->paren_quoting_end);
+      if (should_escape_strchar (flags, data[i], quote_parens))
+        enc_bytes += str_escape_len (data, len, i);
+      else
+        ++enc_bytes;
+    }
+  *use_hex = (enc_bytes > len*2);
+}
+
+static INLINE pdf_status_t
+write_string_char (pdf_token_writer_t writer, pdf_u32_t flags,
+                   const pdf_char_t *data, pdf_char_t len,
+                   pdf_size_t pos)
+{
+  assert (len > 0);
+  pdf_status_t rv;
+  const pdf_char_t *output = data + pos;
+  pdf_size_t outlen = 1;
+  pdf_char_t esc[4] = {92 /* '\\' */, 0, 0, 0};
+
+  pdf_char_t ch = data[pos];
+  pdf_bool_t quote_parens = (pos >= writer->paren_quoting_start
+                              && pos < writer->paren_quoting_end);
+  if (should_escape_strchar (flags, ch, quote_parens))
+    {
+      /* escape the character */
+      output = esc;
+      outlen = 2;
+      switch (ch)
+        {
+          case  8: esc[1] =  98; break; /* 'b' */
+          case  9: esc[1] = 116; break; /* 't' */
+          case 10: esc[1] = 110; break; /* 'n' */
+          case 12: esc[1] = 102; break; /* 'f' */
+          case 13: esc[1] = 114; break; /* 'r' */
+          case 40:  /* '('; fall through */
+          case 41:  /* ')'; fall through */
+          case 92:  /* '\\' */
+            esc[1] = ch;
+            break;
+          default: /* use an octal escape */
+            {
+              pdf_size_t digits;
+              pdf_char_t nextch = (pos+1 < len) ? data[pos+1] : 0;
+              if (nextch >= 48 && nextch <= 57)  /* '0'..'9' */
+                digits = 3;  /* must use 3 octal characters */
+              else if (ch > 0100) digits = 3;
+              else if (ch > 010) digits = 2;
+              else digits = 1;
+
+              outlen = 1;
+              switch (digits)
+                {
+                  /* fall through each case */
+                  case 3: esc[outlen++] = hexchar(ch / 0100);
+                  case 2: esc[outlen++] = hexchar((ch % 0100) / 010);
+                  case 1: esc[outlen++] = hexchar(ch % 010);
+                }
+              }
+        }
+    }
+
+  /* If the line will be too long, split it (the length cannot be equal to
+   * the maximum, since this would leave no room for the backslash). */
+  if (writer->max_line_length > 0 && !pdf_is_eol_char(output[0])
+       && writer->buffered_line_length + outlen >= writer->max_line_length)
+    {
+      rv = reserve_buffer_space (writer, 2);
+      if (rv != PDF_OK) return rv;
+      write_buffered_char_nocheck (writer, 92);  /* '\\' */
+      write_buffered_char_nocheck (writer, 10);  /* newline */
+      assert (writer->buffered_line_length == 0);
+    }
+
+  rv = reserve_buffer_space (writer, outlen);
+  if (rv == PDF_OK)
+    {
+      pdf_size_t i;
+      for (i = 0; i < outlen; ++i)
+        write_buffered_char_nocheck (writer, output[i]);
+    }
+  return rv;
+}
+
+static INLINE pdf_status_t
+write_string_token (pdf_token_writer_t writer, pdf_u32_t flags,
+                    pdf_token_t token)
+{
+  pdf_status_t rv;
+  const pdf_char_t *data = pdf_token_get_string_data (token);
+  pdf_size_t size = pdf_token_get_string_size (token);
+
+  switch (writer->stage)
+    {
+      case 0:
+        {
+          pdf_bool_t use_hex = (flags & PDF_TOKEN_HEX_STRINGS);
+          if (!use_hex)
+            scan_string (writer, flags, data, size, &use_hex);
+
+          if (use_hex)
+            goto hexstring_start;
+        }
+        ++writer->stage;  /* fall through */
+      case 1:
+        {
+          /* Passing a correct length to start_token isn't important
+           * since we can split the string across multiple lines. */
+          pdf_size_t dummy_len = PDF_MIN(20, 2 + size);
+          rv = start_token (writer, PDF_FALSE /*need_wspace*/, dummy_len);
+          if (rv != PDF_OK) return rv;
+        }
+        writer->buffered_line_length = writer->line_length;
+        write_buffered_char_nocheck (writer, 40 /* '(' */);
+        writer->pos = 0;
+        ++writer->stage;  /* fall through */
+      case 2:
+        while (writer->pos < size)
+          {
+            rv = write_string_char (writer, flags, data, size, writer->pos);
+            if (rv != PDF_OK) return rv;
+
+            ++writer->pos;
+          }
+        ++writer->stage;  /* fall through */
+      case 3:
+        rv = write_buffered_char (writer, 41 /* ')' */);
+        if (rv != PDF_OK) return rv;
+        ++writer->stage;  /* fall through */
+      case 4:
+        return flush_buffer (writer);
+
+      /*** hex strings ***/
+hexstring_start:
+      writer->stage = 101;
+      case 101:
+        {
+          pdf_size_t dummy_len = PDF_MIN(20, 2 + size*2);
+          rv = start_token (writer, PDF_FALSE /*need_wspace*/, dummy_len);
+          if (rv != PDF_OK) return rv;
+        }
+        writer->buffered_line_length = writer->line_length;
+        write_buffered_char_nocheck (writer, 60 /* '<' */);
+        writer->pos = 0;
+        ++writer->stage;  /* fall through */
+      case 102:
+        while (writer->pos < size)
+          {
+            /* If this line would be too long, start a new one. */
+            if (writer->buffered_line_length + 2 > writer->max_line_length
+                 && writer->max_line_length > 0)
+              {
+                rv = write_buffered_char (writer, 10);  /* newline */
+                if (rv != PDF_OK) return rv;
+                assert (writer->buffered_line_length == 0);
+              }
+
+            pdf_char_t ch = data[writer->pos];
+            rv = reserve_buffer_space (writer, 2);
+            if (rv != PDF_OK) return rv;
+
+            write_buffered_char_nocheck (writer, hexchar(ch / 16));
+            if (writer->pos == size-1 && (ch%16) == 0)
+              ;  /* don't write a final 0 */
+            else
+              write_buffered_char_nocheck (writer, hexchar(ch % 16));
+            ++writer->pos;
+          }
+        ++writer->stage;  /* fall through */
+      case 103:
+        rv = write_buffered_char (writer, 62 /* '>' */);
+        if (rv != PDF_OK) return rv;
+        ++writer->stage;  /* fall through */
+      case 104:
+        return flush_buffer (writer);
+      default:
+        return PDF_EBADDATA;
+    }
+}
+
+
+/***** Other tokens *****/
+
+static INLINE pdf_status_t
+should_escape_namechar (pdf_u32_t flags, pdf_char_t ch, pdf_bool_t *escape)
+{
+  if (!ch)
+    return PDF_EBADDATA;
+
+  *escape = !pdf_is_regular_char(ch);
+  if (flags & PDF_TOKEN_NO_NAME_ESCAPES)
+    {
+      if (*escape)
+        return PDF_EBADDATA;
+    }
+  else
+    {
+      *escape = *escape || ch == 35 /* '#' */
+                || ch < 33 || ch >= 127;
+    }
+  return PDF_OK;
+}
+
+static INLINE pdf_status_t
+write_name_token (pdf_token_writer_t writer, pdf_u32_t flags,
+                  pdf_token_t token)
+{
+  pdf_status_t rv;
+  pdf_size_t size = pdf_token_get_name_size (token);
+  const pdf_char_t *data = pdf_token_get_name_data (token);
+  switch (writer->stage)
+    {
+      case 0:
+        /* Validate the name; also calculate the encoded size
+         * and store it in ->pos temporarily. */
+        writer->pos = 1 + size;
+        {
+          pdf_size_t i;
+          for (i = 0; i < size; ++i)
+            {
+              pdf_bool_t escape;
+              rv = should_escape_namechar(flags, data[i], &escape);
+              if (rv != PDF_OK) return rv;  /* bad name */
+
+              if (escape)
+                writer->pos += 2;  /* 2 hex characters */
+            }
+        }
+        write_buffered_char_nocheck (writer, 47 /* '/' */);
+        ++writer->stage;  /* fall through */
+      case 1:
+        rv = start_token (writer, PDF_FALSE /*need_wspace*/,
+                          writer->pos /* encoded token length */);
+        if (rv != PDF_OK) return rv;
+
+        writer->pos = 0;
+        ++writer->stage;  /* fall through */
+      case 2:
+        while (writer->pos < size)
+          {
+            pdf_bool_t escape;
+            pdf_char_t ch = data[writer->pos];
+            rv = should_escape_namechar(flags, ch, &escape);
+            if (rv != PDF_OK) return rv;  /* bad name */
+
+            if (escape)
+              {
+                rv = reserve_buffer_space (writer, 3);
+                if (rv != PDF_OK) return rv;
+
+                write_buffered_char_nocheck (writer, 35 /* '#' */);
+                write_buffered_char_nocheck (writer, hexchar(ch / 16));
+                write_buffered_char_nocheck (writer, hexchar(ch % 16));
+              }
+            else
+              {
+                rv = write_buffered_char (writer, ch);
+                if (rv != PDF_OK) return rv;
+              }
+            ++writer->pos;
+          }
+        ++writer->stage;  /* fall through */
+      case 3:
+        return flush_buffer (writer);
+      default:
+        return PDF_EBADDATA;
+    }
+}
+
+static INLINE pdf_status_t
+write_keyword_token (pdf_token_writer_t writer, pdf_token_t token)
+{
+  const pdf_char_t *data = pdf_token_get_keyword_data (token);
+  pdf_size_t size = pdf_token_get_keyword_size (token);
+  pdf_status_t rv;
+  switch (writer->stage)
+    {
+      case 0:
+        if (memchr (data, 0, size))
+          return PDF_EBADDATA;  /* data contains a null byte */
+        ++writer->stage;  /* fall through */
+      case 1:
+        rv = start_token (writer, PDF_TRUE /*need_wspace*/, size);
+        if (rv != PDF_OK) return rv;
+
+        writer->pos = 0;
+        ++writer->stage;  /* fall through */
+      case 2:
+        return write_data_using_pos (writer,
+                                     pdf_token_get_keyword_data (token),
+                                     size);
+      default:
+        return PDF_EBADDATA;
+    }
+}
+
+static INLINE pdf_status_t
+write_comment_token (pdf_token_writer_t writer, pdf_token_t token)
+{
+  const pdf_char_t *data = pdf_token_get_comment_data (token);
+  pdf_size_t size = pdf_token_get_comment_size (token);
+  pdf_status_t rv;
+  switch (writer->stage)
+    {
+      case 0:
+        {
+          /* A comment can't span multiple lines. */
+          pdf_size_t i;
+          for (i = 0; i < size; ++i)
+            {
+              if (pdf_is_eol_char(data[i]))
+              return PDF_EBADDATA;
+            }
+        }
+        ++writer->stage;  /* fall through */
+      case 1:
+        rv = start_token (writer, PDF_FALSE /*need_wspace*/, size+1);
+        if (rv != PDF_OK) return rv;
+        ++writer->stage;  /* fall through */
+      case 2:
+        rv = write_char (writer, 37 /* '%' */);
+        if (rv != PDF_OK) return rv;
+
+        writer->pos = 0;
+        ++writer->stage;  /* fall through */
+      case 3:
+        rv = write_data_using_pos (writer, data, size);
+        if (rv != PDF_OK) return rv;
+        ++writer->stage;  /* fall through */
+      case 4:
+        return write_char (writer, 10 /* '\n' */);
+      default:
+        return PDF_EBADDATA;
+    }
+}
+
+static INLINE pdf_status_t
+write_valueless_token (pdf_token_writer_t writer,
+                       pdf_char_t ch, pdf_size_t len)
+{
+  pdf_char_t buf[2] = {ch,ch};
+  pdf_status_t rv;
+  assert (len == 1 || len == 2);
+
+  switch (writer->stage)
+    {
+      case 0:
+        rv = start_token (writer, PDF_FALSE /*need_wspace*/, len);
+        if (rv != PDF_OK) return rv;
+
+        writer->pos = 0;
+        ++writer->stage;  /* fall through */
+      case 1:
+        return write_data_using_pos (writer, buf, len);
+      default:
+        return PDF_EBADDATA;
+    }
+}
+
+
+/***** Token dispatching *****/
+
+static INLINE pdf_status_t
+write_token_dispatch (pdf_token_writer_t writer, pdf_u32_t flags,
+                      pdf_token_t token)
+{
+  switch (pdf_token_get_type (token))
+    {
+      case PDF_TOKEN_INTEGER:
+        return write_integer_token (writer, token);
+      case PDF_TOKEN_REAL:
+        return write_real_token (writer, token);
+      case PDF_TOKEN_STRING:
+        return write_string_token (writer, flags, token);
+      case PDF_TOKEN_NAME:
+        return write_name_token (writer, flags, token);
+      case PDF_TOKEN_KEYWORD:
+        return write_keyword_token (writer, token);
+      case PDF_TOKEN_COMMENT:
+        return write_comment_token (writer, token);
+      case PDF_TOKEN_DICT_START:
+        return write_valueless_token (writer, 60 /* '<' */, 2);
+      case PDF_TOKEN_DICT_END:
+        return write_valueless_token (writer, 62 /* '>' */, 2);
+      case PDF_TOKEN_ARRAY_START:
+        return write_valueless_token (writer, 91 /* '[' */, 1);
+      case PDF_TOKEN_ARRAY_END:
+        return write_valueless_token (writer, 93 /* ']' */, 1);
+      case PDF_TOKEN_PROC_START:
+        return write_valueless_token (writer, 123 /* '{' */, 1);
+      case PDF_TOKEN_PROC_END:
+        return write_valueless_token (writer, 125 /* '}' */, 1);
+      default:
+        assert (0);
+        return PDF_ERROR;
+    }
+}
+
+pdf_status_t
+pdf_token_write (pdf_token_writer_t writer, pdf_u32_t flags, pdf_token_t token)
+{
+  pdf_status_t rv = write_token_dispatch (writer, flags, token);
+  if (rv == PDF_OK)
+    {
+      pdf_buffer_rewind (writer->buffer);
+      writer->stage = 0;
+    }
+  return rv;
+}
+
+/* End of pdf-token-writer.c */

=== added file 'src/base/pdf-token-writer.h'
--- src/base/pdf-token-writer.h	1970-01-01 00:00:00 +0000
+++ src/base/pdf-token-writer.h	2009-10-25 18:06:21 +0000
@@ -0,0 +1,66 @@
+/* -*- mode: C -*- Time-stamp: "2009-10-25 02:43:11 mgold"
+ *
+ *       File:         pdf-token-writer.h
+ *       Date:         Wed Sep 23 04:30:26 2009
+ *
+ *       GNU PDF Library - Stream token writer
+ *
+ */
+
+/* Copyright (C) 2009 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_TOKEN_WRITER_H
+#define PDF_TOKEN_WRITER_H
+
+#include <config.h>
+
+#include <pdf-types.h>
+#include <pdf-stm.h>
+#include <pdf-token.h>
+#include <pdf-token-reader.h>
+
+/* BEGIN PUBLIC */
+/* pdf-token-writer.h */
+
+struct pdf_token_writer_s;  /* opaque type */
+typedef struct pdf_token_writer_s *pdf_token_writer_t;
+
+pdf_status_t pdf_token_writer_new (pdf_stm_t stm, pdf_token_writer_t *writer);
+pdf_status_t pdf_token_writer_destroy (pdf_token_writer_t writer);
+pdf_status_t pdf_token_writer_reset (pdf_token_writer_t writer);
+pdf_status_t pdf_token_write (pdf_token_writer_t writer, pdf_u32_t flags,
+                              pdf_token_t token);
+
+/* END PUBLIC */
+
+/* Internal state */
+struct pdf_token_writer_s {
+  pdf_stm_t stream;  /* stream to read bytes from */
+  char *decimal_point;
+
+  pdf_bool_t in_keyword;
+  pdf_size_t line_length, buffered_line_length, max_line_length;
+
+  int stage;
+  pdf_size_t pos;
+  pdf_size_t paren_quoting_start, paren_quoting_end;
+  pdf_buffer_t buffer;
+};
+
+#endif
+
+/* End of pdf-token-writer.h */

=== modified file 'utils/pdf-tokeniser.c'
--- utils/pdf-tokeniser.c	2009-10-21 12:59:20 +0000
+++ utils/pdf-tokeniser.c	2009-10-25 18:06:21 +0000
@@ -1,4 +1,4 @@
-/* -*- mode: C -*- Time-stamp: "09/10/21 14:57:10 jemarch"
+/* -*- mode: C -*- Time-stamp: "2009-10-23 06:12:29 mgold"
  *
  *       File:         pdf-tokeniser.c
  *       Date:         Wed May 20 05:25:40 2009
@@ -43,6 +43,9 @@
     {"help", no_argument, NULL, HELP_ARG},
     {"usage", no_argument, NULL, USAGE_ARG},
     {"version", no_argument, NULL, VERSION_ARG},
+    {"token-writer", no_argument, NULL, TOKW_ARG},
+    {"reader-flags", required_argument, NULL, READER_FLAGS_ARG},
+    {"writer-flags", required_argument, NULL, WRITER_FLAGS_ARG},
     {NULL, 0, NULL, 0}
   };
 
@@ -59,6 +62,9 @@
   --help                              print a help message and exit\n\
   --usage                             print a usage message and exit\n\
   --version                           show pdf-tokeniser version and exit\n\
+  --token-writer                      generate output using the token writer\n\
+  --reader-flags=INTEGER              specify token reader flags\n\
+  --writer-flags=INTEGER              specify token writer flags\n\
 ";
 
 char *pdf_tokeniser_help_msg = "";
@@ -183,30 +189,62 @@
 };
 
 void
-print_file (FILE *file)
+print_file (FILE *file, pdf_bool_t use_tokw,
+            pdf_u32_t reader_flags, pdf_u32_t writer_flags)
 {
   pdf_status_t rv;
   pdf_token_reader_t reader = NULL;
+  pdf_token_writer_t writer = NULL;
   pdf_token_t token;
-  pdf_stm_t stm = NULL;
+  pdf_stm_t stm_in = NULL;
+  pdf_stm_t stm_out = NULL;
 
-  rv = pdf_stm_cfile_new (file, 0, 0 /*cache_size*/, PDF_STM_READ, &stm);
+  rv = pdf_stm_cfile_new (file, 0, 0 /*cache_size*/, PDF_STM_READ, &stm_in);
   if (rv != PDF_OK)
     {
-      fprintf(stderr, "failed to create stream\n");
+      fprintf(stderr, "failed to create input stream\n");
       goto out;
     }
 
-  rv = pdf_token_reader_new(stm, &reader);
+  rv = pdf_token_reader_new(stm_in, &reader);
   if (rv != PDF_OK)
     {
       fprintf(stderr, "failed to create reader\n");
       goto out;
     }
 
-  while (( rv = pdf_token_read(reader, 0, &token) ) == PDF_OK)
-    {
-      print_tok(token);
+  if (use_tokw)
+    {
+      rv = pdf_stm_cfile_new (stdout, 0, 0 /*cache_size*/,
+                              PDF_STM_WRITE, &stm_out);
+      if (rv != PDF_OK)
+        {
+          fprintf(stderr, "failed to create output stream\n");
+          goto out;
+        }
+
+      rv = pdf_token_writer_new(stm_out, &writer);
+      if (rv != PDF_OK)
+        {
+          fprintf(stderr, "failed to create writer\n");
+          goto out;
+        }
+    }
+
+  while (( rv = pdf_token_read(reader, reader_flags, &token) ) == PDF_OK)
+    {
+      if (use_tokw)
+        {
+          rv = pdf_token_write(writer, writer_flags, token);
+          if (rv != PDF_OK)
+            {
+              fprintf(stderr, "pdf_token_write error %d\n", rv);
+              goto out;
+            }
+        }
+      else
+        print_tok(token);
+
       pdf_token_destroy(token);
     }
 
@@ -218,14 +256,18 @@
 
   fprintf(stderr, "done\n");
 out:
+  if (writer) pdf_token_writer_destroy(writer);
+  if (stm_out) pdf_stm_destroy(stm_out);
   if (reader) pdf_token_reader_destroy(reader);
-  if (stm) pdf_stm_destroy(stm);
+  if (stm_in) pdf_stm_destroy(stm_in);
 }
 
 int
 main (int argc, char **argv)
 {
   char c;
+  pdf_bool_t use_tokw = PDF_FALSE;
+  pdf_u32_t reader_flags = 0, writer_flags = 0;
 
   /*  set_program_name (argv[0]); */
 
@@ -256,6 +298,21 @@
             exit (0);
             break;
           }
+        case TOKW_ARG:
+          {
+            use_tokw = 1;
+            break;
+          }
+        case READER_FLAGS_ARG:
+          {
+            reader_flags = atoi(optarg);
+            break;
+          }
+        case WRITER_FLAGS_ARG:
+          {
+            writer_flags = atoi(optarg);
+            break;
+          }
         default:
           {
             break;
@@ -264,6 +321,6 @@
     }
 
   setlocale(LC_ALL, "");
-  print_file(stdin);
+  print_file(stdin, use_tokw, reader_flags, writer_flags);
   return 0;
 }

=== modified file 'utils/pdf-tokeniser.h'
--- utils/pdf-tokeniser.h	2009-06-28 09:20:53 +0000
+++ utils/pdf-tokeniser.h	2009-10-25 18:06:21 +0000
@@ -1,4 +1,4 @@
-/* -*- mode: C -*- Time-stamp: "09/06/24 20:56:43 jemarch"
+/* -*- mode: C -*- Time-stamp: "2009-10-23 02:09:23 mgold"
  *
  *       File:         pdf-tokeniser.h
  *       Date:         Wed Jun 24 20:54:49 2009
@@ -35,7 +35,10 @@
 {
   HELP_ARG,
   USAGE_ARG,
-  VERSION_ARG
+  VERSION_ARG,
+  TOKW_ARG,
+  READER_FLAGS_ARG,
+  WRITER_FLAGS_ARG
 };
 
 #endif /* pdf-tokeniser.h */

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

Attachment: signature.asc
Description: Digital signature

Reply via email to