From ed20a73db10a8c03877bef9cf9582ba85561d915 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Mon, 26 Sep 2016 13:21:01 +0900 Subject: [PATCH 2/8] Move encoding routines to src/common/ The following encoding routines are moved for decode and encode: - escape - base64 - hex base64 is planned to be used by SCRAM-SHA-256, moving the others makes sense for consistency. --- src/backend/utils/adt/encode.c | 408 +-------------------- src/backend/utils/adt/varlena.c | 1 + src/common/Makefile | 6 +- .../utils/adt/encode.c => common/encode_utils.c} | 358 +++++++----------- src/include/common/encode_utils.h | 30 ++ src/include/utils/builtins.h | 2 - src/tools/msvc/Mkvcbuild.pm | 2 +- 7 files changed, 169 insertions(+), 638 deletions(-) copy src/{backend/utils/adt/encode.c => common/encode_utils.c} (72%) create mode 100644 src/include/common/encode_utils.h diff --git a/src/backend/utils/adt/encode.c b/src/backend/utils/adt/encode.c index d833efc..306dbdd 100644 --- a/src/backend/utils/adt/encode.c +++ b/src/backend/utils/adt/encode.c @@ -15,6 +15,7 @@ #include +#include "common/encode_utils.h" #include "utils/builtins.h" @@ -106,413 +107,6 @@ binary_decode(PG_FUNCTION_ARGS) /* - * HEX - */ - -static const char hextbl[] = "0123456789abcdef"; - -static const int8 hexlookup[128] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, - -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -}; - -unsigned -hex_encode(const char *src, unsigned len, char *dst) -{ - const char *end = src + len; - - while (src < end) - { - *dst++ = hextbl[(*src >> 4) & 0xF]; - *dst++ = hextbl[*src & 0xF]; - src++; - } - return len * 2; -} - -static inline char -get_hex(char c) -{ - int res = -1; - - if (c > 0 && c < 127) - res = hexlookup[(unsigned char) c]; - - if (res < 0) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid hexadecimal digit: \"%c\"", c))); - - return (char) res; -} - -unsigned -hex_decode(const char *src, unsigned len, char *dst) -{ - const char *s, - *srcend; - char v1, - v2, - *p; - - srcend = src + len; - s = src; - p = dst; - while (s < srcend) - { - if (*s == ' ' || *s == '\n' || *s == '\t' || *s == '\r') - { - s++; - continue; - } - v1 = get_hex(*s++) << 4; - if (s >= srcend) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid hexadecimal data: odd number of digits"))); - - v2 = get_hex(*s++); - *p++ = v1 | v2; - } - - return p - dst; -} - -static unsigned -hex_enc_len(const char *src, unsigned srclen) -{ - return srclen << 1; -} - -static unsigned -hex_dec_len(const char *src, unsigned srclen) -{ - return srclen >> 1; -} - -/* - * BASE64 - */ - -static const char _base64[] = -"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -static const int8 b64lookup[128] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, - -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, -}; - -static unsigned -b64_encode(const char *src, unsigned len, char *dst) -{ - char *p, - *lend = dst + 76; - const char *s, - *end = src + len; - int pos = 2; - uint32 buf = 0; - - s = src; - p = dst; - - while (s < end) - { - buf |= (unsigned char) *s << (pos << 3); - pos--; - s++; - - /* write it out */ - if (pos < 0) - { - *p++ = _base64[(buf >> 18) & 0x3f]; - *p++ = _base64[(buf >> 12) & 0x3f]; - *p++ = _base64[(buf >> 6) & 0x3f]; - *p++ = _base64[buf & 0x3f]; - - pos = 2; - buf = 0; - } - if (p >= lend) - { - *p++ = '\n'; - lend = p + 76; - } - } - if (pos != 2) - { - *p++ = _base64[(buf >> 18) & 0x3f]; - *p++ = _base64[(buf >> 12) & 0x3f]; - *p++ = (pos == 0) ? _base64[(buf >> 6) & 0x3f] : '='; - *p++ = '='; - } - - return p - dst; -} - -static unsigned -b64_decode(const char *src, unsigned len, char *dst) -{ - const char *srcend = src + len, - *s = src; - char *p = dst; - char c; - int b = 0; - uint32 buf = 0; - int pos = 0, - end = 0; - - while (s < srcend) - { - c = *s++; - - if (c == ' ' || c == '\t' || c == '\n' || c == '\r') - continue; - - if (c == '=') - { - /* end sequence */ - if (!end) - { - if (pos == 2) - end = 1; - else if (pos == 3) - end = 2; - else - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("unexpected \"=\" while decoding base64 sequence"))); - } - b = 0; - } - else - { - b = -1; - if (c > 0 && c < 127) - b = b64lookup[(unsigned char) c]; - if (b < 0) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid symbol \"%c\" while decoding base64 sequence", (int) c))); - } - /* add it to buffer */ - buf = (buf << 6) + b; - pos++; - if (pos == 4) - { - *p++ = (buf >> 16) & 255; - if (end == 0 || end > 1) - *p++ = (buf >> 8) & 255; - if (end == 0 || end > 2) - *p++ = buf & 255; - buf = 0; - pos = 0; - } - } - - if (pos != 0) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid base64 end sequence"), - errhint("Input data is missing padding, is truncated, or is otherwise corrupted."))); - - return p - dst; -} - - -static unsigned -b64_enc_len(const char *src, unsigned srclen) -{ - /* 3 bytes will be converted to 4, linefeed after 76 chars */ - return (srclen + 2) * 4 / 3 + srclen / (76 * 3 / 4); -} - -static unsigned -b64_dec_len(const char *src, unsigned srclen) -{ - return (srclen * 3) >> 2; -} - -/* - * Escape - * Minimally escape bytea to text. - * De-escape text to bytea. - * - * We must escape zero bytes and high-bit-set bytes to avoid generating - * text that might be invalid in the current encoding, or that might - * change to something else if passed through an encoding conversion - * (leading to failing to de-escape to the original bytea value). - * Also of course backslash itself has to be escaped. - * - * De-escaping processes \\ and any \### octal - */ - -#define VAL(CH) ((CH) - '0') -#define DIG(VAL) ((VAL) + '0') - -static unsigned -esc_encode(const char *src, unsigned srclen, char *dst) -{ - const char *end = src + srclen; - char *rp = dst; - int len = 0; - - while (src < end) - { - unsigned char c = (unsigned char) *src; - - if (c == '\0' || IS_HIGHBIT_SET(c)) - { - rp[0] = '\\'; - rp[1] = DIG(c >> 6); - rp[2] = DIG((c >> 3) & 7); - rp[3] = DIG(c & 7); - rp += 4; - len += 4; - } - else if (c == '\\') - { - rp[0] = '\\'; - rp[1] = '\\'; - rp += 2; - len += 2; - } - else - { - *rp++ = c; - len++; - } - - src++; - } - - return len; -} - -static unsigned -esc_decode(const char *src, unsigned srclen, char *dst) -{ - const char *end = src + srclen; - char *rp = dst; - int len = 0; - - while (src < end) - { - if (src[0] != '\\') - *rp++ = *src++; - else if (src + 3 < end && - (src[1] >= '0' && src[1] <= '3') && - (src[2] >= '0' && src[2] <= '7') && - (src[3] >= '0' && src[3] <= '7')) - { - int val; - - val = VAL(src[1]); - val <<= 3; - val += VAL(src[2]); - val <<= 3; - *rp++ = val + VAL(src[3]); - src += 4; - } - else if (src + 1 < end && - (src[1] == '\\')) - { - *rp++ = '\\'; - src += 2; - } - else - { - /* - * One backslash, not followed by ### valid octal. Should never - * get here, since esc_dec_len does same check. - */ - ereport(ERROR, - (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type bytea"))); - } - - len++; - } - - return len; -} - -static unsigned -esc_enc_len(const char *src, unsigned srclen) -{ - const char *end = src + srclen; - int len = 0; - - while (src < end) - { - if (*src == '\0' || IS_HIGHBIT_SET(*src)) - len += 4; - else if (*src == '\\') - len += 2; - else - len++; - - src++; - } - - return len; -} - -static unsigned -esc_dec_len(const char *src, unsigned srclen) -{ - const char *end = src + srclen; - int len = 0; - - while (src < end) - { - if (src[0] != '\\') - src++; - else if (src + 3 < end && - (src[1] >= '0' && src[1] <= '3') && - (src[2] >= '0' && src[2] <= '7') && - (src[3] >= '0' && src[3] <= '7')) - { - /* - * backslash + valid octal - */ - src += 4; - } - else if (src + 1 < end && - (src[1] == '\\')) - { - /* - * two backslashes = backslash - */ - src += 2; - } - else - { - /* - * one backslash, not followed by ### valid octal - */ - ereport(ERROR, - (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type bytea"))); - } - - len++; - } - return len; -} - -/* * Common */ diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c index 260a5aa..ac13067 100644 --- a/src/backend/utils/adt/varlena.c +++ b/src/backend/utils/adt/varlena.c @@ -21,6 +21,7 @@ #include "access/tuptoaster.h" #include "catalog/pg_collation.h" #include "catalog/pg_type.h" +#include "common/encode_utils.h" #include "common/md5.h" #include "lib/hyperloglog.h" #include "libpq/pqformat.h" diff --git a/src/common/Makefile b/src/common/Makefile index f1cce0f..3b36c0c 100644 --- a/src/common/Makefile +++ b/src/common/Makefile @@ -40,9 +40,9 @@ override CPPFLAGS += -DVAL_LDFLAGS_EX="\"$(LDFLAGS_EX)\"" override CPPFLAGS += -DVAL_LDFLAGS_SL="\"$(LDFLAGS_SL)\"" override CPPFLAGS += -DVAL_LIBS="\"$(LIBS)\"" -OBJS_COMMON = config_info.o controldata_utils.o exec.o ip.o keywords.o \ - md5.o pg_lzcompress.o pgfnames.o psprintf.o relpath.o rmtree.o \ - string.o username.o wait_error.o +OBJS_COMMON = config_info.o controldata_utils.o exec.o encode_utils.o ip.o \ + keywords.o md5.o pg_lzcompress.o pgfnames.o psprintf.o relpath.o \ + rmtree.o string.o username.o wait_error.o ifeq ($(with_openssl),yes) OBJS_COMMON += sha_openssl.o diff --git a/src/backend/utils/adt/encode.c b/src/common/encode_utils.c similarity index 72% copy from src/backend/utils/adt/encode.c copy to src/common/encode_utils.c index d833efc..490392a 100644 --- a/src/backend/utils/adt/encode.c +++ b/src/common/encode_utils.c @@ -1,200 +1,27 @@ /*------------------------------------------------------------------------- * - * encode.c - * Various data encoding/decoding things. + * encode_utils.c + * Various data encoding/decoding things for base64, hexadecimal and + * escape. In case of failure, those routines return elog(ERROR) in + * the backend, and 0 in the frontend to let the caller handle the + * error handling, something needed by libpq. * * Copyright (c) 2001-2016, PostgreSQL Global Development Group * * * IDENTIFICATION - * src/backend/utils/adt/encode.c + * src/common/encode_utils.c * *------------------------------------------------------------------------- */ -#include "postgres.h" - -#include - -#include "utils/builtins.h" - - -struct pg_encoding -{ - unsigned (*encode_len) (const char *data, unsigned dlen); - unsigned (*decode_len) (const char *data, unsigned dlen); - unsigned (*encode) (const char *data, unsigned dlen, char *res); - unsigned (*decode) (const char *data, unsigned dlen, char *res); -}; - -static const struct pg_encoding *pg_find_encoding(const char *name); - -/* - * SQL functions. - */ - -Datum -binary_encode(PG_FUNCTION_ARGS) -{ - bytea *data = PG_GETARG_BYTEA_P(0); - Datum name = PG_GETARG_DATUM(1); - text *result; - char *namebuf; - int datalen, - resultlen, - res; - const struct pg_encoding *enc; - - datalen = VARSIZE(data) - VARHDRSZ; - - namebuf = TextDatumGetCString(name); - - enc = pg_find_encoding(namebuf); - if (enc == NULL) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("unrecognized encoding: \"%s\"", namebuf))); - - resultlen = enc->encode_len(VARDATA(data), datalen); - result = palloc(VARHDRSZ + resultlen); - - res = enc->encode(VARDATA(data), datalen, VARDATA(result)); - - /* Make this FATAL 'cause we've trodden on memory ... */ - if (res > resultlen) - elog(FATAL, "overflow - encode estimate too small"); - - SET_VARSIZE(result, VARHDRSZ + res); - - PG_RETURN_TEXT_P(result); -} - -Datum -binary_decode(PG_FUNCTION_ARGS) -{ - text *data = PG_GETARG_TEXT_P(0); - Datum name = PG_GETARG_DATUM(1); - bytea *result; - char *namebuf; - int datalen, - resultlen, - res; - const struct pg_encoding *enc; - - datalen = VARSIZE(data) - VARHDRSZ; - - namebuf = TextDatumGetCString(name); - - enc = pg_find_encoding(namebuf); - if (enc == NULL) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("unrecognized encoding: \"%s\"", namebuf))); - - resultlen = enc->decode_len(VARDATA(data), datalen); - result = palloc(VARHDRSZ + resultlen); - - res = enc->decode(VARDATA(data), datalen, VARDATA(result)); - - /* Make this FATAL 'cause we've trodden on memory ... */ - if (res > resultlen) - elog(FATAL, "overflow - decode estimate too small"); - - SET_VARSIZE(result, VARHDRSZ + res); - - PG_RETURN_BYTEA_P(result); -} - - -/* - * HEX - */ - -static const char hextbl[] = "0123456789abcdef"; - -static const int8 hexlookup[128] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, - -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -}; - -unsigned -hex_encode(const char *src, unsigned len, char *dst) -{ - const char *end = src + len; - - while (src < end) - { - *dst++ = hextbl[(*src >> 4) & 0xF]; - *dst++ = hextbl[*src & 0xF]; - src++; - } - return len * 2; -} - -static inline char -get_hex(char c) -{ - int res = -1; - - if (c > 0 && c < 127) - res = hexlookup[(unsigned char) c]; - - if (res < 0) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid hexadecimal digit: \"%c\"", c))); - - return (char) res; -} - -unsigned -hex_decode(const char *src, unsigned len, char *dst) -{ - const char *s, - *srcend; - char v1, - v2, - *p; - - srcend = src + len; - s = src; - p = dst; - while (s < srcend) - { - if (*s == ' ' || *s == '\n' || *s == '\t' || *s == '\r') - { - s++; - continue; - } - v1 = get_hex(*s++) << 4; - if (s >= srcend) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid hexadecimal data: odd number of digits"))); - v2 = get_hex(*s++); - *p++ = v1 | v2; - } - - return p - dst; -} - -static unsigned -hex_enc_len(const char *src, unsigned srclen) -{ - return srclen << 1; -} +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif -static unsigned -hex_dec_len(const char *src, unsigned srclen) -{ - return srclen >> 1; -} +#include "common/encode_utils.h" /* * BASE64 @@ -214,7 +41,7 @@ static const int8 b64lookup[128] = { 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, }; -static unsigned +unsigned b64_encode(const char *src, unsigned len, char *dst) { char *p, @@ -261,7 +88,7 @@ b64_encode(const char *src, unsigned len, char *dst) return p - dst; } -static unsigned +unsigned b64_decode(const char *src, unsigned len, char *dst) { const char *srcend = src + len, @@ -290,9 +117,15 @@ b64_decode(const char *src, unsigned len, char *dst) else if (pos == 3) end = 2; else + { +#ifndef FRONTEND ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("unexpected \"=\" while decoding base64 sequence"))); +#else + return 0; +#endif + } } b = 0; } @@ -302,9 +135,16 @@ b64_decode(const char *src, unsigned len, char *dst) if (c > 0 && c < 127) b = b64lookup[(unsigned char) c]; if (b < 0) + { +#ifndef FRONTEND ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid symbol \"%c\" while decoding base64 sequence", (int) c))); + errmsg("invalid symbol \"%c\" while decoding base64 sequence", + (int) c))); +#else + return 0; +#endif + } } /* add it to buffer */ buf = (buf << 6) + b; @@ -322,23 +162,29 @@ b64_decode(const char *src, unsigned len, char *dst) } if (pos != 0) + { +#ifndef FRONTEND ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid base64 end sequence"), errhint("Input data is missing padding, is truncated, or is otherwise corrupted."))); +#else + return 0; +#endif + } return p - dst; } -static unsigned +unsigned b64_enc_len(const char *src, unsigned srclen) { /* 3 bytes will be converted to 4, linefeed after 76 chars */ return (srclen + 2) * 4 / 3 + srclen / (76 * 3 / 4); } -static unsigned +unsigned b64_dec_len(const char *src, unsigned srclen) { return (srclen * 3) >> 2; @@ -361,7 +207,7 @@ b64_dec_len(const char *src, unsigned srclen) #define VAL(CH) ((CH) - '0') #define DIG(VAL) ((VAL) + '0') -static unsigned +unsigned esc_encode(const char *src, unsigned srclen, char *dst) { const char *end = src + srclen; @@ -400,7 +246,7 @@ esc_encode(const char *src, unsigned srclen, char *dst) return len; } -static unsigned +unsigned esc_decode(const char *src, unsigned srclen, char *dst) { const char *end = src + srclen; @@ -437,9 +283,13 @@ esc_decode(const char *src, unsigned srclen, char *dst) * One backslash, not followed by ### valid octal. Should never * get here, since esc_dec_len does same check. */ +#ifndef FRONTEND ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type bytea"))); +#else + return 0; +#endif } len++; @@ -448,7 +298,7 @@ esc_decode(const char *src, unsigned srclen, char *dst) return len; } -static unsigned +unsigned esc_enc_len(const char *src, unsigned srclen) { const char *end = src + srclen; @@ -469,7 +319,7 @@ esc_enc_len(const char *src, unsigned srclen) return len; } -static unsigned +unsigned esc_dec_len(const char *src, unsigned srclen) { const char *end = src + srclen; @@ -502,9 +352,13 @@ esc_dec_len(const char *src, unsigned srclen) /* * one backslash, not followed by ### valid octal */ +#ifndef FRONTEND ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type bytea"))); +#else + return 0; +#endif } len++; @@ -513,50 +367,104 @@ esc_dec_len(const char *src, unsigned srclen) } /* - * Common + * HEX */ -static const struct -{ - const char *name; - struct pg_encoding enc; -} enclist[] = +static const char hextbl[] = "0123456789abcdef"; + +static const int8 hexlookup[128] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +}; +unsigned +hex_encode(const char *src, unsigned len, char *dst) { + const char *end = src + len; + + while (src < end) { - "hex", - { - hex_enc_len, hex_dec_len, hex_encode, hex_decode - } - }, + *dst++ = hextbl[(*src >> 4) & 0xF]; + *dst++ = hextbl[*src & 0xF]; + src++; + } + return len * 2; +} + +static inline char +get_hex(char c) +{ + int res = -1; + + if (c > 0 && c < 127) + res = hexlookup[(unsigned char) c]; + + if (res < 0) { - "base64", - { - b64_enc_len, b64_dec_len, b64_encode, b64_decode - } - }, +#ifndef FRONTEND + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid hexadecimal digit: \"%c\"", c))); +#else + return 0; +#endif + } + + return (char) res; +} + +unsigned +hex_decode(const char *src, unsigned len, char *dst) +{ + const char *s, + *srcend; + char v1, + v2, + *p; + + srcend = src + len; + s = src; + p = dst; + while (s < srcend) { - "escape", + if (*s == ' ' || *s == '\n' || *s == '\t' || *s == '\r') { - esc_enc_len, esc_dec_len, esc_encode, esc_decode + s++; + continue; } - }, - { - NULL, + v1 = get_hex(*s++) << 4; + if (s >= srcend) { - NULL, NULL, NULL, NULL +#ifndef FRONTEND + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid hexadecimal data: odd number of digits"))); +#else + return 0; +#endif } + + v2 = get_hex(*s++); + *p++ = v1 | v2; } -}; -static const struct pg_encoding * -pg_find_encoding(const char *name) -{ - int i; + return p - dst; +} - for (i = 0; enclist[i].name; i++) - if (pg_strcasecmp(enclist[i].name, name) == 0) - return &enclist[i].enc; +unsigned +hex_enc_len(const char *src, unsigned srclen) +{ + return srclen << 1; +} - return NULL; +unsigned +hex_dec_len(const char *src, unsigned srclen) +{ + return srclen >> 1; } diff --git a/src/include/common/encode_utils.h b/src/include/common/encode_utils.h new file mode 100644 index 0000000..92d5b2f --- /dev/null +++ b/src/include/common/encode_utils.h @@ -0,0 +1,30 @@ +/* + * encode_utils.h + * Encoding and decoding routines for base64, hexadecimal and escape. + * + * Portions Copyright (c) 2001-2016, PostgreSQL Global Development Group + * + * src/include/common/encode_utils.h + */ +#ifndef ENCODE_UTILS_H +#define ENCODE_UTILS_H + +/* base 64 */ +unsigned b64_encode(const char *src, unsigned len, char *dst); +unsigned b64_decode(const char *src, unsigned len, char *dst); +unsigned b64_enc_len(const char *src, unsigned srclen); +unsigned b64_dec_len(const char *src, unsigned srclen); + +/* hex */ +unsigned hex_encode(const char *src, unsigned len, char *dst); +unsigned hex_decode(const char *src, unsigned len, char *dst); +unsigned hex_enc_len(const char *src, unsigned srclen); +unsigned hex_dec_len(const char *src, unsigned srclen); + +/* escape */ +unsigned esc_encode(const char *src, unsigned srclen, char *dst); +unsigned esc_decode(const char *src, unsigned srclen, char *dst); +unsigned esc_enc_len(const char *src, unsigned srclen); +unsigned esc_dec_len(const char *src, unsigned srclen); + +#endif /* ENCODE_UTILS_H */ diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 2ae212a..e36d28e 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -161,8 +161,6 @@ extern int errdomainconstraint(Oid datatypeOid, const char *conname); /* encode.c */ extern Datum binary_encode(PG_FUNCTION_ARGS); extern Datum binary_decode(PG_FUNCTION_ARGS); -extern unsigned hex_encode(const char *src, unsigned len, char *dst); -extern unsigned hex_decode(const char *src, unsigned len, char *dst); /* enum.c */ extern Datum enum_in(PG_FUNCTION_ARGS); diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm index 4ec014d..50b0f4b 100644 --- a/src/tools/msvc/Mkvcbuild.pm +++ b/src/tools/msvc/Mkvcbuild.pm @@ -110,7 +110,7 @@ sub mkvcbuild } our @pgcommonallfiles = qw( - config_info.c controldata_utils.c exec.c ip.c keywords.c + config_info.c controldata_utils.c encode_utils.c exec.c ip.c keywords.c md5.c pg_lzcompress.c pgfnames.c psprintf.c relpath.c rmtree.c string.c username.c wait_error.c); -- 2.10.0