LTP GCOV extension - code coverage report
Current view: directory - src/base - pdf-token-writer.c
Test: libgnupdf.info
Date: 2010-07-31 Instrumented lines: 386
Code covered: 0.0 % Executed lines: 0

       1                 : /* -*- mode: C -*-
       2                 :  *
       3                 :  *       File:         pdf-token-writer.c
       4                 :  *       Date:         Wed Sep 23 04:37:51 2009
       5                 :  *
       6                 :  *       GNU PDF Library - Stream token writer
       7                 :  *
       8                 :  */
       9                 : 
      10                 : /* Copyright (C) 2009 Free Software Foundation, Inc. */
      11                 : 
      12                 : /* This program is free software: you can redistribute it and/or modify
      13                 :  * it under the terms of the GNU General Public License as published by
      14                 :  * the Free Software Foundation, either version 3 of the License, or
      15                 :  * (at your option) any later version.
      16                 :  *
      17                 :  * This program is distributed in the hope that it will be useful,
      18                 :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      19                 :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      20                 :  * GNU General Public License for more details.
      21                 :  *
      22                 :  * You should have received a copy of the GNU General Public License
      23                 :  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
      24                 :  */
      25                 : 
      26                 : #include <config.h>
      27                 : 
      28                 : #include <assert.h>
      29                 : #include <stdlib.h>
      30                 : #include <string.h>
      31                 : #include <locale.h>
      32                 : #include <inttypes.h>
      33                 : #include <math.h>
      34                 : 
      35                 : #include <pdf-token-writer.h>
      36                 : #include <unistr.h>
      37                 : 
      38                 : pdf_status_t
      39                 : pdf_token_writer_new (pdf_stm_t stm, pdf_token_writer_t *writer)
      40               0 : {
      41                 :   pdf_status_t err;
      42                 :   pdf_token_writer_t new_tokw;
      43                 : 
      44               0 :   err = PDF_ENOMEM;
      45               0 :   new_tokw = pdf_alloc (sizeof (*new_tokw));
      46               0 :   if (!new_tokw)
      47               0 :     goto fail;
      48                 : 
      49                 :   /* determine the current locale's decimal point
      50                 :    * (avoid using localeconv since it may not be thread-safe) */
      51               0 :   new_tokw->decimal_point = NULL;
      52                 :   {
      53                 :     int len;
      54                 :     char decpt[16];
      55                 : 
      56               0 :     err = PDF_ERROR;
      57               0 :     len = snprintf (decpt, sizeof (decpt), "%#.0f", 1.0);
      58               0 :     if (len <= 0 || (pdf_size_t)len >= sizeof (decpt))  /* shouldn't happen */
      59               0 :       goto fail;
      60                 : 
      61               0 :     err = PDF_ENOMEM;
      62               0 :     new_tokw->decimal_point = pdf_alloc (len);
      63               0 :     if (!new_tokw->decimal_point)
      64               0 :       goto fail;
      65                 : 
      66                 :     /* this copies the trailing '\0' due to the starting offset */
      67               0 :     memcpy (new_tokw->decimal_point, &decpt[1], len);
      68                 :   }
      69                 : 
      70                 :   /* set max_line_length to 0 for no maximum */
      71               0 :   new_tokw->max_line_length = PDF_TOKW_MAX_LINE_LENGTH;
      72                 : 
      73               0 :   err = PDF_ENOMEM;
      74               0 :   new_tokw->buffer = pdf_buffer_new (PDF_TOKW_BUFFER_SIZE);
      75               0 :   if (!new_tokw->buffer)
      76               0 :     goto fail;
      77                 : 
      78               0 :   err = PDF_EBADDATA;
      79               0 :   if (!stm || pdf_stm_get_mode (stm) != PDF_STM_WRITE)
      80                 :     goto fail;
      81               0 :   new_tokw->stream = stm;
      82                 : 
      83               0 :   pdf_token_writer_reset (new_tokw);
      84                 : 
      85               0 :   *writer = new_tokw;
      86               0 :   return PDF_OK;
      87                 : 
      88               0 : fail:
      89               0 :   if (new_tokw)
      90               0 :     pdf_dealloc (new_tokw->decimal_point);
      91               0 :   pdf_dealloc (new_tokw);
      92                 : 
      93               0 :   return err;
      94                 : }
      95                 : 
      96                 : pdf_status_t
      97                 : pdf_token_writer_reset (pdf_token_writer_t writer)
      98               0 : {
      99               0 :   writer->stage = 0;
     100               0 :   writer->in_keyword = PDF_FALSE;
     101               0 :   writer->line_length = 0;
     102               0 :   return PDF_OK;
     103                 : }
     104                 : 
     105                 : pdf_status_t
     106                 : pdf_token_writer_destroy (pdf_token_writer_t writer)
     107               0 : {
     108               0 :   if (!writer) return PDF_EBADDATA;
     109                 : 
     110               0 :   assert (writer->buffer);
     111               0 :   if (writer->buffer)
     112               0 :     pdf_buffer_destroy (writer->buffer);
     113               0 :   pdf_dealloc (writer->decimal_point);
     114               0 :   pdf_dealloc (writer);
     115                 : 
     116               0 :   return PDF_OK;
     117                 : }
     118                 : 
     119                 : 
     120                 : /***** Unbuffered output *****/
     121                 : 
     122                 : /* Write data to the stream.  All output passes through this function. */
     123                 : static pdf_status_t
     124                 : write_data (pdf_token_writer_t writer, const pdf_char_t *data,
     125                 :             pdf_size_t len, pdf_size_t *written)
     126               0 : {
     127                 :   pdf_size_t i;
     128                 :   pdf_status_t rv;
     129                 : 
     130               0 :   rv = pdf_stm_write (writer->stream, data, len, written);
     131               0 :   if (rv != PDF_OK)
     132               0 :     return rv;
     133                 : 
     134               0 :   for (i = 0; i < *written; ++i)
     135                 :     {
     136               0 :       pdf_char_t ch = data[i];
     137               0 :       ++writer->line_length;
     138               0 :       if (pdf_is_eol_char (ch))
     139               0 :         writer->line_length = 0;
     140                 : 
     141               0 :       writer->in_keyword = pdf_is_regular_char (ch);
     142                 :     }
     143               0 :   return PDF_OK;
     144                 : }
     145                 : 
     146                 : /* Write a single character. */
     147                 : static INLINE pdf_status_t
     148                 : write_char (pdf_token_writer_t writer, pdf_char_t ch)
     149                 : {
     150                 :   pdf_size_t written;
     151               0 :   return write_data (writer, &ch, 1, &written);
     152                 : }
     153                 : 
     154                 : /* Write data starting at writer->pos, incrementing writer->pos as needed. */
     155                 : static INLINE pdf_status_t
     156                 : write_data_using_pos (pdf_token_writer_t writer,
     157                 :                       const pdf_char_t *data, pdf_size_t len)
     158               0 : {
     159                 :   pdf_status_t rv;
     160                 :   pdf_size_t written;
     161               0 :   if (writer->pos > len)
     162               0 :     return PDF_EBADDATA;
     163                 : 
     164               0 :   while (writer->pos < len)
     165                 :     {
     166               0 :       rv = write_data (writer, data + writer->pos, len - writer->pos,
     167                 :                        &written);
     168               0 :       if (rv != PDF_OK)
     169               0 :         return rv;
     170                 : 
     171               0 :       writer->pos += written;
     172                 :     }
     173               0 :   return PDF_OK;
     174                 : }
     175                 : 
     176                 : 
     177                 : /***** Buffered output, buffer management *****/
     178                 : 
     179                 : /* Write all buffered data to the stream. */
     180                 : static pdf_status_t
     181                 : flush_buffer (pdf_token_writer_t writer)
     182               0 : {
     183               0 :   pdf_buffer_t buf = writer->buffer;
     184                 :   pdf_size_t len;
     185               0 :   while ( (len = buf->wp - buf->rp) > 0 )
     186                 :     {
     187                 :       pdf_size_t written;
     188                 :       pdf_status_t rv = write_data (writer,
     189                 :                                     buf->data + buf->rp,
     190               0 :                                     len, &written);
     191               0 :       if (rv != PDF_OK)
     192               0 :         return rv;
     193                 : 
     194               0 :       buf->rp += written;
     195                 :     }
     196               0 :   return pdf_buffer_rewind (buf);
     197                 : }
     198                 : 
     199                 : /* Flush the buffer if there are less than 'len' bytes free. */
     200                 : static INLINE pdf_status_t
     201                 : reserve_buffer_space (pdf_token_writer_t writer, pdf_size_t len)
     202               0 : {
     203               0 :   if (writer->buffer->wp + len > writer->buffer->size)
     204                 :     {
     205               0 :       pdf_status_t rv = flush_buffer (writer);
     206               0 :       if (rv != PDF_OK)
     207               0 :         return rv;
     208                 : 
     209               0 :       assert (len < writer->buffer->size);
     210               0 :       assert (writer->buffer->wp == 0);
     211                 :     }
     212               0 :   return PDF_OK;
     213                 : }
     214                 : 
     215                 : /* Write a character into the buffer; this assumes it will fit. */
     216                 : static INLINE void
     217                 : write_buffered_char_nocheck (pdf_token_writer_t writer, pdf_char_t ch)
     218                 : {
     219               0 :   writer->buffer->data[writer->buffer->wp++] = ch;
     220               0 :   if (pdf_is_eol_char(ch))
     221               0 :     writer->buffered_line_length = 0;
     222                 :   else
     223               0 :     ++writer->buffered_line_length;
     224                 : }
     225                 : 
     226                 : /* Write a character into the buffer.  The buffer is flushed only if
     227                 :  * there's no room to write the character. */
     228                 : static INLINE pdf_status_t
     229                 : write_buffered_char (pdf_token_writer_t writer, pdf_char_t ch)
     230               0 : {
     231               0 :   pdf_status_t rv = reserve_buffer_space (writer, 1);
     232               0 :   if (rv == PDF_OK)
     233               0 :     write_buffered_char_nocheck (writer, ch);
     234               0 :   return rv;
     235                 : }
     236                 : 
     237                 : 
     238                 : /***** Misc. utility functions *****/
     239                 : 
     240                 : /* Takes a number from 0 to 15 and returns the ASCII code for the
     241                 :  * corresponding hexadecimal digit. */
     242                 : static INLINE pdf_char_t
     243                 : hexchar (pdf_char_t value)
     244                 : {
     245               0 :   if (value < 10)
     246               0 :     return 48 + value;       /* '0'--'9' */
     247               0 :   else if (value < 16)
     248               0 :     return 65 + value - 10;  /* 'A'--'F' */
     249               0 :   return 255;
     250                 : }
     251                 : 
     252                 : /* Prepare to write a new token, adding some whitespace if necessary. */
     253                 : static pdf_status_t
     254                 : start_token (pdf_token_writer_t writer, pdf_bool_t need_wspace,
     255                 :              pdf_size_t len)
     256               0 : {
     257               0 :   pdf_bool_t add_wspace = (need_wspace && writer->in_keyword);
     258               0 :   pdf_char_t wspace_char = 32;  /* space */
     259                 : 
     260               0 :   if (add_wspace)
     261               0 :     ++len;
     262                 : 
     263                 :   /* If the token would make this line too long, start a new line. */
     264               0 :   if (writer->line_length + len > writer->max_line_length
     265                 :        && writer->max_line_length > 0)
     266                 :     {
     267               0 :       add_wspace = PDF_TRUE;
     268               0 :       wspace_char = 10;  /* newline */
     269                 :     }
     270                 : 
     271               0 :   if (add_wspace)
     272                 :     {
     273               0 :       pdf_status_t rv = write_char (writer, wspace_char);
     274               0 :       if (rv != PDF_OK) return rv;
     275                 :     }
     276                 : 
     277               0 :   return PDF_OK;
     278                 : }
     279                 : 
     280                 : 
     281                 : /***** Numeric tokens *****/
     282                 : 
     283                 : /* Encode snprintf output for PDF.  'len' is the return value of snprintf.
     284                 :  * Re-encodes bytes 0 to 'len' of writer->buffer and resets buffer->rp/wp. */
     285                 : static pdf_bool_t
     286                 : encode_buffer_number (pdf_token_writer_t writer, int len)
     287               0 : {
     288               0 :   pdf_buffer_t buf = writer->buffer;
     289               0 :   if (len < 0 || len >= buf->size)
     290               0 :     return PDF_FALSE;  /* snprintf failed, or truncated its output. */
     291                 : 
     292               0 :   buf->wp = buf->rp = 0;
     293               0 :   while (buf->rp < len)
     294                 :     {
     295               0 :       char ch = (char)buf->data[buf->rp];
     296               0 :       if (ch == '-')
     297                 :         {
     298               0 :           ++buf->rp;
     299               0 :           buf->data[buf->wp++] = 45;  /* '-' */
     300                 :         }
     301               0 :       else if (ch >= '0' && ch <= '9')
     302                 :         {
     303               0 :           ++buf->rp;
     304               0 :           buf->data[buf->wp++] = 48 + (ch - '0');
     305                 :         }
     306                 :       else
     307                 :         {
     308                 :           /* This should be a decimal point; check it. */
     309               0 :           pdf_size_t declen = strlen (writer->decimal_point);
     310                 :           int cmp = memcmp (buf->data + buf->rp,
     311               0 :                             writer->decimal_point, declen);
     312               0 :           if (cmp != 0)
     313               0 :             return PDF_FALSE;  /* unexpected char */
     314                 : 
     315               0 :           buf->rp += declen;
     316               0 :           buf->data[buf->wp++] = 46;  /* '.' */
     317                 :         }
     318                 :     }
     319               0 :   buf->rp = 0;
     320               0 :   return PDF_TRUE;  /* success */
     321                 : }
     322                 : 
     323                 : static INLINE pdf_status_t
     324                 : write_integer_token (pdf_token_writer_t writer, pdf_token_t token)
     325                 : {
     326                 :   pdf_status_t rv;
     327               0 :   switch (writer->stage)
     328                 :     {
     329                 :       case 0:
     330                 :         {
     331               0 :           pdf_i32_t value = pdf_token_get_integer_value (token);
     332                 :           int len = snprintf ((char*)writer->buffer->data,
     333               0 :                               writer->buffer->size, "%"PRId32, value);
     334               0 :           if (!encode_buffer_number (writer, len)) return PDF_ERROR;
     335                 :         }
     336               0 :         ++writer->stage;  /* fall through */
     337                 :       case 1:
     338               0 :         rv = start_token (writer, PDF_TRUE /*need_wspace*/,
     339                 :                           writer->buffer->wp);
     340               0 :         if (rv != PDF_OK) return rv;
     341               0 :         ++writer->stage;  /* fall through */
     342                 :       case 2:
     343               0 :         return flush_buffer (writer);
     344                 :       default:
     345               0 :         return PDF_EBADDATA;
     346                 :     }
     347                 : }
     348                 : 
     349                 : static INLINE pdf_status_t
     350                 : write_real_token (pdf_token_writer_t writer, pdf_token_t token)
     351                 : {
     352                 :   pdf_status_t rv;
     353               0 :   switch (writer->stage)
     354                 :     {
     355                 :       case 0:
     356                 :         {
     357               0 :           pdf_buffer_t buf = writer->buffer;
     358               0 :           pdf_real_t value = pdf_token_get_real_value (token);
     359               0 :           if (isnan(value) || isinf(value))
     360               0 :             return PDF_EBADDATA;
     361                 : 
     362                 :           /* The '#' flag forces snprintf to write a decimal point. */
     363                 :           int len = snprintf ((char*)buf->data,
     364               0 :                               buf->size, "%#f", (double)value);
     365               0 :           if (!encode_buffer_number (writer, len)) return PDF_ERROR;
     366                 : 
     367                 :           /* strip trailing zeroes */
     368               0 :           while (buf->wp && buf->data[buf->wp-1] == 48 /* '0' */)
     369               0 :             --buf->wp;
     370                 :         }
     371               0 :         ++writer->stage;  /* fall through */
     372                 :       case 1:
     373               0 :         rv = start_token (writer, PDF_TRUE /*need_wspace*/,
     374                 :                           writer->buffer->wp);
     375               0 :         if (rv != PDF_OK) return rv;
     376               0 :         ++writer->stage;  /* fall through */
     377                 :       case 2:
     378               0 :         return flush_buffer (writer);
     379                 :       default:
     380               0 :         return PDF_EBADDATA;
     381                 :     }
     382                 : }
     383                 : 
     384                 : 
     385                 : /***** String tokens *****/
     386                 : 
     387                 : static INLINE pdf_bool_t
     388                 : should_escape_strchar (pdf_u32_t flags, pdf_char_t ch,
     389                 :                        pdf_bool_t quote_parens, pdf_bool_t is_utf8)
     390                 : {
     391               0 :   if (ch == 92 /* '\\' */ || ch == 13 /* CR */)
     392               0 :     return PDF_TRUE;
     393               0 :   if (ch == 40 /* '(' */ || ch == 41 /* ')' */)
     394               0 :     return quote_parens;
     395                 : 
     396               0 :   if (flags & PDF_TOKEN_READABLE_STRINGS)
     397                 :     {
     398               0 :       if (ch == 127 || (ch < 32 && ch != 10)
     399                 :            || (ch >= 128 && !is_utf8))
     400               0 :         return PDF_TRUE;
     401                 :     }
     402                 : 
     403               0 :   return PDF_FALSE;
     404                 : }
     405                 : 
     406                 : static INLINE int
     407                 : str_escape_len (const pdf_char_t *data, pdf_size_t len, pdf_size_t pos)
     408                 : {
     409               0 :   switch (data[pos])
     410                 :     {
     411                 :       /* characters with two-character escape codes */
     412                 :       case  8:
     413                 :       case  9:
     414                 :       case 10:
     415                 :       case 12:
     416                 :       case 13:
     417                 :       case 40:
     418                 :       case 41:
     419                 :       case 92:
     420               0 :         return 2;
     421                 :     }
     422                 : 
     423               0 :   if (data[pos] >= 0100)
     424               0 :     return 4;  /* escaped using a backslash and 3 octal characters */
     425                 : 
     426               0 :   if (pos+1 < len)
     427                 :     {
     428               0 :       if (data[pos+1] >= 48 && data[pos+1] <= 57)  /* '0'..'9' */
     429               0 :         return 4;  /* need to write a 3-character octal number */
     430                 :     }
     431                 : 
     432               0 :   return (data[pos] >= 010) ? 3 : 2;
     433                 : }
     434                 : 
     435                 : static void
     436                 : scan_string (pdf_token_writer_t writer, pdf_u32_t flags,
     437                 :              const pdf_char_t *data, pdf_size_t len, pdf_bool_t *use_hex)
     438               0 : {
     439                 :   /* Match parentheses, and determine the portion of the string
     440                 :    * in which they should be quoted. */
     441               0 :   writer->paren_quoting_start = 0;
     442               0 :   writer->paren_quoting_end = len;
     443                 :   pdf_size_t i, j;
     444               0 :   for (i = 0; i < len; ++i)
     445                 :     {
     446               0 :       if (data[i] == 40)       /* '(' */
     447                 :         {
     448               0 :           for (j = writer->paren_quoting_end - 1; j > i; --j)
     449                 :             {
     450                 :               /* find a matching ')' */
     451               0 :               if (data[j] == 41)
     452                 :                 {
     453               0 :                   writer->paren_quoting_end = j;
     454               0 :                   writer->paren_quoting_start = i + 1;
     455               0 :                   break;
     456                 :                 }
     457                 :             }
     458                 :         }
     459                 :     }
     460                 : 
     461                 :   /* Determine the size of the escaped string. */
     462               0 :   writer->utf8 = (flags & PDF_TOKEN_READABLE_STRINGS)
     463                 :                    && (u8_check (data, len) == NULL);
     464               0 :   pdf_size_t enc_bytes = 0;
     465               0 :   for (i = 0; i < len; ++i)
     466                 :     {
     467                 :       pdf_bool_t quote_parens = (i >= writer->paren_quoting_start
     468               0 :                                   && i < writer->paren_quoting_end);
     469               0 :       if (should_escape_strchar (flags, data[i], quote_parens, writer->utf8))
     470               0 :         enc_bytes += str_escape_len (data, len, i);
     471                 :       else
     472               0 :         ++enc_bytes;
     473                 :     }
     474               0 :   *use_hex = (enc_bytes > len*2);
     475               0 : }
     476                 : 
     477                 : static INLINE pdf_status_t
     478                 : write_string_char (pdf_token_writer_t writer, pdf_u32_t flags,
     479                 :                    const pdf_char_t *data, pdf_char_t len,
     480                 :                    pdf_size_t pos)
     481                 : {
     482               0 :   assert (len > 0);
     483                 :   pdf_status_t rv;
     484               0 :   const pdf_char_t *output = data + pos;
     485               0 :   pdf_size_t outlen = 1;
     486               0 :   pdf_char_t esc[4] = {92 /* '\\' */, 0, 0, 0};
     487                 : 
     488               0 :   pdf_char_t ch = data[pos];
     489                 :   pdf_bool_t quote_parens = (pos >= writer->paren_quoting_start
     490               0 :                               && pos < writer->paren_quoting_end);
     491               0 :   if (should_escape_strchar (flags, ch, quote_parens, writer->utf8))
     492                 :     {
     493                 :       /* escape the character */
     494               0 :       output = esc;
     495               0 :       outlen = 2;
     496               0 :       switch (ch)
     497                 :         {
     498               0 :           case  8: esc[1] =  98; break; /* 'b' */
     499               0 :           case  9: esc[1] = 116; break; /* 't' */
     500               0 :           case 10: esc[1] = 110; break; /* 'n' */
     501               0 :           case 12: esc[1] = 102; break; /* 'f' */
     502               0 :           case 13: esc[1] = 114; break; /* 'r' */
     503                 :           case 40:  /* '('; fall through */
     504                 :           case 41:  /* ')'; fall through */
     505                 :           case 92:  /* '\\' */
     506               0 :             esc[1] = ch;
     507                 :             break;
     508                 :           default: /* use an octal escape */
     509                 :             {
     510                 :               pdf_size_t digits;
     511               0 :               pdf_char_t nextch = (pos+1 < len) ? data[pos+1] : 0;
     512               0 :               if (nextch >= 48 && nextch <= 57)  /* '0'..'9' */
     513               0 :                 digits = 3;  /* must use 3 octal characters */
     514               0 :               else if (ch > 0100) digits = 3;
     515               0 :               else if (ch > 010) digits = 2;
     516               0 :               else digits = 1;
     517                 : 
     518               0 :               outlen = 1;
     519               0 :               switch (digits)
     520                 :                 {
     521                 :                   /* fall through each case */
     522               0 :                   case 3: esc[outlen++] = hexchar (ch / 0100);
     523               0 :                   case 2: esc[outlen++] = hexchar ((ch % 0100) / 010);
     524               0 :                   case 1: esc[outlen++] = hexchar (ch % 010);
     525                 :                 }
     526                 :               }
     527                 :         }
     528                 :     }
     529                 : 
     530                 :   /* If the line will be too long, split it (the length cannot be equal to
     531                 :    * the maximum, since this would leave no room for the backslash). */
     532               0 :   if (writer->max_line_length > 0 && !pdf_is_eol_char (output[0])
     533                 :        && writer->buffered_line_length + outlen >= writer->max_line_length)
     534                 :     {
     535               0 :       rv = reserve_buffer_space (writer, 2);
     536               0 :       if (rv != PDF_OK) return rv;
     537                 :       write_buffered_char_nocheck (writer, 92);  /* '\\' */
     538                 :       write_buffered_char_nocheck (writer, 10);  /* newline */
     539               0 :       assert (writer->buffered_line_length == 0);
     540                 :     }
     541                 : 
     542               0 :   rv = reserve_buffer_space (writer, outlen);
     543               0 :   if (rv == PDF_OK)
     544                 :     {
     545                 :       pdf_size_t i;
     546               0 :       for (i = 0; i < outlen; ++i)
     547               0 :         write_buffered_char_nocheck (writer, output[i]);
     548                 :     }
     549               0 :   return rv;
     550                 : }
     551                 : 
     552                 : static INLINE pdf_status_t
     553                 : write_string_token (pdf_token_writer_t writer, pdf_u32_t flags,
     554                 :                     pdf_token_t token)
     555               0 : {
     556                 :   pdf_status_t rv;
     557               0 :   const pdf_char_t *data = pdf_token_get_string_data (token);
     558               0 :   pdf_size_t size = pdf_token_get_string_size (token);
     559                 : 
     560               0 :   switch (writer->stage)
     561                 :     {
     562                 :       case 0:
     563                 :         {
     564               0 :           pdf_bool_t use_hex = (flags & PDF_TOKEN_HEX_STRINGS);
     565               0 :           if (!use_hex)
     566               0 :             scan_string (writer, flags, data, size, &use_hex);
     567                 : 
     568               0 :           if (use_hex)
     569               0 :             goto hexstring_start;
     570                 :         }
     571               0 :         ++writer->stage;  /* fall through */
     572                 :       case 1:
     573                 :         {
     574                 :           /* Passing a correct length to start_token isn't important
     575                 :            * since we can split the string across multiple lines. */
     576               0 :           pdf_size_t dummy_len = PDF_MIN(20, 2 + size);
     577               0 :           rv = start_token (writer, PDF_FALSE /*need_wspace*/, dummy_len);
     578               0 :           if (rv != PDF_OK) return rv;
     579                 :         }
     580                 : 
     581               0 :         pdf_buffer_rewind (writer->buffer);
     582               0 :         writer->buffered_line_length = writer->line_length;
     583                 :         write_buffered_char_nocheck (writer, 40 /* '(' */);
     584               0 :         writer->pos = 0;
     585               0 :         ++writer->stage;  /* fall through */
     586                 :       case 2:
     587               0 :         while (writer->pos < size)
     588                 :           {
     589               0 :             rv = write_string_char (writer, flags, data, size, writer->pos);
     590               0 :             if (rv != PDF_OK) return rv;
     591                 : 
     592               0 :             ++writer->pos;
     593                 :           }
     594               0 :         ++writer->stage;  /* fall through */
     595                 :       case 3:
     596               0 :         rv = write_buffered_char (writer, 41 /* ')' */);
     597               0 :         if (rv != PDF_OK) return rv;
     598               0 :         ++writer->stage;  /* fall through */
     599                 :       case 4:
     600               0 :         return flush_buffer (writer);
     601                 : 
     602                 :       /*** hex strings ***/
     603               0 : hexstring_start:
     604               0 :       writer->stage = 101;
     605                 :       case 101:
     606                 :         {
     607               0 :           pdf_size_t dummy_len = PDF_MIN(20, 2 + size*2);
     608               0 :           rv = start_token (writer, PDF_FALSE /*need_wspace*/, dummy_len);
     609               0 :           if (rv != PDF_OK) return rv;
     610                 :         }
     611                 : 
     612               0 :         pdf_buffer_rewind (writer->buffer);
     613               0 :         writer->buffered_line_length = writer->line_length;
     614                 :         write_buffered_char_nocheck (writer, 60 /* '<' */);
     615               0 :         writer->pos = 0;
     616               0 :         ++writer->stage;  /* fall through */
     617                 :       case 102:
     618               0 :         while (writer->pos < size)
     619                 :           {
     620                 :             /* If this line would be too long, start a new one. */
     621               0 :             if (writer->buffered_line_length + 2 > writer->max_line_length
     622                 :                  && writer->max_line_length > 0)
     623                 :               {
     624               0 :                 rv = write_buffered_char (writer, 10);  /* newline */
     625               0 :                 if (rv != PDF_OK) return rv;
     626               0 :                 assert (writer->buffered_line_length == 0);
     627                 :               }
     628                 : 
     629               0 :             pdf_char_t ch = data[writer->pos];
     630               0 :             rv = reserve_buffer_space (writer, 2);
     631               0 :             if (rv != PDF_OK) return rv;
     632                 : 
     633               0 :             write_buffered_char_nocheck (writer, hexchar (ch / 16));
     634               0 :             if (writer->pos == size-1 && (ch%16) == 0)
     635                 :               ;  /* don't write a final 0 */
     636                 :             else
     637               0 :               write_buffered_char_nocheck (writer, hexchar (ch % 16));
     638               0 :             ++writer->pos;
     639                 :           }
     640               0 :         ++writer->stage;  /* fall through */
     641                 :       case 103:
     642               0 :         rv = write_buffered_char (writer, 62 /* '>' */);
     643               0 :         if (rv != PDF_OK) return rv;
     644               0 :         ++writer->stage;  /* fall through */
     645                 :       case 104:
     646               0 :         return flush_buffer (writer);
     647                 :       default:
     648               0 :         return PDF_EBADDATA;
     649                 :     }
     650                 : }
     651                 : 
     652                 : 
     653                 : /***** Other tokens *****/
     654                 : 
     655                 : static INLINE pdf_status_t
     656                 : should_escape_namechar (pdf_u32_t flags, pdf_char_t ch, pdf_bool_t *escape)
     657                 : {
     658               0 :   if (!ch)
     659               0 :     return PDF_EBADDATA;
     660                 : 
     661               0 :   *escape = !pdf_is_regular_char (ch);
     662               0 :   if (flags & PDF_TOKEN_NO_NAME_ESCAPES)
     663                 :     {
     664               0 :       if (*escape)
     665               0 :         return PDF_EBADDATA;
     666                 :     }
     667                 :   else
     668                 :     {
     669               0 :       *escape = *escape || ch == 35 /* '#' */
     670                 :                 || ch < 33 || ch >= 127;
     671                 :     }
     672               0 :   return PDF_OK;
     673                 : }
     674                 : 
     675                 : static INLINE pdf_status_t
     676                 : write_name_token (pdf_token_writer_t writer, pdf_u32_t flags,
     677                 :                   pdf_token_t token)
     678                 : {
     679                 :   pdf_status_t rv;
     680               0 :   pdf_size_t size = pdf_token_get_name_size (token);
     681               0 :   const pdf_char_t *data = pdf_token_get_name_data (token);
     682               0 :   switch (writer->stage)
     683                 :     {
     684                 :       case 0:
     685                 :         /* Validate the name; also calculate the encoded size
     686                 :          * and store it in ->pos temporarily. */
     687               0 :         writer->pos = 1 + size;
     688                 :         {
     689                 :           pdf_size_t i;
     690               0 :           for (i = 0; i < size; ++i)
     691                 :             {
     692                 :               pdf_bool_t escape;
     693               0 :               rv = should_escape_namechar (flags, data[i], &escape);
     694               0 :               if (rv != PDF_OK) return rv;  /* bad name */
     695                 : 
     696               0 :               if (escape)
     697               0 :                 writer->pos += 2;  /* 2 hex characters */
     698                 :             }
     699                 :         }
     700               0 :         pdf_buffer_rewind (writer->buffer);
     701                 :         write_buffered_char_nocheck (writer, 47 /* '/' */);
     702               0 :         ++writer->stage;  /* fall through */
     703                 :       case 1:
     704               0 :         rv = start_token (writer, PDF_FALSE /*need_wspace*/,
     705                 :                           writer->pos /* encoded token length */);
     706               0 :         if (rv != PDF_OK) return rv;
     707                 : 
     708               0 :         writer->pos = 0;
     709               0 :         ++writer->stage;  /* fall through */
     710                 :       case 2:
     711               0 :         while (writer->pos < size)
     712                 :           {
     713                 :             pdf_bool_t escape;
     714               0 :             pdf_char_t ch = data[writer->pos];
     715               0 :             rv = should_escape_namechar (flags, ch, &escape);
     716               0 :             if (rv != PDF_OK) return rv;  /* bad name */
     717                 : 
     718               0 :             if (escape)
     719                 :               {
     720               0 :                 rv = reserve_buffer_space (writer, 3);
     721               0 :                 if (rv != PDF_OK) return rv;
     722                 : 
     723                 :                 write_buffered_char_nocheck (writer, 35 /* '#' */);
     724               0 :                 write_buffered_char_nocheck (writer, hexchar (ch / 16));
     725               0 :                 write_buffered_char_nocheck (writer, hexchar (ch % 16));
     726                 :               }
     727                 :             else
     728                 :               {
     729               0 :                 rv = write_buffered_char (writer, ch);
     730               0 :                 if (rv != PDF_OK) return rv;
     731                 :               }
     732               0 :             ++writer->pos;
     733                 :           }
     734               0 :         ++writer->stage;  /* fall through */
     735                 :       case 3:
     736               0 :         return flush_buffer (writer);
     737                 :       default:
     738               0 :         return PDF_EBADDATA;
     739                 :     }
     740                 : }
     741                 : 
     742                 : static INLINE pdf_status_t
     743                 : write_keyword_token (pdf_token_writer_t writer, pdf_token_t token)
     744                 : {
     745               0 :   const pdf_char_t *data = pdf_token_get_keyword_data (token);
     746               0 :   pdf_size_t size = pdf_token_get_keyword_size (token);
     747                 :   pdf_status_t rv;
     748               0 :   switch (writer->stage)
     749                 :     {
     750                 :       case 0:
     751               0 :         if (memchr (data, 0, size))
     752               0 :           return PDF_EBADDATA;  /* data contains a null byte */
     753               0 :         ++writer->stage;  /* fall through */
     754                 :       case 1:
     755               0 :         rv = start_token (writer, PDF_TRUE /*need_wspace*/, size);
     756               0 :         if (rv != PDF_OK) return rv;
     757                 : 
     758               0 :         writer->pos = 0;
     759               0 :         ++writer->stage;  /* fall through */
     760                 :       case 2:
     761               0 :         return write_data_using_pos (writer,
     762                 :                                      pdf_token_get_keyword_data (token),
     763                 :                                      size);
     764                 :       default:
     765               0 :         return PDF_EBADDATA;
     766                 :     }
     767                 : }
     768                 : 
     769                 : static INLINE pdf_status_t
     770                 : write_comment_token (pdf_token_writer_t writer, pdf_token_t token)
     771                 : {
     772               0 :   const pdf_char_t *data = pdf_token_get_comment_data (token);
     773               0 :   pdf_size_t size = pdf_token_get_comment_size (token);
     774                 :   pdf_status_t rv;
     775               0 :   switch (writer->stage)
     776                 :     {
     777                 :       case 0:
     778                 :         {
     779                 :           /* A comment can't span multiple lines. */
     780                 :           pdf_size_t i;
     781               0 :           for (i = 0; i < size; ++i)
     782                 :             {
     783               0 :               if (pdf_is_eol_char(data[i]))
     784               0 :               return PDF_EBADDATA;
     785                 :             }
     786                 :         }
     787               0 :         ++writer->stage;  /* fall through */
     788                 :       case 1:
     789               0 :         rv = start_token (writer, PDF_FALSE /*need_wspace*/, size+1);
     790               0 :         if (rv != PDF_OK) return rv;
     791               0 :         ++writer->stage;  /* fall through */
     792                 :       case 2:
     793               0 :         rv = write_char (writer, 37 /* '%' */);
     794               0 :         if (rv != PDF_OK) return rv;
     795                 : 
     796               0 :         writer->pos = 0;
     797               0 :         ++writer->stage;  /* fall through */
     798                 :       case 3:
     799               0 :         rv = write_data_using_pos (writer, data, size);
     800               0 :         if (rv != PDF_OK) return rv;
     801               0 :         ++writer->stage;  /* fall through */
     802                 :       case 4:
     803               0 :         return write_char (writer, 10 /* '\n' */);
     804                 :       default:
     805               0 :         return PDF_EBADDATA;
     806                 :     }
     807                 : }
     808                 : 
     809                 : static INLINE pdf_status_t
     810                 : write_valueless_token (pdf_token_writer_t writer,
     811                 :                        pdf_char_t ch, pdf_size_t len)
     812               0 : {
     813               0 :   pdf_char_t buf[2] = {ch,ch};
     814                 :   pdf_status_t rv;
     815               0 :   assert (len == 1 || len == 2);
     816                 : 
     817               0 :   switch (writer->stage)
     818                 :     {
     819                 :       case 0:
     820               0 :         rv = start_token (writer, PDF_FALSE /*need_wspace*/, len);
     821               0 :         if (rv != PDF_OK) return rv;
     822                 : 
     823               0 :         writer->pos = 0;
     824               0 :         ++writer->stage;  /* fall through */
     825                 :       case 1:
     826               0 :         return write_data_using_pos (writer, buf, len);
     827                 :       default:
     828               0 :         return PDF_EBADDATA;
     829                 :     }
     830                 : }
     831                 : 
     832                 : 
     833                 : /***** Token dispatching *****/
     834                 : 
     835                 : pdf_status_t
     836                 : pdf_token_write (pdf_token_writer_t writer, pdf_u32_t flags, pdf_token_t token)
     837               0 : {
     838                 :   pdf_status_t rv;
     839               0 :   switch (pdf_token_get_type (token))
     840                 :     {
     841                 :       case PDF_TOKEN_INTEGER:
     842               0 :         rv = write_integer_token (writer, token);
     843               0 :         break;
     844                 :       case PDF_TOKEN_REAL:
     845               0 :         rv = write_real_token (writer, token);
     846               0 :         break;
     847                 :       case PDF_TOKEN_STRING:
     848               0 :         rv = write_string_token (writer, flags, token);
     849               0 :         break;
     850                 :       case PDF_TOKEN_NAME:
     851               0 :         rv = write_name_token (writer, flags, token);
     852               0 :         break;
     853                 :       case PDF_TOKEN_KEYWORD:
     854               0 :         rv = write_keyword_token (writer, token);
     855               0 :         break;
     856                 :       case PDF_TOKEN_COMMENT:
     857               0 :         rv = write_comment_token (writer, token);
     858               0 :         break;
     859                 :       case PDF_TOKEN_DICT_START:
     860               0 :         rv = write_valueless_token (writer, 60 /* '<' */, 2);
     861               0 :         break;
     862                 :       case PDF_TOKEN_DICT_END:
     863               0 :         rv = write_valueless_token (writer, 62 /* '>' */, 2);
     864               0 :         break;
     865                 :       case PDF_TOKEN_ARRAY_START:
     866               0 :         rv = write_valueless_token (writer, 91 /* '[' */, 1);
     867               0 :         break;
     868                 :       case PDF_TOKEN_ARRAY_END:
     869               0 :         rv = write_valueless_token (writer, 93 /* ']' */, 1);
     870               0 :         break;
     871                 :       case PDF_TOKEN_PROC_START:
     872               0 :         rv = write_valueless_token (writer, 123 /* '{' */, 1);
     873               0 :         break;
     874                 :       case PDF_TOKEN_PROC_END:
     875               0 :         rv = write_valueless_token (writer, 125 /* '}' */, 1);
     876               0 :         break;
     877                 :       default:
     878               0 :         assert (0);
     879                 :         return PDF_ERROR;
     880                 :     }
     881                 : 
     882               0 :   if (rv == PDF_OK)
     883               0 :     writer->stage = 0;
     884               0 :   return rv;
     885                 : }
     886                 : 
     887                 : /* End of pdf-token-writer.c */

Generated by: LTP GCOV extension version 1.6