LCOV - code coverage report
Current view: top level - src/base - pdf-token-writer.c (source / functions) Hit Total Coverage
Test: libgnupdf.info Lines: 259 408 63.5 %
Date: 2011-12-09 Functions: 17 21 81.0 %
Branches: 195 384 50.8 %

           Branch data     Line data    Source code
       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-2011 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 <stdlib.h>
      29                 :            : #include <string.h>
      30                 :            : 
      31                 :            : #include <inttypes.h>
      32                 :            : #include <unistr.h>
      33                 :            : 
      34                 :            : #include <pdf-tokeniser.h>
      35                 :            : #include <pdf-token-writer.h>
      36                 :            : 
      37                 :            : /* Internal state */
      38                 :            : struct pdf_token_writer_s {
      39                 :            :   pdf_stm_t *stream;  /* stream to write bytes to */
      40                 :            : 
      41                 :            :   pdf_bool_t in_keyword;
      42                 :            :   pdf_size_t line_length;
      43                 :            :   pdf_size_t buffered_line_length;
      44                 :            :   pdf_size_t max_line_length;
      45                 :            : 
      46                 :            :   int state; /* This field is used by the writing routines to denote
      47                 :            :                 several states in the writing of the tokens.  Thus its
      48                 :            :                 concrete meaning depends on the specific writing
      49                 :            :                 routine.  See the write_*_token functions in
      50                 :            :                 pdf-token-writer.c for more information. */
      51                 :            :   pdf_size_t pos;
      52                 :            :   pdf_size_t paren_quoting_start, paren_quoting_end;
      53                 :            :   pdf_bool_t utf8;
      54                 :            :   pdf_buffer_t *buffer;
      55                 :            : };
      56                 :            : 
      57                 :            : /* Returns 255 on invalid hex values */
      58                 :            : #define HEXCHAR(value)                          \
      59                 :            :   (value < 10 ? value + '0' :                   \
      60                 :            :    (value < 16 ? value - 10 + 'A' :             \
      61                 :            :     255))
      62                 :            : 
      63                 :            : /* PDF32000 7.5.1: "lines that are not part of stream object data
      64                 :            :  * are limited to no more than 255 characters"... */
      65                 :            : #define PDF_TOKW_MAX_LINE_LENGTH 255
      66                 :            : 
      67                 :            : /* The buffer size is mostly arbitrary, but the buffer must be large
      68                 :            :  * enough for snprintf to write any possible floating point value.
      69                 :            :  * Any number over 50 should be fine. */
      70                 :            : #define PDF_TOKW_BUFFER_SIZE 32768
      71                 :            : 
      72                 :            : pdf_token_writer_t *
      73                 :         32 : pdf_token_writer_new (pdf_stm_t    *stm,
      74                 :            :                       pdf_error_t **error)
      75                 :            : {
      76                 :         32 :   pdf_token_writer_t *tokw = NULL;
      77                 :            : 
      78         [ -  + ]:         32 :   PDF_ASSERT_POINTER_RETURN_VAL (stm, NULL);
      79                 :            : 
      80                 :            :   /* Allow only write streams */
      81         [ -  + ]:         32 :   if (pdf_stm_get_mode (stm) != PDF_STM_WRITE)
      82                 :            :     {
      83                 :          0 :       pdf_set_error (error,
      84                 :            :                      PDF_EDOMAIN_BASE_TOKENISER,
      85                 :            :                      PDF_EBADDATA,
      86                 :            :                      "cannot create token writer: "
      87                 :            :                      "write stream needed");
      88                 :          0 :       return NULL;
      89                 :            :     }
      90                 :            : 
      91                 :         32 :   tokw = pdf_alloc (sizeof (struct pdf_token_writer_s));
      92         [ -  + ]:         32 :   if (!tokw)
      93                 :            :     {
      94                 :          0 :       pdf_set_error (error,
      95                 :            :                      PDF_EDOMAIN_BASE_TOKENISER,
      96                 :            :                      PDF_ENOMEM,
      97                 :            :                      "cannot create token writer: "
      98                 :            :                      "couldn't allocate '%lu' bytes",
      99                 :            :                      (unsigned long)sizeof (struct pdf_token_writer_s));
     100                 :          0 :       return NULL;
     101                 :            :     }
     102                 :            : 
     103                 :         32 :   tokw->buffer = pdf_buffer_new (PDF_TOKW_BUFFER_SIZE, error);
     104         [ -  + ]:         32 :   if (!tokw->buffer)
     105                 :            :     {
     106                 :          0 :       pdf_token_writer_destroy (tokw);
     107                 :          0 :       return NULL;
     108                 :            :     }
     109                 :            : 
     110                 :            :   /* set max_line_length to 0 for no maximum */
     111                 :         32 :   tokw->max_line_length = PDF_TOKW_MAX_LINE_LENGTH;
     112                 :         32 :   tokw->stream = stm;
     113                 :            : 
     114         [ -  + ]:         32 :   if (!pdf_token_writer_reset (tokw, error))
     115                 :            :     {
     116                 :          0 :       pdf_token_writer_destroy (tokw);
     117                 :          0 :       return NULL;
     118                 :            :     }
     119                 :            : 
     120                 :         32 :   return tokw;
     121                 :            : }
     122                 :            : 
     123                 :            : pdf_bool_t
     124                 :         32 : pdf_token_writer_reset (pdf_token_writer_t  *writer,
     125                 :            :                         pdf_error_t        **error)
     126                 :            : {
     127         [ -  + ]:         32 :   PDF_ASSERT_POINTER_RETURN_VAL (writer, PDF_FALSE);
     128                 :            : 
     129                 :         32 :   writer->state = 0;
     130                 :         32 :   writer->in_keyword = PDF_FALSE;
     131                 :         32 :   writer->line_length = 0;
     132                 :         32 :   return PDF_TRUE;
     133                 :            : }
     134                 :            : 
     135                 :            : void
     136                 :         32 : pdf_token_writer_destroy (pdf_token_writer_t *writer)
     137                 :            : {
     138         [ +  - ]:         32 :   if (!writer)
     139                 :            :     return;
     140                 :            : 
     141         [ +  - ]:         32 :   if (writer->buffer)
     142                 :         32 :     pdf_buffer_destroy (writer->buffer);
     143                 :         32 :   pdf_dealloc (writer);
     144                 :            : }
     145                 :            : 
     146                 :            : /***** Unbuffered output *****/
     147                 :            : 
     148                 :            : /* Write data to the stream.  All output passes through this function. */
     149                 :            : static pdf_bool_t
     150                 :         32 : write_data (pdf_token_writer_t  *writer,
     151                 :            :             const pdf_uchar_t   *data,
     152                 :            :             pdf_size_t           len,
     153                 :            :             pdf_size_t          *written,
     154                 :            :             pdf_error_t        **error)
     155                 :            : {
     156                 :            :   pdf_size_t i;
     157                 :         32 :   pdf_error_t *inner_error = NULL;
     158                 :            :   pdf_size_t n_written;
     159                 :            : 
     160 [ -  + ][ #  # ]:         32 :   if (!pdf_stm_write (writer->stream, data, len, &n_written, &inner_error) &&
     161                 :          0 :       inner_error)
     162                 :            :     {
     163         [ #  # ]:          0 :       if (written)
     164                 :          0 :         *written = n_written;
     165                 :          0 :       pdf_propagate_error (error, inner_error);
     166                 :          0 :       return PDF_FALSE;
     167                 :            :     }
     168                 :            : 
     169         [ +  + ]:        273 :   for (i = 0; i < n_written; ++i)
     170                 :            :     {
     171                 :        241 :       writer->line_length++;
     172         [ +  + ]:        241 :       if (pdf_is_eol_char (data[i]))
     173                 :          2 :         writer->line_length = 0;
     174                 :            : 
     175 [ +  + ][ +  + ]:        241 :       writer->in_keyword = pdf_is_regular_char (data[i]);
         [ +  + ][ +  - ]
         [ +  - ][ +  + ]
         [ +  + ][ +  + ]
         [ +  + ][ +  + ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     176                 :            :     }
     177                 :            : 
     178         [ +  - ]:         32 :   if (written)
     179                 :         32 :     *written = n_written;
     180                 :         32 :   return PDF_TRUE;
     181                 :            : }
     182                 :            : 
     183                 :            : static pdf_bool_t
     184                 :            : write_char (pdf_token_writer_t  *writer,
     185                 :            :             pdf_uchar_t          ch,
     186                 :            :             pdf_error_t        **error)
     187                 :            : {
     188                 :          0 :   return write_data (writer, &ch, 1, NULL, error);
     189                 :            : }
     190                 :            : 
     191                 :            : /* Write data starting at writer->pos, incrementing writer->pos as needed. */
     192                 :            : static pdf_bool_t
     193                 :          0 : write_data_using_pos (pdf_token_writer_t  *writer,
     194                 :            :                       const pdf_uchar_t   *data,
     195                 :            :                       pdf_size_t           len,
     196                 :            :                       pdf_error_t        **error)
     197                 :            : {
     198                 :            :   pdf_size_t written;
     199                 :            : 
     200                 :            :   /* Just in case... */
     201         [ #  # ]:          0 :   if (writer->pos > len)
     202                 :            :     {
     203                 :          0 :       PDF_ASSERT_TRACE_NOT_REACHED ();
     204                 :          0 :       return PDF_FALSE;
     205                 :            :     }
     206                 :            : 
     207         [ #  # ]:          0 :   while (writer->pos < len)
     208                 :            :     {
     209         [ #  # ]:          0 :       if (!write_data (writer,
     210                 :            :                        data + writer->pos,
     211                 :            :                        len - writer->pos,
     212                 :            :                        &written,
     213                 :            :                        error))
     214                 :          0 :         return PDF_FALSE;
     215                 :            : 
     216                 :          0 :       writer->pos += written;
     217                 :            :     }
     218                 :            : 
     219                 :          0 :   return PDF_TRUE;
     220                 :            : }
     221                 :            : 
     222                 :            : /***** Buffered output, buffer management *****/
     223                 :            : 
     224                 :            : /* Write all buffered data to the stream. */
     225                 :            : static pdf_bool_t
     226                 :         32 : flush_buffer (pdf_token_writer_t  *writer,
     227                 :            :               pdf_error_t        **error)
     228                 :            : {
     229                 :            :   pdf_size_t len;
     230                 :            : 
     231         [ +  + ]:         64 :   while ((len = writer->buffer->wp - writer->buffer->rp) > 0)
     232                 :            :     {
     233                 :            :       pdf_size_t written;
     234                 :            : 
     235         [ -  + ]:         32 :       if (!write_data (writer,
     236                 :         64 :                        writer->buffer->data + writer->buffer->rp,
     237                 :            :                        len,
     238                 :            :                        &written,
     239                 :            :                        error))
     240                 :          0 :         return PDF_FALSE;
     241                 :            : 
     242                 :         32 :       writer->buffer->rp += written;
     243                 :            :     }
     244                 :            : 
     245                 :         32 :   pdf_buffer_rewind (writer->buffer);
     246                 :         32 :   return PDF_TRUE;
     247                 :            : }
     248                 :            : 
     249                 :            : /* Flush the buffer if there are less than 'len' bytes free. */
     250                 :            : static pdf_bool_t
     251                 :        178 : reserve_buffer_space (pdf_token_writer_t  *writer,
     252                 :            :                       pdf_size_t           len,
     253                 :            :                       pdf_error_t        **error)
     254                 :            : {
     255         [ -  + ]:        178 :   if (writer->buffer->wp + len > writer->buffer->size)
     256                 :            :     {
     257         [ #  # ]:          0 :       if (!flush_buffer (writer, error))
     258                 :          0 :         return PDF_FALSE;
     259                 :            : 
     260         [ #  # ]:          0 :       PDF_ASSERT_RETURN_VAL (len < writer->buffer->size, PDF_FALSE);
     261         [ #  # ]:          0 :       PDF_ASSERT_RETURN_VAL (writer->buffer->wp == 0, PDF_FALSE);
     262                 :            :     }
     263                 :            : 
     264                 :        178 :   return PDF_TRUE;
     265                 :            : }
     266                 :            : 
     267                 :            : /* Write a character into the buffer; this assumes it will fit. */
     268                 :            : static void
     269                 :            : write_buffered_char_nocheck (pdf_token_writer_t *writer,
     270                 :            :                              pdf_char_t          ch)
     271                 :            : {
     272                 :        225 :   writer->buffer->data[writer->buffer->wp++] = ch;
     273 [ #  # ][ #  # ]:        225 :   if (pdf_is_eol_char(ch))
         [ +  + ][ -  +  
             -  +  -  + ]
                 [ -  + ]
           [ -  +  -  + ]
         [ -  + ][ -  + ]
                 [ -  + ]
     274                 :          2 :     writer->buffered_line_length = 0;
     275                 :            :   else
     276                 :        223 :     writer->buffered_line_length++;
     277                 :            : }
     278                 :            : 
     279                 :            : /* Write a character into the buffer.  The buffer is flushed only if
     280                 :            :  * there's no room to write the character. */
     281                 :            : static pdf_bool_t
     282                 :        116 : write_buffered_char (pdf_token_writer_t  *writer,
     283                 :            :                      pdf_char_t           ch,
     284                 :            :                      pdf_error_t        **error)
     285                 :            : {
     286         [ -  + ]:        116 :   if (!reserve_buffer_space (writer, 1, error))
     287                 :          0 :     return PDF_FALSE;
     288                 :            : 
     289                 :        116 :   write_buffered_char_nocheck (writer, ch);
     290                 :        116 :   return PDF_TRUE;
     291                 :            : }
     292                 :            : 
     293                 :            : /***** Misc. utility functions *****/
     294                 :            : 
     295                 :            : /* Prepare to write a new token, adding some whitespace if necessary. */
     296                 :            : static pdf_bool_t
     297                 :         32 : start_token (pdf_token_writer_t  *writer,
     298                 :            :              pdf_bool_t           need_wspace,
     299                 :            :              pdf_size_t           len,
     300                 :            :              pdf_error_t        **error)
     301                 :            : {
     302                 :         32 :   const pdf_uchar_t *add_char = NULL;
     303                 :            :   static const pdf_uchar_t wspace_char = ' ';
     304                 :            :   static const pdf_uchar_t newline_char = '\n';
     305                 :            : 
     306 [ +  + ][ -  + ]:         32 :   if (need_wspace && writer->in_keyword)
     307                 :            :     {
     308                 :          0 :       add_char = &wspace_char;
     309                 :          0 :       len++;
     310                 :            :     }
     311                 :            : 
     312                 :            :   /* If the token would make this line too long, start a new line. */
     313 [ -  + ][ #  # ]:         32 :   if (writer->line_length + len > writer->max_line_length &&
     314                 :          0 :       writer->max_line_length > 0)
     315                 :            :     {
     316                 :          0 :       add_char = &newline_char;
     317                 :            :     }
     318                 :            : 
     319 [ -  + ][ #  # ]:         32 :   return ((add_char &&
     320                 :            :            !write_data (writer, add_char, 1, NULL, error)) ?
     321                 :            :           PDF_FALSE : PDF_TRUE);
     322                 :            : }
     323                 :            : 
     324                 :            : /***** Numeric tokens *****/
     325                 :            : 
     326                 :            : /* Encode snprintf output for PDF.  'len' is the return value of snprintf.
     327                 :            :  * Re-encodes bytes 0 to 'len' of writer->buffer and resets buffer->rp/wp. */
     328                 :            : static pdf_bool_t
     329                 :          5 : encode_buffer_number (pdf_token_writer_t  *writer,
     330                 :            :                       pdf_error_t        **error,
     331                 :            :                       const pdf_char_t    *number_format,
     332                 :            :                       ...)
     333                 :            : {
     334                 :            :   int len;
     335                 :            :   va_list args;
     336                 :            : 
     337                 :          5 :   va_start (args, number_format);
     338                 :            : 
     339                 :            :   /* Print the number in the buffer */
     340                 :         10 :   len = vsnprintf ((char *)writer->buffer->data,
     341                 :          5 :                    writer->buffer->size,
     342                 :            :                    number_format,
     343                 :            :                    args);
     344                 :          5 :   va_end (args);
     345                 :            : 
     346         [ -  + ]:          5 :   if (len < 0)
     347                 :            :     {
     348                 :          0 :       pdf_set_error (error,
     349                 :            :                      PDF_EDOMAIN_BASE_TOKENISER,
     350                 :            :                      PDF_ERROR,
     351                 :            :                      "couldn't encode number in buffer");
     352                 :          0 :       return PDF_FALSE;
     353                 :            :     }
     354         [ -  + ]:          5 :   else if (len >= writer->buffer->size)
     355                 :            :     {
     356                 :            :       /* TODO: Can't we just reserve more buffer space? */
     357                 :          0 :       pdf_set_error (error,
     358                 :            :                      PDF_EDOMAIN_BASE_TOKENISER,
     359                 :            :                      PDF_EAGAIN,
     360                 :            :                      "couldn't encode number in buffer: "
     361                 :            :                      "not enough space (%u needed, %u available)",
     362                 :            :                      (unsigned long)len,
     363                 :          0 :                      (unsigned long)writer->buffer->size);
     364                 :          0 :       return PDF_FALSE;
     365                 :            :     }
     366                 :            : 
     367                 :          5 :   writer->buffer->wp = 0;
     368                 :          5 :   writer->buffer->rp = 0;
     369         [ +  + ]:         38 :   while (writer->buffer->rp < len)
     370                 :            :     {
     371                 :         33 :       pdf_char_t ch = writer->buffer->data[writer->buffer->rp];
     372                 :            : 
     373         [ +  + ]:         33 :       if ((ch == '-') ||
     374                 :         33 :           (ch >= '0' && ch <= '9'))
     375                 :            :         {
     376                 :         30 :           writer->buffer->rp++;
     377                 :         30 :           writer->buffer->data[writer->buffer->wp++] = ch;
     378                 :            :         }
     379                 :            :       else
     380                 :            :         {
     381                 :            :           /* This should be a decimal point; check it. */
     382                 :            :           const pdf_char_t *decimal_point;
     383                 :            :           pdf_size_t declen;
     384                 :            : 
     385                 :          3 :           decimal_point = pdf_tokeniser_get_decimal_point ();
     386                 :          3 :           declen = strlen (decimal_point);
     387                 :            : 
     388         [ -  + ]:          3 :           if (memcmp (writer->buffer->data + writer->buffer->rp,
     389                 :            :                       decimal_point,
     390                 :            :                       declen) != 0)
     391                 :            :             {
     392                 :          0 :               pdf_set_error (error,
     393                 :            :                              PDF_EDOMAIN_BASE_TOKENISER,
     394                 :            :                              PDF_ERROR,
     395                 :            :                              "couldn't encode number in buffer: "
     396                 :            :                              "expecting decimal point, unexpected char found");
     397                 :          0 :               return PDF_FALSE;
     398                 :            :             }
     399                 :            : 
     400                 :          3 :           writer->buffer->rp += declen;
     401                 :          3 :           writer->buffer->data[writer->buffer->wp++] = '.';
     402                 :            :         }
     403                 :            :     }
     404                 :            : 
     405                 :          5 :   writer->buffer->rp = 0;
     406                 :          5 :   return PDF_TRUE;  /* success */
     407                 :            : }
     408                 :            : 
     409                 :            : static pdf_bool_t
     410                 :          2 : write_integer_token (pdf_token_writer_t  *writer,
     411                 :            :                      const pdf_token_t   *token,
     412                 :            :                      pdf_error_t        **error)
     413                 :            : {
     414   [ +  -  -  - ]:          2 :   switch (writer->state)
     415                 :            :     {
     416                 :            :     case 0:
     417         [ -  + ]:          2 :       if (!encode_buffer_number (writer,
     418                 :            :                                  error,
     419                 :            :                                  "%"PRId32,
     420                 :            :                                  pdf_token_get_integer_value (token)))
     421                 :          0 :         return PDF_FALSE;
     422                 :          2 :       writer->state++;
     423                 :            :       /* fall through */
     424                 :            : 
     425                 :            :     case 1:
     426         [ -  + ]:          2 :       if (!start_token (writer,
     427                 :            :                         PDF_TRUE /* need_wspace */,
     428                 :          2 :                         writer->buffer->wp,
     429                 :            :                         error))
     430                 :          0 :         return PDF_FALSE;
     431                 :          2 :       writer->state++;
     432                 :            :       /* fall through */
     433                 :            : 
     434                 :            :     case 2:
     435                 :          2 :       return flush_buffer (writer, error);
     436                 :            :     default:
     437                 :          0 :       PDF_ASSERT_TRACE_NOT_REACHED ();
     438                 :          2 :       return PDF_FALSE;
     439                 :            :     }
     440                 :            : }
     441                 :            : 
     442                 :            : static pdf_bool_t
     443                 :          3 : write_real_token (pdf_token_writer_t  *writer,
     444                 :            :                   const pdf_token_t   *token,
     445                 :            :                   pdf_error_t        **error)
     446                 :            : {
     447   [ +  -  -  - ]:          3 :   switch (writer->state)
     448                 :            :     {
     449                 :            :     case 0:
     450                 :            :       {
     451                 :            :         pdf_real_t value;
     452                 :            : 
     453                 :          3 :         value = pdf_token_get_real_value (token);
     454   [ +  -  -  + ]:          3 :         if (isnan (value) || isinf (value))
     455                 :            :           {
     456         [ #  # ]:          0 :             pdf_set_error (error,
     457                 :            :                            PDF_EDOMAIN_BASE_TOKENISER,
     458                 :            :                            PDF_EBADDATA,
     459                 :            :                            "cannot write real token: %s value",
     460                 :          0 :                            isnan (value) ? "NaN" : "Infinite");
     461                 :          0 :             return PDF_FALSE;
     462                 :            :           }
     463                 :            : 
     464         [ -  + ]:          3 :         if (!encode_buffer_number (writer,
     465                 :            :                                    error,
     466                 :            :                                    "%#f",
     467                 :            :                                    value))
     468                 :          0 :           return PDF_FALSE;
     469                 :            : 
     470                 :            :         /* strip trailing zeroes */
     471 [ +  - ][ +  + ]:         20 :         while (writer->buffer->wp &&
     472                 :         20 :                writer->buffer->data[writer->buffer->wp - 1] == '0')
     473                 :         17 :           writer->buffer->wp--;
     474                 :            :       }
     475                 :          3 :       writer->state++;
     476                 :            :       /* fall through */
     477                 :            : 
     478                 :            :     case 1:
     479         [ -  + ]:          3 :       if (!start_token (writer,
     480                 :            :                         PDF_TRUE /* need_wspace */,
     481                 :          3 :                         writer->buffer->wp,
     482                 :            :                         error))
     483                 :          0 :         return PDF_FALSE;;
     484                 :          3 :       writer->state++;
     485                 :            :       /* fall through */
     486                 :            : 
     487                 :            :     case 2:
     488                 :          3 :       return flush_buffer (writer, error);
     489                 :            : 
     490                 :            :     default:
     491                 :          0 :       PDF_ASSERT_TRACE_NOT_REACHED ();
     492                 :          3 :       return PDF_FALSE;
     493                 :            :     }
     494                 :            : }
     495                 :            : 
     496                 :            : /***** String tokens *****/
     497                 :            : 
     498                 :            : static pdf_bool_t
     499                 :            : should_escape_strchar (pdf_u32_t  flags,
     500                 :            :                        pdf_char_t ch,
     501                 :            :                        pdf_bool_t quote_parens,
     502                 :            :                        pdf_bool_t is_utf8)
     503                 :            : {
     504 [ +  + ][ +  + ]:        114 :   if (ch == '\\' || ch == '\r')
     505                 :          8 :     return PDF_TRUE;
     506                 :            : 
     507 [ +  + ][ +  + ]:        106 :   if (ch == '(' || ch == ')')
     508                 :          8 :     return quote_parens;
     509                 :            : 
     510 [ +  + ][ +  + ]:         98 :   if (flags & PDF_TOKEN_READABLE_STRINGS)
     511                 :            :     {
     512 [ +  - ][ +  + ]:         26 :       if (ch == 127 ||
         [ +  - ][ +  + ]
     513                 :         26 :           (ch < 32 && ch != 10) ||
     514                 :            :           (ch >= 128 && !is_utf8))
     515                 :         10 :         return PDF_TRUE;
     516                 :            :     }
     517                 :            : 
     518                 :         88 :   return PDF_FALSE;
     519                 :            : }
     520                 :            : 
     521                 :            : static pdf_i32_t
     522                 :            : str_escape_len (const pdf_char_t *data,
     523                 :            :                 pdf_size_t        len,
     524                 :            :                 pdf_size_t        pos)
     525                 :            : {
     526         [ +  + ]:         13 :   switch (data[pos])
     527                 :            :     {
     528                 :            :       /* characters with two-character escape codes */
     529                 :            :       case  8:
     530                 :            :       case  9:
     531                 :            :       case 10:
     532                 :            :       case 12:
     533                 :            :       case 13:
     534                 :            :       case 40:
     535                 :            :       case 41:
     536                 :            :       case 92:
     537                 :         12 :         return 2;
     538                 :            :     }
     539                 :            : 
     540         [ -  + ]:          1 :   if (data[pos] >= 0100)
     541                 :          0 :     return 4;  /* escaped using a backslash and 3 octal characters */
     542                 :            : 
     543         [ +  - ]:          1 :   if (pos + 1 < len)
     544                 :            :     {
     545         [ -  + ]:          1 :       if (data[pos + 1] >= '0' && data[pos + 1] <= '9')
     546                 :          0 :         return 4;  /* need to write a 3-character octal number */
     547                 :            :     }
     548                 :            : 
     549         [ -  + ]:          1 :   return (data[pos] >= 010) ? 3 : 2;
     550                 :            : }
     551                 :            : 
     552                 :            : static void
     553                 :         14 : scan_string (pdf_token_writer_t *writer,
     554                 :            :              pdf_u32_t           flags,
     555                 :            :              const pdf_char_t   *data,
     556                 :            :              pdf_size_t          len,
     557                 :            :              pdf_bool_t         *use_hex)
     558                 :            : {
     559                 :            :   pdf_size_t i;
     560                 :         14 :   pdf_size_t enc_bytes = 0;
     561                 :            : 
     562                 :            :   /* Match parentheses, and determine the portion of the string
     563                 :            :    * in which they should be quoted. */
     564                 :         14 :   writer->paren_quoting_start = 0;
     565                 :         14 :   writer->paren_quoting_end = len;
     566                 :            : 
     567         [ +  + ]:         71 :   for (i = 0; i < len; ++i)
     568                 :            :     {
     569         [ +  + ]:         57 :       if (data[i] == '(')
     570                 :            :         {
     571                 :            :           pdf_size_t j;
     572                 :            : 
     573         [ +  + ]:          6 :           for (j = writer->paren_quoting_end - 1; j > i; --j)
     574                 :            :             {
     575                 :            :               /* find a matching ')' */
     576         [ -  + ]:          4 :               if (data[j] == ')')
     577                 :            :                 {
     578                 :          0 :                   writer->paren_quoting_end = j;
     579                 :          0 :                   writer->paren_quoting_start = i + 1;
     580                 :          0 :                   break;
     581                 :            :                 }
     582                 :            :             }
     583                 :            :         }
     584                 :            :     }
     585                 :            : 
     586                 :            :   /* Determine the size of the escaped string. */
     587   [ +  +  +  - ]:         17 :   writer->utf8 = ((flags & PDF_TOKEN_READABLE_STRINGS) &&
     588                 :          3 :                   (u8_check ((uint8_t *) data, len) == NULL));
     589                 :            : 
     590         [ +  + ]:         71 :   for (i = 0; i < len; ++i)
     591                 :            :     {
     592         [ +  + ]:         57 :       if (should_escape_strchar (flags,
     593                 :         57 :                                  data[i],
     594 [ +  - ][ +  - ]:         57 :                                  ((i >= writer->paren_quoting_start &&
     595                 :         57 :                                    i < writer->paren_quoting_end) ?
     596                 :            :                                   PDF_TRUE : PDF_FALSE),
     597                 :         57 :                                  writer->utf8))
     598                 :         13 :         enc_bytes += str_escape_len (data, len, i);
     599                 :            :       else
     600                 :         44 :         enc_bytes++;
     601                 :            :     }
     602                 :         14 :   *use_hex = (enc_bytes > len * 2);
     603                 :         14 : }
     604                 :            : 
     605                 :            : static pdf_bool_t
     606                 :         57 : write_string_char (pdf_token_writer_t  *writer,
     607                 :            :                    pdf_u32_t            flags,
     608                 :            :                    const pdf_char_t    *data,
     609                 :            :                    pdf_char_t           len,
     610                 :            :                    pdf_size_t           pos,
     611                 :            :                    pdf_error_t        **error)
     612                 :            : {
     613                 :            :   const pdf_char_t *output;
     614                 :         57 :   pdf_size_t outlen = 1;
     615                 :         57 :   pdf_char_t esc[4] = { '\\', 0, 0, 0 };
     616                 :            :   pdf_char_t ch;
     617                 :            :   pdf_bool_t quote_parens;
     618                 :            :   pdf_size_t i;
     619                 :            : 
     620                 :         57 :   output = data + pos;
     621                 :         57 :   ch = data[pos];
     622 [ +  - ][ +  - ]:         57 :   quote_parens = (pos >= writer->paren_quoting_start &&
     623                 :         57 :                   pos < writer->paren_quoting_end);
     624                 :            : 
     625         [ +  + ]:         57 :   if (should_escape_strchar (flags, ch, quote_parens, writer->utf8))
     626                 :            :     {
     627                 :            :       /* escape the character */
     628                 :         13 :       output = esc;
     629                 :         13 :       outlen = 2;
     630                 :            : 
     631 [ -  +  -  +  + :         13 :       switch (ch)
                   +  + ]
     632                 :            :         {
     633                 :          0 :         case  8: esc[1] = 'b'; break;
     634                 :          2 :         case  9: esc[1] = 't'; break;
     635                 :          0 :         case 10: esc[1] = 'n'; break;
     636                 :          2 :         case 12: esc[1] = 'f'; break;
     637                 :          2 :         case 13: esc[1] = 'r'; break;
     638                 :            :         case 40:  /* '('; fall through */
     639                 :            :         case 41:  /* ')'; fall through */
     640                 :            :         case 92:  /* '\\' */
     641                 :          6 :           esc[1] = ch;
     642                 :          6 :           break;
     643                 :            :         default: /* use an octal escape */
     644                 :            :           {
     645                 :            :             pdf_size_t digits;
     646                 :            :             pdf_char_t nextch;
     647                 :            : 
     648         [ +  - ]:          1 :             nextch = (pos + 1 < len) ? data[pos + 1] : 0;
     649         [ -  + ]:          1 :             if (nextch >= '0' && nextch <= '9')
     650                 :          0 :               digits = 3;  /* must use 3 octal characters */
     651         [ -  + ]:          1 :             else if (ch > 0100)
     652                 :          0 :               digits = 3;
     653         [ -  + ]:          1 :             else if (ch > 010)
     654                 :          0 :               digits = 2;
     655                 :            :             else
     656                 :          1 :               digits = 1;
     657                 :            : 
     658                 :          1 :             outlen = 1;
     659   [ -  -  +  - ]:          1 :             switch (digits)
     660                 :            :               {
     661                 :            :                 /* fall through each case */
     662                 :          0 :               case 3: esc[outlen++] = HEXCHAR (ch / 0100);
     663         [ #  # ]:          0 :               case 2: esc[outlen++] = HEXCHAR ((ch % 0100) / 010);
     664 [ +  - ][ #  # ]:          1 :               case 1: esc[outlen++] = HEXCHAR (ch % 010);
     665                 :            :               }
     666                 :            :           }
     667                 :            :         }
     668                 :            :     }
     669                 :            : 
     670                 :            :   /* If the line will be too long, split it (the length cannot be equal to
     671                 :            :    * the maximum, since this would leave no room for the backslash). */
     672 [ +  - ][ +  + ]:         57 :   if (writer->max_line_length > 0 &&
                 [ -  + ]
     673                 :         57 :       !pdf_is_eol_char (output[0]) &&
     674                 :         55 :       writer->buffered_line_length + outlen >= writer->max_line_length)
     675                 :            :     {
     676         [ #  # ]:          0 :       if (!reserve_buffer_space (writer, 2, error))
     677                 :          0 :         return PDF_FALSE;
     678                 :            : 
     679                 :            :       write_buffered_char_nocheck (writer, '\\');
     680                 :            :       write_buffered_char_nocheck (writer, '\n');  /* newline */
     681                 :            :     }
     682                 :            : 
     683         [ -  + ]:         57 :   if (!reserve_buffer_space (writer, outlen, error))
     684                 :          0 :     return PDF_FALSE;
     685                 :            : 
     686         [ +  + ]:        127 :   for (i = 0; i < outlen; ++i)
     687                 :         70 :     write_buffered_char_nocheck (writer, output[i]);
     688                 :            : 
     689                 :         57 :   return PDF_TRUE;
     690                 :            : }
     691                 :            : 
     692                 :            : static pdf_bool_t
     693                 :         16 : write_string_token (pdf_token_writer_t  *writer,
     694                 :            :                     pdf_u32_t           flags,
     695                 :            :                     const pdf_token_t  *token,
     696                 :            :                     pdf_error_t       **error)
     697                 :            : {
     698                 :            :   const pdf_char_t *data;
     699                 :            :   pdf_size_t size;
     700                 :            : 
     701                 :         16 :   data = pdf_token_get_string_data (token);
     702                 :         16 :   size = pdf_token_get_string_size (token);
     703                 :            : 
     704 [ +  -  -  -  - :         16 :   switch (writer->state)
          -  -  -  -  - ]
     705                 :            :     {
     706                 :            :     case 0:
     707                 :            :       {
     708                 :         16 :         pdf_bool_t use_hex = (flags & PDF_TOKEN_HEX_STRINGS);
     709                 :            : 
     710         [ +  + ]:         16 :         if (!use_hex)
     711                 :         14 :           scan_string (writer, flags, data, size, &use_hex);
     712                 :            : 
     713         [ +  + ]:         16 :         if (use_hex)
     714                 :            :           goto hexstring_start;
     715                 :            :       }
     716                 :         14 :       writer->state++;
     717                 :            :       /* fall through */
     718                 :            : 
     719                 :            :     case 1:
     720                 :            :       {
     721                 :            :         /* Passing a correct length to start_token isn't important
     722                 :            :          * since we can split the string across multiple lines. */
     723                 :         14 :         pdf_size_t dummy_len = PDF_MIN (20, 2 + size);
     724                 :            : 
     725         [ -  + ]:         14 :         if (!start_token (writer,
     726                 :            :                           PDF_FALSE /* need_wspace */,
     727                 :            :                           dummy_len,
     728                 :            :                           error))
     729                 :          0 :           return PDF_FALSE;
     730                 :            :       }
     731                 :            : 
     732                 :         14 :       pdf_buffer_rewind (writer->buffer);
     733                 :         14 :       writer->buffered_line_length = writer->line_length;
     734                 :            :       write_buffered_char_nocheck (writer, '(');
     735                 :         14 :       writer->pos = 0;
     736                 :         14 :       writer->state++;
     737                 :            :       /* fall through */
     738                 :            : 
     739                 :            :     case 2:
     740         [ +  + ]:         71 :       while (writer->pos < size)
     741                 :            :         {
     742         [ -  + ]:         57 :           if (!write_string_char (writer,
     743                 :            :                                   flags,
     744                 :            :                                   data,
     745                 :            :                                   size,
     746                 :            :                                   writer->pos,
     747                 :            :                                   error))
     748                 :          0 :             return PDF_FALSE;
     749                 :         57 :           writer->pos++;
     750                 :            :         }
     751                 :         14 :       writer->state++;
     752                 :            :       /* fall through */
     753                 :            : 
     754                 :            :     case 3:
     755         [ -  + ]:         14 :       if (!write_buffered_char (writer, ')', error))
     756                 :          0 :         return PDF_FALSE;
     757                 :         14 :       writer->state++;
     758                 :            :       /* fall through */
     759                 :            : 
     760                 :            :     case 4:
     761                 :         14 :       return flush_buffer (writer, error);
     762                 :            : 
     763                 :            :       /*** hex strings ***/
     764                 :            :     hexstring_start:
     765                 :          2 :       writer->state = 101;
     766                 :            :     case 101:
     767                 :            :       {
     768                 :          2 :         pdf_size_t dummy_len = PDF_MIN (20, 2 + size * 2);
     769                 :            : 
     770         [ -  + ]:          2 :         if (!start_token (writer,
     771                 :            :                           PDF_FALSE /* need_wspace */,
     772                 :            :                           dummy_len,
     773                 :            :                           error))
     774                 :          0 :           return PDF_FALSE;
     775                 :            :       }
     776                 :            : 
     777                 :          2 :       pdf_buffer_rewind (writer->buffer);
     778                 :          2 :       writer->buffered_line_length = writer->line_length;
     779                 :            :       write_buffered_char_nocheck (writer, '<');
     780                 :          2 :       writer->pos = 0;
     781                 :          2 :       writer->state++;
     782                 :            :       /* fall through */
     783                 :            : 
     784                 :            :     case 102:
     785         [ +  + ]:          5 :       while (writer->pos < size)
     786                 :            :         {
     787                 :            :           pdf_char_t ch;
     788                 :            : 
     789                 :            :           /* If this line would be too long, start a new one. */
     790 [ -  + ][ #  # ]:          3 :           if (writer->buffered_line_length + 2 > writer->max_line_length
     791                 :          3 :               && writer->max_line_length > 0)
     792                 :            :             {
     793         [ #  # ]:          0 :               if (!write_buffered_char (writer, '\n', error))
     794                 :          0 :                 return PDF_FALSE;
     795                 :            :             }
     796                 :            : 
     797                 :          3 :           ch = data[writer->pos];
     798         [ -  + ]:          3 :           if (!reserve_buffer_space (writer, 2, error))
     799                 :          0 :             return PDF_FALSE;
     800                 :            : 
     801                 :          3 :           write_buffered_char_nocheck (writer, HEXCHAR (ch / 16));
     802 [ +  + ][ +  - ]:          3 :           if (writer->pos != (size - 1) ||
     803                 :          1 :               (ch % 16) != 0)
     804 [ +  - ][ #  # ]:          3 :             write_buffered_char_nocheck (writer, HEXCHAR (ch % 16));
     805                 :          3 :           writer->pos++;
     806                 :            :         }
     807                 :          2 :         writer->state++;
     808                 :            :         /* fall through */
     809                 :            : 
     810                 :            :       case 103:
     811         [ -  + ]:          2 :         if (!write_buffered_char (writer, '>', error))
     812                 :          0 :           return PDF_FALSE;
     813                 :            : 
     814                 :          2 :         writer->state++;
     815                 :            :         /* fall through */
     816                 :            : 
     817                 :            :       case 104:
     818                 :          2 :         return flush_buffer (writer, error);
     819                 :            : 
     820                 :            :       default:
     821                 :          0 :         PDF_ASSERT_TRACE_NOT_REACHED ();
     822                 :         16 :         return PDF_FALSE;
     823                 :            :     }
     824                 :            : }
     825                 :            : 
     826                 :            : /***** Other tokens *****/
     827                 :            : 
     828                 :            : static pdf_bool_t
     829                 :        204 : should_escape_namechar (pdf_u32_t   flags,
     830                 :            :                         pdf_char_t  ch,
     831                 :            :                         pdf_bool_t *escape)
     832                 :            : {
     833         [ -  + ]:        204 :   if (!ch)
     834                 :          0 :     return PDF_FALSE;
     835                 :            : 
     836 [ +  - ][ +  + ]:        204 :   *escape = !pdf_is_regular_char (ch);
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ -  + ]
     837         [ -  + ]:        204 :   if (flags & PDF_TOKEN_NO_NAME_ESCAPES)
     838                 :            :     {
     839         [ #  # ]:          0 :       if (*escape)
     840                 :          0 :         return PDF_FALSE;
     841                 :            :     }
     842                 :            :   else
     843                 :            :     {
     844 [ +  + ][ +  + ]:        204 :       *escape = (*escape ||
                 [ -  + ]
     845                 :        202 :                  ch == '#' ||
     846                 :        202 :                  ch < 33 ||
     847                 :            :                  ch >= 127);
     848                 :            :     }
     849                 :            : 
     850                 :        204 :   return PDF_TRUE;
     851                 :            : }
     852                 :            : 
     853                 :            : static pdf_bool_t
     854                 :         11 : write_name_token (pdf_token_writer_t  *writer,
     855                 :            :                   pdf_u32_t            flags,
     856                 :            :                   const pdf_token_t   *token,
     857                 :            :                   pdf_error_t        **error)
     858                 :            : {
     859                 :            :   pdf_size_t size;
     860                 :            :   const pdf_char_t *data;
     861                 :            : 
     862                 :         11 :   data = pdf_token_get_name_data (token);
     863                 :         11 :   size = pdf_token_get_name_size (token);
     864                 :            : 
     865   [ +  -  -  -  :         11 :   switch (writer->state)
                      - ]
     866                 :            :     {
     867                 :            :     case 0:
     868                 :            :       {
     869                 :            :         pdf_size_t i;
     870                 :            : 
     871                 :            :         /* Validate the name; also calculate the encoded size
     872                 :            :          * and store it in ->pos temporarily. */
     873                 :            : 
     874                 :         11 :         writer->pos = 1 + size;
     875         [ +  + ]:        113 :         for (i = 0; i < size; ++i)
     876                 :            :           {
     877                 :            :             pdf_bool_t escape;
     878                 :            : 
     879         [ -  + ]:        102 :             if (!should_escape_namechar (flags, data[i], &escape))
     880                 :            :               {
     881                 :          0 :                 pdf_set_error (error,
     882                 :            :                                PDF_EDOMAIN_BASE_TOKENISER,
     883                 :            :                                PDF_EBADDATA,
     884                 :            :                                "cannot write name token: "
     885                 :            :                                "bad name");
     886                 :          0 :                 return PDF_FALSE;
     887                 :            :               }
     888                 :            : 
     889         [ +  + ]:        102 :             if (escape)
     890                 :          2 :               writer->pos += 2;  /* 2 hex characters */
     891                 :            :           }
     892                 :            : 
     893                 :         11 :         pdf_buffer_rewind (writer->buffer);
     894                 :            :         write_buffered_char_nocheck (writer, '/');
     895                 :            :       }
     896                 :         11 :       writer->state++;
     897                 :            :       /* fall through */
     898                 :            : 
     899                 :            :     case 1:
     900         [ -  + ]:         11 :       if (!start_token (writer,
     901                 :            :                         PDF_FALSE, /* need_wspace */
     902                 :            :                         writer->pos, /* encoded token length */
     903                 :            :                         error))
     904                 :          0 :         return PDF_FALSE;
     905                 :            : 
     906                 :         11 :       writer->pos = 0;
     907                 :         11 :       writer->state++;
     908                 :            :       /* fall through */
     909                 :            : 
     910                 :            :     case 2:
     911         [ +  + ]:        113 :       while (writer->pos < size)
     912                 :            :         {
     913                 :            :           pdf_bool_t escape;
     914                 :            :           pdf_char_t ch;
     915                 :            : 
     916                 :        102 :           ch = data[writer->pos];
     917         [ -  + ]:        102 :           if (!should_escape_namechar (flags, ch, &escape))
     918                 :            :             {
     919                 :          0 :               pdf_set_error (error,
     920                 :            :                              PDF_EDOMAIN_BASE_TOKENISER,
     921                 :            :                              PDF_EBADDATA,
     922                 :            :                              "cannot write name token: "
     923                 :            :                              "bad name");
     924                 :          0 :               return PDF_FALSE;
     925                 :            :             }
     926                 :            : 
     927         [ +  + ]:        102 :           if (escape)
     928                 :            :             {
     929         [ -  + ]:          2 :               if (!reserve_buffer_space (writer, 3, error))
     930                 :          0 :                 return PDF_FALSE;
     931                 :            : 
     932                 :            :               write_buffered_char_nocheck (writer, '#');
     933                 :          2 :               write_buffered_char_nocheck (writer, HEXCHAR (ch / 16));
     934 [ +  + ][ +  - ]:          2 :               write_buffered_char_nocheck (writer, HEXCHAR (ch % 16));
     935                 :            :             }
     936                 :            :           else
     937                 :            :             {
     938         [ -  + ]:        100 :               if (!write_buffered_char (writer, ch, error))
     939                 :          0 :                 return PDF_FALSE;
     940                 :            :             }
     941                 :        102 :           writer->pos++;
     942                 :            :         }
     943                 :         11 :       writer->state++;
     944                 :            :       /* fall through */
     945                 :            : 
     946                 :            :       case 3:
     947                 :         11 :         return flush_buffer (writer, error);
     948                 :            : 
     949                 :            :       default:
     950                 :          0 :         PDF_ASSERT_TRACE_NOT_REACHED ();
     951                 :         11 :         return PDF_FALSE;
     952                 :            :     }
     953                 :            : }
     954                 :            : 
     955                 :            : static pdf_bool_t
     956                 :          0 : write_keyword_token (pdf_token_writer_t  *writer,
     957                 :            :                      const pdf_token_t   *token,
     958                 :            :                      pdf_error_t        **error)
     959                 :            : {
     960                 :            :   const pdf_char_t *data;
     961                 :            :   pdf_size_t size;
     962                 :            : 
     963                 :          0 :   data = pdf_token_get_keyword_data (token);
     964                 :          0 :   size = pdf_token_get_keyword_size (token);
     965                 :            : 
     966   [ #  #  #  # ]:          0 :   switch (writer->state)
     967                 :            :     {
     968                 :            :     case 0:
     969         [ #  # ]:          0 :       if (memchr (data, 0, size))
     970                 :            :         {
     971                 :          0 :           pdf_set_error (error,
     972                 :            :                          PDF_EDOMAIN_BASE_TOKENISER,
     973                 :            :                          PDF_EBADDATA,
     974                 :            :                          "cannot write keyword token: "
     975                 :            :                          "contains NUL bytes");
     976                 :          0 :           return PDF_FALSE;
     977                 :            :         }
     978                 :          0 :       writer->state++;
     979                 :            :       /* fall through */
     980                 :            : 
     981                 :            :     case 1:
     982         [ #  # ]:          0 :       if (!start_token (writer,
     983                 :            :                         PDF_TRUE /* need_wspace */,
     984                 :            :                         size,
     985                 :            :                         error))
     986                 :          0 :         return PDF_FALSE;
     987                 :            : 
     988                 :          0 :       writer->pos = 0;
     989                 :          0 :       writer->state++;
     990                 :            :       /* fall through */
     991                 :            : 
     992                 :            :     case 2:
     993                 :          0 :       return write_data_using_pos (writer,
     994                 :            :                                    (pdf_uchar_t *)pdf_token_get_keyword_data (token),
     995                 :            :                                    size,
     996                 :            :                                    error);
     997                 :            : 
     998                 :            :     default:
     999                 :          0 :       PDF_ASSERT_TRACE_NOT_REACHED ();
    1000                 :          0 :       return PDF_FALSE;
    1001                 :            :     }
    1002                 :            : }
    1003                 :            : 
    1004                 :            : static pdf_bool_t
    1005                 :          0 : write_comment_token (pdf_token_writer_t  *writer,
    1006                 :            :                      const pdf_token_t   *token,
    1007                 :            :                      pdf_error_t        **error)
    1008                 :            : {
    1009                 :            :   const pdf_char_t *data;
    1010                 :            :   pdf_size_t size;
    1011                 :            : 
    1012                 :          0 :   data = pdf_token_get_comment_data (token);
    1013                 :          0 :   size = pdf_token_get_comment_size (token);
    1014                 :            : 
    1015 [ #  #  #  #  # :          0 :   switch (writer->state)
                      # ]
    1016                 :            :     {
    1017                 :            :     case 0:
    1018                 :            :       {
    1019                 :            :         /* A comment can't span multiple lines. */
    1020                 :            :         pdf_size_t i;
    1021                 :            : 
    1022         [ #  # ]:          0 :         for (i = 0; i < size; ++i)
    1023                 :            :           {
    1024         [ #  # ]:          0 :             if (pdf_is_eol_char (data[i]))
    1025                 :            :               {
    1026                 :          0 :                 pdf_set_error (error,
    1027                 :            :                                PDF_EDOMAIN_BASE_TOKENISER,
    1028                 :            :                                PDF_EBADDATA,
    1029                 :            :                                "cannot write comment token: "
    1030                 :            :                                "comment must not span multiple lines");
    1031                 :          0 :                 return PDF_FALSE;
    1032                 :            :               }
    1033                 :            :           }
    1034                 :            :       }
    1035                 :          0 :       writer->state++;
    1036                 :            :       /* fall through */
    1037                 :            : 
    1038                 :            :       case 1:
    1039         [ #  # ]:          0 :         if (!start_token (writer,
    1040                 :            :                           PDF_FALSE, /* need_wspace */
    1041                 :            :                           size + 1,
    1042                 :            :                           error))
    1043                 :          0 :           return PDF_FALSE;
    1044                 :          0 :         writer->state++;
    1045                 :            :         /* fall through */
    1046                 :            : 
    1047                 :            :       case 2:
    1048         [ #  # ]:          0 :         if (!write_char (writer, '%', error))
    1049                 :          0 :           return PDF_FALSE;
    1050                 :          0 :         writer->pos = 0;
    1051                 :          0 :         writer->state++;
    1052                 :            :         /* fall through */
    1053                 :            : 
    1054                 :            :       case 3:
    1055         [ #  # ]:          0 :         if (!write_data_using_pos (writer, (pdf_uchar_t *)data, size, error))
    1056                 :          0 :           return PDF_FALSE;
    1057                 :          0 :         writer->state++;
    1058                 :            :         /* fall through */
    1059                 :            : 
    1060                 :            :       case 4:
    1061                 :          0 :         return write_char (writer, '\n', error);
    1062                 :            : 
    1063                 :            :       default:
    1064                 :          0 :         PDF_ASSERT_TRACE_NOT_REACHED ();
    1065                 :          0 :         return PDF_FALSE;
    1066                 :            :     }
    1067                 :            : }
    1068                 :            : 
    1069                 :            : static pdf_bool_t
    1070                 :          0 : write_valueless_token (pdf_token_writer_t  *writer,
    1071                 :            :                        pdf_char_t           ch,
    1072                 :            :                        pdf_size_t           len,
    1073                 :            :                        pdf_error_t        **error)
    1074                 :            : {
    1075                 :          0 :   pdf_uchar_t buf[2] = {ch , ch};
    1076                 :            : 
    1077      [ #  #  # ]:          0 :   switch (writer->state)
    1078                 :            :     {
    1079                 :            :     case 0:
    1080         [ #  # ]:          0 :       if (!start_token (writer,
    1081                 :            :                         PDF_FALSE, /* need_wspace */
    1082                 :            :                         len,
    1083                 :            :                         error))
    1084                 :          0 :         return PDF_FALSE;
    1085                 :          0 :       writer->pos = 0;
    1086                 :          0 :       writer->state++;
    1087                 :            :       /* fall through */
    1088                 :            : 
    1089                 :            :     case 1:
    1090                 :          0 :       return write_data_using_pos (writer, buf, len, error);
    1091                 :            : 
    1092                 :            :     default:
    1093                 :          0 :       PDF_ASSERT_TRACE_NOT_REACHED ();
    1094                 :          0 :       return PDF_FALSE;
    1095                 :            :     }
    1096                 :            : }
    1097                 :            : 
    1098                 :            : /***** Token dispatching *****/
    1099                 :            : 
    1100                 :            : pdf_bool_t
    1101                 :         32 : pdf_token_writer_write (pdf_token_writer_t  *writer,
    1102                 :            :                         pdf_u32_t            flags,
    1103                 :            :                         const pdf_token_t   *token,
    1104                 :            :                         pdf_error_t        **error)
    1105                 :            : {
    1106                 :            :   pdf_bool_t rv;
    1107                 :            : 
    1108 [ +  +  +  +  - :         32 :   switch (pdf_token_get_type (token))
          -  -  -  -  -  
                -  -  - ]
    1109                 :            :     {
    1110                 :            :     case PDF_TOKEN_INTEGER:
    1111                 :          2 :       rv = write_integer_token (writer, token, error);
    1112                 :          2 :       break;
    1113                 :            :     case PDF_TOKEN_REAL:
    1114                 :          3 :       rv = write_real_token (writer, token, error);
    1115                 :          3 :       break;
    1116                 :            :     case PDF_TOKEN_STRING:
    1117                 :         16 :       rv = write_string_token (writer, flags, token, error);
    1118                 :         16 :       break;
    1119                 :            :     case PDF_TOKEN_NAME:
    1120                 :         11 :       rv = write_name_token (writer, flags, token, error);
    1121                 :         11 :       break;
    1122                 :            :     case PDF_TOKEN_KEYWORD:
    1123                 :          0 :       rv = write_keyword_token (writer, token, error);
    1124                 :          0 :       break;
    1125                 :            :     case PDF_TOKEN_COMMENT:
    1126                 :          0 :       rv = write_comment_token (writer, token, error);
    1127                 :          0 :       break;
    1128                 :            :     case PDF_TOKEN_DICT_START:
    1129                 :          0 :       rv = write_valueless_token (writer, '<', 2, error);
    1130                 :          0 :       break;
    1131                 :            :     case PDF_TOKEN_DICT_END:
    1132                 :          0 :       rv = write_valueless_token (writer, '>', 2, error);
    1133                 :          0 :       break;
    1134                 :            :     case PDF_TOKEN_ARRAY_START:
    1135                 :          0 :       rv = write_valueless_token (writer, '[', 1, error);
    1136                 :          0 :       break;
    1137                 :            :     case PDF_TOKEN_ARRAY_END:
    1138                 :          0 :       rv = write_valueless_token (writer, ']', 1, error);
    1139                 :          0 :       break;
    1140                 :            :     case PDF_TOKEN_PROC_START:
    1141                 :          0 :       rv = write_valueless_token (writer, '{', 1, error);
    1142                 :          0 :       break;
    1143                 :            :     case PDF_TOKEN_PROC_END:
    1144                 :          0 :       rv = write_valueless_token (writer, '}', 1, error);
    1145                 :          0 :       break;
    1146                 :            :     default:
    1147                 :          0 :       PDF_ASSERT_TRACE_NOT_REACHED ();
    1148                 :          0 :       return PDF_FALSE;
    1149                 :            :     }
    1150                 :            : 
    1151         [ +  - ]:         32 :   if (rv)
    1152                 :         32 :     writer->state = 0;
    1153                 :         32 :   return rv;
    1154                 :            : }
    1155                 :            : 
    1156                 :            : /* End of pdf-token-writer.c */

Generated by: LCOV version 1.8