LCOV - code coverage report
Current view: top level - src/base - pdf-text.c (source / functions) Hit Total Coverage
Test: libgnupdf.info Lines: 553 701 78.9 %
Date: 2011-12-09 Functions: 42 43 97.7 %
Branches: 301 464 64.9 %

           Branch data     Line data    Source code
       1                 :            : /* -*- mode: C -*-
       2                 :            :  *
       3                 :            :  *       File:         pdf-text.c
       4                 :            :  *       Date:         Fri Jan 11 21:09:56 2008
       5                 :            :  *
       6                 :            :  *       GNU PDF Library - Encoded Text handling utilities
       7                 :            :  *
       8                 :            :  */
       9                 :            : 
      10                 :            : /* Copyright (C) 2008-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 <limits.h>
      29                 :            : #include <stdlib.h>
      30                 :            : #include <string.h>
      31                 :            : #include <stdint.h>
      32                 :            : #ifdef HAVE_MALLOC_H
      33                 :            : #include <malloc.h>
      34                 :            : #endif /* HAVE_MALLOC_H */
      35                 :            : #include <math.h>
      36                 :            : 
      37                 :            : #include <pdf-text.h>
      38                 :            : #include <pdf-text-encoding.h>
      39                 :            : #include <pdf-text-host-encoding.h>
      40                 :            : #include <pdf-text-context.h>
      41                 :            : #include <pdf-text-filter.h>
      42                 :            : #include <pdf-text-ucd.h>
      43                 :            : 
      44                 :            : 
      45                 :            : /* Lang/Country Minimum Length, in bytes, of the Lang/Country information within
      46                 :            :  *  a UTF16BEstring (2bytes for the first marker, 2 bytes for LANG and 2 bytes
      47                 :            :  *  for the last marker). */
      48                 :            : #define PDF_TEXT_LCMINL     6
      49                 :            : 
      50                 :            : /* Maximum size, in bytes, of the Lang/Country information within a UTF16BE
      51                 :            :  *  string (Minimum size + 2 bytes for COUNTRY). */
      52                 :            : #define PDF_TEXT_LCMAXL     8
      53                 :            : 
      54                 :            : 
      55                 :            : /* Longest header length when requesting a unicode string with options is that
      56                 :            :  * of UTF-16BE with BOM and lang/country information: 2bytes-BOM +
      57                 :            :  * 8bytes-lang/country = 10 bytes (+ 1 NUL byte) */
      58                 :            : #define PDF_TEXT_USHMAXL    11
      59                 :            : 
      60                 :            : typedef struct pdf_text_repl_s {
      61                 :            :   pdf_char_t *data_ptr;
      62                 :            :   int old_pattern_i;
      63                 :            : } pdf_text_repl_t;
      64                 :            : 
      65                 :            : /* ---------------- Static (private) functions prototypes ------------------- */
      66                 :            : 
      67                 :            : /* This function receives as input a valid pdf_text_t element, where the
      68                 :            :  *  language and country code informations will be stored. In addition to this,
      69                 :            :  *  the function receives as input the data string (starting in the first
      70                 :            :  *  marker), and stores a pointer to the continuation of the data string, after
      71                 :            :  *  having read the language/country information. This function really assumes
      72                 :            :  *  that the input data string contains in the first bytes the country/lang
      73                 :            :  *  information.
      74                 :            :  * Two options are possible:
      75                 :            :  *   XXllXX   (6 bytes, XX is the marker, ll the language)
      76                 :            :  *   XXllccXX (8 bytes, XX is the marker, ll the language and cc the country)
      77                 :            :  */
      78                 :            : static pdf_bool_t
      79                 :            : pdf_text_get_lang_from_utf16be (pdf_text_t        *element,
      80                 :            :                                 const pdf_char_t  *str_in,
      81                 :            :                                 const pdf_size_t   str_in_length,
      82                 :            :                                 pdf_char_t       **str_out,
      83                 :            :                                 pdf_size_t        *str_out_length,
      84                 :            :                                 pdf_error_t      **error);
      85                 :            : 
      86                 :            : /* Function to get the header of a unicode string as requested in the
      87                 :            :  * `options' field when calling `pdf_text_get_unicode'. The header can be:
      88                 :            :  *  - BOM
      89                 :            :  *  - BOM + Lang/Country info (only if UTF-16BE requested)
      90                 :            :  *  - Lang/Country info (only if UTF-16BE requested)
      91                 :            :  */
      92                 :            : static void
      93                 :            : pdf_text_get_unicode_string_header (enum pdf_text_unicode_encoding_e enc,
      94                 :            :                                     pdf_u32_t         options,
      95                 :            :                                     const pdf_char_t *language,
      96                 :            :                                     const pdf_char_t *country,
      97                 :            :                                     pdf_char_t        header[PDF_TEXT_USHMAXL],
      98                 :            :                                     pdf_size_t       *header_length);
      99                 :            : 
     100                 :            : /* Function to convert a given Unicode Host Endian enumeration to the `real'
     101                 :            :  *  endianness (BE or LE). If a non-HE enumeration is passed to the function,
     102                 :            :  *  it will return the same enumeration value unchanged */
     103                 :            : static enum pdf_text_unicode_encoding_e
     104                 :            : pdf_text_transform_he_to_unicode_encoding (enum pdf_text_unicode_encoding_e enc);
     105                 :            : 
     106                 :            : /* Function to compare two given words */
     107                 :            : static pdf_i32_t pdf_text_compare_words (const pdf_char_t  *word1,
     108                 :            :                                          const pdf_size_t   size1,
     109                 :            :                                          const pdf_char_t  *word2,
     110                 :            :                                          const pdf_size_t   size2,
     111                 :            :                                          const pdf_char_t  *language1,
     112                 :            :                                          const pdf_char_t  *language2,
     113                 :            :                                          pdf_error_t      **error);
     114                 :            : 
     115                 :            : /* Non-Case sensitive comparison of text objects */
     116                 :            : static pdf_i32_t pdf_text_cmp_non_case_sensitive (const pdf_text_t   *text1,
     117                 :            :                                                   const pdf_text_t   *text2,
     118                 :            :                                                   pdf_error_t       **error);
     119                 :            : 
     120                 :            : /* Clean (destroy and create empty) Word Boundaries list */
     121                 :            : static pdf_bool_t pdf_text_clean_word_boundaries_list (pdf_list_t  **p_word_boundaries,
     122                 :            :                                                        pdf_error_t **error);
     123                 :            : /* Fill in the Word Boundaries list using the given data */
     124                 :            : static pdf_bool_t pdf_text_fill_word_boundaries_list (pdf_list_t        *word_boundaries,
     125                 :            :                                                       const pdf_char_t  *data,
     126                 :            :                                                       const pdf_size_t   size,
     127                 :            :                                                       pdf_error_t      **error);
     128                 :            : 
     129                 :            : /* ----------------------------- Public functions ----------------------------*/
     130                 :            : 
     131                 :            : pdf_bool_t
     132                 :        745 : pdf_text_init (pdf_error_t **error)
     133                 :            : {
     134                 :            :   /* Initiate Text module context */
     135                 :        745 :   return pdf_text_context_init (error);
     136                 :            : }
     137                 :            : 
     138                 :            : void
     139                 :        745 : pdf_text_deinit (void)
     140                 :            : {
     141                 :            :   /* Deinit Text module context */
     142         [ +  - ]:        745 :   if (pdf_text_context_initialized ())
     143                 :        745 :     pdf_text_context_deinit ();
     144                 :        745 : }
     145                 :            : 
     146                 :            : pdf_text_t *
     147                 :       1743 : pdf_text_new (pdf_error_t **error)
     148                 :            : {
     149                 :            :   pdf_text_t *text;
     150                 :            : 
     151                 :            :   /* The text global state should be initialized! */
     152         [ -  + ]:       1743 :   if (!pdf_text_context_initialized ())
     153                 :            :     {
     154                 :          0 :       pdf_set_error (error,
     155                 :            :                      PDF_EDOMAIN_BASE_TEXT,
     156                 :            :                      PDF_EBADCONTEXT,
     157                 :            :                      "cannot create new text object: "
     158                 :            :                      "context not initialized");
     159                 :          0 :       return NULL;
     160                 :            :     }
     161                 :            : 
     162                 :            :   /* Allocate memory for the new text structure */
     163                 :       1743 :   text = (pdf_text_t *) pdf_alloc (sizeof (struct pdf_text_s));
     164         [ -  + ]:       1743 :   if (!text)
     165                 :            :     {
     166                 :          0 :       pdf_set_error (error,
     167                 :            :                      PDF_EDOMAIN_BASE_TEXT,
     168                 :            :                      PDF_ENOMEM,
     169                 :            :                      "cannot create new text object: "
     170                 :            :                      "couldn't allocate %lu bytes",
     171                 :            :                      (unsigned long)sizeof (struct pdf_text_s));
     172                 :            :       /* Out of memory condition */
     173                 :          0 :       return NULL;
     174                 :            :     }
     175                 :            : 
     176                 :            :   /* Initialize all contents */
     177                 :       1743 :   text->data = NULL;
     178                 :       1743 :   text->size = 0;
     179                 :       1743 :   text->printable = NULL;
     180                 :       1743 :   text->modified = PDF_FALSE;
     181                 :       1743 :   memset (&(text->lang[0]), 0, PDF_TEXT_CCL);
     182                 :       1743 :   memset (&(text->country[0]), 0, PDF_TEXT_CCL);
     183                 :            : 
     184                 :            :   /* Create empty word boundaries list */
     185                 :       1743 :   text->word_boundaries = pdf_text_create_word_boundaries_list (error);
     186         [ -  + ]:       1743 :   if (!text->word_boundaries)
     187                 :            :     {
     188                 :          0 :       pdf_text_destroy (text);
     189                 :          0 :       return NULL;
     190                 :            :     }
     191                 :            : 
     192                 :            :   /* Success! */
     193                 :       1743 :   return text;
     194                 :            : }
     195                 :            : 
     196                 :            : void
     197                 :       1539 : pdf_text_destroy (pdf_text_t *text)
     198                 :            : {
     199         [ +  - ]:       1539 :   if (!text)
     200                 :            :     return;
     201                 :            : 
     202                 :            :   /* Dealloc memory */
     203         [ +  + ]:       1539 :   if (text->data != NULL)
     204                 :       1310 :     pdf_dealloc (text->data);
     205                 :            : 
     206         [ -  + ]:       1539 :   if (text->printable != NULL)
     207                 :          0 :     pdf_dealloc (text->printable);
     208                 :            : 
     209                 :            :   /* Destroy word boundaries list */
     210                 :       1539 :   pdf_text_destroy_word_boundaries_list (&text->word_boundaries);
     211                 :            : 
     212                 :       1539 :   pdf_dealloc (text);
     213                 :            : }
     214                 :            : 
     215                 :            : pdf_text_t *
     216                 :         30 : pdf_text_dup (const pdf_text_t  *text,
     217                 :            :               pdf_error_t      **error)
     218                 :            : {
     219                 :            :   pdf_text_t *element;
     220                 :            : 
     221         [ -  + ]:         30 :   PDF_ASSERT_POINTER_RETURN_VAL (text, NULL);
     222                 :            : 
     223                 :            :   /* Allocate and initialize element */
     224                 :         30 :   element = pdf_text_new (error);
     225         [ -  + ]:         30 :   if (!element)
     226                 :            :     {
     227                 :          0 :       pdf_prefix_error (error, "cannot duplicate text object: ");
     228                 :          0 :       return NULL;
     229                 :            :     }
     230                 :            : 
     231                 :            :   /* Duplicate size */
     232                 :         30 :   element->size = text->size;
     233                 :            : 
     234                 :            :   /* Duplicate contents (if size > 0) */
     235         [ +  + ]:         30 :   if (element->size > 0)
     236                 :            :     {
     237                 :         29 :       element->data = (pdf_char_t *) pdf_alloc (element->size);
     238         [ -  + ]:         29 :       if (!element->data)
     239                 :            :         {
     240                 :          0 :           pdf_set_error (error,
     241                 :            :                          PDF_EDOMAIN_BASE_TEXT,
     242                 :            :                          PDF_ENOMEM,
     243                 :            :                          "cannot duplicate text object: "
     244                 :            :                          "couldn't allocate %lu bytes",
     245                 :            :                          (unsigned long)element->size);
     246                 :          0 :           return NULL;
     247                 :            :         }
     248                 :            : 
     249                 :         29 :       memcpy (element->data, text->data, (size_t)element->size);
     250                 :            :     }
     251                 :            : 
     252                 :            :   /* Duplicate Language code and Country code (if available) */
     253                 :         30 :   memcpy (element->lang, text->lang, (size_t) PDF_TEXT_CCL);
     254                 :         30 :   memcpy (element->country, text->country, (size_t) PDF_TEXT_CCL);
     255                 :            : 
     256                 :            :   /* We don't really need to duplicate the contents of the word
     257                 :            :    *  boundaries list, as it is a side product, same with printable */
     258                 :            : 
     259                 :         30 :   return element;
     260                 :            : }
     261                 :            : 
     262                 :            : pdf_text_t *
     263                 :          5 : pdf_text_new_from_host (const pdf_char_t  *str,
     264                 :            :                         const pdf_size_t   size,
     265                 :            :                         const pdf_char_t  *enc,
     266                 :            :                         pdf_error_t      **error)
     267                 :            : {
     268                 :            :   pdf_text_t *element;
     269                 :            : 
     270         [ -  + ]:          5 :   PDF_ASSERT_POINTER_RETURN_VAL (str, NULL);
     271         [ -  + ]:          5 :   PDF_ASSERT_RETURN_VAL (size > 0, NULL);
     272         [ -  + ]:          5 :   PDF_ASSERT_POINTER_RETURN_VAL (enc, NULL);
     273                 :            : 
     274                 :            :   /* Allocate and initialize element */
     275                 :          5 :   element = pdf_text_new (error);
     276         [ -  + ]:          5 :   if (!element)
     277                 :            :     {
     278                 :          0 :       pdf_prefix_error (error,
     279                 :            :                         "cannot create text object from string "
     280                 :            :                         "encoded in '%s' host encoding: ",
     281                 :            :                         enc);
     282                 :          0 :       return NULL;
     283                 :            :     }
     284                 :            : 
     285                 :            :   /* Set Host Encoding contents */
     286         [ +  + ]:          5 :   if (!pdf_text_set_host (element, str, size, enc, error))
     287                 :            :     {
     288                 :          2 :       pdf_prefix_error (error,
     289                 :            :                         "cannot create text object from string "
     290                 :            :                         "encoded in '%s' host encoding: ",
     291                 :            :                         enc);
     292                 :            :       /* Conversion went wrong... so destroy object contents */
     293                 :          2 :       pdf_text_destroy (element);
     294                 :          2 :       return NULL;
     295                 :            :     }
     296                 :            : 
     297                 :          5 :   return element;
     298                 :            : }
     299                 :            : 
     300                 :            : pdf_text_t *
     301                 :         47 : pdf_text_new_from_pdf_string (const pdf_char_t  *str,
     302                 :            :                               const pdf_size_t   size,
     303                 :            :                               pdf_char_t       **remaining_str,
     304                 :            :                               pdf_size_t        *remaining_length,
     305                 :            :                               pdf_error_t      **error)
     306                 :            : {
     307                 :            :   pdf_text_t *element;
     308                 :         47 :   pdf_bool_t bom_found = PDF_FALSE;
     309                 :         47 :   pdf_bool_t lang_found = PDF_FALSE;
     310                 :            : 
     311         [ -  + ]:         47 :   PDF_ASSERT_POINTER_RETURN_VAL (str, NULL);
     312         [ -  + ]:         47 :   PDF_ASSERT_RETURN_VAL (size > 0, NULL);
     313                 :            : 
     314                 :            :   /* Allocate and initialize element */
     315                 :         47 :   element = pdf_text_new (error);
     316         [ -  + ]:         47 :   if (!element)
     317                 :            :     {
     318                 :          0 :       pdf_prefix_error (error,
     319                 :            :                         "cannot create text object "
     320                 :            :                         "from PDF string: ");
     321                 :          0 :       return NULL;
     322                 :            :     }
     323                 :            : 
     324                 :            :   /* First of all, check first two bytes to detect UTF-16BE BOM or lang/country
     325                 :            :    *  code initializer.
     326                 :            :    *  If length of the text is less than 2, then we can assume it is encoded in
     327                 :            :    *  PDF Doc Encoding */
     328         [ +  - ]:         47 :   if (size >= 2)
     329                 :            :     {
     330                 :            :       /* Check Unicode Byte Order Marker encoded in UTF-16BE */
     331         [ +  + ]:         47 :       if (pdf_text_check_unicode_bom (str, size, PDF_TEXT_UTF16_BE, 0))
     332                 :            :         {
     333                 :         21 :           bom_found = PDF_TRUE;
     334                 :            :           /* Check Lang/Country Code initializer */
     335 [ +  - ][ +  + ]:         21 :           if ((size >= 4) &&
                 [ +  - ]
     336                 :         21 :               (str[3] == PDF_TEXT_LCI_1) &&
     337                 :         16 :               (str[2] == PDF_TEXT_LCI_0))
     338                 :            :             {
     339                 :         16 :               lang_found = PDF_TRUE;
     340                 :            :             }
     341                 :            :         }
     342                 :            :       /* Check Lang/Country Code initializer (if this is the nth call to the
     343                 :            :        *  function parsing a single UTF-16BE string.*/
     344 [ +  + ][ +  - ]:         26 :       else if ((str[1] == PDF_TEXT_LCI_1) &&
     345                 :         12 :                (str[0] == PDF_TEXT_LCI_0))
     346                 :            :         {
     347                 :         12 :           lang_found = PDF_TRUE;
     348                 :            :         }
     349                 :            :     }
     350                 :            : 
     351                 :            :   /* If either BOM or Lang Marker are found, process PDF string as encoded
     352                 :            :    *  in UTF16-BE */
     353 [ +  + ][ +  + ]:         47 :   if (bom_found || lang_found)
     354                 :            :     {
     355                 :         33 :       pdf_char_t *string_start = (pdf_char_t *)str;
     356                 :         33 :       pdf_size_t string_length = size;
     357                 :            : 
     358                 :            :       /* Skip 2-bytes BOM */
     359         [ +  + ]:         33 :       if (bom_found)
     360                 :            :         {
     361                 :         21 :           string_start += 2;
     362                 :         21 :           string_length -= 2;
     363                 :            :         }
     364                 :            : 
     365                 :            :       /* If lang/country code available, obtain and store the information */
     366 [ +  + ][ -  + ]:         61 :       if ((lang_found) &&
     367                 :            :           (!pdf_text_get_lang_from_utf16be (element,
     368                 :            :                                             string_start,
     369                 :            :                                             string_length,
     370                 :            :                                             &string_start,
     371                 :            :                                             &string_length,
     372                 :            :                                             error)))
     373                 :            :         {
     374                 :          0 :           pdf_prefix_error (error,
     375                 :            :                             "cannot create text object "
     376                 :            :                             "from PDF string: ");
     377                 :          0 :           pdf_text_destroy (element);
     378                 :          0 :           return NULL;
     379                 :            :         }
     380                 :            : 
     381                 :            :       /* And finally convert to UTF-32... */
     382         [ -  + ]:         33 :       if (!pdf_text_utf16be_to_utf32he (string_start,
     383                 :            :                                         string_length,
     384                 :            :                                         &(element->data),
     385                 :            :                                         &(element->size),
     386                 :            :                                         remaining_str,
     387                 :            :                                         remaining_length,
     388                 :            :                                         error))
     389                 :            :         {
     390                 :          0 :           pdf_prefix_error (error,
     391                 :            :                             "cannot create text object "
     392                 :            :                             "from PDF string: ");
     393                 :          0 :           pdf_text_destroy (element);
     394                 :          0 :           return NULL;
     395                 :            :         }
     396                 :            : 
     397                 :            :       /* Return newly created element */
     398                 :         33 :       return element;
     399                 :            :     }
     400                 :            : 
     401                 :            :   /* Else, process PDF string as encoded in PDF Doc Encoding */
     402                 :            : 
     403                 :            :   /* We already know that this string will be fully stored, without
     404                 :            :    *  splitting in chunks */
     405         [ +  - ]:         14 :   if (remaining_length != NULL)
     406                 :         14 :     *remaining_length = 0;
     407         [ +  - ]:         14 :   if (remaining_str != NULL)
     408                 :         14 :     *remaining_str = NULL;
     409                 :            : 
     410                 :            :   /* And perform the conversion */
     411         [ +  + ]:         14 :   if (!pdf_text_pdfdocenc_to_utf32he (str,
     412                 :            :                                       size,
     413                 :            :                                       &(element->data),
     414                 :            :                                       &(element->size),
     415                 :            :                                       error))
     416                 :            :     {
     417                 :         11 :       pdf_prefix_error (error,
     418                 :            :                         "cannot create text object "
     419                 :            :                         "from PDF string: ");
     420                 :         11 :       pdf_text_destroy (element);
     421                 :         11 :       return NULL;
     422                 :            :     }
     423                 :            : 
     424                 :         47 :   return element;
     425                 :            : }
     426                 :            : 
     427                 :            : pdf_text_t *
     428                 :       1387 : pdf_text_new_from_unicode (const pdf_char_t  *str,
     429                 :            :                            const pdf_size_t   size,
     430                 :            :                            const enum pdf_text_unicode_encoding_e enc,
     431                 :            :                            pdf_error_t      **error)
     432                 :            : {
     433                 :            :   pdf_text_t *element;
     434                 :            : 
     435         [ -  + ]:       1387 :   PDF_ASSERT_POINTER_RETURN_VAL (str, NULL);
     436                 :            :   /* size == 0 is actually valid */
     437         [ -  + ]:       1387 :   PDF_ASSERT_RETURN_VAL (enc >= PDF_TEXT_UTF8, NULL);
     438         [ -  + ]:       1387 :   PDF_ASSERT_RETURN_VAL (enc < PDF_TEXT_MAX_UNICODE_ENC, NULL);
     439                 :            : 
     440                 :            :   /* Allocate and initialize element */
     441                 :       1387 :   element = pdf_text_new (error);
     442         [ -  + ]:       1387 :   if (!element)
     443                 :            :     {
     444                 :          0 :       pdf_prefix_error (error,
     445                 :            :                         "cannot create text object "
     446                 :            :                         "from '%s' encoded Unicode string: ",
     447                 :            :                         pdf_text_get_unicode_encoding_name (enc));
     448                 :          0 :       return NULL;
     449                 :            :     }
     450                 :            : 
     451                 :            :   /* Set Unicode contents */
     452 [ +  + ][ +  + ]:       1387 :   if (size > 0 &&
     453                 :            :       !pdf_text_set_unicode (element, str, size, enc, error))
     454                 :            :     {
     455                 :         80 :       pdf_prefix_error (error,
     456                 :            :                         "cannot create text object "
     457                 :            :                         "from '%s' encoded Unicode string: ",
     458                 :            :                         pdf_text_get_unicode_encoding_name (enc));
     459                 :         80 :       pdf_text_destroy (element);
     460                 :         80 :       return NULL;
     461                 :            :     }
     462                 :            : 
     463                 :       1387 :   return element;
     464                 :            : }
     465                 :            : 
     466                 :            : pdf_text_t *
     467                 :          2 : pdf_text_new_from_u32 (const pdf_u32_t   number,
     468                 :            :                        pdf_error_t     **error)
     469                 :            : {
     470                 :          2 :   pdf_error_t *inner_error = NULL;
     471                 :            :   pdf_text_t *element;
     472                 :            : 
     473                 :            :   /* Longest number to hold in 32bit: 2^32 = 4294967296 (10 chars) */
     474                 :            :   pdf_char_t temp[11];
     475                 :            :   int n;
     476                 :            : 
     477                 :            :   /* Print number in temporal char array, and get number of output chars */
     478                 :          2 :   n = sprintf (&temp[0], "%u", (unsigned int)number);
     479                 :            : 
     480                 :            :   /* Treat the generated string as UTF-8 encoded (just numbers in ASCII) */
     481                 :          2 :   element = pdf_text_new_from_unicode (&temp[0], n, PDF_TEXT_UTF8, &inner_error);
     482         [ -  + ]:          2 :   if (!element)
     483                 :            :     {
     484                 :            :       /* We should never get a PDF_ETEXTENC error */
     485         [ #  # ]:          0 :       PDF_ASSERT (pdf_error_get_status (inner_error) != PDF_ETEXTENC);
     486                 :          0 :       pdf_propagate_error (error, inner_error);
     487                 :          0 :       pdf_prefix_error (error,
     488                 :            :                         "cannot create text object "
     489                 :            :                         "from u32 (%u): ",
     490                 :            :                         (unsigned int)number);
     491                 :          0 :       return NULL;
     492                 :            :     }
     493                 :          2 :   return element;
     494                 :            : }
     495                 :            : 
     496                 :            : /* Return the country associated with a text variable */
     497                 :            : const pdf_char_t *
     498                 :        332 : pdf_text_get_country (const pdf_text_t *text)
     499                 :            : {
     500         [ -  + ]:        332 :   PDF_ASSERT_POINTER_RETURN_VAL (text, NULL);
     501                 :            : 
     502                 :        332 :   return (const pdf_char_t *)text->country;
     503                 :            : }
     504                 :            : 
     505                 :            : /* Return the language associated with a text variable */
     506                 :            : const pdf_char_t *
     507                 :        442 : pdf_text_get_language (const pdf_text_t *text)
     508                 :            : {
     509         [ -  + ]:        442 :   PDF_ASSERT_POINTER_RETURN_VAL (text, NULL);
     510                 :            : 
     511                 :        442 :   return (const pdf_char_t *)text->lang;
     512                 :            : }
     513                 :            : 
     514                 :            : /* Associate a text variable (full text) with a country code */
     515                 :            : void
     516                 :        152 : pdf_text_set_country (pdf_text_t       *text,
     517                 :            :                       const pdf_char_t *code)
     518                 :            : {
     519         [ -  + ]:        152 :   PDF_ASSERT_POINTER_RETURN (text);
     520         [ -  + ]:        152 :   PDF_ASSERT_POINTER_RETURN (code);
     521         [ -  + ]:        152 :   PDF_ASSERT_RETURN (strlen (code) == (PDF_TEXT_CCL - 1));
     522                 :            : 
     523                 :        152 :   memcpy (&(text->country[0]), code, PDF_TEXT_CCL - 1);
     524                 :            :   /* Make sure that last byte is NUL */
     525                 :        152 :   text->country[PDF_TEXT_CCL - 1] = '\0';
     526                 :            : }
     527                 :            : 
     528                 :            : /* Associate a text variable (full text) with a language code */
     529                 :            : void
     530                 :        291 : pdf_text_set_language (pdf_text_t       *text,
     531                 :            :                        const pdf_char_t *code)
     532                 :            : {
     533         [ -  + ]:        291 :   PDF_ASSERT_POINTER_RETURN (text);
     534         [ -  + ]:        291 :   PDF_ASSERT_POINTER_RETURN (code);
     535         [ -  + ]:        291 :   PDF_ASSERT_RETURN (strlen (code) == (PDF_TEXT_CCL - 1));
     536                 :            : 
     537                 :        291 :   memcpy (&(text->lang[0]), code, PDF_TEXT_CCL - 1);
     538                 :            :   /* Make sure that last byte is NUL */
     539                 :        291 :   text->lang[PDF_TEXT_CCL - 1] = '\0';
     540                 :            : }
     541                 :            : 
     542                 :            : /* Determine if a given text variable is empty (contains no text) */
     543                 :            : pdf_bool_t
     544                 :         41 : pdf_text_empty_p (const pdf_text_t *text)
     545                 :            : {
     546         [ -  + ]:         41 :   PDF_ASSERT_POINTER_RETURN_VAL (text, PDF_TRUE);
     547                 :            : 
     548                 :         41 :   return ((text->size != 0) ? PDF_FALSE : PDF_TRUE);
     549                 :            : }
     550                 :            : 
     551                 :            : /* Get default system host encoding */
     552                 :            : const pdf_char_t *
     553                 :         28 : pdf_text_get_host_encoding (void)
     554                 :            : {
     555                 :         28 :   return pdf_text_context_get_host_encoding ();
     556                 :            : }
     557                 :            : 
     558                 :            : /* Check if host encoding is available */
     559                 :            : pdf_bool_t
     560                 :          3 : pdf_text_check_host_encoding (const pdf_char_t  *encoding_name,
     561                 :            :                               pdf_error_t      **error)
     562                 :            : {
     563         [ -  + ]:          3 :   PDF_ASSERT_POINTER_RETURN_VAL (encoding_name, PDF_FALSE);
     564                 :            : 
     565                 :          3 :   return pdf_text_host_encoding_is_available (encoding_name,
     566                 :            :                                               error);
     567                 :            : }
     568                 :            : 
     569                 :            : const pdf_char_t *
     570                 :          1 : pdf_text_get_best_encoding (const pdf_text_t *text,
     571                 :            :                             const pdf_char_t *preferred_encoding)
     572                 :            : {
     573                 :            :   int i;
     574                 :            : #ifdef PDF_HOST_WIN32
     575                 :            :   static const pdf_char_t *to_check [3] = {
     576                 :            :     (pdf_char_t *) "CP1200",  /* UTF-16LE */
     577                 :            :     (pdf_char_t *) "CP65001", /* UTF-8 */
     578                 :            :     (pdf_char_t *) "CP12000"  /* UTF-32LE */
     579                 :            :   };
     580                 :            : #else
     581                 :            :   static const pdf_char_t *to_check [3] = {
     582                 :            :     (pdf_char_t *) "UTF-8",
     583                 :            :     (pdf_char_t *) "UTF-16",
     584                 :            :     (pdf_char_t *) "UTF-32"
     585                 :            :   };
     586                 :            : #endif
     587                 :            : 
     588         [ -  + ]:          1 :   PDF_ASSERT_POINTER_RETURN_VAL (text, NULL);
     589                 :            : 
     590                 :            :   /* TODO: In the case of win32, we could actually check if all characters
     591                 :            :    * in the text are ASCII-7, and if so, return for example CP1252 instead
     592                 :            :    * of UTF-16. */
     593                 :            : 
     594         [ -  + ]:          1 :   PDF_ASSERT_POINTER_RETURN_VAL (text, NULL);
     595                 :            : 
     596                 :            :   /* Check for Unicode support as host encoding */
     597         [ +  - ]:          1 :   for (i = 0; i < 3; i++)
     598                 :            :     {
     599         [ +  - ]:          1 :       if (pdf_text_check_host_encoding (to_check[i], NULL))
     600                 :          1 :         return to_check[i];
     601                 :            :     }
     602                 :            : 
     603                 :            :   /* If host does not support any Unicode encoding conversion, return the
     604                 :            :    *  preferred one directly */
     605                 :          1 :   return preferred_encoding;
     606                 :            : }
     607                 :            : 
     608                 :            : pdf_char_t *
     609                 :         33 : pdf_text_get_host (const pdf_text_t  *text,
     610                 :            :                    const pdf_char_t  *enc,
     611                 :            :                    pdf_size_t        *length,
     612                 :            :                    pdf_error_t      **error)
     613                 :            : {
     614                 :            :   pdf_char_t *contents;
     615                 :            : 
     616         [ -  + ]:         33 :   PDF_ASSERT_POINTER_RETURN_VAL (text, NULL);
     617         [ -  + ]:         33 :   PDF_ASSERT_POINTER_RETURN_VAL (enc, NULL);
     618                 :            :   /* You should really get and check the length of the returned string */
     619         [ -  + ]:         33 :   PDF_ASSERT_POINTER_RETURN_VAL (length, NULL);
     620                 :            : 
     621         [ +  + ]:         33 :   if (!pdf_text_utf32he_to_host (text->data,
     622                 :            :                                  text->size,
     623                 :            :                                  enc,
     624                 :            :                                  &contents,
     625                 :            :                                  length,
     626                 :            :                                  error))
     627                 :            :     {
     628                 :          3 :       pdf_prefix_error (error,
     629                 :            :                         "cannot get contents encoded in "
     630                 :            :                         "'%s' host encoding: ",
     631                 :            :                         enc);
     632                 :          3 :       return NULL;
     633                 :            :     }
     634                 :         33 :   return contents;
     635                 :            : }
     636                 :            : 
     637                 :            : /* Get the contents of a text variable encoded in PDFDocEncoding, as a NUL
     638                 :            :  *  terminated string */
     639                 :            : pdf_char_t *
     640                 :         20 : pdf_text_get_pdfdocenc (const pdf_text_t  *text,
     641                 :            :                         pdf_error_t      **error)
     642                 :            : {
     643                 :         20 :   pdf_char_t *data = NULL;
     644                 :            :   pdf_char_t *resized;
     645                 :         20 :   pdf_size_t size = -1;
     646                 :            : 
     647         [ -  + ]:         20 :   PDF_ASSERT_POINTER_RETURN_VAL (text, NULL);
     648                 :            : 
     649         [ -  + ]:         20 :   if (!pdf_text_utf32he_to_pdfdocenc (text->data,
     650                 :            :                                       text->size,
     651                 :            :                                       &data,
     652                 :            :                                       &size,
     653                 :            :                                       error))
     654                 :            :     {
     655                 :          0 :       pdf_prefix_error (error,
     656                 :            :                         "cannot get contents encoded in"
     657                 :            :                         " PDF Doc Encoding: ");
     658                 :          0 :       return NULL;
     659                 :            :     }
     660                 :            : 
     661                 :            :   /* Add NUL character at the end of the array */
     662                 :         20 :   resized = pdf_realloc (data, size + 1);
     663         [ -  + ]:         20 :   if (!resized)
     664                 :            :     {
     665                 :          0 :       pdf_dealloc (data);
     666                 :          0 :       pdf_set_error (error,
     667                 :            :                      PDF_EDOMAIN_BASE_TEXT,
     668                 :            :                      PDF_ENOMEM,
     669                 :            :                      "cannot get contents encoded in"
     670                 :            :                      " PDF Doc Encoding: "
     671                 :            :                      "couldn't reallocate %lu bytes",
     672                 :            :                      (unsigned long)(size + 1));
     673                 :          0 :       return NULL;
     674                 :            :     }
     675                 :            : 
     676                 :         20 :   resized[size] = '\0';
     677                 :            : 
     678                 :         20 :   return resized;
     679                 :            : }
     680                 :            : 
     681                 :            : pdf_char_t *
     682                 :        661 : pdf_text_get_unicode (const pdf_text_t  *text,
     683                 :            :                       enum pdf_text_unicode_encoding_e enc,
     684                 :            :                       pdf_u32_t          options,
     685                 :            :                       pdf_size_t        *length,
     686                 :            :                       pdf_error_t      **error)
     687                 :            : {
     688                 :        661 :   pdf_char_t *out_data = NULL;
     689                 :        661 :   pdf_size_t out_length = 0;
     690                 :            :   pdf_bool_t ret;
     691                 :            : 
     692         [ -  + ]:        661 :   PDF_ASSERT_POINTER_RETURN_VAL (text, NULL);
     693         [ -  + ]:        661 :   PDF_ASSERT_RETURN_VAL (enc >= PDF_TEXT_UTF8, NULL);
     694         [ -  + ]:        661 :   PDF_ASSERT_RETURN_VAL (enc < PDF_TEXT_MAX_UNICODE_ENC, NULL);
     695                 :            : 
     696                 :            :   /* Lang/Country info only available for UTF-16BE */
     697         [ +  + ]:        661 :   if ((options & PDF_TEXT_UTF16BE_WITH_LANGCODE) &&
     698                 :        661 :       (enc != PDF_TEXT_UTF16_BE))
     699                 :            :     {
     700                 :        164 :       pdf_set_error (error,
     701                 :            :                      PDF_EDOMAIN_BASE_TEXT,
     702                 :            :                      PDF_ETEXTENC,
     703                 :            :                      "cannot get text contents unicode encoded: "
     704                 :            :                      "language-code request only possible for UTF-16BE");
     705                 :        164 :       return NULL;
     706                 :            :     }
     707                 :            : 
     708                 :            :   /* If host endianness required, check it and convert input encoding */
     709                 :        497 :   enc = pdf_text_transform_he_to_unicode_encoding (enc);
     710                 :            : 
     711                 :            :   /* If text is empty, set empty string */
     712 [ +  + ][ +  + ]:        497 :   if ((text->data == NULL) ||
     713                 :        465 :       (text->size == 0))
     714                 :            :     {
     715                 :         38 :       ret = PDF_TRUE;
     716                 :         38 :       out_data = NULL;
     717                 :            :       /* Length is optional because you can ask for unicode output with NUL trailer */
     718         [ +  - ]:         38 :       if (length)
     719                 :         38 :         *length = 0;
     720                 :            :     }
     721                 :            :   else
     722                 :            :     {
     723                 :            :       /* Perform conversion */
     724 [ +  +  +  +  + :        459 :       switch (enc)
                      - ]
     725                 :            :         {
     726                 :            :         case PDF_TEXT_UTF8: /* UTF-8 */
     727                 :         86 :           ret = pdf_text_utf32he_to_utf8 (text->data,
     728                 :            :                                           text->size,
     729                 :            :                                           &out_data,
     730                 :            :                                           &out_length,
     731                 :            :                                           error);
     732                 :         86 :           break;
     733                 :            :         case PDF_TEXT_UTF16_LE: /* UTF-16LE */
     734                 :         20 :           ret = pdf_text_utf32he_to_utf16le (text->data,
     735                 :            :                                              text->size,
     736                 :            :                                              &out_data,
     737                 :            :                                              &out_length,
     738                 :            :                                              error);
     739                 :         20 :           break;
     740                 :            :         case PDF_TEXT_UTF16_BE: /* UTF-16BE */
     741                 :         60 :           ret = pdf_text_utf32he_to_utf16be (text->data,
     742                 :            :                                              text->size,
     743                 :            :                                              &out_data,
     744                 :            :                                              &out_length,
     745                 :            :                                              error);
     746                 :         60 :           break;
     747                 :            :         case PDF_TEXT_UTF32_LE: /* UTF-32LE */
     748                 :        217 :           ret = pdf_text_utf32he_to_utf32le (text->data,
     749                 :            :                                              text->size,
     750                 :            :                                              &out_data,
     751                 :            :                                              &out_length,
     752                 :            :                                              error);
     753                 :        217 :           break;
     754                 :            :         case PDF_TEXT_UTF32_BE: /* UTF-32BE */
     755                 :         76 :           ret = pdf_text_utf32he_to_utf32be (text->data,
     756                 :            :                                              text->size,
     757                 :            :                                              &out_data,
     758                 :            :                                              &out_length,
     759                 :            :                                              error);
     760                 :         76 :           break;
     761                 :            :         default:
     762                 :          0 :           pdf_set_error (error,
     763                 :            :                          PDF_EDOMAIN_BASE_TEXT,
     764                 :            :                          PDF_ETEXTENC,
     765                 :            :                          "couldn't get text contents in the given unicode "
     766                 :            :                          "encoding (%d)",
     767                 :            :                          enc);
     768                 :          0 :           ret = PDF_FALSE;
     769                 :            :           break;
     770                 :            :         }
     771                 :            :     }
     772                 :            : 
     773         [ -  + ]:        497 :   if (!ret)
     774                 :            :     {
     775         [ #  # ]:          0 :       if (out_data)
     776                 :          0 :         pdf_dealloc (out_data);
     777                 :          0 :       return NULL;
     778                 :            :     }
     779                 :            : 
     780                 :            :   /* Check if specific options were requested */
     781         [ +  + ]:        497 :   if (options != PDF_TEXT_UNICODE_NO_OPTION)
     782                 :            :     {
     783                 :            :       pdf_char_t header[PDF_TEXT_USHMAXL];
     784                 :        201 :       pdf_size_t header_size = 0;
     785                 :        201 :       pdf_size_t trailer_size = 0;
     786                 :            : 
     787                 :            :       /* Compute header if needed */
     788         [ +  + ]:        201 :       if ((options & PDF_TEXT_UNICODE_WITH_BOM) ||
     789                 :            :           (options & PDF_TEXT_UTF16BE_WITH_LANGCODE))
     790                 :            :         {
     791                 :            :           /* Clear header array */
     792                 :        108 :           memset (&(header[0]), 0, PDF_TEXT_USHMAXL);
     793                 :            :           /* Get requested header (BOM and/or lang/country info) */
     794                 :        108 :           pdf_text_get_unicode_string_header (enc,
     795                 :            :                                               options,
     796                 :            :                                               pdf_text_get_language(text),
     797                 :            :                                               pdf_text_get_country(text),
     798                 :            :                                               header,
     799                 :            :                                               &header_size);
     800                 :            :         }
     801                 :            : 
     802                 :            :       /* Compute trailer if needed */
     803         [ +  + ]:        201 :       if (options & PDF_TEXT_UNICODE_WITH_NUL_SUFFIX)
     804                 :            :         {
     805   [ +  +  +  - ]:        147 :           switch (enc)
     806                 :            :             {
     807                 :            :             case PDF_TEXT_UTF8:
     808                 :         75 :               trailer_size = 1;
     809                 :         75 :               break;
     810                 :            :             case PDF_TEXT_UTF16_BE:
     811                 :            :             case PDF_TEXT_UTF16_LE:
     812                 :            :             case PDF_TEXT_UTF16_HE:
     813                 :         48 :               trailer_size = 2;
     814                 :         48 :               break;
     815                 :            :             case PDF_TEXT_UTF32_BE:
     816                 :            :             case PDF_TEXT_UTF32_LE:
     817                 :            :             case PDF_TEXT_UTF32_HE:
     818                 :         24 :               trailer_size = 4;
     819                 :         24 :               break;
     820                 :            :             default:
     821                 :          0 :               trailer_size = 0;
     822                 :            :               break;
     823                 :            :             }
     824                 :            :         }
     825                 :            : 
     826         [ +  - ]:        201 :       if ((header_size > 0) ||
     827                 :            :           (trailer_size > 0))
     828                 :            :         {
     829                 :            :           pdf_char_t *new_out_data;
     830                 :            :           pdf_size_t new_size;
     831                 :            : 
     832                 :            :           /* Allocate memory for new string */
     833                 :        201 :           new_size = out_length + header_size + trailer_size;
     834                 :        201 :           new_out_data = (pdf_char_t *) pdf_alloc (new_size);
     835         [ -  + ]:        201 :           if (!new_out_data)
     836                 :            :             {
     837                 :          0 :               pdf_set_error (error,
     838                 :            :                              PDF_EDOMAIN_BASE_TEXT,
     839                 :            :                              PDF_ENOMEM,
     840                 :            :                              "couldn't get text contents in the given unicode "
     841                 :            :                              "encoding: "
     842                 :            :                              "couldn't reallocate %lu bytes",
     843                 :            :                              (unsigned long)new_size);
     844                 :          0 :               return NULL;
     845                 :            :             }
     846                 :            : 
     847                 :            :           /* Store header */
     848                 :        201 :           memcpy (new_out_data, &header[0], header_size);
     849                 :            : 
     850 [ +  + ][ +  - ]:        201 :           if ((out_data != NULL) &&
     851                 :        178 :               (out_length != 0))
     852                 :            :             {
     853                 :            :               /* Store unicode data, if any */
     854                 :        178 :               memcpy (&new_out_data[header_size], out_data, out_length);
     855                 :            :               /* Reset output data array, if any */
     856                 :        178 :               pdf_dealloc (out_data);
     857                 :            :             }
     858                 :            : 
     859                 :            :           /* Store trailer (N-byte NUL) */
     860         [ +  + ]:        201 :           if (trailer_size > 0)
     861                 :        147 :             memset (&new_out_data[out_length+header_size], 0, trailer_size);
     862                 :            : 
     863                 :        201 :           out_data = new_out_data;
     864                 :        201 :           out_length += (header_size + trailer_size);
     865                 :            :         }
     866                 :            :     }
     867                 :            : 
     868                 :            :   /* Length is optional because you can ask for unicode output with NUL trailer */
     869         [ +  + ]:        497 :   if (length)
     870                 :        466 :     *length = out_length;
     871                 :        661 :   return out_data;
     872                 :            : }
     873                 :            : 
     874                 :            : pdf_char_t *
     875                 :          2 : pdf_text_get_hex (const pdf_text_t  *text,
     876                 :            :                   const pdf_char_t   delimiter,
     877                 :            :                   pdf_error_t      **error)
     878                 :            : {
     879                 :            :   pdf_char_t *new_str;
     880                 :            : 
     881         [ -  + ]:          2 :   PDF_ASSERT_POINTER_RETURN_VAL (text, NULL);
     882                 :            : 
     883         [ +  + ]:          2 :   if (text->size > 0)
     884                 :            :     {
     885                 :            :       int i;
     886                 :            :       int j;
     887                 :            :       unsigned int new_str_length;
     888                 :            :       char new_hex_char [3];
     889                 :            : 
     890                 :            :       /* Get new string length. If input string has N bytes, we need:
     891                 :            :        * - 1 byte for last NUL char
     892                 :            :        * - 2N bytes for hexadecimal char representation of each byte...
     893                 :            :        * - N-1 bytes for the separator ':'
     894                 :            :        * So... a total of (1+2N+N-1) = 3N bytes are needed... */
     895                 :          1 :       new_str_length = 3 * text->size;
     896                 :            : 
     897                 :            :       /* Allocate memory for new array and initialize contents to NUL */
     898                 :          1 :       new_str = (pdf_char_t *) pdf_alloc (new_str_length);
     899         [ -  + ]:          1 :       if (!new_str)
     900                 :            :         {
     901                 :          0 :           pdf_set_error (error,
     902                 :            :                          PDF_EDOMAIN_BASE_TEXT,
     903                 :            :                          PDF_ENOMEM,
     904                 :            :                          "cannot get hexadecimal representation of the text "
     905                 :            :                          "object contents: "
     906                 :            :                          "couldn't allocate %lu bytes",
     907                 :            :                          (unsigned long)new_str_length);
     908                 :          0 :           return NULL;
     909                 :            :         }
     910                 :            : 
     911                 :          1 :       memset (new_str, 0, new_str_length);
     912                 :            : 
     913                 :            :       /* Print hexadecimal representation of each byte... */
     914         [ +  + ]:          9 :       for (i=0, j=0; i < text->size; i++, j+=3)
     915                 :            :         {
     916                 :            :           /* Clear helper array... */
     917                 :          8 :           memset (&new_hex_char[0], 0, 3);
     918                 :            :           /* Print character in helper array... */
     919                 :          8 :           sprintf (new_hex_char, "%02X", (unsigned int)text->data[i]);
     920                 :            :           /* Copy to output string... */
     921                 :          8 :           memcpy (&new_str[j], &new_hex_char[0], 2);
     922                 :            :           /* And if needed, add separator */
     923         [ +  + ]:          8 :           if (i != (text->size - 1))
     924                 :          7 :             new_str[j+2] = delimiter;
     925                 :            :         }
     926                 :            :     }
     927                 :            :   else
     928                 :            :     {
     929                 :          1 :       new_str = (pdf_char_t *) pdf_alloc (1);
     930         [ -  + ]:          1 :       if (!new_str)
     931                 :            :         {
     932                 :          0 :           pdf_set_error (error,
     933                 :            :                          PDF_EDOMAIN_BASE_TEXT,
     934                 :            :                          PDF_ENOMEM,
     935                 :            :                          "cannot get hexadecimal representation of the text "
     936                 :            :                          "object contents: "
     937                 :            :                          "couldn't allocate 1 byte");
     938                 :          0 :           return NULL;
     939                 :            :         }
     940                 :          1 :         new_str[0] = '\0';
     941                 :            :     }
     942                 :            : 
     943                 :            :   /* Set output string */
     944                 :          2 :   return new_str;
     945                 :            : }
     946                 :            : 
     947                 :            : pdf_bool_t
     948                 :         10 : pdf_text_set_host (pdf_text_t        *text,
     949                 :            :                    const pdf_char_t  *str,
     950                 :            :                    pdf_size_t         size,
     951                 :            :                    const pdf_char_t  *enc,
     952                 :            :                    pdf_error_t      **error)
     953                 :            : {
     954                 :            :   pdf_char_t *temp_data;
     955                 :            :   pdf_size_t temp_size;
     956                 :            : 
     957         [ -  + ]:         10 :   PDF_ASSERT_POINTER_RETURN_VAL (str, PDF_FALSE);
     958         [ -  + ]:         10 :   PDF_ASSERT_POINTER_RETURN_VAL (enc, PDF_FALSE);
     959         [ -  + ]:         10 :   PDF_ASSERT_RETURN_VAL (size > 0, PDF_FALSE);
     960                 :            : 
     961         [ +  + ]:         10 :   if (!pdf_text_host_to_utf32he (str,
     962                 :            :                                  size,
     963                 :            :                                  enc,
     964                 :            :                                  &temp_data,
     965                 :            :                                  &temp_size,
     966                 :            :                                  error))
     967                 :            :     {
     968                 :          4 :       pdf_prefix_error (error,
     969                 :            :                         "cannot set string encoded in "
     970                 :            :                         "'%s' host encoding: ",
     971                 :            :                         enc);
     972                 :          4 :       return PDF_FALSE;
     973                 :            :     }
     974                 :            : 
     975                 :            :   /* Destroy previous contents of text variable, if any */
     976         [ -  + ]:          6 :   if (!pdf_text_clean_contents (text, error))
     977                 :            :     {
     978                 :          0 :       pdf_prefix_error (error,
     979                 :            :                         "cannot set string encoded in "
     980                 :            :                         "'%s' host encoding: ",
     981                 :            :                         enc);
     982                 :          0 :       pdf_dealloc (temp_data);
     983                 :          0 :       return PDF_FALSE;
     984                 :            :     }
     985                 :            : 
     986                 :            :   /* Really set contents */
     987                 :          6 :   text->data = temp_data;
     988                 :          6 :   text->size = temp_size;
     989                 :            : 
     990                 :         10 :   return PDF_TRUE;
     991                 :            : }
     992                 :            : 
     993                 :            : /* Set PDF Doc Endoded string */
     994                 :            : pdf_bool_t
     995                 :         20 : pdf_text_set_pdfdocenc (pdf_text_t        *text,
     996                 :            :                         const pdf_char_t  *str,
     997                 :            :                         pdf_error_t      **error)
     998                 :            : {
     999                 :            :   pdf_char_t *temp_data;
    1000                 :            :   pdf_size_t temp_size;
    1001                 :            : 
    1002         [ -  + ]:         20 :   PDF_ASSERT_POINTER_RETURN_VAL (text, PDF_FALSE);
    1003         [ -  + ]:         20 :   PDF_ASSERT_POINTER_RETURN_VAL (str, PDF_FALSE);
    1004                 :            : 
    1005         [ +  + ]:         20 :   if (!pdf_text_pdfdocenc_to_utf32he (str,
    1006                 :            :                                       strlen (str),
    1007                 :            :                                       &temp_data,
    1008                 :            :                                       &temp_size,
    1009                 :            :                                       error))
    1010                 :            :     {
    1011                 :          1 :       pdf_prefix_error (error,
    1012                 :            :                         "cannot set string encoded in"
    1013                 :            :                         " PDF Doc Encoding: ");
    1014                 :          1 :       return PDF_FALSE;
    1015                 :            :     }
    1016                 :            : 
    1017                 :            :   /* Destroy previous contents of text variable, if any */
    1018         [ -  + ]:         19 :   if (!pdf_text_clean_contents (text, error))
    1019                 :            :     {
    1020                 :          0 :       pdf_prefix_error (error,
    1021                 :            :                         "cannot set string encoded in"
    1022                 :            :                         " PDF Doc Encoding: ");
    1023                 :          0 :       pdf_dealloc (temp_data);
    1024                 :          0 :       return PDF_FALSE;
    1025                 :            :     }
    1026                 :            : 
    1027                 :            :   /* Really set contents */
    1028                 :         19 :   text->data = temp_data;
    1029                 :         19 :   text->size = temp_size;
    1030                 :         20 :   return PDF_TRUE;
    1031                 :            : }
    1032                 :            : 
    1033                 :            : pdf_bool_t
    1034                 :       1544 : pdf_text_set_unicode (pdf_text_t        *text,
    1035                 :            :                       const pdf_char_t  *str,
    1036                 :            :                       pdf_size_t         size,
    1037                 :            :                       enum pdf_text_unicode_encoding_e enc,
    1038                 :            :                       pdf_error_t      **error)
    1039                 :            : {
    1040                 :       1544 :   pdf_char_t *temp_data = NULL;
    1041                 :            :   pdf_size_t temp_size;
    1042                 :            :   pdf_bool_t ret;
    1043                 :            : 
    1044         [ -  + ]:       1544 :   PDF_ASSERT_POINTER_RETURN_VAL (text, PDF_FALSE);
    1045         [ -  + ]:       1544 :   PDF_ASSERT_POINTER_RETURN_VAL (str, PDF_FALSE);
    1046         [ -  + ]:       1544 :   PDF_ASSERT_RETURN_VAL (size > 0, PDF_FALSE);
    1047         [ -  + ]:       1544 :   PDF_ASSERT_RETURN_VAL (enc >= PDF_TEXT_UTF8, NULL);
    1048         [ -  + ]:       1544 :   PDF_ASSERT_RETURN_VAL (enc < PDF_TEXT_MAX_UNICODE_ENC, NULL);
    1049                 :            : 
    1050                 :            :   /* If host endianness required, check it and convert input encoding */
    1051                 :       1544 :   enc = pdf_text_transform_he_to_unicode_encoding (enc);
    1052                 :            : 
    1053 [ +  +  +  +  + :       1544 :   switch (enc)
                      - ]
    1054                 :            :     {
    1055                 :            :     case PDF_TEXT_UTF8: /* UTF-8 */
    1056                 :        948 :       ret = pdf_text_utf8_to_utf32he (str,
    1057                 :            :                                       size,
    1058                 :            :                                       &temp_data,
    1059                 :            :                                       &temp_size,
    1060                 :            :                                       error);
    1061                 :        948 :       break;
    1062                 :            :     case PDF_TEXT_UTF16_LE: /* UTF-16LE */
    1063                 :         80 :       ret = pdf_text_utf16le_to_utf32he (str,
    1064                 :            :                                          size,
    1065                 :            :                                          &temp_data,
    1066                 :            :                                          &temp_size,
    1067                 :            :                                          error);
    1068                 :         80 :       break;
    1069                 :            :     case PDF_TEXT_UTF16_BE: /* UTF-16BE */
    1070                 :         50 :       ret = pdf_text_utf16be_to_utf32he (str,
    1071                 :            :                                          size,
    1072                 :            :                                          &temp_data,
    1073                 :            :                                          &temp_size,
    1074                 :            :                                          NULL,
    1075                 :            :                                          NULL,
    1076                 :            :                                          error);
    1077                 :         50 :       break;
    1078                 :            :     case PDF_TEXT_UTF32_LE: /* UTF-32LE */
    1079                 :         80 :       ret = pdf_text_utf32le_to_utf32he (str,
    1080                 :            :                                          size,
    1081                 :            :                                          &temp_data,
    1082                 :            :                                          &temp_size,
    1083                 :            :                                          error);
    1084                 :         80 :       break;
    1085                 :            :     case PDF_TEXT_UTF32_BE: /* UTF-32BE */
    1086                 :        386 :       ret = pdf_text_utf32be_to_utf32he (str,
    1087                 :            :                                          size,
    1088                 :            :                                          &temp_data,
    1089                 :            :                                          &temp_size,
    1090                 :            :                                          error);
    1091                 :        386 :       break;
    1092                 :            :     default:
    1093                 :          0 :       ret = PDF_TRUE;
    1094                 :            :     }
    1095                 :            : 
    1096         [ +  + ]:       1544 :   if (!ret)
    1097                 :        160 :     return PDF_FALSE;
    1098                 :            : 
    1099                 :            :   /* Destroy previous contents of text variable, if any */
    1100         [ -  + ]:       1384 :   if (!pdf_text_clean_contents (text, error))
    1101                 :            :     {
    1102                 :          0 :       pdf_dealloc (temp_data);
    1103                 :          0 :       return PDF_FALSE;
    1104                 :            :     }
    1105                 :            : 
    1106                 :            :   /* Really set contents */
    1107                 :       1384 :   text->data = temp_data;
    1108                 :       1384 :   text->size = temp_size;
    1109                 :       1544 :   return PDF_TRUE;
    1110                 :            : }
    1111                 :            : 
    1112                 :            : /* Concatenate the two text variables, only if country/lang info is equal */
    1113                 :            : pdf_bool_t
    1114                 :         16 : pdf_text_concat (pdf_text_t        *text1,
    1115                 :            :                  const pdf_text_t  *text2,
    1116                 :            :                  pdf_bool_t         override_langinfo,
    1117                 :            :                  pdf_error_t      **error)
    1118                 :            : {
    1119                 :            :   pdf_char_t *tmp;
    1120                 :            : 
    1121         [ -  + ]:         16 :   PDF_ASSERT_POINTER_RETURN_VAL (text1, PDF_FALSE);
    1122         [ -  + ]:         16 :   PDF_ASSERT_POINTER_RETURN_VAL (text2, PDF_FALSE);
    1123                 :            : 
    1124         [ +  + ]:         16 :   if (!override_langinfo)
    1125                 :            :     {
    1126                 :            :       /* An error will be returned if lang code is different */
    1127         [ +  + ]:          6 :       if (strcmp (text1->lang, text2->lang) != 0)
    1128                 :            :         {
    1129                 :          2 :           pdf_set_error (error,
    1130                 :            :                          PDF_EDOMAIN_BASE_TEXT,
    1131                 :            :                          PDF_ETEXTENC,
    1132                 :            :                          "cannot concatenate two text objects: "
    1133                 :            :                          "different language codes ('%s' and '%s')",
    1134                 :            :                          text1->lang,
    1135                 :            :                          text2->lang);
    1136                 :          2 :           return PDF_FALSE;
    1137                 :            :         }
    1138                 :            : 
    1139                 :            :       /* An error will be returned if country code is different */
    1140         [ -  + ]:          4 :       if (strcmp (text1->country, text2->country) != 0)
    1141                 :            :         {
    1142                 :          0 :           pdf_set_error (error,
    1143                 :            :                          PDF_EDOMAIN_BASE_TEXT,
    1144                 :            :                          PDF_ETEXTENC,
    1145                 :            :                          "cannot concatenate two text objects: "
    1146                 :            :                          "different country codes ('%s' and '%s')",
    1147                 :            :                          text1->country,
    1148                 :            :                          text2->country);
    1149                 :          0 :           return PDF_FALSE;
    1150                 :            :         }
    1151                 :            :     }
    1152                 :            : 
    1153                 :            :   /* Ok, so language/country info is equal or non-existent, start
    1154                 :            :    *  concatenation */
    1155                 :            : 
    1156         [ +  + ]:         14 :   if (text2->size == 0)
    1157                 :          5 :     return PDF_TRUE;
    1158                 :            : 
    1159                 :            :   /* Re-allocate memory in first text element */
    1160                 :          9 :   tmp = (pdf_char_t *) pdf_realloc (text1->data,
    1161                 :            :                                     text1->size + text2->size);
    1162         [ -  + ]:          9 :   if (!tmp)
    1163                 :            :     {
    1164                 :          0 :       pdf_set_error (error,
    1165                 :            :                      PDF_EDOMAIN_BASE_TEXT,
    1166                 :            :                      PDF_ENOMEM,
    1167                 :            :                      "cannot concatenate two text objects: "
    1168                 :            :                      "couldn't reallocate %lu bytes",
    1169                 :            :                      (unsigned long)(text1->size + text2->size));
    1170                 :          0 :       return PDF_FALSE;
    1171                 :            :     }
    1172                 :            : 
    1173                 :          9 :   text1->data = tmp;
    1174                 :            : 
    1175                 :            :   /* Copy contents of second element after the first one */
    1176                 :          9 :   memcpy (&(text1->data[text1->size]), text2->data, text2->size);
    1177                 :            : 
    1178                 :            :   /* Update size of first element */
    1179                 :          9 :   text1->size += text2->size;
    1180                 :            : 
    1181                 :          9 :   text1->modified = PDF_TRUE;
    1182                 :            : 
    1183                 :         16 :   return PDF_TRUE;
    1184                 :            : }
    1185                 :            : 
    1186                 :            : /* Concatenate a text variable with an ascii string */
    1187                 :            : pdf_bool_t
    1188                 :          4 : pdf_text_concat_ascii (pdf_text_t        *text1,
    1189                 :            :                        const pdf_char_t  *ascii_str,
    1190                 :            :                        pdf_error_t      **error)
    1191                 :            : {
    1192                 :            :   pdf_size_t len;
    1193                 :            :   pdf_char_t *tmp;
    1194                 :            :   pdf_char_t *tmp_data;
    1195                 :            :   pdf_size_t tmp_size;
    1196                 :            : 
    1197         [ -  + ]:          4 :   PDF_ASSERT_POINTER_RETURN_VAL (text1, PDF_FALSE);
    1198         [ -  + ]:          4 :   PDF_ASSERT_POINTER_RETURN_VAL (ascii_str, PDF_FALSE);
    1199                 :            : 
    1200                 :          4 :   len = (pdf_size_t) strlen (ascii_str);
    1201                 :            : 
    1202         [ +  + ]:          4 :   if (len == 0)
    1203                 :          2 :     return PDF_TRUE;
    1204                 :            : 
    1205                 :            :   /* Check if input string is ascii */
    1206         [ -  + ]:          2 :   if (!pdf_text_is_ascii7 (ascii_str, len))
    1207                 :            :     {
    1208                 :          0 :       pdf_set_error (error,
    1209                 :            :                      PDF_EDOMAIN_BASE_TEXT,
    1210                 :            :                      PDF_ETEXTENC,
    1211                 :            :                      "cannot concatenate ASCII string: "
    1212                 :            :                      "not an ASCII input string");
    1213                 :          0 :       return PDF_FALSE;
    1214                 :            :     }
    1215                 :            : 
    1216                 :            :   /* ascii string is valid utf8 */
    1217         [ -  + ]:          2 :   if (!pdf_text_utf8_to_utf32he (ascii_str,
    1218                 :            :                                  len,
    1219                 :            :                                  &tmp_data,
    1220                 :            :                                  &tmp_size,
    1221                 :            :                                  error))
    1222                 :          0 :     return PDF_FALSE;
    1223                 :            : 
    1224                 :          2 :   tmp = (pdf_char_t *) pdf_realloc (text1->data, text1->size + tmp_size);
    1225         [ -  + ]:          2 :   if (!tmp)
    1226                 :            :     {
    1227                 :          0 :       pdf_set_error (error,
    1228                 :            :                      PDF_EDOMAIN_BASE_TEXT,
    1229                 :            :                      PDF_ENOMEM,
    1230                 :            :                      "cannot concatenate ASCII string: "
    1231                 :            :                      "couldn't reallocate %lu bytes",
    1232                 :            :                      (unsigned long)(text1->size + tmp_size));
    1233                 :          0 :       return PDF_FALSE;
    1234                 :            :     }
    1235                 :            : 
    1236                 :          2 :   text1->data = tmp;
    1237                 :          2 :   memcpy (&(text1->data[text1->size]), tmp_data, tmp_size);
    1238                 :          2 :   text1->size += tmp_size;
    1239                 :          2 :   pdf_dealloc (tmp_data);
    1240                 :            : 
    1241                 :          4 :   return PDF_TRUE;
    1242                 :            : }
    1243                 :            : 
    1244                 :            : /* Default initial size of the list of replacements */
    1245                 :            : #define PDF_TEXT_ISLR 32
    1246                 :            : 
    1247                 :            : /* Replace a given pattern in a text object */
    1248                 :            : pdf_bool_t
    1249                 :         20 : pdf_text_replace (pdf_text_t        *text,
    1250                 :            :                   const pdf_text_t  *new_pattern,
    1251                 :            :                   const pdf_text_t  *old_pattern,
    1252                 :            :                   pdf_error_t      **error)
    1253                 :            : {
    1254         [ -  + ]:         20 :   PDF_ASSERT_POINTER_RETURN_VAL (text, PDF_FALSE);
    1255         [ -  + ]:         20 :   PDF_ASSERT_POINTER_RETURN_VAL (new_pattern, PDF_FALSE);
    1256         [ -  + ]:         20 :   PDF_ASSERT_POINTER_RETURN_VAL (old_pattern, PDF_FALSE);
    1257                 :            : 
    1258                 :         20 :   return pdf_text_replace_multiple (text,
    1259                 :            :                                     new_pattern,
    1260                 :            :                                     &old_pattern,
    1261                 :            :                                     1,
    1262                 :            :                                     error);
    1263                 :            : }
    1264                 :            : 
    1265                 :            : /* Check replacement patterns and get minimum size */
    1266                 :            : static pdf_bool_t
    1267                 :            : pdf_text_check_replacement_patterns (const pdf_text_t **p_old_patterns,
    1268                 :            :                                      int                n_old_patterns,
    1269                 :            :                                      pdf_size_t        *p_min_old_pattern_size,
    1270                 :            :                                      pdf_error_t      **error)
    1271                 :            : {
    1272                 :         24 :   pdf_size_t minimum_old_pattern_size = -1;
    1273                 :            :   int i_pattern;
    1274                 :            : 
    1275         [ +  + ]:         60 :   for (i_pattern = 0; i_pattern < n_old_patterns; ++i_pattern)
    1276                 :            :     {
    1277                 :            :       /* Get minimum old pattern size */
    1278 [ +  + ][ +  + ]:         36 :       if ((i_pattern == 0) ||
    1279                 :         12 :           ((p_old_patterns[i_pattern])->size < minimum_old_pattern_size))
    1280                 :            :         {
    1281                 :         28 :           minimum_old_pattern_size = (p_old_patterns[i_pattern])->size;
    1282                 :            :         }
    1283                 :            :       /* Empty old pattern is not allowed */
    1284         [ -  + ]:         36 :       if (pdf_text_empty_p (p_old_patterns[i_pattern]))
    1285                 :            :         {
    1286                 :          0 :           pdf_set_error (error,
    1287                 :            :                          PDF_EDOMAIN_BASE_TEXT,
    1288                 :            :                          PDF_ETEXTENC,
    1289                 :            :                          "cannot check replacement patterns: "
    1290                 :            :                          "input empty pattern found");
    1291                 :          0 :           return PDF_FALSE;
    1292                 :            :         }
    1293                 :            :     }
    1294                 :            : 
    1295                 :            :   /* Set output var and exit correctly */
    1296                 :         24 :   *p_min_old_pattern_size = minimum_old_pattern_size;
    1297                 :         24 :   return PDF_TRUE;
    1298                 :            : }
    1299                 :            : 
    1300                 :            : static pdf_bool_t
    1301                 :         20 : pdf_text_get_replacement_pointers (pdf_text_repl_t  **p_rep_ptrs,
    1302                 :            :                                    long              *p_n_replacements,
    1303                 :            :                                    pdf_size_t        *p_new_size,
    1304                 :            :                                    const pdf_text_t  *text,
    1305                 :            :                                    pdf_size_t         minimum_old_pattern_size,
    1306                 :            :                                    const pdf_text_t  *new_pattern,
    1307                 :            :                                    const pdf_text_t **p_old_patterns,
    1308                 :            :                                    int                n_old_patterns,
    1309                 :            :                                    pdf_error_t      **error)
    1310                 :            : {
    1311                 :            :   pdf_size_t new_size;
    1312                 :            :   int i_pattern;
    1313                 :            :   long i;
    1314                 :            :   long n_replacements;
    1315                 :         20 :   pdf_text_repl_t *rep_ptrs = NULL;
    1316                 :         20 :   long rep_ptrs_size = PDF_TEXT_ISLR/2;
    1317                 :            : 
    1318                 :         20 :   n_replacements = 0;
    1319                 :         20 :   i = 0;
    1320                 :         20 :   new_size = 0;
    1321         [ +  + ]:        633 :   while (i <= (text->size - minimum_old_pattern_size))
    1322                 :            :     {
    1323                 :            :       /* If old pattern found... */
    1324                 :        613 :       int old_pattern_found = 0;
    1325                 :            : 
    1326                 :        613 :       i_pattern = 0;
    1327         [ +  + ]:       1604 :       while ((!old_pattern_found) &&
    1328                 :       1604 :              (i_pattern < n_old_patterns))
    1329                 :            :         {
    1330 [ +  + ][ +  + ]:       1025 :           if (((text->size - i) >= ((p_old_patterns[i_pattern])->size)) &&
    1331                 :       1848 :               (memcmp (&(text->data[i]),
    1332                 :        924 :                        (p_old_patterns[i_pattern])->data,
    1333                 :        924 :                        (p_old_patterns[i_pattern])->size) == 0))
    1334                 :            :             {
    1335                 :         34 :               old_pattern_found = 1;
    1336                 :            :               /* Duplicate size of replacement pointers list, if needed */
    1337         [ +  + ]:         34 :               if ((!rep_ptrs) ||
    1338                 :         34 :                   (rep_ptrs_size == n_replacements))
    1339                 :            :                 {
    1340                 :         12 :                   rep_ptrs = (pdf_text_repl_t *) pdf_realloc (rep_ptrs,
    1341                 :            :                                                               (2 * rep_ptrs_size *
    1342                 :            :                                                                sizeof (pdf_text_repl_t)));
    1343         [ -  + ]:         12 :                   if (!rep_ptrs)
    1344                 :            :                     {
    1345                 :          0 :                       pdf_set_error (error,
    1346                 :            :                                      PDF_EDOMAIN_BASE_TEXT,
    1347                 :            :                                      PDF_ENOMEM,
    1348                 :            :                                      "cannot get replacement pointers: "
    1349                 :            :                                      "couldn't reallocate %lu bytes",
    1350                 :            :                                      (unsigned long)(2 * rep_ptrs_size *
    1351                 :            :                                                      sizeof (pdf_text_repl_t)));
    1352                 :          0 :                       return PDF_FALSE;
    1353                 :            :                     }
    1354                 :            :                 }
    1355                 :            : 
    1356                 :            :               /* Store pointer to old pattern */
    1357                 :         34 :               rep_ptrs[n_replacements].data_ptr = &(text->data[i]);
    1358                 :         34 :               rep_ptrs[n_replacements].old_pattern_i = i_pattern;
    1359                 :         34 :               n_replacements++;
    1360                 :            : 
    1361                 :            :               /* The index must be updated to skip the replacement */
    1362                 :         34 :               i += (p_old_patterns[i_pattern])->size;
    1363                 :            : 
    1364                 :            :               /* Update new size */
    1365                 :         34 :               new_size += new_pattern->size;
    1366                 :            :             }
    1367                 :            :           else
    1368                 :            :             {
    1369                 :        957 :               i_pattern++;
    1370                 :            :             }
    1371                 :            :         }
    1372                 :            : 
    1373         [ +  + ]:        613 :       if(!old_pattern_found)
    1374                 :            :         {
    1375                 :        579 :           i += 4;
    1376                 :        579 :           new_size += 4;
    1377                 :            :         }
    1378                 :            :     }
    1379                 :            : 
    1380                 :            :   /* Udpate new size with remaining data in old array */
    1381                 :         20 :   new_size += (text->size - i);
    1382                 :            : 
    1383                 :            :   /* Set output data and exit correctly */
    1384                 :         20 :   *p_new_size = new_size;
    1385                 :         20 :   *p_rep_ptrs = rep_ptrs;
    1386                 :         20 :   *p_n_replacements = n_replacements;
    1387                 :            : 
    1388                 :         20 :   return PDF_TRUE;
    1389                 :            : }
    1390                 :            : 
    1391                 :            : static pdf_bool_t
    1392                 :         12 : pdf_text_perform_replacements (pdf_text_t             *text,
    1393                 :            :                                pdf_size_t              new_size,
    1394                 :            :                                const pdf_text_t       *new_pattern,
    1395                 :            :                                const pdf_text_t      **p_old_patterns,
    1396                 :            :                                int                     n_old_patterns,
    1397                 :            :                                const pdf_text_repl_t  *rep_ptrs,
    1398                 :            :                                long                    n_replacements,
    1399                 :            :                                pdf_error_t           **error)
    1400                 :            : {
    1401                 :            :   int k;
    1402                 :            :   pdf_char_t *new_data;
    1403                 :            :   pdf_char_t *new_walker;
    1404                 :            :   pdf_char_t *old_walker;
    1405                 :            : 
    1406                 :            :   /* Allocate new memory chunk */
    1407                 :         12 :   new_data = (pdf_char_t *) pdf_alloc (new_size);
    1408         [ -  + ]:         12 :   if (!new_data)
    1409                 :            :     {
    1410                 :          0 :       pdf_set_error (error,
    1411                 :            :                      PDF_EDOMAIN_BASE_TEXT,
    1412                 :            :                      PDF_ENOMEM,
    1413                 :            :                      "cannot perform replacements: "
    1414                 :            :                      "couldn't reallocate %lu bytes",
    1415                 :            :                      (unsigned long)(new_size));
    1416                 :          0 :       return PDF_FALSE;
    1417                 :            :     }
    1418                 :            : 
    1419                 :            :   /* Walk the list of replacements */
    1420                 :         12 :   new_walker = new_data;
    1421                 :         12 :   old_walker = text->data;
    1422         [ +  + ]:         46 :   for (k = 0; k < n_replacements; ++k)
    1423                 :            :     {
    1424                 :            :       pdf_size_t prev_size;
    1425                 :            : 
    1426                 :            :       /* Store the data previous to the pointer */
    1427                 :         34 :       prev_size = (rep_ptrs[k].data_ptr - old_walker);
    1428         [ +  + ]:         34 :       if (prev_size > 0)
    1429                 :            :         {
    1430                 :         26 :           memcpy (new_walker, old_walker, prev_size);
    1431                 :         26 :           new_walker += prev_size;
    1432                 :         26 :           old_walker += prev_size;
    1433                 :            :         }
    1434                 :            :       /* Perform the replacement */
    1435                 :         34 :       memcpy (new_walker, new_pattern->data, new_pattern->size);
    1436                 :         34 :       new_walker += (new_pattern->size);
    1437                 :         34 :       old_walker += (p_old_patterns[rep_ptrs[k].old_pattern_i]->size);
    1438                 :            :     }
    1439                 :            : 
    1440                 :            :   /* Add final data */
    1441         [ +  + ]:         12 :   if (((&(text->data[text->size])) - old_walker) > 0)
    1442                 :            :     {
    1443                 :          2 :       memcpy (new_walker,
    1444                 :            :               old_walker,
    1445                 :          2 :              ((&(text->data[text->size])) - old_walker));
    1446                 :            :     }
    1447                 :            : 
    1448                 :            :   /* Set correct final size and final content */
    1449                 :         12 :   pdf_dealloc (text->data);
    1450                 :         12 :   text->data = new_data;
    1451                 :         12 :   text->size = new_size;
    1452                 :            : 
    1453                 :         12 :   return PDF_TRUE;
    1454                 :            : }
    1455                 :            : 
    1456                 :            : pdf_bool_t
    1457                 :         24 : pdf_text_replace_multiple (pdf_text_t        *text,
    1458                 :            :                            const pdf_text_t  *new_pattern,
    1459                 :            :                            const pdf_text_t **p_old_patterns,
    1460                 :            :                            int                n_old_patterns,
    1461                 :            :                            pdf_error_t      **error)
    1462                 :            : {
    1463                 :            :   pdf_size_t new_size;
    1464                 :            :   pdf_size_t minimum_old_pattern_size;
    1465                 :            :   long n_replacements;
    1466                 :         24 :   pdf_text_repl_t *rep_ptrs = NULL;
    1467                 :            : 
    1468         [ -  + ]:         24 :   PDF_ASSERT_POINTER_RETURN_VAL (text, PDF_FALSE);
    1469         [ -  + ]:         24 :   PDF_ASSERT_POINTER_RETURN_VAL (new_pattern, PDF_FALSE);
    1470         [ -  + ]:         24 :   PDF_ASSERT_POINTER_RETURN_VAL (p_old_patterns, PDF_FALSE);
    1471         [ -  + ]:         24 :   PDF_ASSERT_RETURN_VAL (n_old_patterns > 0, PDF_FALSE);
    1472                 :            : 
    1473         [ -  + ]:         24 :   if (!pdf_text_check_replacement_patterns (p_old_patterns,
    1474                 :            :                                             n_old_patterns,
    1475                 :            :                                             &minimum_old_pattern_size,
    1476                 :            :                                             error))
    1477                 :            :     {
    1478                 :          0 :       pdf_prefix_error (error, "cannot replace text pattern: ");
    1479                 :          0 :       return PDF_FALSE;
    1480                 :            :     }
    1481                 :            : 
    1482                 :            :   /* If input text is shorter than the smallest old pattern, there is no
    1483                 :            :    *  replacement to be done */
    1484         [ +  + ]:         24 :   if (minimum_old_pattern_size > text->size)
    1485                 :          4 :     return PDF_TRUE;
    1486                 :            : 
    1487                 :            :   /* First, count number of replacements to be done... a replacement pointer
    1488                 :            :    * will be stored for each replacement needed */
    1489                 :         20 :   new_size = 0;
    1490                 :         20 :   minimum_old_pattern_size = -1;
    1491         [ -  + ]:         20 :   if (!pdf_text_get_replacement_pointers (&rep_ptrs,
    1492                 :            :                                           &n_replacements,
    1493                 :            :                                           &new_size,
    1494                 :            :                                           text,
    1495                 :            :                                           minimum_old_pattern_size,
    1496                 :            :                                           new_pattern,
    1497                 :            :                                           p_old_patterns,
    1498                 :            :                                           n_old_patterns,
    1499                 :            :                                           error))
    1500                 :            :     {
    1501                 :          0 :       pdf_prefix_error (error, "cannot replace text pattern: ");
    1502                 :          0 :       return PDF_FALSE;
    1503                 :            :     }
    1504                 :            : 
    1505                 :            :   /* Now, really perform replacements, if required */
    1506         [ +  + ]:         20 :   if (n_replacements > 0)
    1507                 :            :     {
    1508         [ -  + ]:         12 :       if (!pdf_text_perform_replacements (text,
    1509                 :            :                                           new_size,
    1510                 :            :                                           new_pattern,
    1511                 :            :                                           p_old_patterns,
    1512                 :            :                                           n_old_patterns,
    1513                 :            :                                           rep_ptrs,
    1514                 :            :                                           n_replacements,
    1515                 :            :                                           error))
    1516                 :            :         {
    1517                 :          0 :           pdf_prefix_error (error, "cannot replace text pattern: ");
    1518                 :          0 :           return PDF_FALSE;
    1519                 :            :         }
    1520                 :            : 
    1521                 :            :       /* Dealloc list of pointers to replacements */
    1522         [ +  - ]:         12 :       if (rep_ptrs)
    1523                 :         12 :         pdf_dealloc (rep_ptrs);
    1524                 :            : 
    1525                 :         12 :       text->modified = PDF_TRUE;
    1526                 :            :     }
    1527                 :            : 
    1528                 :         24 :   return PDF_TRUE;
    1529                 :            : }
    1530                 :            : 
    1531                 :            : /* Replace a given ASCII-7 pattern in a text object */
    1532                 :            : pdf_bool_t
    1533                 :         12 : pdf_text_replace_ascii (pdf_text_t        *text,
    1534                 :            :                         const pdf_char_t  *new_pattern,
    1535                 :            :                         const pdf_char_t  *old_pattern,
    1536                 :            :                         pdf_error_t      **error)
    1537                 :            : {
    1538                 :            :   pdf_text_t *new_pattern_text;
    1539                 :            :   pdf_text_t *old_pattern_text;
    1540                 :            :   pdf_bool_t ret_code;
    1541                 :            : 
    1542         [ -  + ]:         12 :   PDF_ASSERT_POINTER_RETURN_VAL (text, PDF_FALSE);
    1543         [ -  + ]:         12 :   PDF_ASSERT_POINTER_RETURN_VAL (new_pattern, PDF_FALSE);
    1544         [ -  + ]:         12 :   PDF_ASSERT_POINTER_RETURN_VAL (old_pattern, PDF_FALSE);
    1545                 :            : 
    1546                 :            :   /* Check if patterns are real ASCII-7 valid strings */
    1547 [ +  - ][ -  + ]:         12 :   if ((!pdf_text_is_ascii7 (old_pattern,
    1548                 :            :                             (pdf_size_t) strlen (old_pattern))) ||
    1549                 :            :      (!pdf_text_is_ascii7 (new_pattern,
    1550                 :            :                            (pdf_size_t) strlen (new_pattern))))
    1551                 :            :     {
    1552                 :          0 :       pdf_set_error (error,
    1553                 :            :                      PDF_EDOMAIN_BASE_TEXT,
    1554                 :            :                      PDF_ETEXTENC,
    1555                 :            :                      "cannot replace ASCII pattern: "
    1556                 :            :                      "at least one of the requested patterns is not ASCII-7");
    1557                 :          0 :       return PDF_FALSE;
    1558                 :            :     }
    1559                 :            : 
    1560                 :            :   /* Ok, so load ASCII strings as if it were UTF-8 strings */
    1561                 :            : 
    1562                 :            :   /* Create intermediate pdf_text_t variables */
    1563                 :         12 :   new_pattern_text = pdf_text_new_from_unicode (new_pattern,
    1564                 :            :                                                 (pdf_size_t) strlen (new_pattern),
    1565                 :            :                                                 PDF_TEXT_UTF8,
    1566                 :            :                                                 error);
    1567         [ -  + ]:         12 :   if (!new_pattern_text)
    1568                 :            :     {
    1569                 :          0 :       pdf_prefix_error (error, "cannot replace ASCII pattern: ");
    1570                 :          0 :       return PDF_FALSE;
    1571                 :            :     }
    1572                 :            : 
    1573                 :         12 :   old_pattern_text = pdf_text_new_from_unicode (old_pattern,
    1574                 :            :                                                 (pdf_size_t) strlen (old_pattern),
    1575                 :            :                                                 PDF_TEXT_UTF8,
    1576                 :            :                                                 error);
    1577         [ -  + ]:         12 :   if (!old_pattern_text)
    1578                 :            :     {
    1579                 :          0 :       pdf_prefix_error (error, "cannot replace ASCII pattern: ");
    1580                 :          0 :       pdf_text_destroy (new_pattern_text);
    1581                 :          0 :       return PDF_FALSE;
    1582                 :            :     }
    1583                 :            : 
    1584                 :            :   /* Perform replacement */
    1585                 :         12 :   ret_code = pdf_text_replace (text,
    1586                 :            :                                new_pattern_text,
    1587                 :            :                                old_pattern_text,
    1588                 :            :                                error);
    1589         [ -  + ]:         12 :   if (!ret_code)
    1590                 :            :     {
    1591                 :          0 :       pdf_prefix_error (error, "cannot replace ASCII pattern: ");
    1592                 :            :     }
    1593                 :            : 
    1594                 :            :   /* Destroy used intermediate variables */
    1595                 :         12 :   pdf_text_destroy (new_pattern_text);
    1596                 :         12 :   pdf_text_destroy (old_pattern_text);
    1597                 :            : 
    1598                 :         12 :   return ret_code;
    1599                 :            : }
    1600                 :            : 
    1601                 :            : pdf_bool_t
    1602                 :         69 : pdf_text_filter (pdf_text_t   *text,
    1603                 :            :                  pdf_u32_t     filter,
    1604                 :            :                  pdf_error_t **error)
    1605                 :            : {
    1606         [ -  + ]:         69 :   PDF_ASSERT_POINTER_RETURN_VAL (text, PDF_FALSE);
    1607                 :            : 
    1608                 :            :   /* More than one filter at the same time can be requested! But Caution!
    1609                 :            :    *  UpperCase filter, LowerCase filter and TitleCase filter are mutually
    1610                 :            :    *  exclusive (at most only one of them must be enabled) */
    1611                 :            : 
    1612         [ -  + ]:         69 :   if ((((filter & PDF_TEXT_FILTER_UPPER_CASE) ? 1 : 0) +
    1613                 :         69 :        ((filter & PDF_TEXT_FILTER_LOWER_CASE) ? 1 : 0) +
    1614                 :         69 :        ((filter & PDF_TEXT_FILTER_TITLE_CASE) ? 1 : 0)) > 1)
    1615                 :            :     {
    1616                 :          0 :       pdf_set_error (error,
    1617                 :            :                      PDF_EDOMAIN_BASE_TEXT,
    1618                 :            :                      PDF_ETEXTENC,
    1619                 :            :                      "cannot apply filters to text: "
    1620                 :            :                      "at most only one case conversion filter can be applied");
    1621                 :          0 :       return PDF_FALSE;
    1622                 :            :     }
    1623                 :            : 
    1624                 :            :   /* 0x00000001 */
    1625 [ +  + ][ -  + ]:         69 :   if ((filter & PDF_TEXT_FILTER_LINE_ENDINGS) &&
    1626                 :            :       (!pdf_text_filter_normalize_line_endings (text, error)))
    1627                 :            :     {
    1628                 :          0 :       pdf_prefix_error (error, "cannot apply filters to text: ");
    1629                 :          0 :       return PDF_FALSE;
    1630                 :            :     }
    1631                 :            : 
    1632                 :            :   /* 0x00000010 */
    1633 [ +  + ][ -  + ]:         69 :   if ((filter & PDF_TEXT_FILTER_UPPER_CASE) &&
    1634                 :            :       (!pdf_text_filter_upper_case (text, error)))
    1635                 :            :     {
    1636                 :          0 :       pdf_prefix_error (error, "cannot apply filters to text: ");
    1637                 :          0 :       return PDF_FALSE;
    1638                 :            :     }
    1639                 :            :   /* 0x00000100 */
    1640 [ +  + ][ -  + ]:         69 :   else if ((filter & PDF_TEXT_FILTER_LOWER_CASE) &&
    1641                 :            :            (!pdf_text_filter_lower_case (text, error)))
    1642                 :            :     {
    1643                 :          0 :       pdf_prefix_error (error, "cannot apply filters to text: ");
    1644                 :          0 :       return PDF_FALSE;
    1645                 :            :     }
    1646                 :            :   /* 0x00001000 */
    1647 [ +  + ][ -  + ]:         69 :   else if ((filter & PDF_TEXT_FILTER_TITLE_CASE) &&
    1648                 :            :            (!pdf_text_filter_title_case (text, error)))
    1649                 :            :     {
    1650                 :          0 :       pdf_prefix_error (error, "cannot apply filters to text: ");
    1651                 :          0 :       return PDF_FALSE;
    1652                 :            :     }
    1653                 :            : 
    1654                 :            :   /* 0x00010000 */
    1655 [ +  + ][ -  + ]:         69 :   if ((filter & PDF_TEXT_FILTER_REMOVE_AMP) &&
    1656                 :            :       (!pdf_text_filter_remove_amp (text, error)))
    1657                 :            :     {
    1658                 :          0 :       pdf_prefix_error (error, "cannot apply filters to text: ");
    1659                 :          0 :       return PDF_FALSE;
    1660                 :            :     }
    1661                 :            : 
    1662                 :            :   /* 0x00100000 */
    1663 [ +  + ][ -  + ]:         69 :   if ((filter & PDF_TEXT_FILTER_NORM_WITH_FULL_WIDTH) &&
    1664                 :            :       (!pdf_text_filter_normalize_full_width_ascii (text, error)))
    1665                 :            :     {
    1666                 :          0 :       pdf_prefix_error (error, "cannot apply filters to text: ");
    1667                 :          0 :       return PDF_FALSE;
    1668                 :            :     }
    1669                 :            : 
    1670                 :            :   /* 0x01000000 */
    1671 [ +  + ][ -  + ]:         69 :   if ((filter & PDF_TEXT_FILTER_REMOVE_LINE_ENDINGS) &&
    1672                 :            :       (!pdf_text_filter_remove_line_endings (text, error)))
    1673                 :            :     {
    1674                 :          0 :       pdf_prefix_error (error, "cannot apply filters to text: ");
    1675                 :          0 :       return PDF_FALSE;
    1676                 :            :     }
    1677                 :            : 
    1678                 :         69 :   text->modified = PDF_TRUE;
    1679                 :         69 :   return PDF_TRUE;
    1680                 :            : }
    1681                 :            : 
    1682                 :            : const pdf_char_t *
    1683                 :          0 : pdf_text_get_printable (pdf_text_t *text)
    1684                 :            : {
    1685                 :            :   pdf_size_t size;
    1686                 :            : 
    1687         [ #  # ]:          0 :   PDF_ASSERT_POINTER_RETURN_VAL (text, NULL);
    1688                 :            : 
    1689         [ #  # ]:          0 :   if (text->printable != NULL)
    1690                 :            :     {
    1691         [ #  # ]:          0 :       if (!text->modified)
    1692                 :          0 :         return text->printable;
    1693                 :          0 :       pdf_dealloc (text->printable);
    1694                 :            :     }
    1695                 :            : 
    1696                 :            : #ifdef PDF_HOST_WIN32
    1697                 :            :   text->printable = pdf_text_get_unicode (text,
    1698                 :            :                                           PDF_TEXT_UTF16_LE,
    1699                 :            :                                           PDF_TEXT_UNICODE_WITH_NUL_SUFFIX,
    1700                 :            :                                           &size,
    1701                 :            :                                           NULL);
    1702                 :            :     return NULL;
    1703                 :            : #else
    1704                 :          0 :   text->printable = pdf_text_get_unicode (text,
    1705                 :            :                                           PDF_TEXT_UTF8,
    1706                 :            :                                           PDF_TEXT_UNICODE_WITH_NUL_SUFFIX,
    1707                 :            :                                           &size,
    1708                 :            :                                           NULL);
    1709                 :            : #endif /*PDF_HOST_WIN32*/
    1710                 :            : 
    1711         [ #  # ]:          0 :   if (text->printable)
    1712                 :          0 :     text->modified = PDF_FALSE;
    1713                 :            : 
    1714                 :          0 :   return text->printable;
    1715                 :            : }
    1716                 :            : 
    1717                 :            : pdf_i32_t
    1718                 :          9 : pdf_text_cmp (const pdf_text_t *text1,
    1719                 :            :               const pdf_text_t *text2,
    1720                 :            :               pdf_bool_t        case_sensitive,
    1721                 :            :               pdf_error_t      **error)
    1722                 :            : {
    1723                 :          9 :   pdf_error_t *inner_error = NULL;
    1724                 :            :   pdf_i32_t ret;
    1725                 :            : 
    1726         [ -  + ]:          9 :   PDF_ASSERT_POINTER_RETURN_VAL (text1, -1);
    1727         [ -  + ]:          9 :   PDF_ASSERT_POINTER_RETURN_VAL (text2, -1);
    1728                 :            : 
    1729                 :            :   /* Compare sizes of the texts */
    1730         [ +  + ]:          9 :   if (text1->size != text2->size)
    1731         [ +  - ]:          2 :     return ((text1->size > text2->size) ? 1 : -1);
    1732                 :            : 
    1733         [ +  + ]:          7 :   if (case_sensitive)
    1734                 :          5 :     return memcmp (text1->data, text2->data, text1->size);
    1735                 :            : 
    1736                 :          2 :   ret = pdf_text_cmp_non_case_sensitive (text1, text2, &inner_error);
    1737         [ -  + ]:          2 :   if (inner_error)
    1738                 :            :     {
    1739                 :          0 :       pdf_propagate_error (error, inner_error);
    1740                 :          0 :       pdf_prefix_error (error, "cannot compare text objects: ");
    1741                 :            :     }
    1742                 :          9 :   return ret;
    1743                 :            : }
    1744                 :            : 
    1745                 :            : /* -------------------------- Private functions ----------------------------- */
    1746                 :            : 
    1747                 :            : static pdf_i32_t
    1748                 :          2 : pdf_text_cmp_non_case_sensitive (const pdf_text_t  *text1,
    1749                 :            :                                  const pdf_text_t  *text2,
    1750                 :            :                                  pdf_error_t      **error)
    1751                 :            : {
    1752                 :            :   pdf_list_iterator_t it1;
    1753                 :            :   pdf_list_iterator_t it2;
    1754                 :            :   pdf_i32_t cmpret;
    1755                 :            : 
    1756                 :            :   /* Generate word boundaries list, if not already done */
    1757 [ +  - ][ -  + ]:          2 :   if ((!pdf_text_fill_word_boundaries_list (text1->word_boundaries,
    1758                 :          2 :                                             text1->data,
    1759                 :            :                                             text1->size,
    1760                 :            :                                             error)) ||
    1761                 :            :       (!pdf_text_fill_word_boundaries_list (text2->word_boundaries,
    1762                 :          2 :                                             text2->data,
    1763                 :            :                                             text2->size,
    1764                 :            :                                             error)))
    1765                 :            :     {
    1766                 :          0 :       pdf_prefix_error (error,
    1767                 :            :                         "cannot compare text non-case-sensitive: ");
    1768                 :          0 :       return -1; /* An error happened computing word boundaries! */
    1769                 :            :     }
    1770                 :            : 
    1771                 :            :   /* Perform a word-per-word lower case comparison */
    1772                 :          2 :   pdf_list_iterator_init (&it1, text1->word_boundaries);
    1773                 :          2 :   pdf_list_iterator_init (&it2, text2->word_boundaries);
    1774                 :            : 
    1775                 :            :   while (PDF_TRUE)
    1776                 :            :     {
    1777                 :         20 :       const struct pdf_text_wb_s *p_word1 = NULL;
    1778                 :         20 :       const struct pdf_text_wb_s *p_word2 = NULL;
    1779                 :            : 
    1780                 :         20 :       pdf_list_iterator_next (&it1, (const void **)&p_word1, NULL);
    1781                 :         20 :       pdf_list_iterator_next (&it2, (const void **)&p_word2, NULL);
    1782                 :            : 
    1783         [ +  + ]:         20 :       if (p_word1)
    1784                 :            :         {
    1785         [ -  + ]:         18 :           if (!p_word2)
    1786                 :            :             {
    1787                 :          0 :               cmpret = 1;
    1788                 :          0 :               break;
    1789                 :            :             }
    1790                 :            :           else
    1791                 :            :             {
    1792                 :         18 :               pdf_error_t *inner_error = NULL;
    1793                 :            : 
    1794                 :            :               /* We got 2 words to compare */
    1795                 :         18 :               cmpret = pdf_text_compare_words (p_word1->word_start,
    1796                 :         18 :                                                p_word1->word_size,
    1797                 :         18 :                                                p_word2->word_start,
    1798                 :         18 :                                                p_word2->word_size,
    1799                 :            :                                                pdf_text_get_language (text1),
    1800                 :            :                                                pdf_text_get_language (text2),
    1801                 :            :                                                &inner_error);
    1802         [ -  + ]:         18 :               if (inner_error)
    1803                 :            :                 {
    1804                 :          0 :                   pdf_propagate_error (error, inner_error);
    1805                 :          0 :                   pdf_prefix_error (error,
    1806                 :            :                                     "cannot compare text non-case-sensitive: ");
    1807                 :          0 :                   cmpret = -1;
    1808                 :          0 :                   break;
    1809                 :            :                 }
    1810                 :            : 
    1811                 :            :               /* If words are not equal, return the code */
    1812         [ +  - ]:         18 :               if (cmpret != 0)
    1813                 :            :                 break;
    1814                 :            :               /* else, continue looping... */
    1815                 :            :             }
    1816                 :            :         }
    1817                 :            :       else
    1818                 :            :         {
    1819         [ -  + ]:          2 :           cmpret = p_word2 ? -1 : 0;
    1820                 :          2 :           break;
    1821                 :            :         }
    1822                 :            :     }
    1823                 :            : 
    1824                 :          2 :   pdf_list_iterator_deinit (&it1);
    1825                 :          2 :   pdf_list_iterator_deinit (&it2);
    1826                 :            : 
    1827                 :          2 :   return cmpret;
    1828                 :            : }
    1829                 :            : 
    1830                 :            : static pdf_i32_t
    1831                 :         18 : pdf_text_compare_words (const pdf_char_t  *word1,
    1832                 :            :                         const pdf_size_t   size1,
    1833                 :            :                         const pdf_char_t  *word2,
    1834                 :            :                         const pdf_size_t   size2,
    1835                 :            :                         const pdf_char_t  *language1,
    1836                 :            :                         const pdf_char_t  *language2,
    1837                 :            :                         pdf_error_t      **error)
    1838                 :            : {
    1839                 :            :   pdf_char_t *lower1;
    1840                 :            :   pdf_char_t *lower2;
    1841                 :            :   pdf_size_t new_size1;
    1842                 :            :   pdf_size_t new_size2;
    1843                 :            :   pdf_size_t worst_size;
    1844                 :            :   pdf_i32_t ret_val;
    1845                 :            : 
    1846                 :            :   /* Compare sizes of words */
    1847         [ -  + ]:         18 :   if (size1 != size2)
    1848         [ #  # ]:          0 :     return ((size1 > size2) ? 1 : -1);
    1849                 :            : 
    1850                 :            :   /* Compute new worst word length */
    1851                 :         18 :   worst_size = size1 * UCD_SC_MAX_EXPAND;
    1852                 :            : 
    1853                 :            :   /* Allocate memory for lowercases */
    1854                 :         18 :   lower1 = (pdf_char_t *) pdf_alloc (worst_size);
    1855                 :         18 :   lower2 = (pdf_char_t *) pdf_alloc (worst_size);
    1856                 :            : 
    1857         [ -  + ]:         18 :   if ((!lower1) || (!lower2))
    1858                 :            :     {
    1859                 :          0 :       pdf_set_error (error,
    1860                 :            :                      PDF_EDOMAIN_BASE_TEXT,
    1861                 :            :                      PDF_ENOMEM,
    1862                 :            :                      "Couldn't allocate 2 chunks of %lu bytes",
    1863                 :            :                      (unsigned long)worst_size);
    1864                 :          0 :       pdf_dealloc (lower1);
    1865                 :          0 :       pdf_dealloc (lower2);
    1866                 :          0 :       return -1;
    1867                 :            :     }
    1868                 :            : 
    1869                 :            :   /* Lowercase words */
    1870         [ -  + ]:         18 :   if (!pdf_text_ucd_word_change_case (lower1,
    1871                 :            :                                       &new_size1,
    1872                 :            :                                       UNICODE_CASE_INFO_LOWER_CASE,
    1873                 :            :                                       word1,
    1874                 :            :                                       size1,
    1875                 :            :                                       language1,
    1876                 :            :                                       error))
    1877                 :            :     {
    1878                 :          0 :       pdf_dealloc (lower1);
    1879                 :          0 :       pdf_dealloc (lower2);
    1880                 :          0 :       return -1;
    1881                 :            :     }
    1882                 :            : 
    1883         [ -  + ]:         18 :   if (!pdf_text_ucd_word_change_case (lower2,
    1884                 :            :                                       &new_size2,
    1885                 :            :                                       UNICODE_CASE_INFO_LOWER_CASE,
    1886                 :            :                                       word2,
    1887                 :            :                                       size2,
    1888                 :            :                                       language2,
    1889                 :            :                                       error))
    1890                 :            :     {
    1891                 :          0 :       pdf_dealloc (lower1);
    1892                 :          0 :       pdf_dealloc (lower2);
    1893                 :          0 :       return -1;
    1894                 :            :     }
    1895                 :            : 
    1896                 :            :   /* Compare NEW sizes of words */
    1897         [ -  + ]:         18 :   if (new_size1 != new_size2)
    1898                 :            :     {
    1899                 :          0 :       pdf_dealloc (lower1);
    1900                 :          0 :       pdf_dealloc (lower2);
    1901         [ #  # ]:          0 :       return ((new_size1 > new_size2) ? 1 : -1);
    1902                 :            :     }
    1903                 :            : 
    1904                 :            :   /* Compare contents of words */
    1905                 :         18 :   ret_val = memcmp (lower1, lower2, new_size1);
    1906                 :         18 :   pdf_dealloc (lower1);
    1907                 :         18 :   pdf_dealloc (lower2);
    1908                 :         18 :   return ret_val;
    1909                 :            : }
    1910                 :            : 
    1911                 :            : /* Function to clean all contents of a given pdf_text_t variable */
    1912                 :            : pdf_bool_t
    1913                 :       1409 : pdf_text_clean_contents (pdf_text_t   *text,
    1914                 :            :                          pdf_error_t **error)
    1915                 :            : {
    1916                 :            :   /* Clean list of word breaks (destroy and create empty) */
    1917         [ -  + ]:       1409 :   if (!pdf_text_clean_word_boundaries_list (&(text->word_boundaries), error))
    1918                 :          0 :     return PDF_FALSE;
    1919                 :            : 
    1920                 :            :   /* Clear all contents */
    1921         [ -  + ]:       1409 :   if (text->data != NULL)
    1922                 :            :     {
    1923                 :          0 :       pdf_dealloc (text->data);
    1924                 :          0 :       text->data = NULL;
    1925                 :            :     }
    1926                 :            : 
    1927                 :            :   /* Clean country and language info */
    1928                 :       1409 :   memset (&(text->lang[0]), 0, PDF_TEXT_CCL);
    1929                 :       1409 :   memset (&(text->country[0]), 0, PDF_TEXT_CCL);
    1930                 :            :   /* Reset data size */
    1931                 :       1409 :   text->size = 0;
    1932                 :            : 
    1933                 :       1409 :   text->modified = PDF_FALSE;
    1934         [ -  + ]:       1409 :   if (text->printable != NULL)
    1935                 :            :     {
    1936                 :          0 :       pdf_dealloc (text->printable);
    1937                 :          0 :       text->printable = NULL;
    1938                 :            :     }
    1939                 :       1409 :   return PDF_TRUE;
    1940                 :            : }
    1941                 :            : 
    1942                 :            : static pdf_bool_t
    1943                 :            : pdf_text_get_lang_from_utf16be (pdf_text_t        *element,
    1944                 :            :                                 const pdf_char_t  *str_in,
    1945                 :            :                                 const pdf_size_t   str_in_length,
    1946                 :            :                                 pdf_char_t       **str_out,
    1947                 :            :                                 pdf_size_t        *str_out_length,
    1948                 :            :                                 pdf_error_t      **error)
    1949                 :            : {
    1950                 :            :   /* Country code is optional */
    1951                 :         28 :   pdf_bool_t country_available = PDF_FALSE;
    1952                 :            :   pdf_char_t aux[PDF_TEXT_CCL];
    1953                 :            : 
    1954                 :            :   /* Check last code marker position and MAXIMUM length of array.
    1955                 :            :    *  Additionally, set `str_out' and `str_out_length' */
    1956 [ +  + ][ -  + ]:         28 :   if ((str_in[5] != PDF_TEXT_LCI_1) ||
    1957                 :         14 :       (str_in[4] != PDF_TEXT_LCI_0))
    1958                 :            :     {
    1959                 :            :       /* Check last marker in bytes 6 and 7... */
    1960 [ +  - ][ +  - ]:         14 :       if ((str_in_length >= PDF_TEXT_LCMAXL) &&
                 [ +  - ]
    1961                 :         14 :           (str_in[7] == PDF_TEXT_LCI_1) &&
    1962                 :         14 :           (str_in[6] == PDF_TEXT_LCI_0))
    1963                 :            :         {
    1964                 :         14 :           country_available = PDF_TRUE;
    1965                 :         14 :           *str_out = (pdf_char_t *)str_in + PDF_TEXT_LCMAXL;
    1966                 :         14 :           *str_out_length = str_in_length - PDF_TEXT_LCMAXL;
    1967                 :            :         }
    1968                 :            :     }
    1969                 :            :   else
    1970                 :            :     {
    1971                 :            :       /* There is no optional country code info */
    1972                 :         14 :       *str_out = (pdf_char_t *)str_in + PDF_TEXT_LCMINL;
    1973                 :         14 :       *str_out_length = str_in_length - PDF_TEXT_LCMINL;
    1974                 :            :     }
    1975                 :            : 
    1976                 :            :   /* Store 2-bytes ISO 639 language code */
    1977                 :         28 :   memcpy (&aux[0], &str_in[2], PDF_TEXT_CCL-1);
    1978                 :         28 :   aux[PDF_TEXT_CCL-1] = '\0';
    1979                 :         28 :   pdf_text_set_language (element, (pdf_char_t *)aux);
    1980                 :            : 
    1981                 :            :   /* If optional country code is also available, store it... */
    1982         [ +  + ]:         28 :   if (country_available)
    1983                 :            :     {
    1984                 :         14 :       memcpy (&aux[0], &str_in[4], PDF_TEXT_CCL-1);
    1985                 :            :       /* Last NUL byte is already set */
    1986                 :            :       /* Store 2-bytes ISO 3166 country code */
    1987                 :         14 :       pdf_text_set_country (element, (pdf_char_t *)aux);
    1988                 :            :     }
    1989                 :            : 
    1990                 :         28 :   return PDF_TRUE;
    1991                 :            : }
    1992                 :            : 
    1993                 :            : static enum pdf_text_unicode_encoding_e
    1994                 :            : pdf_text_transform_he_to_unicode_encoding (enum pdf_text_unicode_encoding_e enc)
    1995                 :            : {
    1996 [ +  + ][ +  + ]:       2041 :   if ((enc == PDF_TEXT_UTF16_HE) || (enc == PDF_TEXT_UTF32_HE))
    1997                 :        277 :     enc += (PDF_IS_BIG_ENDIAN ? PDF_TEXT_HE_TO_BE : PDF_TEXT_HE_TO_LE);
    1998                 :       2041 :   return enc;
    1999                 :            : }
    2000                 :            : 
    2001                 :            : static void
    2002                 :        108 : pdf_text_get_unicode_string_header (enum pdf_text_unicode_encoding_e enc,
    2003                 :            :                                     pdf_u32_t         options,
    2004                 :            :                                     const pdf_char_t *language,
    2005                 :            :                                     const pdf_char_t *country,
    2006                 :            :                                     pdf_char_t        header[PDF_TEXT_USHMAXL],
    2007                 :            :                                     pdf_size_t       *header_length)
    2008                 :            : {
    2009                 :            :   short bom_bytes;
    2010                 :            :   short lang_bytes;
    2011                 :            :   pdf_text_bom_t bom;
    2012                 :            : 
    2013                 :        108 :   bom = pdf_text_get_unicode_bom (enc);
    2014                 :            : 
    2015                 :            :   /* Check if BOM really requested */
    2016                 :        108 :   bom_bytes = 0;
    2017         [ +  + ]:        108 :   if (options & PDF_TEXT_UNICODE_WITH_BOM)
    2018                 :         84 :     bom_bytes = bom.bom_bytes;
    2019                 :            : 
    2020                 :            :   /* Check if Lang/Country code really requested (only for UTF16BE!!) */
    2021                 :        108 :   lang_bytes = 0;
    2022 [ +  + ][ +  + ]:        108 :   if ((enc == PDF_TEXT_UTF16_BE) &&
                 [ +  - ]
    2023                 :         60 :       (options & PDF_TEXT_UTF16BE_WITH_LANGCODE) &&
    2024                 :         48 :       (strlen (language) == 2))
    2025                 :            :     {
    2026                 :            :       /* At least language is available, but country may also be
    2027                 :            :        *  available */
    2028         [ +  + ]:         48 :       lang_bytes = (strlen (country) == 2) ? PDF_TEXT_LCMAXL : PDF_TEXT_LCMINL;
    2029                 :            :     }
    2030                 :            : 
    2031                 :            :   /* Modify header array, if needed, to add Language/Country info and/or
    2032                 :            :    *  BOM */
    2033                 :        108 :   *header_length = lang_bytes + bom_bytes;
    2034         [ +  - ]:        108 :   if ((*header_length > 0) &&
    2035                 :            :       (*header_length < PDF_TEXT_USHMAXL)) /* (just in case) */
    2036                 :            :     {
    2037                 :            :       pdf_char_t *walker;
    2038                 :            : 
    2039                 :        108 :       walker = &header[0];
    2040                 :            :       /* Add BOM */
    2041         [ +  + ]:        108 :       if (bom_bytes > 0)
    2042                 :            :         {
    2043                 :         84 :           memcpy (walker, bom.bom_data, bom_bytes);
    2044                 :            :           /* Update walker */
    2045                 :         84 :           walker += bom_bytes;
    2046                 :            :         }
    2047                 :            : 
    2048                 :            :       /* Add Lang/Country */
    2049         [ +  + ]:        108 :       if (lang_bytes > 0)
    2050                 :            :         {
    2051                 :            :           /* Language and Country */
    2052         [ +  + ]:         48 :           if (lang_bytes == PDF_TEXT_LCMAXL)
    2053                 :            :             {
    2054                 :         24 :               sprintf (walker, "%c%c%2s%2s%c%c",
    2055                 :            :                        PDF_TEXT_LCI_0,PDF_TEXT_LCI_1,
    2056                 :            :                        language, country,
    2057                 :            :                        PDF_TEXT_LCI_0,PDF_TEXT_LCI_1);
    2058                 :            :             }
    2059                 :            :           /* Language only */
    2060                 :            :           else
    2061                 :            :             {
    2062                 :         24 :               sprintf (walker, "%c%c%2s%c%c",
    2063                 :            :                        PDF_TEXT_LCI_0,PDF_TEXT_LCI_1,
    2064                 :            :                        language,
    2065                 :            :                        PDF_TEXT_LCI_0,PDF_TEXT_LCI_1);
    2066                 :            :             }
    2067                 :            :         }
    2068                 :            :     }
    2069                 :        108 : }
    2070                 :            : 
    2071                 :            : pdf_bool_t
    2072                 :         26 : pdf_text_is_ascii7 (const pdf_char_t *utf8data,
    2073                 :            :                     const pdf_size_t  size)
    2074                 :            : {
    2075                 :            :   pdf_size_t i;
    2076                 :            : 
    2077         [ +  + ]:        140 :   for (i = 0; i < size; ++i)
    2078                 :            :     {
    2079                 :            :       /* Just check the MSB. In ASCII-7 it must be 0 */
    2080         [ -  + ]:        114 :       if (utf8data[i] & 0x80)
    2081                 :          0 :         return PDF_FALSE;
    2082                 :            :     }
    2083                 :         26 :   return PDF_TRUE;
    2084                 :            : }
    2085                 :            : 
    2086                 :            : /* Generate Word Boundaries list from text object */
    2087                 :            : pdf_bool_t
    2088                 :         60 : pdf_text_generate_word_boundaries (pdf_text_t   *text,
    2089                 :            :                                    pdf_error_t **error)
    2090                 :            : {
    2091         [ +  - ]:        120 :   return ((pdf_list_size (text->word_boundaries) == 0) ?
    2092                 :         60 :           pdf_text_fill_word_boundaries_list (text->word_boundaries,
    2093                 :         60 :                                               text->data,
    2094                 :            :                                               text->size,
    2095                 :            :                                               error) :
    2096                 :            :           PDF_TRUE);
    2097                 :            : }
    2098                 :            : 
    2099                 :            : void
    2100                 :       1599 : pdf_text_destroy_word_boundaries_list (pdf_list_t **p_word_boundaries)
    2101                 :            : {
    2102                 :            :   pdf_list_iterator_t itr;
    2103                 :            :   const void *element;
    2104                 :            : 
    2105                 :       1599 :   pdf_list_iterator_init (&itr, *p_word_boundaries);
    2106                 :            : 
    2107         [ +  + ]:       1947 :   while (pdf_list_iterator_next (&itr, &element, NULL))
    2108                 :            :     {
    2109                 :            :       /* Dealloc word (pointed by the list element) */
    2110                 :        348 :       pdf_dealloc (element);
    2111                 :            :     }
    2112                 :            : 
    2113                 :       1599 :   pdf_list_iterator_deinit (&itr);
    2114                 :            : 
    2115                 :            :   /* Destroy list */
    2116                 :       1599 :   pdf_list_destroy (*p_word_boundaries);
    2117                 :       1599 :   *p_word_boundaries = NULL;
    2118                 :       1599 : }
    2119                 :            : 
    2120                 :            : /* Create empty Word Boundaries list */
    2121                 :            : pdf_list_t *
    2122                 :       1803 : pdf_text_create_word_boundaries_list (pdf_error_t **error)
    2123                 :            : {
    2124                 :            :   /* Initialize word boundaries list */
    2125                 :       1803 :   return pdf_list_new (NULL,
    2126                 :            :                        NULL,
    2127                 :            :                        PDF_TRUE,
    2128                 :            :                        error);
    2129                 :            : }
    2130                 :            : 
    2131                 :            : /* Clean (destroy and create empty) Word Boundaries list */
    2132                 :            : static pdf_bool_t
    2133                 :            : pdf_text_clean_word_boundaries_list (pdf_list_t  **p_word_boundaries,
    2134                 :            :                                      pdf_error_t **error)
    2135                 :            : {
    2136                 :            :   /* Only destroy+create if list is not empty! */
    2137         [ +  - ]:       1409 :   if (pdf_list_size (*p_word_boundaries) == 0)
    2138                 :            :     /* List is already empty */
    2139                 :       1409 :     return PDF_TRUE;
    2140                 :            : 
    2141                 :            :   /* Destroy element contents */
    2142                 :          0 :   pdf_text_destroy_word_boundaries_list (p_word_boundaries);
    2143                 :            : 
    2144                 :            :   /* Create empty list */
    2145                 :          0 :   *p_word_boundaries = pdf_text_create_word_boundaries_list (error);
    2146                 :            : 
    2147                 :          0 :   return (*p_word_boundaries != NULL ?
    2148                 :            :           PDF_TRUE :
    2149                 :            :           PDF_FALSE);
    2150                 :            : }
    2151                 :            : 
    2152                 :            : /* Fill in the Word Boundaries list using the given data */
    2153                 :            : static pdf_bool_t
    2154                 :         64 : pdf_text_fill_word_boundaries_list (pdf_list_t        *word_boundaries,
    2155                 :            :                                     const pdf_char_t  *data,
    2156                 :            :                                     const pdf_size_t   size,
    2157                 :            :                                     pdf_error_t      **error)
    2158                 :            : {
    2159                 :            :   pdf_char_t *walker;
    2160                 :            :   pdf_size_t n_bytes_left;
    2161                 :            : 
    2162                 :            :   /* Perform a basic check of data length */
    2163         [ -  + ]:         64 :   if (size % 4 != 0)
    2164                 :            :     {
    2165                 :          0 :       pdf_set_error (error,
    2166                 :            :                      PDF_EDOMAIN_BASE_TEXT,
    2167                 :            :                      PDF_EBADDATA,
    2168                 :            :                      "cannot fill word boundaries list: "
    2169                 :            :                      "wrong stream size (%lu), must be multiple of 4",
    2170                 :            :                      (unsigned long) size);
    2171                 :          0 :       return PDF_FALSE;
    2172                 :            :     }
    2173                 :            : 
    2174                 :            :   /* Only try to find word boundaries if length is greater than 0! */
    2175         [ +  + ]:         64 :   if (size == 0)
    2176                 :          6 :     return PDF_TRUE;
    2177                 :            : 
    2178                 :            :   /* Initialize walker and number of bytes left */
    2179                 :         58 :   walker = (pdf_char_t *)data;
    2180                 :         58 :   n_bytes_left = size;
    2181                 :            : 
    2182         [ +  + ]:        250 :   while (n_bytes_left > 0)
    2183                 :            :     {
    2184                 :            :       struct pdf_text_wb_s *p_word;
    2185                 :            : 
    2186                 :            :       /* Allocate new word */
    2187                 :        192 :       p_word = (struct pdf_text_wb_s *) pdf_alloc (sizeof (struct pdf_text_wb_s));
    2188         [ -  + ]:        192 :       if (!p_word)
    2189                 :            :         {
    2190                 :          0 :           pdf_set_error (error,
    2191                 :            :                          PDF_EDOMAIN_BASE_TEXT,
    2192                 :            :                          PDF_ENOMEM,
    2193                 :            :                          "cannot fill word boundaries list: "
    2194                 :            :                          "couldn't allocate %lu bytes",
    2195                 :            :                          sizeof (struct pdf_text_wb_s));
    2196                 :          0 :           return PDF_FALSE;
    2197                 :            :         }
    2198                 :            : 
    2199                 :            :       /* RULE WB1: Break at the start of text ( SOT % ) */
    2200                 :        192 :       p_word->word_start = walker;
    2201                 :            : 
    2202         [ -  + ]:        192 :       if (pdf_text_ucd_wb_detect_next (walker,
    2203                 :            :                                        n_bytes_left,
    2204                 :            :                                        &(p_word->word_stop),
    2205                 :            :                                        &n_bytes_left) != PDF_TRUE)
    2206                 :            :         {
    2207                 :          0 :           pdf_set_error (error,
    2208                 :            :                          PDF_EDOMAIN_BASE_TEXT,
    2209                 :            :                          PDF_ETEXTENC,
    2210                 :            :                          "cannot fill word boundaries list: "
    2211                 :            :                          "couldn't detect next word break");
    2212                 :          0 :           return PDF_FALSE;
    2213                 :            :         }
    2214                 :            : 
    2215                 :            :       /* Compute word size in bytes */
    2216                 :        192 :       p_word->word_size = (p_word->word_stop - p_word->word_start) + 4;
    2217                 :            : 
    2218                 :            :       /* Add new word boundary to list */
    2219         [ -  + ]:        192 :       if (!pdf_list_add_last (word_boundaries,
    2220                 :            :                               p_word,
    2221                 :            :                               error))
    2222                 :          0 :         return PDF_FALSE;
    2223                 :            : 
    2224                 :            :       /* Update walker */
    2225                 :        192 :       walker = p_word->word_stop + 4;
    2226                 :            :     }
    2227                 :            : 
    2228                 :         64 :   return PDF_TRUE;
    2229                 :            : }
    2230                 :            : 
    2231                 :            : /* End of pdf-text.c */

Generated by: LCOV version 1.8