LCOV - code coverage report
Current view: top level - src/backend/utils/mb - conv.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 84.1 % 390 328
Test Date: 2026-01-26 10:56:24 Functions: 100.0 % 11 11
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 69.3 % 280 194

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  *        Utility functions for conversion procs.
       4                 :             :  *
       5                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       6                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
       7                 :             :  *
       8                 :             :  * IDENTIFICATION
       9                 :             :  *        src/backend/utils/mb/conv.c
      10                 :             :  *
      11                 :             :  *-------------------------------------------------------------------------
      12                 :             :  */
      13                 :             : #include "postgres.h"
      14                 :             : #include "mb/pg_wchar.h"
      15                 :             : 
      16                 :             : 
      17                 :             : /*
      18                 :             :  * local2local: a generic single byte charset encoding
      19                 :             :  * conversion between two ASCII-superset encodings.
      20                 :             :  *
      21                 :             :  * l points to the source string of length len
      22                 :             :  * p is the output area (must be large enough!)
      23                 :             :  * src_encoding is the PG identifier for the source encoding
      24                 :             :  * dest_encoding is the PG identifier for the target encoding
      25                 :             :  * tab holds conversion entries for the source charset
      26                 :             :  * starting from 128 (0x80). each entry in the table holds the corresponding
      27                 :             :  * code point for the target charset, or 0 if there is no equivalent code.
      28                 :             :  *
      29                 :             :  * Returns the number of input bytes consumed.  If noError is true, this can
      30                 :             :  * be less than 'len'.
      31                 :             :  */
      32                 :             : int
      33                 :          38 : local2local(const unsigned char *l,
      34                 :             :                         unsigned char *p,
      35                 :             :                         int len,
      36                 :             :                         int src_encoding,
      37                 :             :                         int dest_encoding,
      38                 :             :                         const unsigned char *tab,
      39                 :             :                         bool noError)
      40                 :             : {
      41                 :          38 :         const unsigned char *start = l;
      42                 :          38 :         unsigned char c1,
      43                 :             :                                 c2;
      44                 :             : 
      45         [ +  + ]:         122 :         while (len > 0)
      46                 :             :         {
      47                 :         102 :                 c1 = *l;
      48         [ +  + ]:         102 :                 if (c1 == 0)
      49                 :             :                 {
      50         [ +  + ]:          18 :                         if (noError)
      51                 :           9 :                                 break;
      52                 :           9 :                         report_invalid_encoding(src_encoding, (const char *) l, len);
      53                 :             :                 }
      54         [ +  + ]:          84 :                 if (!IS_HIGHBIT_SET(c1))
      55                 :          51 :                         *p++ = c1;
      56                 :             :                 else
      57                 :             :                 {
      58                 :          33 :                         c2 = tab[c1 - HIGHBIT];
      59         [ +  - ]:          33 :                         if (c2)
      60                 :          33 :                                 *p++ = c2;
      61                 :             :                         else
      62                 :             :                         {
      63         [ #  # ]:           0 :                                 if (noError)
      64                 :           0 :                                         break;
      65                 :           0 :                                 report_untranslatable_char(src_encoding, dest_encoding,
      66                 :           0 :                                                                                    (const char *) l, len);
      67                 :             :                         }
      68                 :             :                 }
      69                 :          84 :                 l++;
      70                 :          84 :                 len--;
      71                 :             :         }
      72                 :          29 :         *p = '\0';
      73                 :             : 
      74                 :          58 :         return l - start;
      75                 :          29 : }
      76                 :             : 
      77                 :             : /*
      78                 :             :  * LATINn ---> MIC when the charset's local codes map directly to MIC
      79                 :             :  *
      80                 :             :  * l points to the source string of length len
      81                 :             :  * p is the output area (must be large enough!)
      82                 :             :  * lc is the mule character set id for the local encoding
      83                 :             :  * encoding is the PG identifier for the local encoding
      84                 :             :  *
      85                 :             :  * Returns the number of input bytes consumed.  If noError is true, this can
      86                 :             :  * be less than 'len'.
      87                 :             :  */
      88                 :             : int
      89                 :           5 : latin2mic(const unsigned char *l, unsigned char *p, int len,
      90                 :             :                   int lc, int encoding, bool noError)
      91                 :             : {
      92                 :           5 :         const unsigned char *start = l;
      93                 :           5 :         int                     c1;
      94                 :             : 
      95         [ +  + ]:          20 :         while (len > 0)
      96                 :             :         {
      97                 :          15 :                 c1 = *l;
      98         [ +  - ]:          15 :                 if (c1 == 0)
      99                 :             :                 {
     100         [ #  # ]:           0 :                         if (noError)
     101                 :           0 :                                 break;
     102                 :           0 :                         report_invalid_encoding(encoding, (const char *) l, len);
     103                 :             :                 }
     104         [ +  - ]:          15 :                 if (IS_HIGHBIT_SET(c1))
     105                 :           0 :                         *p++ = lc;
     106                 :          15 :                 *p++ = c1;
     107                 :          15 :                 l++;
     108                 :          15 :                 len--;
     109                 :             :         }
     110                 :           5 :         *p = '\0';
     111                 :             : 
     112                 :          10 :         return l - start;
     113                 :           5 : }
     114                 :             : 
     115                 :             : /*
     116                 :             :  * MIC ---> LATINn when the charset's local codes map directly to MIC
     117                 :             :  *
     118                 :             :  * mic points to the source string of length len
     119                 :             :  * p is the output area (must be large enough!)
     120                 :             :  * lc is the mule character set id for the local encoding
     121                 :             :  * encoding is the PG identifier for the local encoding
     122                 :             :  *
     123                 :             :  * Returns the number of input bytes consumed.  If noError is true, this can
     124                 :             :  * be less than 'len'.
     125                 :             :  */
     126                 :             : int
     127                 :          59 : mic2latin(const unsigned char *mic, unsigned char *p, int len,
     128                 :             :                   int lc, int encoding, bool noError)
     129                 :             : {
     130                 :          59 :         const unsigned char *start = mic;
     131                 :          59 :         int                     c1;
     132                 :             : 
     133         [ +  + ]:         140 :         while (len > 0)
     134                 :             :         {
     135                 :         129 :                 c1 = *mic;
     136         [ +  - ]:         129 :                 if (c1 == 0)
     137                 :             :                 {
     138         [ #  # ]:           0 :                         if (noError)
     139                 :           0 :                                 break;
     140                 :           0 :                         report_invalid_encoding(PG_MULE_INTERNAL, (const char *) mic, len);
     141                 :             :                 }
     142         [ +  + ]:         129 :                 if (!IS_HIGHBIT_SET(c1))
     143                 :             :                 {
     144                 :             :                         /* easy for ASCII */
     145                 :          60 :                         *p++ = c1;
     146                 :          60 :                         mic++;
     147                 :          60 :                         len--;
     148                 :          60 :                 }
     149                 :             :                 else
     150                 :             :                 {
     151                 :          69 :                         int                     l = pg_mule_mblen(mic);
     152                 :             : 
     153         [ +  + ]:          69 :                         if (len < l)
     154                 :             :                         {
     155         [ +  + ]:          18 :                                 if (noError)
     156                 :           9 :                                         break;
     157                 :          18 :                                 report_invalid_encoding(PG_MULE_INTERNAL, (const char *) mic,
     158                 :           9 :                                                                                 len);
     159                 :             :                         }
     160   [ +  +  +  -  :          51 :                         if (l != 2 || c1 != lc || !IS_HIGHBIT_SET(mic[1]))
                   +  + ]
     161                 :             :                         {
     162         [ +  + ]:          30 :                                 if (noError)
     163                 :          15 :                                         break;
     164                 :          30 :                                 report_untranslatable_char(PG_MULE_INTERNAL, encoding,
     165                 :          15 :                                                                                    (const char *) mic, len);
     166                 :             :                         }
     167                 :          21 :                         *p++ = mic[1];
     168                 :          21 :                         mic += 2;
     169                 :          21 :                         len -= 2;
     170      [ -  +  + ]:          45 :                 }
     171                 :             :         }
     172                 :          35 :         *p = '\0';
     173                 :             : 
     174                 :          70 :         return mic - start;
     175                 :          35 : }
     176                 :             : 
     177                 :             : 
     178                 :             : /*
     179                 :             :  * latin2mic_with_table: a generic single byte charset encoding
     180                 :             :  * conversion from a local charset to the mule internal code.
     181                 :             :  *
     182                 :             :  * l points to the source string of length len
     183                 :             :  * p is the output area (must be large enough!)
     184                 :             :  * lc is the mule character set id for the local encoding
     185                 :             :  * encoding is the PG identifier for the local encoding
     186                 :             :  * tab holds conversion entries for the local charset
     187                 :             :  * starting from 128 (0x80). each entry in the table holds the corresponding
     188                 :             :  * code point for the mule encoding, or 0 if there is no equivalent code.
     189                 :             :  *
     190                 :             :  * Returns the number of input bytes consumed.  If noError is true, this can
     191                 :             :  * be less than 'len'.
     192                 :             :  */
     193                 :             : int
     194                 :          28 : latin2mic_with_table(const unsigned char *l,
     195                 :             :                                          unsigned char *p,
     196                 :             :                                          int len,
     197                 :             :                                          int lc,
     198                 :             :                                          int encoding,
     199                 :             :                                          const unsigned char *tab,
     200                 :             :                                          bool noError)
     201                 :             : {
     202                 :          28 :         const unsigned char *start = l;
     203                 :          28 :         unsigned char c1,
     204                 :             :                                 c2;
     205                 :             : 
     206         [ +  + ]:          82 :         while (len > 0)
     207                 :             :         {
     208                 :          72 :                 c1 = *l;
     209         [ +  + ]:          72 :                 if (c1 == 0)
     210                 :             :                 {
     211         [ +  + ]:          18 :                         if (noError)
     212                 :           9 :                                 break;
     213                 :           9 :                         report_invalid_encoding(encoding, (const char *) l, len);
     214                 :             :                 }
     215         [ +  + ]:          54 :                 if (!IS_HIGHBIT_SET(c1))
     216                 :          21 :                         *p++ = c1;
     217                 :             :                 else
     218                 :             :                 {
     219                 :          33 :                         c2 = tab[c1 - HIGHBIT];
     220         [ +  - ]:          33 :                         if (c2)
     221                 :             :                         {
     222                 :          33 :                                 *p++ = lc;
     223                 :          33 :                                 *p++ = c2;
     224                 :          33 :                         }
     225                 :             :                         else
     226                 :             :                         {
     227         [ #  # ]:           0 :                                 if (noError)
     228                 :           0 :                                         break;
     229                 :           0 :                                 report_untranslatable_char(encoding, PG_MULE_INTERNAL,
     230                 :           0 :                                                                                    (const char *) l, len);
     231                 :             :                         }
     232                 :             :                 }
     233                 :          54 :                 l++;
     234                 :          54 :                 len--;
     235                 :             :         }
     236                 :          19 :         *p = '\0';
     237                 :             : 
     238                 :          38 :         return l - start;
     239                 :          19 : }
     240                 :             : 
     241                 :             : /*
     242                 :             :  * mic2latin_with_table: a generic single byte charset encoding
     243                 :             :  * conversion from the mule internal code to a local charset.
     244                 :             :  *
     245                 :             :  * mic points to the source string of length len
     246                 :             :  * p is the output area (must be large enough!)
     247                 :             :  * lc is the mule character set id for the local encoding
     248                 :             :  * encoding is the PG identifier for the local encoding
     249                 :             :  * tab holds conversion entries for the mule internal code's second byte,
     250                 :             :  * starting from 128 (0x80). each entry in the table holds the corresponding
     251                 :             :  * code point for the local charset, or 0 if there is no equivalent code.
     252                 :             :  *
     253                 :             :  * Returns the number of input bytes consumed.  If noError is true, this can
     254                 :             :  * be less than 'len'.
     255                 :             :  */
     256                 :             : int
     257                 :          58 : mic2latin_with_table(const unsigned char *mic,
     258                 :             :                                          unsigned char *p,
     259                 :             :                                          int len,
     260                 :             :                                          int lc,
     261                 :             :                                          int encoding,
     262                 :             :                                          const unsigned char *tab,
     263                 :             :                                          bool noError)
     264                 :             : {
     265                 :          58 :         const unsigned char *start = mic;
     266                 :          58 :         unsigned char c1,
     267                 :             :                                 c2;
     268                 :             : 
     269         [ +  + ]:         136 :         while (len > 0)
     270                 :             :         {
     271                 :         126 :                 c1 = *mic;
     272         [ +  - ]:         126 :                 if (c1 == 0)
     273                 :             :                 {
     274         [ #  # ]:           0 :                         if (noError)
     275                 :           0 :                                 break;
     276                 :           0 :                         report_invalid_encoding(PG_MULE_INTERNAL, (const char *) mic, len);
     277                 :             :                 }
     278         [ +  + ]:         126 :                 if (!IS_HIGHBIT_SET(c1))
     279                 :             :                 {
     280                 :             :                         /* easy for ASCII */
     281                 :          57 :                         *p++ = c1;
     282                 :          57 :                         mic++;
     283                 :          57 :                         len--;
     284                 :          57 :                 }
     285                 :             :                 else
     286                 :             :                 {
     287                 :          69 :                         int                     l = pg_mule_mblen(mic);
     288                 :             : 
     289         [ +  + ]:          69 :                         if (len < l)
     290                 :             :                         {
     291         [ +  + ]:          18 :                                 if (noError)
     292                 :           9 :                                         break;
     293                 :          18 :                                 report_invalid_encoding(PG_MULE_INTERNAL, (const char *) mic,
     294                 :           9 :                                                                                 len);
     295                 :             :                         }
     296   [ +  +  +  -  :          51 :                         if (l != 2 || c1 != lc || !IS_HIGHBIT_SET(mic[1]) ||
             +  +  -  + ]
     297                 :          21 :                                 (c2 = tab[mic[1] - HIGHBIT]) == 0)
     298                 :             :                         {
     299         [ +  + ]:          30 :                                 if (noError)
     300                 :          15 :                                         break;
     301                 :          30 :                                 report_untranslatable_char(PG_MULE_INTERNAL, encoding,
     302                 :          15 :                                                                                    (const char *) mic, len);
     303                 :             :                                 break;                  /* keep compiler quiet */
     304                 :             :                         }
     305                 :          21 :                         *p++ = c2;
     306                 :          21 :                         mic += 2;
     307                 :          21 :                         len -= 2;
     308      [ -  +  + ]:          45 :                 }
     309                 :             :         }
     310                 :          34 :         *p = '\0';
     311                 :             : 
     312                 :          68 :         return mic - start;
     313                 :          34 : }
     314                 :             : 
     315                 :             : /*
     316                 :             :  * comparison routine for bsearch()
     317                 :             :  * this routine is intended for combined UTF8 -> local code
     318                 :             :  */
     319                 :             : static int
     320                 :          78 : compare3(const void *p1, const void *p2)
     321                 :             : {
     322                 :          78 :         uint32          s1,
     323                 :             :                                 s2,
     324                 :             :                                 d1,
     325                 :             :                                 d2;
     326                 :             : 
     327                 :          78 :         s1 = *(const uint32 *) p1;
     328                 :          78 :         s2 = *((const uint32 *) p1 + 1);
     329                 :          78 :         d1 = ((const pg_utf_to_local_combined *) p2)->utf1;
     330                 :          78 :         d2 = ((const pg_utf_to_local_combined *) p2)->utf2;
     331   [ +  +  +  +  :          78 :         return (s1 > d1 || (s1 == d1 && s2 > d2)) ? 1 : ((s1 == d1 && s2 == d2) ? 0 : -1);
             -  +  +  + ]
     332                 :          78 : }
     333                 :             : 
     334                 :             : /*
     335                 :             :  * comparison routine for bsearch()
     336                 :             :  * this routine is intended for local code -> combined UTF8
     337                 :             :  */
     338                 :             : static int
     339                 :          27 : compare4(const void *p1, const void *p2)
     340                 :             : {
     341                 :          27 :         uint32          v1,
     342                 :             :                                 v2;
     343                 :             : 
     344                 :          27 :         v1 = *(const uint32 *) p1;
     345                 :          27 :         v2 = ((const pg_local_to_utf_combined *) p2)->code;
     346         [ +  + ]:          27 :         return (v1 > v2) ? 1 : ((v1 == v2) ? 0 : -1);
     347                 :          27 : }
     348                 :             : 
     349                 :             : /*
     350                 :             :  * store 32bit character representation into multibyte stream
     351                 :             :  */
     352                 :             : static inline unsigned char *
     353                 :         192 : store_coded_char(unsigned char *dest, uint32 code)
     354                 :             : {
     355         [ +  + ]:         192 :         if (code & 0xff000000)
     356                 :          21 :                 *dest++ = code >> 24;
     357         [ +  + ]:         192 :         if (code & 0x00ff0000)
     358                 :          90 :                 *dest++ = code >> 16;
     359         [ +  + ]:         192 :         if (code & 0x0000ff00)
     360                 :         171 :                 *dest++ = code >> 8;
     361         [ -  + ]:         192 :         if (code & 0x000000ff)
     362                 :         192 :                 *dest++ = code;
     363                 :         192 :         return dest;
     364                 :             : }
     365                 :             : 
     366                 :             : /*
     367                 :             :  * Convert a character using a conversion radix tree.
     368                 :             :  *
     369                 :             :  * 'l' is the length of the input character in bytes, and b1-b4 are
     370                 :             :  * the input character's bytes.
     371                 :             :  */
     372                 :             : static inline uint32
     373                 :         333 : pg_mb_radix_conv(const pg_mb_radix_tree *rt,
     374                 :             :                                  int l,
     375                 :             :                                  unsigned char b1,
     376                 :             :                                  unsigned char b2,
     377                 :             :                                  unsigned char b3,
     378                 :             :                                  unsigned char b4)
     379                 :             : {
     380         [ +  + ]:         333 :         if (l == 4)
     381                 :             :         {
     382                 :             :                 /* 4-byte code */
     383                 :             : 
     384                 :             :                 /* check code validity */
     385   [ +  -  +  - ]:          15 :                 if (b1 < rt->b4_1_lower || b1 > rt->b4_1_upper ||
     386   [ +  -  +  - ]:          15 :                         b2 < rt->b4_2_lower || b2 > rt->b4_2_upper ||
     387   [ +  -  +  - ]:          15 :                         b3 < rt->b4_3_lower || b3 > rt->b4_3_upper ||
     388   [ +  -  -  + ]:          15 :                         b4 < rt->b4_4_lower || b4 > rt->b4_4_upper)
     389                 :           0 :                         return 0;
     390                 :             : 
     391                 :             :                 /* perform lookup */
     392         [ +  - ]:          15 :                 if (rt->chars32)
     393                 :             :                 {
     394                 :          15 :                         uint32          idx = rt->b4root;
     395                 :             : 
     396                 :          15 :                         idx = rt->chars32[b1 + idx - rt->b4_1_lower];
     397                 :          15 :                         idx = rt->chars32[b2 + idx - rt->b4_2_lower];
     398                 :          15 :                         idx = rt->chars32[b3 + idx - rt->b4_3_lower];
     399                 :          15 :                         return rt->chars32[b4 + idx - rt->b4_4_lower];
     400                 :          15 :                 }
     401                 :             :                 else
     402                 :             :                 {
     403                 :           0 :                         uint16          idx = rt->b4root;
     404                 :             : 
     405                 :           0 :                         idx = rt->chars16[b1 + idx - rt->b4_1_lower];
     406                 :           0 :                         idx = rt->chars16[b2 + idx - rt->b4_2_lower];
     407                 :           0 :                         idx = rt->chars16[b3 + idx - rt->b4_3_lower];
     408                 :           0 :                         return rt->chars16[b4 + idx - rt->b4_4_lower];
     409                 :           0 :                 }
     410                 :             :         }
     411         [ +  + ]:         318 :         else if (l == 3)
     412                 :             :         {
     413                 :             :                 /* 3-byte code */
     414                 :             : 
     415                 :             :                 /* check code validity */
     416   [ +  -  +  + ]:         156 :                 if (b2 < rt->b3_1_lower || b2 > rt->b3_1_upper ||
     417   [ +  -  +  - ]:          48 :                         b3 < rt->b3_2_lower || b3 > rt->b3_2_upper ||
     418   [ +  -  -  + ]:          48 :                         b4 < rt->b3_3_lower || b4 > rt->b3_3_upper)
     419                 :         108 :                         return 0;
     420                 :             : 
     421                 :             :                 /* perform lookup */
     422         [ +  - ]:          48 :                 if (rt->chars32)
     423                 :             :                 {
     424                 :          48 :                         uint32          idx = rt->b3root;
     425                 :             : 
     426                 :          48 :                         idx = rt->chars32[b2 + idx - rt->b3_1_lower];
     427                 :          48 :                         idx = rt->chars32[b3 + idx - rt->b3_2_lower];
     428                 :          48 :                         return rt->chars32[b4 + idx - rt->b3_3_lower];
     429                 :          48 :                 }
     430                 :             :                 else
     431                 :             :                 {
     432                 :           0 :                         uint16          idx = rt->b3root;
     433                 :             : 
     434                 :           0 :                         idx = rt->chars16[b2 + idx - rt->b3_1_lower];
     435                 :           0 :                         idx = rt->chars16[b3 + idx - rt->b3_2_lower];
     436                 :           0 :                         return rt->chars16[b4 + idx - rt->b3_3_lower];
     437                 :           0 :                 }
     438                 :             :         }
     439         [ +  + ]:         162 :         else if (l == 2)
     440                 :             :         {
     441                 :             :                 /* 2-byte code */
     442                 :             : 
     443                 :             :                 /* check code validity - first byte */
     444   [ +  -  +  + ]:         129 :                 if (b3 < rt->b2_1_lower || b3 > rt->b2_1_upper ||
     445   [ +  -  -  + ]:         117 :                         b4 < rt->b2_2_lower || b4 > rt->b2_2_upper)
     446                 :          12 :                         return 0;
     447                 :             : 
     448                 :             :                 /* perform lookup */
     449         [ +  + ]:         117 :                 if (rt->chars32)
     450                 :             :                 {
     451                 :          90 :                         uint32          idx = rt->b2root;
     452                 :             : 
     453                 :          90 :                         idx = rt->chars32[b3 + idx - rt->b2_1_lower];
     454                 :          90 :                         return rt->chars32[b4 + idx - rt->b2_2_lower];
     455                 :          90 :                 }
     456                 :             :                 else
     457                 :             :                 {
     458                 :          27 :                         uint16          idx = rt->b2root;
     459                 :             : 
     460                 :          27 :                         idx = rt->chars16[b3 + idx - rt->b2_1_lower];
     461                 :          27 :                         return rt->chars16[b4 + idx - rt->b2_2_lower];
     462                 :          27 :                 }
     463                 :             :         }
     464         [ +  - ]:          33 :         else if (l == 1)
     465                 :             :         {
     466                 :             :                 /* 1-byte code */
     467                 :             : 
     468                 :             :                 /* check code validity - first byte */
     469   [ +  -  -  + ]:          33 :                 if (b4 < rt->b1_lower || b4 > rt->b1_upper)
     470                 :           0 :                         return 0;
     471                 :             : 
     472                 :             :                 /* perform lookup */
     473         [ +  - ]:          33 :                 if (rt->chars32)
     474                 :          33 :                         return rt->chars32[b4 + rt->b1root - rt->b1_lower];
     475                 :             :                 else
     476                 :           0 :                         return rt->chars16[b4 + rt->b1root - rt->b1_lower];
     477                 :             :         }
     478                 :           0 :         return 0;                                       /* shouldn't happen */
     479                 :         333 : }
     480                 :             : 
     481                 :             : /*
     482                 :             :  * UTF8 ---> local code
     483                 :             :  *
     484                 :             :  * utf: input string in UTF8 encoding (need not be null-terminated)
     485                 :             :  * len: length of input string (in bytes)
     486                 :             :  * iso: pointer to the output area (must be large enough!)
     487                 :             :  *                (output string will be null-terminated)
     488                 :             :  * map: conversion map for single characters
     489                 :             :  * cmap: conversion map for combined characters
     490                 :             :  *                (optional, pass NULL if none)
     491                 :             :  * cmapsize: number of entries in the conversion map for combined characters
     492                 :             :  *                (optional, pass 0 if none)
     493                 :             :  * conv_func: algorithmic encoding conversion function
     494                 :             :  *                (optional, pass NULL if none)
     495                 :             :  * encoding: PG identifier for the local encoding
     496                 :             :  *
     497                 :             :  * For each character, the cmap (if provided) is consulted first; if no match,
     498                 :             :  * the map is consulted next; if still no match, the conv_func (if provided)
     499                 :             :  * is applied.  An error is raised if no match is found.
     500                 :             :  *
     501                 :             :  * See pg_wchar.h for more details about the data structures used here.
     502                 :             :  *
     503                 :             :  * Returns the number of input bytes consumed.  If noError is true, this can
     504                 :             :  * be less than 'len'.
     505                 :             :  */
     506                 :             : int
     507                 :         378 : UtfToLocal(const unsigned char *utf, int len,
     508                 :             :                    unsigned char *iso,
     509                 :             :                    const pg_mb_radix_tree *map,
     510                 :             :                    const pg_utf_to_local_combined *cmap, int cmapsize,
     511                 :             :                    utf_local_conversion_func conv_func,
     512                 :             :                    int encoding, bool noError)
     513                 :             : {
     514                 :         378 :         uint32          iutf;
     515                 :         378 :         int                     l;
     516                 :         378 :         const pg_utf_to_local_combined *cp;
     517                 :         378 :         const unsigned char *start = utf;
     518                 :             : 
     519         [ +  - ]:         378 :         if (!PG_VALID_ENCODING(encoding))
     520   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     521                 :             :                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     522                 :             :                                  errmsg("invalid encoding number: %d", encoding)));
     523                 :             : 
     524         [ +  + ]:        1176 :         for (; len > 0; len -= l)
     525                 :             :         {
     526                 :        1068 :                 unsigned char b1 = 0;
     527                 :        1068 :                 unsigned char b2 = 0;
     528                 :        1068 :                 unsigned char b3 = 0;
     529                 :        1068 :                 unsigned char b4 = 0;
     530                 :             : 
     531                 :             :                 /* "break" cases all represent errors */
     532         [ +  + ]:        1068 :                 if (*utf == '\0')
     533                 :          30 :                         break;
     534                 :             : 
     535                 :        1038 :                 l = pg_utf_mblen(utf);
     536         [ +  + ]:        1038 :                 if (len < l)
     537                 :          36 :                         break;
     538                 :             : 
     539         [ +  + ]:        1002 :                 if (!pg_utf8_islegal(utf, l))
     540                 :          60 :                         break;
     541                 :             : 
     542         [ +  + ]:         942 :                 if (l == 1)
     543                 :             :                 {
     544                 :             :                         /* ASCII case is easy, assume it's one-to-one conversion */
     545                 :         708 :                         *iso++ = *utf++;
     546                 :         708 :                         continue;
     547                 :             :                 }
     548                 :             : 
     549                 :             :                 /* collect coded char of length l */
     550         [ +  + ]:         234 :                 if (l == 2)
     551                 :             :                 {
     552                 :          69 :                         b3 = *utf++;
     553                 :          69 :                         b4 = *utf++;
     554                 :          69 :                 }
     555         [ +  - ]:         165 :                 else if (l == 3)
     556                 :             :                 {
     557                 :         165 :                         b2 = *utf++;
     558                 :         165 :                         b3 = *utf++;
     559                 :         165 :                         b4 = *utf++;
     560                 :         165 :                 }
     561         [ #  # ]:           0 :                 else if (l == 4)
     562                 :             :                 {
     563                 :           0 :                         b1 = *utf++;
     564                 :           0 :                         b2 = *utf++;
     565                 :           0 :                         b3 = *utf++;
     566                 :           0 :                         b4 = *utf++;
     567                 :           0 :                 }
     568                 :             :                 else
     569                 :             :                 {
     570   [ #  #  #  # ]:           0 :                         elog(ERROR, "unsupported character length %d", l);
     571                 :           0 :                         iutf = 0;                       /* keep compiler quiet */
     572                 :             :                 }
     573                 :         234 :                 iutf = (b1 << 24 | b2 << 16 | b3 << 8 | b4);
     574                 :             : 
     575                 :             :                 /* First, try with combined map if possible */
     576   [ +  +  +  + ]:         234 :                 if (cmap && len > l)
     577                 :             :                 {
     578                 :          24 :                         const unsigned char *utf_save = utf;
     579                 :          24 :                         int                     len_save = len;
     580                 :          24 :                         int                     l_save = l;
     581                 :             : 
     582                 :             :                         /* collect next character, same as above */
     583                 :          24 :                         len -= l;
     584                 :             : 
     585                 :          24 :                         l = pg_utf_mblen(utf);
     586         [ +  + ]:          24 :                         if (len < l)
     587                 :             :                         {
     588                 :             :                                 /* need more data to decide if this is a combined char */
     589                 :           6 :                                 utf -= l_save;
     590                 :           6 :                                 break;
     591                 :             :                         }
     592                 :             : 
     593         [ +  - ]:          18 :                         if (!pg_utf8_islegal(utf, l))
     594                 :             :                         {
     595         [ #  # ]:           0 :                                 if (!noError)
     596                 :           0 :                                         report_invalid_encoding(PG_UTF8, (const char *) utf, len);
     597                 :           0 :                                 utf -= l_save;
     598                 :           0 :                                 break;
     599                 :             :                         }
     600                 :             : 
     601                 :             :                         /* We assume ASCII character cannot be in combined map */
     602         [ -  + ]:          18 :                         if (l > 1)
     603                 :             :                         {
     604                 :          18 :                                 uint32          iutf2;
     605                 :          18 :                                 uint32          cutf[2];
     606                 :             : 
     607         [ +  + ]:          18 :                                 if (l == 2)
     608                 :             :                                 {
     609                 :           9 :                                         iutf2 = *utf++ << 8;
     610                 :           9 :                                         iutf2 |= *utf++;
     611                 :           9 :                                 }
     612         [ +  - ]:           9 :                                 else if (l == 3)
     613                 :             :                                 {
     614                 :           9 :                                         iutf2 = *utf++ << 16;
     615                 :           9 :                                         iutf2 |= *utf++ << 8;
     616                 :           9 :                                         iutf2 |= *utf++;
     617                 :           9 :                                 }
     618         [ #  # ]:           0 :                                 else if (l == 4)
     619                 :             :                                 {
     620                 :           0 :                                         iutf2 = *utf++ << 24;
     621                 :           0 :                                         iutf2 |= *utf++ << 16;
     622                 :           0 :                                         iutf2 |= *utf++ << 8;
     623                 :           0 :                                         iutf2 |= *utf++;
     624                 :           0 :                                 }
     625                 :             :                                 else
     626                 :             :                                 {
     627   [ #  #  #  # ]:           0 :                                         elog(ERROR, "unsupported character length %d", l);
     628                 :           0 :                                         iutf2 = 0;      /* keep compiler quiet */
     629                 :             :                                 }
     630                 :             : 
     631                 :          18 :                                 cutf[0] = iutf;
     632                 :          18 :                                 cutf[1] = iutf2;
     633                 :             : 
     634                 :          18 :                                 cp = bsearch(cutf, cmap, cmapsize,
     635                 :             :                                                          sizeof(pg_utf_to_local_combined), compare3);
     636                 :             : 
     637         [ +  + ]:          18 :                                 if (cp)
     638                 :             :                                 {
     639                 :           3 :                                         iso = store_coded_char(iso, cp->code);
     640                 :           3 :                                         continue;
     641                 :             :                                 }
     642         [ +  + ]:          18 :                         }
     643                 :             : 
     644                 :             :                         /* fail, so back up to reprocess second character next time */
     645                 :          15 :                         utf = utf_save;
     646                 :          15 :                         len = len_save;
     647                 :          15 :                         l = l_save;
     648         [ +  + ]:          24 :                 }
     649                 :             : 
     650                 :             :                 /* Now check ordinary map */
     651         [ -  + ]:         225 :                 if (map)
     652                 :             :                 {
     653                 :         225 :                         uint32          converted = pg_mb_radix_conv(map, l, b1, b2, b3, b4);
     654                 :             : 
     655         [ +  + ]:         225 :                         if (converted)
     656                 :             :                         {
     657                 :          75 :                                 iso = store_coded_char(iso, converted);
     658                 :          75 :                                 continue;
     659                 :             :                         }
     660         [ +  + ]:         225 :                 }
     661                 :             : 
     662                 :             :                 /* if there's a conversion function, try that */
     663         [ +  + ]:         150 :                 if (conv_func)
     664                 :             :                 {
     665                 :          12 :                         uint32          converted = (*conv_func) (iutf);
     666                 :             : 
     667         [ -  + ]:          12 :                         if (converted)
     668                 :             :                         {
     669                 :          12 :                                 iso = store_coded_char(iso, converted);
     670                 :          12 :                                 continue;
     671                 :             :                         }
     672         [ +  - ]:          12 :                 }
     673                 :             : 
     674                 :             :                 /* failed to translate this character */
     675                 :         138 :                 utf -= l;
     676         [ +  + ]:         138 :                 if (noError)
     677                 :          69 :                         break;
     678                 :         138 :                 report_untranslatable_char(PG_UTF8, encoding,
     679                 :          69 :                                                                    (const char *) utf, len);
     680      [ -  +  + ]:         999 :         }
     681                 :             : 
     682                 :             :         /* if we broke out of loop early, must be invalid input */
     683   [ +  +  +  + ]:         309 :         if (len > 0 && !noError)
     684                 :          66 :                 report_invalid_encoding(PG_UTF8, (const char *) utf, len);
     685                 :             : 
     686                 :         243 :         *iso = '\0';
     687                 :             : 
     688                 :         486 :         return utf - start;
     689                 :         243 : }
     690                 :             : 
     691                 :             : /*
     692                 :             :  * local code ---> UTF8
     693                 :             :  *
     694                 :             :  * iso: input string in local encoding (need not be null-terminated)
     695                 :             :  * len: length of input string (in bytes)
     696                 :             :  * utf: pointer to the output area (must be large enough!)
     697                 :             :  *                (output string will be null-terminated)
     698                 :             :  * map: conversion map for single characters
     699                 :             :  * cmap: conversion map for combined characters
     700                 :             :  *                (optional, pass NULL if none)
     701                 :             :  * cmapsize: number of entries in the conversion map for combined characters
     702                 :             :  *                (optional, pass 0 if none)
     703                 :             :  * conv_func: algorithmic encoding conversion function
     704                 :             :  *                (optional, pass NULL if none)
     705                 :             :  * encoding: PG identifier for the local encoding
     706                 :             :  *
     707                 :             :  * For each character, the map is consulted first; if no match, the cmap
     708                 :             :  * (if provided) is consulted next; if still no match, the conv_func
     709                 :             :  * (if provided) is applied.  An error is raised if no match is found.
     710                 :             :  *
     711                 :             :  * See pg_wchar.h for more details about the data structures used here.
     712                 :             :  *
     713                 :             :  * Returns the number of input bytes consumed.  If noError is true, this can
     714                 :             :  * be less than 'len'.
     715                 :             :  */
     716                 :             : int
     717                 :         223 : LocalToUtf(const unsigned char *iso, int len,
     718                 :             :                    unsigned char *utf,
     719                 :             :                    const pg_mb_radix_tree *map,
     720                 :             :                    const pg_local_to_utf_combined *cmap, int cmapsize,
     721                 :             :                    utf_local_conversion_func conv_func,
     722                 :             :                    int encoding,
     723                 :             :                    bool noError)
     724                 :             : {
     725                 :         223 :         uint32          iiso;
     726                 :         223 :         int                     l;
     727                 :         223 :         const pg_local_to_utf_combined *cp;
     728                 :         223 :         const unsigned char *start = iso;
     729                 :             : 
     730         [ +  - ]:         223 :         if (!PG_VALID_ENCODING(encoding))
     731   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     732                 :             :                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     733                 :             :                                  errmsg("invalid encoding number: %d", encoding)));
     734                 :             : 
     735         [ +  + ]:        1012 :         for (; len > 0; len -= l)
     736                 :             :         {
     737                 :         927 :                 unsigned char b1 = 0;
     738                 :         927 :                 unsigned char b2 = 0;
     739                 :         927 :                 unsigned char b3 = 0;
     740                 :         927 :                 unsigned char b4 = 0;
     741                 :             : 
     742                 :             :                 /* "break" cases all represent errors */
     743         [ +  + ]:         927 :                 if (*iso == '\0')
     744                 :          54 :                         break;
     745                 :             : 
     746         [ +  + ]:         873 :                 if (!IS_HIGHBIT_SET(*iso))
     747                 :             :                 {
     748                 :             :                         /* ASCII case is easy, assume it's one-to-one conversion */
     749                 :         693 :                         *utf++ = *iso++;
     750                 :         693 :                         l = 1;
     751                 :         693 :                         continue;
     752                 :             :                 }
     753                 :             : 
     754                 :         180 :                 l = pg_encoding_verifymbchar(encoding, (const char *) iso, len);
     755         [ +  + ]:         180 :                 if (l < 0)
     756                 :          72 :                         break;
     757                 :             : 
     758                 :             :                 /* collect coded char of length l */
     759         [ +  + ]:         108 :                 if (l == 1)
     760                 :          33 :                         b4 = *iso++;
     761         [ +  + ]:          75 :                 else if (l == 2)
     762                 :             :                 {
     763                 :          60 :                         b3 = *iso++;
     764                 :          60 :                         b4 = *iso++;
     765                 :          60 :                 }
     766         [ -  + ]:          15 :                 else if (l == 3)
     767                 :             :                 {
     768                 :           0 :                         b2 = *iso++;
     769                 :           0 :                         b3 = *iso++;
     770                 :           0 :                         b4 = *iso++;
     771                 :           0 :                 }
     772         [ +  - ]:          15 :                 else if (l == 4)
     773                 :             :                 {
     774                 :          15 :                         b1 = *iso++;
     775                 :          15 :                         b2 = *iso++;
     776                 :          15 :                         b3 = *iso++;
     777                 :          15 :                         b4 = *iso++;
     778                 :          15 :                 }
     779                 :             :                 else
     780                 :             :                 {
     781   [ #  #  #  # ]:           0 :                         elog(ERROR, "unsupported character length %d", l);
     782                 :           0 :                         iiso = 0;                       /* keep compiler quiet */
     783                 :             :                 }
     784                 :         108 :                 iiso = (b1 << 24 | b2 << 16 | b3 << 8 | b4);
     785                 :             : 
     786         [ -  + ]:         108 :                 if (map)
     787                 :             :                 {
     788                 :         108 :                         uint32          converted = pg_mb_radix_conv(map, l, b1, b2, b3, b4);
     789                 :             : 
     790         [ +  + ]:         108 :                         if (converted)
     791                 :             :                         {
     792                 :          81 :                                 utf = store_coded_char(utf, converted);
     793                 :          81 :                                 continue;
     794                 :             :                         }
     795                 :             : 
     796                 :             :                         /* If there's a combined character map, try that */
     797         [ +  + ]:          27 :                         if (cmap)
     798                 :             :                         {
     799                 :           6 :                                 cp = bsearch(&iiso, cmap, cmapsize,
     800                 :             :                                                          sizeof(pg_local_to_utf_combined), compare4);
     801                 :             : 
     802         [ +  - ]:           6 :                                 if (cp)
     803                 :             :                                 {
     804                 :           6 :                                         utf = store_coded_char(utf, cp->utf1);
     805                 :           6 :                                         utf = store_coded_char(utf, cp->utf2);
     806                 :           6 :                                         continue;
     807                 :             :                                 }
     808                 :           0 :                         }
     809         [ +  + ]:         108 :                 }
     810                 :             : 
     811                 :             :                 /* if there's a conversion function, try that */
     812         [ +  + ]:          21 :                 if (conv_func)
     813                 :             :                 {
     814                 :          15 :                         uint32          converted = (*conv_func) (iiso);
     815                 :             : 
     816         [ +  + ]:          15 :                         if (converted)
     817                 :             :                         {
     818                 :           9 :                                 utf = store_coded_char(utf, converted);
     819                 :           9 :                                 continue;
     820                 :             :                         }
     821         [ +  + ]:          15 :                 }
     822                 :             : 
     823                 :             :                 /* failed to translate this character */
     824                 :          12 :                 iso -= l;
     825         [ +  + ]:          12 :                 if (noError)
     826                 :           6 :                         break;
     827                 :          12 :                 report_untranslatable_char(encoding, PG_UTF8,
     828                 :           6 :                                                                    (const char *) iso, len);
     829      [ -  +  + ]:         921 :         }
     830                 :             : 
     831                 :             :         /* if we broke out of loop early, must be invalid input */
     832   [ +  +  +  + ]:         217 :         if (len > 0 && !noError)
     833                 :          62 :                 report_invalid_encoding(encoding, (const char *) iso, len);
     834                 :             : 
     835                 :         155 :         *utf = '\0';
     836                 :             : 
     837                 :         310 :         return iso - start;
     838                 :         155 : }
        

Generated by: LCOV version 2.3.2-1