LCOV - code coverage report
Current view: top level - src/backend/utils/adt - encode.c (source / functions) Hit Total Coverage
Test: PostgreSQL 12beta2 Lines: 142 211 67.3 %
Date: 2019-06-19 14:06:47 Functions: 14 16 87.5 %
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-2019, 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 "utils/builtins.h"
      19             : 
      20             : 
      21             : struct pg_encoding
      22             : {
      23             :     unsigned    (*encode_len) (const char *data, unsigned dlen);
      24             :     unsigned    (*decode_len) (const char *data, unsigned dlen);
      25             :     unsigned    (*encode) (const char *data, unsigned dlen, char *res);
      26             :     unsigned    (*decode) (const char *data, unsigned dlen, char *res);
      27             : };
      28             : 
      29             : static const struct pg_encoding *pg_find_encoding(const char *name);
      30             : 
      31             : /*
      32             :  * SQL functions.
      33             :  */
      34             : 
      35             : Datum
      36         224 : binary_encode(PG_FUNCTION_ARGS)
      37             : {
      38         224 :     bytea      *data = PG_GETARG_BYTEA_PP(0);
      39         224 :     Datum       name = PG_GETARG_DATUM(1);
      40             :     text       *result;
      41             :     char       *namebuf;
      42             :     int         datalen,
      43             :                 resultlen,
      44             :                 res;
      45             :     const struct pg_encoding *enc;
      46             : 
      47         224 :     datalen = VARSIZE_ANY_EXHDR(data);
      48             : 
      49         224 :     namebuf = TextDatumGetCString(name);
      50             : 
      51         224 :     enc = pg_find_encoding(namebuf);
      52         224 :     if (enc == NULL)
      53           0 :         ereport(ERROR,
      54             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
      55             :                  errmsg("unrecognized encoding: \"%s\"", namebuf)));
      56             : 
      57         224 :     resultlen = enc->encode_len(VARDATA_ANY(data), datalen);
      58         224 :     result = palloc(VARHDRSZ + resultlen);
      59             : 
      60         224 :     res = enc->encode(VARDATA_ANY(data), datalen, VARDATA(result));
      61             : 
      62             :     /* Make this FATAL 'cause we've trodden on memory ... */
      63         224 :     if (res > resultlen)
      64           0 :         elog(FATAL, "overflow - encode estimate too small");
      65             : 
      66         224 :     SET_VARSIZE(result, VARHDRSZ + res);
      67             : 
      68         224 :     PG_RETURN_TEXT_P(result);
      69             : }
      70             : 
      71             : Datum
      72         178 : binary_decode(PG_FUNCTION_ARGS)
      73             : {
      74         178 :     text       *data = PG_GETARG_TEXT_PP(0);
      75         178 :     Datum       name = PG_GETARG_DATUM(1);
      76             :     bytea      *result;
      77             :     char       *namebuf;
      78             :     int         datalen,
      79             :                 resultlen,
      80             :                 res;
      81             :     const struct pg_encoding *enc;
      82             : 
      83         178 :     datalen = VARSIZE_ANY_EXHDR(data);
      84             : 
      85         178 :     namebuf = TextDatumGetCString(name);
      86             : 
      87         178 :     enc = pg_find_encoding(namebuf);
      88         178 :     if (enc == NULL)
      89           0 :         ereport(ERROR,
      90             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
      91             :                  errmsg("unrecognized encoding: \"%s\"", namebuf)));
      92             : 
      93         178 :     resultlen = enc->decode_len(VARDATA_ANY(data), datalen);
      94         178 :     result = palloc(VARHDRSZ + resultlen);
      95             : 
      96         178 :     res = enc->decode(VARDATA_ANY(data), datalen, VARDATA(result));
      97             : 
      98             :     /* Make this FATAL 'cause we've trodden on memory ... */
      99         178 :     if (res > resultlen)
     100           0 :         elog(FATAL, "overflow - decode estimate too small");
     101             : 
     102         178 :     SET_VARSIZE(result, VARHDRSZ + res);
     103             : 
     104         178 :     PG_RETURN_BYTEA_P(result);
     105             : }
     106             : 
     107             : 
     108             : /*
     109             :  * HEX
     110             :  */
     111             : 
     112             : static const char hextbl[] = "0123456789abcdef";
     113             : 
     114             : static const int8 hexlookup[128] = {
     115             :     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     116             :     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     117             :     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     118             :     0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
     119             :     -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     120             :     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     121             :     -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     122             :     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     123             : };
     124             : 
     125             : unsigned
     126        4870 : hex_encode(const char *src, unsigned len, char *dst)
     127             : {
     128        4870 :     const char *end = src + len;
     129             : 
     130       80560 :     while (src < end)
     131             :     {
     132       70820 :         *dst++ = hextbl[(*src >> 4) & 0xF];
     133       70820 :         *dst++ = hextbl[*src & 0xF];
     134       70820 :         src++;
     135             :     }
     136        4870 :     return len * 2;
     137             : }
     138             : 
     139             : static inline char
     140        6060 : get_hex(char c)
     141             : {
     142        6060 :     int         res = -1;
     143             : 
     144        6060 :     if (c > 0 && c < 127)
     145        6060 :         res = hexlookup[(unsigned char) c];
     146             : 
     147        6060 :     if (res < 0)
     148           4 :         ereport(ERROR,
     149             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     150             :                  errmsg("invalid hexadecimal digit: \"%c\"", c)));
     151             : 
     152        6056 :     return (char) res;
     153             : }
     154             : 
     155             : unsigned
     156         202 : hex_decode(const char *src, unsigned len, char *dst)
     157             : {
     158             :     const char *s,
     159             :                *srcend;
     160             :     char        v1,
     161             :                 v2,
     162             :                *p;
     163             : 
     164         202 :     srcend = src + len;
     165         202 :     s = src;
     166         202 :     p = dst;
     167        3630 :     while (s < srcend)
     168             :     {
     169        3234 :         if (*s == ' ' || *s == '\n' || *s == '\t' || *s == '\r')
     170             :         {
     171         202 :             s++;
     172         202 :             continue;
     173             :         }
     174        3032 :         v1 = get_hex(*s++) << 4;
     175        3032 :         if (s >= srcend)
     176           4 :             ereport(ERROR,
     177             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     178             :                      errmsg("invalid hexadecimal data: odd number of digits")));
     179             : 
     180        3028 :         v2 = get_hex(*s++);
     181        3024 :         *p++ = v1 | v2;
     182             :     }
     183             : 
     184         194 :     return p - dst;
     185             : }
     186             : 
     187             : static unsigned
     188         212 : hex_enc_len(const char *src, unsigned srclen)
     189             : {
     190         212 :     return srclen << 1;
     191             : }
     192             : 
     193             : static unsigned
     194         158 : hex_dec_len(const char *src, unsigned srclen)
     195             : {
     196         158 :     return srclen >> 1;
     197             : }
     198             : 
     199             : /*
     200             :  * BASE64
     201             :  */
     202             : 
     203             : static const char _base64[] =
     204             : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
     205             : 
     206             : static const int8 b64lookup[128] = {
     207             :     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     208             :     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     209             :     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
     210             :     52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
     211             :     -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
     212             :     15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
     213             :     -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
     214             :     41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
     215             : };
     216             : 
     217             : static unsigned
     218           0 : pg_base64_encode(const char *src, unsigned len, char *dst)
     219             : {
     220             :     char       *p,
     221           0 :                *lend = dst + 76;
     222             :     const char *s,
     223           0 :                *end = src + len;
     224           0 :     int         pos = 2;
     225           0 :     uint32      buf = 0;
     226             : 
     227           0 :     s = src;
     228           0 :     p = dst;
     229             : 
     230           0 :     while (s < end)
     231             :     {
     232           0 :         buf |= (unsigned char) *s << (pos << 3);
     233           0 :         pos--;
     234           0 :         s++;
     235             : 
     236             :         /* write it out */
     237           0 :         if (pos < 0)
     238             :         {
     239           0 :             *p++ = _base64[(buf >> 18) & 0x3f];
     240           0 :             *p++ = _base64[(buf >> 12) & 0x3f];
     241           0 :             *p++ = _base64[(buf >> 6) & 0x3f];
     242           0 :             *p++ = _base64[buf & 0x3f];
     243             : 
     244           0 :             pos = 2;
     245           0 :             buf = 0;
     246             :         }
     247           0 :         if (p >= lend)
     248             :         {
     249           0 :             *p++ = '\n';
     250           0 :             lend = p + 76;
     251             :         }
     252             :     }
     253           0 :     if (pos != 2)
     254             :     {
     255           0 :         *p++ = _base64[(buf >> 18) & 0x3f];
     256           0 :         *p++ = _base64[(buf >> 12) & 0x3f];
     257           0 :         *p++ = (pos == 0) ? _base64[(buf >> 6) & 0x3f] : '=';
     258           0 :         *p++ = '=';
     259             :     }
     260             : 
     261           0 :     return p - dst;
     262             : }
     263             : 
     264             : static unsigned
     265           4 : pg_base64_decode(const char *src, unsigned len, char *dst)
     266             : {
     267           4 :     const char *srcend = src + len,
     268           4 :                *s = src;
     269           4 :     char       *p = dst;
     270             :     char        c;
     271           4 :     int         b = 0;
     272           4 :     uint32      buf = 0;
     273           4 :     int         pos = 0,
     274           4 :                 end = 0;
     275             : 
     276          40 :     while (s < srcend)
     277             :     {
     278          32 :         c = *s++;
     279             : 
     280          32 :         if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
     281           0 :             continue;
     282             : 
     283          32 :         if (c == '=')
     284             :         {
     285             :             /* end sequence */
     286           4 :             if (!end)
     287             :             {
     288           4 :                 if (pos == 2)
     289           0 :                     end = 1;
     290           4 :                 else if (pos == 3)
     291           4 :                     end = 2;
     292             :                 else
     293           0 :                     ereport(ERROR,
     294             :                             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     295             :                              errmsg("unexpected \"=\" while decoding base64 sequence")));
     296             :             }
     297           4 :             b = 0;
     298             :         }
     299             :         else
     300             :         {
     301          28 :             b = -1;
     302          28 :             if (c > 0 && c < 127)
     303          28 :                 b = b64lookup[(unsigned char) c];
     304          28 :             if (b < 0)
     305           0 :                 ereport(ERROR,
     306             :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     307             :                          errmsg("invalid symbol \"%c\" while decoding base64 sequence", (int) c)));
     308             :         }
     309             :         /* add it to buffer */
     310          32 :         buf = (buf << 6) + b;
     311          32 :         pos++;
     312          32 :         if (pos == 4)
     313             :         {
     314           8 :             *p++ = (buf >> 16) & 255;
     315           8 :             if (end == 0 || end > 1)
     316           8 :                 *p++ = (buf >> 8) & 255;
     317           8 :             if (end == 0 || end > 2)
     318           4 :                 *p++ = buf & 255;
     319           8 :             buf = 0;
     320           8 :             pos = 0;
     321             :         }
     322             :     }
     323             : 
     324           4 :     if (pos != 0)
     325           0 :         ereport(ERROR,
     326             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     327             :                  errmsg("invalid base64 end sequence"),
     328             :                  errhint("Input data is missing padding, is truncated, or is otherwise corrupted.")));
     329             : 
     330           4 :     return p - dst;
     331             : }
     332             : 
     333             : 
     334             : static unsigned
     335           0 : pg_base64_enc_len(const char *src, unsigned srclen)
     336             : {
     337             :     /* 3 bytes will be converted to 4, linefeed after 76 chars */
     338           0 :     return (srclen + 2) * 4 / 3 + srclen / (76 * 3 / 4);
     339             : }
     340             : 
     341             : static unsigned
     342           4 : pg_base64_dec_len(const char *src, unsigned srclen)
     343             : {
     344           4 :     return (srclen * 3) >> 2;
     345             : }
     346             : 
     347             : /*
     348             :  * Escape
     349             :  * Minimally escape bytea to text.
     350             :  * De-escape text to bytea.
     351             :  *
     352             :  * We must escape zero bytes and high-bit-set bytes to avoid generating
     353             :  * text that might be invalid in the current encoding, or that might
     354             :  * change to something else if passed through an encoding conversion
     355             :  * (leading to failing to de-escape to the original bytea value).
     356             :  * Also of course backslash itself has to be escaped.
     357             :  *
     358             :  * De-escaping processes \\ and any \### octal
     359             :  */
     360             : 
     361             : #define VAL(CH)         ((CH) - '0')
     362             : #define DIG(VAL)        ((VAL) + '0')
     363             : 
     364             : static unsigned
     365          12 : esc_encode(const char *src, unsigned srclen, char *dst)
     366             : {
     367          12 :     const char *end = src + srclen;
     368          12 :     char       *rp = dst;
     369          12 :     int         len = 0;
     370             : 
     371         116 :     while (src < end)
     372             :     {
     373          92 :         unsigned char c = (unsigned char) *src;
     374             : 
     375          92 :         if (c == '\0' || IS_HIGHBIT_SET(c))
     376             :         {
     377           8 :             rp[0] = '\\';
     378           8 :             rp[1] = DIG(c >> 6);
     379           8 :             rp[2] = DIG((c >> 3) & 7);
     380           8 :             rp[3] = DIG(c & 7);
     381           8 :             rp += 4;
     382           8 :             len += 4;
     383             :         }
     384          84 :         else if (c == '\\')
     385             :         {
     386           0 :             rp[0] = '\\';
     387           0 :             rp[1] = '\\';
     388           0 :             rp += 2;
     389           0 :             len += 2;
     390             :         }
     391             :         else
     392             :         {
     393          84 :             *rp++ = c;
     394          84 :             len++;
     395             :         }
     396             : 
     397          92 :         src++;
     398             :     }
     399             : 
     400          12 :     return len;
     401             : }
     402             : 
     403             : static unsigned
     404          16 : esc_decode(const char *src, unsigned srclen, char *dst)
     405             : {
     406          16 :     const char *end = src + srclen;
     407          16 :     char       *rp = dst;
     408          16 :     int         len = 0;
     409             : 
     410     1600032 :     while (src < end)
     411             :     {
     412     1600000 :         if (src[0] != '\\')
     413     1600000 :             *rp++ = *src++;
     414           0 :         else if (src + 3 < end &&
     415           0 :                  (src[1] >= '0' && src[1] <= '3') &&
     416           0 :                  (src[2] >= '0' && src[2] <= '7') &&
     417           0 :                  (src[3] >= '0' && src[3] <= '7'))
     418           0 :         {
     419             :             int         val;
     420             : 
     421           0 :             val = VAL(src[1]);
     422           0 :             val <<= 3;
     423           0 :             val += VAL(src[2]);
     424           0 :             val <<= 3;
     425           0 :             *rp++ = val + VAL(src[3]);
     426           0 :             src += 4;
     427             :         }
     428           0 :         else if (src + 1 < end &&
     429           0 :                  (src[1] == '\\'))
     430             :         {
     431           0 :             *rp++ = '\\';
     432           0 :             src += 2;
     433             :         }
     434             :         else
     435             :         {
     436             :             /*
     437             :              * One backslash, not followed by ### valid octal. Should never
     438             :              * get here, since esc_dec_len does same check.
     439             :              */
     440           0 :             ereport(ERROR,
     441             :                     (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     442             :                      errmsg("invalid input syntax for type %s", "bytea")));
     443             :         }
     444             : 
     445     1600000 :         len++;
     446             :     }
     447             : 
     448          16 :     return len;
     449             : }
     450             : 
     451             : static unsigned
     452          12 : esc_enc_len(const char *src, unsigned srclen)
     453             : {
     454          12 :     const char *end = src + srclen;
     455          12 :     int         len = 0;
     456             : 
     457         116 :     while (src < end)
     458             :     {
     459          92 :         if (*src == '\0' || IS_HIGHBIT_SET(*src))
     460           8 :             len += 4;
     461          84 :         else if (*src == '\\')
     462           0 :             len += 2;
     463             :         else
     464          84 :             len++;
     465             : 
     466          92 :         src++;
     467             :     }
     468             : 
     469          12 :     return len;
     470             : }
     471             : 
     472             : static unsigned
     473          16 : esc_dec_len(const char *src, unsigned srclen)
     474             : {
     475          16 :     const char *end = src + srclen;
     476          16 :     int         len = 0;
     477             : 
     478     1600032 :     while (src < end)
     479             :     {
     480     1600000 :         if (src[0] != '\\')
     481     1600000 :             src++;
     482           0 :         else if (src + 3 < end &&
     483           0 :                  (src[1] >= '0' && src[1] <= '3') &&
     484           0 :                  (src[2] >= '0' && src[2] <= '7') &&
     485           0 :                  (src[3] >= '0' && src[3] <= '7'))
     486             :         {
     487             :             /*
     488             :              * backslash + valid octal
     489             :              */
     490           0 :             src += 4;
     491             :         }
     492           0 :         else if (src + 1 < end &&
     493           0 :                  (src[1] == '\\'))
     494             :         {
     495             :             /*
     496             :              * two backslashes = backslash
     497             :              */
     498           0 :             src += 2;
     499             :         }
     500             :         else
     501             :         {
     502             :             /*
     503             :              * one backslash, not followed by ### valid octal
     504             :              */
     505           0 :             ereport(ERROR,
     506             :                     (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     507             :                      errmsg("invalid input syntax for type %s", "bytea")));
     508             :         }
     509             : 
     510     1600000 :         len++;
     511             :     }
     512          16 :     return len;
     513             : }
     514             : 
     515             : /*
     516             :  * Common
     517             :  */
     518             : 
     519             : static const struct
     520             : {
     521             :     const char *name;
     522             :     struct pg_encoding enc;
     523             : }           enclist[] =
     524             : 
     525             : {
     526             :     {
     527             :         "hex",
     528             :         {
     529             :             hex_enc_len, hex_dec_len, hex_encode, hex_decode
     530             :         }
     531             :     },
     532             :     {
     533             :         "base64",
     534             :         {
     535             :             pg_base64_enc_len, pg_base64_dec_len, pg_base64_encode, pg_base64_decode
     536             :         }
     537             :     },
     538             :     {
     539             :         "escape",
     540             :         {
     541             :             esc_enc_len, esc_dec_len, esc_encode, esc_decode
     542             :         }
     543             :     },
     544             :     {
     545             :         NULL,
     546             :         {
     547             :             NULL, NULL, NULL, NULL
     548             :         }
     549             :     }
     550             : };
     551             : 
     552             : static const struct pg_encoding *
     553         402 : pg_find_encoding(const char *name)
     554             : {
     555             :     int         i;
     556             : 
     557         462 :     for (i = 0; enclist[i].name; i++)
     558         462 :         if (pg_strcasecmp(enclist[i].name, name) == 0)
     559         402 :             return &enclist[i].enc;
     560             : 
     561           0 :     return NULL;
     562             : }

Generated by: LCOV version 1.13