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