LCOV - code coverage report
Current view: top level - src/backend/utils/adt - encode.c (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 239 257 93.0 %
Date: 2025-10-02 06:18:21 Functions: 23 23 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * encode.c
       4             :  *    Various data encoding/decoding things.
       5             :  *
       6             :  * Copyright (c) 2001-2025, PostgreSQL Global Development Group
       7             :  *
       8             :  *
       9             :  * IDENTIFICATION
      10             :  *    src/backend/utils/adt/encode.c
      11             :  *
      12             :  *-------------------------------------------------------------------------
      13             :  */
      14             : #include "postgres.h"
      15             : 
      16             : #include <ctype.h>
      17             : 
      18             : #include "mb/pg_wchar.h"
      19             : #include "utils/builtins.h"
      20             : #include "utils/memutils.h"
      21             : #include "varatt.h"
      22             : 
      23             : 
      24             : /*
      25             :  * Encoding conversion API.
      26             :  * encode_len() and decode_len() compute the amount of space needed, while
      27             :  * encode() and decode() perform the actual conversions.  It is okay for
      28             :  * the _len functions to return an overestimate, but not an underestimate.
      29             :  * (Having said that, large overestimates could cause unnecessary errors,
      30             :  * so it's better to get it right.)  The conversion routines write to the
      31             :  * buffer at *res and return the true length of their output.
      32             :  */
      33             : struct pg_encoding
      34             : {
      35             :     uint64      (*encode_len) (const char *data, size_t dlen);
      36             :     uint64      (*decode_len) (const char *data, size_t dlen);
      37             :     uint64      (*encode) (const char *data, size_t dlen, char *res);
      38             :     uint64      (*decode) (const char *data, size_t dlen, char *res);
      39             : };
      40             : 
      41             : static const struct pg_encoding *pg_find_encoding(const char *name);
      42             : 
      43             : /*
      44             :  * SQL functions.
      45             :  */
      46             : 
      47             : Datum
      48      526232 : binary_encode(PG_FUNCTION_ARGS)
      49             : {
      50      526232 :     bytea      *data = PG_GETARG_BYTEA_PP(0);
      51      526232 :     Datum       name = PG_GETARG_DATUM(1);
      52             :     text       *result;
      53             :     char       *namebuf;
      54             :     char       *dataptr;
      55             :     size_t      datalen;
      56             :     uint64      resultlen;
      57             :     uint64      res;
      58             :     const struct pg_encoding *enc;
      59             : 
      60      526232 :     namebuf = TextDatumGetCString(name);
      61             : 
      62      526232 :     enc = pg_find_encoding(namebuf);
      63      526232 :     if (enc == NULL)
      64           0 :         ereport(ERROR,
      65             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
      66             :                  errmsg("unrecognized encoding: \"%s\"", namebuf)));
      67             : 
      68      526232 :     dataptr = VARDATA_ANY(data);
      69      526232 :     datalen = VARSIZE_ANY_EXHDR(data);
      70             : 
      71      526232 :     resultlen = enc->encode_len(dataptr, datalen);
      72             : 
      73             :     /*
      74             :      * resultlen possibly overflows uint32, therefore on 32-bit machines it's
      75             :      * unsafe to rely on palloc's internal check.
      76             :      */
      77      526232 :     if (resultlen > MaxAllocSize - VARHDRSZ)
      78           0 :         ereport(ERROR,
      79             :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
      80             :                  errmsg("result of encoding conversion is too large")));
      81             : 
      82      526232 :     result = palloc(VARHDRSZ + resultlen);
      83             : 
      84      526232 :     res = enc->encode(dataptr, datalen, VARDATA(result));
      85             : 
      86             :     /* Make this FATAL 'cause we've trodden on memory ... */
      87      526232 :     if (res > resultlen)
      88           0 :         elog(FATAL, "overflow - encode estimate too small");
      89             : 
      90      526232 :     SET_VARSIZE(result, VARHDRSZ + res);
      91             : 
      92      526232 :     PG_RETURN_TEXT_P(result);
      93             : }
      94             : 
      95             : Datum
      96       32972 : binary_decode(PG_FUNCTION_ARGS)
      97             : {
      98       32972 :     text       *data = PG_GETARG_TEXT_PP(0);
      99       32972 :     Datum       name = PG_GETARG_DATUM(1);
     100             :     bytea      *result;
     101             :     char       *namebuf;
     102             :     char       *dataptr;
     103             :     size_t      datalen;
     104             :     uint64      resultlen;
     105             :     uint64      res;
     106             :     const struct pg_encoding *enc;
     107             : 
     108       32972 :     namebuf = TextDatumGetCString(name);
     109             : 
     110       32972 :     enc = pg_find_encoding(namebuf);
     111       32972 :     if (enc == NULL)
     112           0 :         ereport(ERROR,
     113             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     114             :                  errmsg("unrecognized encoding: \"%s\"", namebuf)));
     115             : 
     116       32972 :     dataptr = VARDATA_ANY(data);
     117       32972 :     datalen = VARSIZE_ANY_EXHDR(data);
     118             : 
     119       32972 :     resultlen = enc->decode_len(dataptr, datalen);
     120             : 
     121             :     /*
     122             :      * resultlen possibly overflows uint32, therefore on 32-bit machines it's
     123             :      * unsafe to rely on palloc's internal check.
     124             :      */
     125       32972 :     if (resultlen > MaxAllocSize - VARHDRSZ)
     126           0 :         ereport(ERROR,
     127             :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     128             :                  errmsg("result of decoding conversion is too large")));
     129             : 
     130       32972 :     result = palloc(VARHDRSZ + resultlen);
     131             : 
     132       32972 :     res = enc->decode(dataptr, datalen, VARDATA(result));
     133             : 
     134             :     /* Make this FATAL 'cause we've trodden on memory ... */
     135       32954 :     if (res > resultlen)
     136           0 :         elog(FATAL, "overflow - decode estimate too small");
     137             : 
     138       32954 :     SET_VARSIZE(result, VARHDRSZ + res);
     139             : 
     140       32954 :     PG_RETURN_BYTEA_P(result);
     141             : }
     142             : 
     143             : 
     144             : /*
     145             :  * HEX
     146             :  */
     147             : 
     148             : /*
     149             :  * The hex expansion of each possible byte value (two chars per value).
     150             :  */
     151             : static const char hextbl[512] =
     152             : "000102030405060708090a0b0c0d0e0f"
     153             : "101112131415161718191a1b1c1d1e1f"
     154             : "202122232425262728292a2b2c2d2e2f"
     155             : "303132333435363738393a3b3c3d3e3f"
     156             : "404142434445464748494a4b4c4d4e4f"
     157             : "505152535455565758595a5b5c5d5e5f"
     158             : "606162636465666768696a6b6c6d6e6f"
     159             : "707172737475767778797a7b7c7d7e7f"
     160             : "808182838485868788898a8b8c8d8e8f"
     161             : "909192939495969798999a9b9c9d9e9f"
     162             : "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
     163             : "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
     164             : "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
     165             : "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
     166             : "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
     167             : "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";
     168             : 
     169             : static const int8 hexlookup[128] = {
     170             :     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     171             :     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     172             :     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     173             :     0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
     174             :     -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     175             :     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     176             :     -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     177             :     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     178             : };
     179             : 
     180             : uint64
     181     1391308 : hex_encode(const char *src, size_t len, char *dst)
     182             : {
     183     1391308 :     const char *end = src + len;
     184             : 
     185    37754898 :     while (src < end)
     186             :     {
     187    36363590 :         unsigned char usrc = *((const unsigned char *) src);
     188             : 
     189    36363590 :         memcpy(dst, &hextbl[2 * usrc], 2);
     190    36363590 :         src++;
     191    36363590 :         dst += 2;
     192             :     }
     193     1391308 :     return (uint64) len * 2;
     194             : }
     195             : 
     196             : static inline bool
     197     7929046 : get_hex(const char *cp, char *out)
     198             : {
     199     7929046 :     unsigned char c = (unsigned char) *cp;
     200     7929046 :     int         res = -1;
     201             : 
     202     7929046 :     if (c < 127)
     203     7929046 :         res = hexlookup[c];
     204             : 
     205     7929046 :     *out = (char) res;
     206             : 
     207     7929046 :     return (res >= 0);
     208             : }
     209             : 
     210             : uint64
     211       32824 : hex_decode(const char *src, size_t len, char *dst)
     212             : {
     213       32824 :     return hex_decode_safe(src, len, dst, NULL);
     214             : }
     215             : 
     216             : uint64
     217      144420 : hex_decode_safe(const char *src, size_t len, char *dst, Node *escontext)
     218             : {
     219             :     const char *s,
     220             :                *srcend;
     221             :     char        v1,
     222             :                 v2,
     223             :                *p;
     224             : 
     225      144420 :     srcend = src + len;
     226      144420 :     s = src;
     227      144420 :     p = dst;
     228     4108982 :     while (s < srcend)
     229             :     {
     230     3964592 :         if (*s == ' ' || *s == '\n' || *s == '\t' || *s == '\r')
     231             :         {
     232          60 :             s++;
     233          60 :             continue;
     234             :         }
     235     3964532 :         if (!get_hex(s, &v1))
     236           0 :             ereturn(escontext, 0,
     237             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     238             :                      errmsg("invalid hexadecimal digit: \"%.*s\"",
     239             :                             pg_mblen(s), s)));
     240     3964532 :         s++;
     241     3964532 :         if (s >= srcend)
     242          18 :             ereturn(escontext, 0,
     243             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     244             :                      errmsg("invalid hexadecimal data: odd number of digits")));
     245     3964514 :         if (!get_hex(s, &v2))
     246          12 :             ereturn(escontext, 0,
     247             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     248             :                      errmsg("invalid hexadecimal digit: \"%.*s\"",
     249             :                             pg_mblen(s), s)));
     250     3964502 :         s++;
     251     3964502 :         *p++ = (v1 << 4) | v2;
     252             :     }
     253             : 
     254      144390 :     return p - dst;
     255             : }
     256             : 
     257             : static uint64
     258      526050 : hex_enc_len(const char *src, size_t srclen)
     259             : {
     260      526050 :     return (uint64) srclen << 1;
     261             : }
     262             : 
     263             : static uint64
     264       32824 : hex_dec_len(const char *src, size_t srclen)
     265             : {
     266       32824 :     return (uint64) srclen >> 1;
     267             : }
     268             : 
     269             : /*
     270             :  * BASE64 and BASE64URL
     271             :  */
     272             : 
     273             : static const char _base64[] =
     274             : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
     275             : 
     276             : static const char _base64url[] =
     277             : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
     278             : 
     279             : static const int8 b64lookup[128] = {
     280             :     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     281             :     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     282             :     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
     283             :     52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
     284             :     -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
     285             :     15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
     286             :     -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
     287             :     41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
     288             : };
     289             : 
     290             : /*
     291             :  * pg_base64_encode_internal
     292             :  *
     293             :  * Helper for decoding base64 or base64url.  When url is passed as true the
     294             :  * input will be encoded using base64url.  len bytes in src is encoded into
     295             :  * dst.
     296             :  */
     297             : static uint64
     298         114 : pg_base64_encode_internal(const char *src, size_t len, char *dst, bool url)
     299             : {
     300             :     char       *p,
     301         114 :                *lend = dst + 76;
     302             :     const char *s,
     303         114 :                *end = src + len;
     304         114 :     int         pos = 2;
     305         114 :     uint32      buf = 0;
     306         114 :     const char *alphabet = url ? _base64url : _base64;
     307             : 
     308         114 :     s = src;
     309         114 :     p = dst;
     310             : 
     311        1212 :     while (s < end)
     312             :     {
     313        1098 :         buf |= (unsigned char) *s << (pos << 3);
     314        1098 :         pos--;
     315        1098 :         s++;
     316             : 
     317             :         /* write it out */
     318        1098 :         if (pos < 0)
     319             :         {
     320         336 :             *p++ = alphabet[(buf >> 18) & 0x3f];
     321         336 :             *p++ = alphabet[(buf >> 12) & 0x3f];
     322         336 :             *p++ = alphabet[(buf >> 6) & 0x3f];
     323         336 :             *p++ = alphabet[buf & 0x3f];
     324             : 
     325         336 :             pos = 2;
     326         336 :             buf = 0;
     327             : 
     328         336 :             if (!url && p >= lend)
     329             :             {
     330          12 :                 *p++ = '\n';
     331          12 :                 lend = p + 76;
     332             :             }
     333             :         }
     334             :     }
     335             : 
     336             :     /* Handle remaining bytes in buf */
     337         114 :     if (pos != 2)
     338             :     {
     339          72 :         *p++ = alphabet[(buf >> 18) & 0x3f];
     340          72 :         *p++ = alphabet[(buf >> 12) & 0x3f];
     341             : 
     342          72 :         if (pos == 0)
     343             :         {
     344          18 :             *p++ = alphabet[(buf >> 6) & 0x3f];
     345          18 :             if (!url)
     346           0 :                 *p++ = '=';
     347             :         }
     348          54 :         else if (!url)
     349             :         {
     350          12 :             *p++ = '=';
     351          12 :             *p++ = '=';
     352             :         }
     353             :     }
     354             : 
     355         114 :     return p - dst;
     356             : }
     357             : 
     358             : static uint64
     359          12 : pg_base64_encode(const char *src, size_t len, char *dst)
     360             : {
     361          12 :     return pg_base64_encode_internal(src, len, dst, false);
     362             : }
     363             : 
     364             : static uint64
     365         102 : pg_base64url_encode(const char *src, size_t len, char *dst)
     366             : {
     367         102 :     return pg_base64_encode_internal(src, len, dst, true);
     368             : }
     369             : 
     370             : /*
     371             :  * pg_base64_decode_internal
     372             :  *
     373             :  * Helper for decoding base64 or base64url. When url is passed as true the
     374             :  * input will be assumed to be encoded using base64url.
     375             :  */
     376             : static uint64
     377         118 : pg_base64_decode_internal(const char *src, size_t len, char *dst, bool url)
     378             : {
     379         118 :     const char *srcend = src + len,
     380         118 :                *s = src;
     381         118 :     char       *p = dst;
     382             :     char        c;
     383         118 :     int         b = 0;
     384         118 :     uint32      buf = 0;
     385         118 :     int         pos = 0,
     386         118 :                 end = 0;
     387             : 
     388        1140 :     while (s < srcend)
     389             :     {
     390        1034 :         c = *s++;
     391             : 
     392        1034 :         if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
     393           6 :             continue;
     394             : 
     395             :         /* convert base64url to base64 */
     396        1028 :         if (url)
     397             :         {
     398         420 :             if (c == '-')
     399          18 :                 c = '+';
     400         402 :             else if (c == '_')
     401          12 :                 c = '/';
     402             :         }
     403             : 
     404        1028 :         if (c == '=')
     405             :         {
     406             :             /* end sequence */
     407          34 :             if (!end)
     408             :             {
     409          22 :                 if (pos == 2)
     410          12 :                     end = 1;
     411          10 :                 else if (pos == 3)
     412           4 :                     end = 2;
     413             :                 else
     414             :                 {
     415             :                     /* translator: %s is the name of an encoding scheme */
     416           6 :                     ereport(ERROR,
     417             :                             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     418             :                              errmsg("unexpected \"=\" while decoding %s sequence", url ? "base64url" : "base64")));
     419             :                 }
     420             :             }
     421          28 :             b = 0;
     422             :         }
     423             :         else
     424             :         {
     425         994 :             b = -1;
     426         994 :             if (c > 0 && c < 127)
     427         994 :                 b = b64lookup[(unsigned char) c];
     428         994 :             if (b < 0)
     429             :             {
     430             :                 /* translator: %s is the name of an encoding scheme */
     431           6 :                 ereport(ERROR,
     432             :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     433             :                          errmsg("invalid symbol \"%.*s\" found while decoding %s sequence",
     434             :                                 pg_mblen(s - 1), s - 1,
     435             :                                 url ? "base64url" : "base64")));
     436             :             }
     437             :         }
     438             :         /* add it to buffer */
     439        1016 :         buf = (buf << 6) + b;
     440        1016 :         pos++;
     441        1016 :         if (pos == 4)
     442             :         {
     443         218 :             *p++ = (buf >> 16) & 255;
     444         218 :             if (end == 0 || end > 1)
     445         206 :                 *p++ = (buf >> 8) & 255;
     446         218 :             if (end == 0 || end > 2)
     447         202 :                 *p++ = buf & 255;
     448         218 :             buf = 0;
     449         218 :             pos = 0;
     450             :         }
     451             :     }
     452             : 
     453         106 :     if (pos == 2)
     454             :     {
     455          36 :         buf <<= 12;
     456          36 :         *p++ = (buf >> 16) & 0xFF;
     457             :     }
     458          70 :     else if (pos == 3)
     459             :     {
     460          18 :         buf <<= 6;
     461          18 :         *p++ = (buf >> 16) & 0xFF;
     462          18 :         *p++ = (buf >> 8) & 0xFF;
     463             :     }
     464          52 :     else if (pos != 0)
     465             :     {
     466             :         /* translator: %s is the name of an encoding scheme */
     467           6 :         ereport(ERROR,
     468             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     469             :                  errmsg("invalid %s end sequence", url ? "base64url" : "base64"),
     470             :                  errhint("Input data is missing padding, is truncated, or is otherwise corrupted.")));
     471             :     }
     472             : 
     473         100 :     return p - dst;
     474             : }
     475             : 
     476             : static uint64
     477          10 : pg_base64_decode(const char *src, size_t len, char *dst)
     478             : {
     479          10 :     return pg_base64_decode_internal(src, len, dst, false);
     480             : }
     481             : 
     482             : static uint64
     483         108 : pg_base64url_decode(const char *src, size_t len, char *dst)
     484             : {
     485         108 :     return pg_base64_decode_internal(src, len, dst, true);
     486             : }
     487             : 
     488             : static uint64
     489          12 : pg_base64_enc_len(const char *src, size_t srclen)
     490             : {
     491             :     /* 3 bytes will be converted to 4, linefeed after 76 chars */
     492          12 :     return ((uint64) srclen + 2) / 3 * 4 + (uint64) srclen / (76 * 3 / 4);
     493             : }
     494             : 
     495             : static uint64
     496          10 : pg_base64_dec_len(const char *src, size_t srclen)
     497             : {
     498          10 :     return ((uint64) srclen * 3) >> 2;
     499             : }
     500             : 
     501             : static uint64
     502         102 : pg_base64url_enc_len(const char *src, size_t srclen)
     503             : {
     504             :     /*
     505             :      * Unlike standard base64, base64url doesn't use padding characters when
     506             :      * the input length is not divisible by 3
     507             :      */
     508         102 :     return (srclen + 2) / 3 * 4;
     509             : }
     510             : 
     511             : static uint64
     512         108 : pg_base64url_dec_len(const char *src, size_t srclen)
     513             : {
     514             :     /*
     515             :      * For base64, each 4 characters of input produce at most 3 bytes of
     516             :      * output.  For base64url without padding, we need to round up to the
     517             :      * nearest 4
     518             :      */
     519         108 :     size_t      adjusted_len = srclen;
     520             : 
     521         108 :     if (srclen % 4 != 0)
     522          60 :         adjusted_len += 4 - (srclen % 4);
     523             : 
     524         108 :     return (adjusted_len * 3) / 4;
     525             : }
     526             : 
     527             : /*
     528             :  * Escape
     529             :  * Minimally escape bytea to text.
     530             :  * De-escape text to bytea.
     531             :  *
     532             :  * We must escape zero bytes and high-bit-set bytes to avoid generating
     533             :  * text that might be invalid in the current encoding, or that might
     534             :  * change to something else if passed through an encoding conversion
     535             :  * (leading to failing to de-escape to the original bytea value).
     536             :  * Also of course backslash itself has to be escaped.
     537             :  *
     538             :  * De-escaping processes \\ and any \### octal
     539             :  */
     540             : 
     541             : #define VAL(CH)         ((CH) - '0')
     542             : #define DIG(VAL)        ((VAL) + '0')
     543             : 
     544             : static uint64
     545          68 : esc_encode(const char *src, size_t srclen, char *dst)
     546             : {
     547          68 :     const char *end = src + srclen;
     548          68 :     char       *rp = dst;
     549          68 :     uint64      len = 0;
     550             : 
     551         656 :     while (src < end)
     552             :     {
     553         588 :         unsigned char c = (unsigned char) *src;
     554             : 
     555         588 :         if (c == '\0' || IS_HIGHBIT_SET(c))
     556             :         {
     557          90 :             rp[0] = '\\';
     558          90 :             rp[1] = DIG(c >> 6);
     559          90 :             rp[2] = DIG((c >> 3) & 7);
     560          90 :             rp[3] = DIG(c & 7);
     561          90 :             rp += 4;
     562          90 :             len += 4;
     563             :         }
     564         498 :         else if (c == '\\')
     565             :         {
     566           2 :             rp[0] = '\\';
     567           2 :             rp[1] = '\\';
     568           2 :             rp += 2;
     569           2 :             len += 2;
     570             :         }
     571             :         else
     572             :         {
     573         496 :             *rp++ = c;
     574         496 :             len++;
     575             :         }
     576             : 
     577         588 :         src++;
     578             :     }
     579             : 
     580          68 :     return len;
     581             : }
     582             : 
     583             : static uint64
     584          30 : esc_decode(const char *src, size_t srclen, char *dst)
     585             : {
     586          30 :     const char *end = src + srclen;
     587          30 :     char       *rp = dst;
     588          30 :     uint64      len = 0;
     589             : 
     590     2400084 :     while (src < end)
     591             :     {
     592     2400054 :         if (src[0] != '\\')
     593     2400024 :             *rp++ = *src++;
     594          30 :         else if (src + 3 < end &&
     595          30 :                  (src[1] >= '0' && src[1] <= '3') &&
     596          30 :                  (src[2] >= '0' && src[2] <= '7') &&
     597          30 :                  (src[3] >= '0' && src[3] <= '7'))
     598          30 :         {
     599             :             int         val;
     600             : 
     601          30 :             val = VAL(src[1]);
     602          30 :             val <<= 3;
     603          30 :             val += VAL(src[2]);
     604          30 :             val <<= 3;
     605          30 :             *rp++ = val + VAL(src[3]);
     606          30 :             src += 4;
     607             :         }
     608           0 :         else if (src + 1 < end &&
     609           0 :                  (src[1] == '\\'))
     610             :         {
     611           0 :             *rp++ = '\\';
     612           0 :             src += 2;
     613             :         }
     614             :         else
     615             :         {
     616             :             /*
     617             :              * One backslash, not followed by ### valid octal. Should never
     618             :              * get here, since esc_dec_len does same check.
     619             :              */
     620           0 :             ereport(ERROR,
     621             :                     (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     622             :                      errmsg("invalid input syntax for type %s", "bytea")));
     623             :         }
     624             : 
     625     2400054 :         len++;
     626             :     }
     627             : 
     628          30 :     return len;
     629             : }
     630             : 
     631             : static uint64
     632          68 : esc_enc_len(const char *src, size_t srclen)
     633             : {
     634          68 :     const char *end = src + srclen;
     635          68 :     uint64      len = 0;
     636             : 
     637         656 :     while (src < end)
     638             :     {
     639         588 :         if (*src == '\0' || IS_HIGHBIT_SET(*src))
     640          90 :             len += 4;
     641         498 :         else if (*src == '\\')
     642           2 :             len += 2;
     643             :         else
     644         496 :             len++;
     645             : 
     646         588 :         src++;
     647             :     }
     648             : 
     649          68 :     return len;
     650             : }
     651             : 
     652             : static uint64
     653          30 : esc_dec_len(const char *src, size_t srclen)
     654             : {
     655          30 :     const char *end = src + srclen;
     656          30 :     uint64      len = 0;
     657             : 
     658     2400084 :     while (src < end)
     659             :     {
     660     2400054 :         if (src[0] != '\\')
     661     2400024 :             src++;
     662          30 :         else if (src + 3 < end &&
     663          30 :                  (src[1] >= '0' && src[1] <= '3') &&
     664          30 :                  (src[2] >= '0' && src[2] <= '7') &&
     665          30 :                  (src[3] >= '0' && src[3] <= '7'))
     666             :         {
     667             :             /*
     668             :              * backslash + valid octal
     669             :              */
     670          30 :             src += 4;
     671             :         }
     672           0 :         else if (src + 1 < end &&
     673           0 :                  (src[1] == '\\'))
     674             :         {
     675             :             /*
     676             :              * two backslashes = backslash
     677             :              */
     678           0 :             src += 2;
     679             :         }
     680             :         else
     681             :         {
     682             :             /*
     683             :              * one backslash, not followed by ### valid octal
     684             :              */
     685           0 :             ereport(ERROR,
     686             :                     (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     687             :                      errmsg("invalid input syntax for type %s", "bytea")));
     688             :         }
     689             : 
     690     2400054 :         len++;
     691             :     }
     692          30 :     return len;
     693             : }
     694             : 
     695             : /*
     696             :  * Common
     697             :  */
     698             : 
     699             : static const struct
     700             : {
     701             :     const char *name;
     702             :     struct pg_encoding enc;
     703             : }           enclist[] =
     704             : 
     705             : {
     706             :     {
     707             :         "hex",
     708             :         {
     709             :             hex_enc_len, hex_dec_len, hex_encode, hex_decode
     710             :         }
     711             :     },
     712             :     {
     713             :         "base64",
     714             :         {
     715             :             pg_base64_enc_len, pg_base64_dec_len, pg_base64_encode, pg_base64_decode
     716             :         }
     717             :     },
     718             :     {
     719             :         "base64url",
     720             :         {
     721             :             pg_base64url_enc_len, pg_base64url_dec_len, pg_base64url_encode, pg_base64url_decode
     722             :         }
     723             :     },
     724             :     {
     725             :         "escape",
     726             :         {
     727             :             esc_enc_len, esc_dec_len, esc_encode, esc_decode
     728             :         }
     729             :     },
     730             :     {
     731             :         NULL,
     732             :         {
     733             :             NULL, NULL, NULL, NULL
     734             :         }
     735             :     }
     736             : };
     737             : 
     738             : static const struct pg_encoding *
     739      559204 : pg_find_encoding(const char *name)
     740             : {
     741             :     int         i;
     742             : 
     743      559940 :     for (i = 0; enclist[i].name; i++)
     744      559940 :         if (pg_strcasecmp(enclist[i].name, name) == 0)
     745      559204 :             return &enclist[i].enc;
     746             : 
     747           0 :     return NULL;
     748             : }

Generated by: LCOV version 1.16