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 : }
|