Age Owner Branch data TLA 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
8822 bruce@momjian.us 48 :CBC 262665 : binary_encode(PG_FUNCTION_ARGS)
49 : : {
3100 noah@leadboat.com 50 : 262665 : bytea *data = PG_GETARG_BYTEA_PP(0);
8822 bruce@momjian.us 51 : 262665 : 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 : :
6374 tgl@sss.pgh.pa.us 60 : 262665 : namebuf = TextDatumGetCString(name);
61 : :
8822 bruce@momjian.us 62 : 262665 : enc = pg_find_encoding(namebuf);
63 [ - + ]: 262665 : if (enc == NULL)
8077 tgl@sss.pgh.pa.us 64 [ # # ]:UBC 0 : ereport(ERROR,
65 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
66 : : errmsg("unrecognized encoding: \"%s\"", namebuf)));
67 : :
1978 tgl@sss.pgh.pa.us 68 [ - + ]:CBC 262665 : dataptr = VARDATA_ANY(data);
69 [ - + - - : 262665 : datalen = VARSIZE_ANY_EXHDR(data);
- - - - -
+ ]
70 : :
71 : 262665 : 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 [ - + ]: 262665 : if (resultlen > MaxAllocSize - VARHDRSZ)
1978 tgl@sss.pgh.pa.us 78 [ # # ]:UBC 0 : ereport(ERROR,
79 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
80 : : errmsg("result of encoding conversion is too large")));
81 : :
8822 bruce@momjian.us 82 :CBC 262665 : result = palloc(VARHDRSZ + resultlen);
83 : :
1479 michael@paquier.xyz 84 : 262665 : res = enc->encode(dataptr, datalen, VARDATA(result));
85 : :
86 : : /* Make this FATAL 'cause we've trodden on memory ... */
87 [ - + ]: 262665 : if (res > resultlen)
1479 michael@paquier.xyz 88 [ # # ]:UBC 0 : elog(FATAL, "overflow - encode estimate too small");
89 : :
6766 tgl@sss.pgh.pa.us 90 :CBC 262665 : SET_VARSIZE(result, VARHDRSZ + res);
91 : :
8822 bruce@momjian.us 92 : 262665 : PG_RETURN_TEXT_P(result);
93 : : }
94 : :
95 : : Datum
96 : 16432 : binary_decode(PG_FUNCTION_ARGS)
97 : : {
3100 noah@leadboat.com 98 : 16432 : text *data = PG_GETARG_TEXT_PP(0);
8822 bruce@momjian.us 99 : 16432 : 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 : :
6374 tgl@sss.pgh.pa.us 108 : 16432 : namebuf = TextDatumGetCString(name);
109 : :
8822 bruce@momjian.us 110 : 16432 : enc = pg_find_encoding(namebuf);
111 [ - + ]: 16432 : if (enc == NULL)
8077 tgl@sss.pgh.pa.us 112 [ # # ]:UBC 0 : ereport(ERROR,
113 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
114 : : errmsg("unrecognized encoding: \"%s\"", namebuf)));
115 : :
1978 tgl@sss.pgh.pa.us 116 [ - + ]:CBC 16432 : dataptr = VARDATA_ANY(data);
117 [ - + - - : 16432 : datalen = VARSIZE_ANY_EXHDR(data);
- - - - -
+ ]
118 : :
119 : 16432 : 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 [ - + ]: 16432 : if (resultlen > MaxAllocSize - VARHDRSZ)
1978 tgl@sss.pgh.pa.us 126 [ # # ]:UBC 0 : ereport(ERROR,
127 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
128 : : errmsg("result of decoding conversion is too large")));
129 : :
8822 bruce@momjian.us 130 :CBC 16432 : result = palloc(VARHDRSZ + resultlen);
131 : :
1479 michael@paquier.xyz 132 : 16432 : res = enc->decode(dataptr, datalen, VARDATA(result));
133 : :
134 : : /* Make this FATAL 'cause we've trodden on memory ... */
135 [ - + ]: 16432 : if (res > resultlen)
1479 michael@paquier.xyz 136 [ # # ]:UBC 0 : elog(FATAL, "overflow - decode estimate too small");
137 : :
6766 tgl@sss.pgh.pa.us 138 :CBC 16432 : SET_VARSIZE(result, VARHDRSZ + res);
139 : :
8822 bruce@momjian.us 140 : 16432 : 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
1479 michael@paquier.xyz 181 : 700166 : hex_encode(const char *src, size_t len, char *dst)
182 : : {
183 : 700166 : const char *end = src + len;
184 : :
185 [ + + ]: 18899182 : while (src < end)
186 : : {
234 john.naylor@postgres 187 : 18199016 : unsigned char usrc = *((const unsigned char *) src);
188 : :
189 : 18199016 : memcpy(dst, &hextbl[2 * usrc], 2);
1479 michael@paquier.xyz 190 : 18199016 : src++;
234 john.naylor@postgres 191 : 18199016 : dst += 2;
192 : : }
1479 michael@paquier.xyz 193 : 700166 : return (uint64) len * 2;
194 : : }
195 : :
196 : : static inline bool
997 tgl@sss.pgh.pa.us 197 : 3974837 : get_hex(const char *cp, char *out)
198 : : {
1479 michael@paquier.xyz 199 : 3974837 : unsigned char c = (unsigned char) *cp;
200 : 3974837 : int res = -1;
201 : :
202 [ + - ]: 3974837 : if (c < 127)
203 : 3974837 : res = hexlookup[c];
204 : :
997 tgl@sss.pgh.pa.us 205 : 3974837 : *out = (char) res;
206 : :
207 : 3974837 : return (res >= 0);
208 : : }
209 : :
210 : : uint64
1479 michael@paquier.xyz 211 : 16412 : hex_decode(const char *src, size_t len, char *dst)
212 : : {
997 tgl@sss.pgh.pa.us 213 : 16412 : return hex_decode_safe(src, len, dst, NULL);
214 : : }
215 : :
216 : : uint64
217 : 72240 : 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 : :
1479 michael@paquier.xyz 225 : 72240 : srcend = src + len;
226 : 72240 : s = src;
227 : 72240 : p = dst;
228 [ + + ]: 2059678 : while (s < srcend)
229 : : {
230 [ + + + - : 1987453 : if (*s == ' ' || *s == '\n' || *s == '\t' || *s == '\r')
+ - - + ]
231 : : {
232 : 30 : s++;
233 : 30 : continue;
234 : : }
997 tgl@sss.pgh.pa.us 235 [ - + ]: 1987423 : if (!get_hex(s, &v1))
997 tgl@sss.pgh.pa.us 236 [ # # ]:UBC 0 : ereturn(escontext, 0,
237 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
238 : : errmsg("invalid hexadecimal digit: \"%.*s\"",
239 : : pg_mblen(s), s)));
1479 michael@paquier.xyz 240 :CBC 1987423 : s++;
241 [ + + ]: 1987423 : if (s >= srcend)
997 tgl@sss.pgh.pa.us 242 [ + + ]: 9 : ereturn(escontext, 0,
243 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
244 : : errmsg("invalid hexadecimal data: odd number of digits")));
245 [ + + ]: 1987414 : if (!get_hex(s, &v2))
246 [ + - ]: 6 : ereturn(escontext, 0,
247 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
248 : : errmsg("invalid hexadecimal digit: \"%.*s\"",
249 : : pg_mblen(s), s)));
1479 michael@paquier.xyz 250 : 1987408 : s++;
997 tgl@sss.pgh.pa.us 251 : 1987408 : *p++ = (v1 << 4) | v2;
252 : : }
253 : :
1479 michael@paquier.xyz 254 : 72225 : return p - dst;
255 : : }
256 : :
257 : : static uint64
1978 tgl@sss.pgh.pa.us 258 : 262625 : hex_enc_len(const char *src, size_t srclen)
259 : : {
1479 michael@paquier.xyz 260 : 262625 : return (uint64) srclen << 1;
261 : : }
262 : :
263 : : static uint64
1978 tgl@sss.pgh.pa.us 264 : 16412 : hex_dec_len(const char *src, size_t srclen)
265 : : {
1479 michael@paquier.xyz 266 : 16412 : return (uint64) srclen >> 1;
267 : : }
268 : :
269 : : /*
270 : : * BASE64
271 : : */
272 : :
273 : : static const char _base64[] =
274 : : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
275 : :
276 : : static const int8 b64lookup[128] = {
277 : : -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
278 : : -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
279 : : -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
280 : : 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
281 : : -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
282 : : 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
283 : : -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
284 : : 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
285 : : };
286 : :
287 : : static uint64
288 : 6 : pg_base64_encode(const char *src, size_t len, char *dst)
289 : : {
290 : : char *p,
8822 bruce@momjian.us 291 : 6 : *lend = dst + 76;
292 : : const char *s,
1479 michael@paquier.xyz 293 : 6 : *end = src + len;
8822 bruce@momjian.us 294 : 6 : int pos = 2;
295 : 6 : uint32 buf = 0;
296 : :
297 : 6 : s = src;
298 : 6 : p = dst;
299 : :
300 [ + + ]: 426 : while (s < end)
301 : : {
7287 tgl@sss.pgh.pa.us 302 : 420 : buf |= (unsigned char) *s << (pos << 3);
8822 bruce@momjian.us 303 : 420 : pos--;
304 : 420 : s++;
305 : :
306 : : /* write it out */
307 [ + + ]: 420 : if (pos < 0)
308 : : {
309 : 138 : *p++ = _base64[(buf >> 18) & 0x3f];
310 : 138 : *p++ = _base64[(buf >> 12) & 0x3f];
311 : 138 : *p++ = _base64[(buf >> 6) & 0x3f];
312 : 138 : *p++ = _base64[buf & 0x3f];
313 : :
314 : 138 : pos = 2;
315 : 138 : buf = 0;
316 : : }
317 [ + + ]: 420 : if (p >= lend)
318 : : {
319 : 6 : *p++ = '\n';
320 : 6 : lend = p + 76;
321 : : }
322 : : }
323 [ + - ]: 6 : if (pos != 2)
324 : : {
325 : 6 : *p++ = _base64[(buf >> 18) & 0x3f];
326 : 6 : *p++ = _base64[(buf >> 12) & 0x3f];
327 [ - + ]: 6 : *p++ = (pos == 0) ? _base64[(buf >> 6) & 0x3f] : '=';
328 : 6 : *p++ = '=';
329 : : }
330 : :
331 : 6 : return p - dst;
332 : : }
333 : :
334 : : static uint64
1479 michael@paquier.xyz 335 : 5 : pg_base64_decode(const char *src, size_t len, char *dst)
336 : : {
337 : 5 : const char *srcend = src + len,
8822 bruce@momjian.us 338 : 5 : *s = src;
7287 tgl@sss.pgh.pa.us 339 : 5 : char *p = dst;
340 : : char c;
8822 bruce@momjian.us 341 : 5 : int b = 0;
342 : 5 : uint32 buf = 0;
343 : 5 : int pos = 0,
344 : 5 : end = 0;
345 : :
346 [ + + ]: 312 : while (s < srcend)
347 : : {
348 : 307 : c = *s++;
349 : :
350 [ + - + - : 307 : if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
+ + - + ]
351 : 3 : continue;
352 : :
353 [ + + ]: 304 : if (c == '=')
354 : : {
355 : : /* end sequence */
356 [ + + ]: 8 : if (!end)
357 : : {
358 [ + + ]: 5 : if (pos == 2)
359 : 3 : end = 1;
360 [ + - ]: 2 : else if (pos == 3)
361 : 2 : end = 2;
362 : : else
8077 tgl@sss.pgh.pa.us 363 [ # # ]:UBC 0 : ereport(ERROR,
364 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
365 : : errmsg("unexpected \"=\" while decoding base64 sequence")));
366 : : }
8822 bruce@momjian.us 367 :CBC 8 : b = 0;
368 : : }
369 : : else
370 : : {
371 : 296 : b = -1;
372 [ + - + - ]: 296 : if (c > 0 && c < 127)
7287 tgl@sss.pgh.pa.us 373 : 296 : b = b64lookup[(unsigned char) c];
8822 bruce@momjian.us 374 [ - + ]: 296 : if (b < 0)
8077 tgl@sss.pgh.pa.us 375 [ # # ]:UBC 0 : ereport(ERROR,
376 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
377 : : errmsg("invalid symbol \"%.*s\" found while decoding base64 sequence",
378 : : pg_mblen(s - 1), s - 1)));
379 : : }
380 : : /* add it to buffer */
8822 bruce@momjian.us 381 :CBC 304 : buf = (buf << 6) + b;
382 : 304 : pos++;
383 [ + + ]: 304 : if (pos == 4)
384 : : {
385 : 76 : *p++ = (buf >> 16) & 255;
386 [ + + + + ]: 76 : if (end == 0 || end > 1)
387 : 73 : *p++ = (buf >> 8) & 255;
388 [ + + - + ]: 76 : if (end == 0 || end > 2)
389 : 71 : *p++ = buf & 255;
390 : 76 : buf = 0;
391 : 76 : pos = 0;
392 : : }
393 : : }
394 : :
395 [ - + ]: 5 : if (pos != 0)
8077 tgl@sss.pgh.pa.us 396 [ # # ]:UBC 0 : ereport(ERROR,
397 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
398 : : errmsg("invalid base64 end sequence"),
399 : : errhint("Input data is missing padding, is truncated, or is otherwise corrupted.")));
400 : :
8822 bruce@momjian.us 401 :CBC 5 : return p - dst;
402 : : }
403 : :
404 : :
405 : : static uint64
1978 tgl@sss.pgh.pa.us 406 : 6 : pg_base64_enc_len(const char *src, size_t srclen)
407 : : {
408 : : /* 3 bytes will be converted to 4, linefeed after 76 chars */
821 409 : 6 : return ((uint64) srclen + 2) / 3 * 4 + (uint64) srclen / (76 * 3 / 4);
410 : : }
411 : :
412 : : static uint64
1978 413 : 5 : pg_base64_dec_len(const char *src, size_t srclen)
414 : : {
415 : 5 : return ((uint64) srclen * 3) >> 2;
416 : : }
417 : :
418 : : /*
419 : : * Escape
420 : : * Minimally escape bytea to text.
421 : : * De-escape text to bytea.
422 : : *
423 : : * We must escape zero bytes and high-bit-set bytes to avoid generating
424 : : * text that might be invalid in the current encoding, or that might
425 : : * change to something else if passed through an encoding conversion
426 : : * (leading to failing to de-escape to the original bytea value).
427 : : * Also of course backslash itself has to be escaped.
428 : : *
429 : : * De-escaping processes \\ and any \### octal
430 : : */
431 : :
432 : : #define VAL(CH) ((CH) - '0')
433 : : #define DIG(VAL) ((VAL) + '0')
434 : :
435 : : static uint64
1479 michael@paquier.xyz 436 : 34 : esc_encode(const char *src, size_t srclen, char *dst)
437 : : {
7287 tgl@sss.pgh.pa.us 438 : 34 : const char *end = src + srclen;
439 : 34 : char *rp = dst;
1978 440 : 34 : uint64 len = 0;
441 : :
8758 bruce@momjian.us 442 [ + + ]: 328 : while (src < end)
443 : : {
6402 tgl@sss.pgh.pa.us 444 : 294 : unsigned char c = (unsigned char) *src;
445 : :
446 [ + + + + ]: 294 : if (c == '\0' || IS_HIGHBIT_SET(c))
447 : : {
8758 bruce@momjian.us 448 : 47 : rp[0] = '\\';
6402 tgl@sss.pgh.pa.us 449 : 47 : rp[1] = DIG(c >> 6);
450 : 47 : rp[2] = DIG((c >> 3) & 7);
451 : 47 : rp[3] = DIG(c & 7);
8758 bruce@momjian.us 452 : 47 : rp += 4;
453 : 47 : len += 4;
454 : : }
6402 tgl@sss.pgh.pa.us 455 [ - + ]: 247 : else if (c == '\\')
456 : : {
8758 bruce@momjian.us 457 :UBC 0 : rp[0] = '\\';
458 : 0 : rp[1] = '\\';
459 : 0 : rp += 2;
460 : 0 : len += 2;
461 : : }
462 : : else
463 : : {
6402 tgl@sss.pgh.pa.us 464 :CBC 247 : *rp++ = c;
8758 bruce@momjian.us 465 : 247 : len++;
466 : : }
467 : :
468 : 294 : src++;
469 : : }
470 : :
471 : 34 : return len;
472 : : }
473 : :
474 : : static uint64
1479 michael@paquier.xyz 475 : 15 : esc_decode(const char *src, size_t srclen, char *dst)
476 : : {
7287 tgl@sss.pgh.pa.us 477 : 15 : const char *end = src + srclen;
478 : 15 : char *rp = dst;
1978 479 : 15 : uint64 len = 0;
480 : :
8758 bruce@momjian.us 481 [ + + ]: 1200042 : while (src < end)
482 : : {
483 [ + + ]: 1200027 : if (src[0] != '\\')
484 : 1200012 : *rp++ = *src++;
8717 485 [ + - ]: 15 : else if (src + 3 < end &&
486 [ + - + - ]: 15 : (src[1] >= '0' && src[1] <= '3') &&
487 [ + - + - ]: 15 : (src[2] >= '0' && src[2] <= '7') &&
488 [ + - + - ]: 15 : (src[3] >= '0' && src[3] <= '7'))
8758 489 : 15 : {
490 : : int val;
491 : :
492 : 15 : val = VAL(src[1]);
493 : 15 : val <<= 3;
494 : 15 : val += VAL(src[2]);
495 : 15 : val <<= 3;
496 : 15 : *rp++ = val + VAL(src[3]);
497 : 15 : src += 4;
498 : : }
8717 bruce@momjian.us 499 [ # # ]:UBC 0 : else if (src + 1 < end &&
500 [ # # ]: 0 : (src[1] == '\\'))
501 : : {
8758 502 : 0 : *rp++ = '\\';
503 : 0 : src += 2;
504 : : }
505 : : else
506 : : {
507 : : /*
508 : : * One backslash, not followed by ### valid octal. Should never
509 : : * get here, since esc_dec_len does same check.
510 : : */
8077 tgl@sss.pgh.pa.us 511 [ # # ]: 0 : ereport(ERROR,
512 : : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
513 : : errmsg("invalid input syntax for type %s", "bytea")));
514 : : }
515 : :
8758 bruce@momjian.us 516 :CBC 1200027 : len++;
517 : : }
518 : :
519 : 15 : return len;
520 : : }
521 : :
522 : : static uint64
1978 tgl@sss.pgh.pa.us 523 : 34 : esc_enc_len(const char *src, size_t srclen)
524 : : {
7287 525 : 34 : const char *end = src + srclen;
1978 526 : 34 : uint64 len = 0;
527 : :
8758 bruce@momjian.us 528 [ + + ]: 328 : while (src < end)
529 : : {
6402 tgl@sss.pgh.pa.us 530 [ + + + + ]: 294 : if (*src == '\0' || IS_HIGHBIT_SET(*src))
8758 bruce@momjian.us 531 : 47 : len += 4;
532 [ - + ]: 247 : else if (*src == '\\')
8758 bruce@momjian.us 533 :UBC 0 : len += 2;
534 : : else
8758 bruce@momjian.us 535 :CBC 247 : len++;
536 : :
537 : 294 : src++;
538 : : }
539 : :
540 : 34 : return len;
541 : : }
542 : :
543 : : static uint64
1978 tgl@sss.pgh.pa.us 544 : 15 : esc_dec_len(const char *src, size_t srclen)
545 : : {
7287 546 : 15 : const char *end = src + srclen;
1978 547 : 15 : uint64 len = 0;
548 : :
8758 bruce@momjian.us 549 [ + + ]: 1200042 : while (src < end)
550 : : {
551 [ + + ]: 1200027 : if (src[0] != '\\')
552 : 1200012 : src++;
8717 553 [ + - ]: 15 : else if (src + 3 < end &&
554 [ + - + - ]: 15 : (src[1] >= '0' && src[1] <= '3') &&
555 [ + - + - ]: 15 : (src[2] >= '0' && src[2] <= '7') &&
556 [ + - + - ]: 15 : (src[3] >= '0' && src[3] <= '7'))
557 : : {
558 : : /*
559 : : * backslash + valid octal
560 : : */
8758 561 : 15 : src += 4;
562 : : }
8717 bruce@momjian.us 563 [ # # ]:UBC 0 : else if (src + 1 < end &&
564 [ # # ]: 0 : (src[1] == '\\'))
565 : : {
566 : : /*
567 : : * two backslashes = backslash
568 : : */
8758 569 : 0 : src += 2;
570 : : }
571 : : else
572 : : {
573 : : /*
574 : : * one backslash, not followed by ### valid octal
575 : : */
8077 tgl@sss.pgh.pa.us 576 [ # # ]: 0 : ereport(ERROR,
577 : : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
578 : : errmsg("invalid input syntax for type %s", "bytea")));
579 : : }
580 : :
8758 bruce@momjian.us 581 :CBC 1200027 : len++;
582 : : }
583 : 15 : return len;
584 : : }
585 : :
586 : : /*
587 : : * Common
588 : : */
589 : :
590 : : static const struct
591 : : {
592 : : const char *name;
593 : : struct pg_encoding enc;
594 : : } enclist[] =
595 : :
596 : : {
597 : : {
598 : : "hex",
599 : : {
600 : : hex_enc_len, hex_dec_len, hex_encode, hex_decode
601 : : }
602 : : },
603 : : {
604 : : "base64",
605 : : {
606 : : pg_base64_enc_len, pg_base64_dec_len, pg_base64_encode, pg_base64_decode
607 : : }
608 : : },
609 : : {
610 : : "escape",
611 : : {
612 : : esc_enc_len, esc_dec_len, esc_encode, esc_decode
613 : : }
614 : : },
615 : : {
616 : : NULL,
617 : : {
618 : : NULL, NULL, NULL, NULL
619 : : }
620 : : }
621 : : };
622 : :
623 : : static const struct pg_encoding *
8822 624 : 279097 : pg_find_encoding(const char *name)
625 : : {
626 : : int i;
627 : :
628 [ + - ]: 279206 : for (i = 0; enclist[i].name; i++)
7792 tgl@sss.pgh.pa.us 629 [ + + ]: 279206 : if (pg_strcasecmp(enclist[i].name, name) == 0)
8822 bruce@momjian.us 630 : 279097 : return &enclist[i].enc;
631 : :
8822 bruce@momjian.us 632 :UBC 0 : return NULL;
633 : : }
|