diff options
author | Bruce Momjian <bruce@momjian.us> | 2001-07-12 14:05:31 +0000 |
---|---|---|
committer | Bruce Momjian <bruce@momjian.us> | 2001-07-12 14:05:31 +0000 |
commit | 79d78bb26a61989e52b5a39b5a094d73e9c97d94 (patch) | |
tree | c17de42adcbb3a0900a3ba5b9d2e2feeff6eaa03 /src/backend/utils/adt/encode.c | |
parent | b9f3a929ee6b0309c50d837f464da7440303d2ef (diff) | |
download | postgresql-79d78bb26a61989e52b5a39b5a094d73e9c97d94.tar.gz postgresql-79d78bb26a61989e52b5a39b5a094d73e9c97d94.zip |
Add missing encode file.
Diffstat (limited to 'src/backend/utils/adt/encode.c')
-rw-r--r-- | src/backend/utils/adt/encode.c | 346 |
1 files changed, 346 insertions, 0 deletions
diff --git a/src/backend/utils/adt/encode.c b/src/backend/utils/adt/encode.c new file mode 100644 index 00000000000..89ba357aa57 --- /dev/null +++ b/src/backend/utils/adt/encode.c @@ -0,0 +1,346 @@ +/*------------------------------------------------------------------------- + * + * encode.c + * Various data encoding/decoding things. + * + * Copyright (c) 2001 PostgreSQL Global Development Group + * + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/backend/utils/adt/encode.c,v 1.1 2001/07/12 14:05:31 momjian Exp $ + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include <ctype.h> +#include "utils/builtins.h" + + +struct pg_encoding +{ + unsigned (*encode_len) (unsigned dlen); + unsigned (*decode_len) (unsigned dlen); + unsigned (*encode) (const uint8 *data, unsigned dlen, uint8 *res); + unsigned (*decode) (const uint8 *data, unsigned dlen, uint8 *res); +}; + +static 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 namelen, datalen, resultlen, res; + struct pg_encoding *enc; + + datalen = VARSIZE(data) - VARHDRSZ; + namelen = VARSIZE(name) - VARHDRSZ; + + namebuf = (char *)DirectFunctionCall1(textout, name); + + enc = pg_find_encoding(namebuf); + if (enc == NULL) + elog(ERROR, "No such encoding"); + + resultlen = enc->encode_len(datalen); + result = palloc(VARHDRSZ + resultlen); + + res = enc->encode(VARDATA(data), datalen, VARDATA(result)); + if (res > resultlen) + elog(ERROR, "Overflow - encode estimate too small"); + + VARATT_SIZEP(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 namelen, datalen, resultlen, res; + struct pg_encoding *enc; + + datalen = VARSIZE(data) - VARHDRSZ; + namelen = VARSIZE(name) - VARHDRSZ; + + namebuf = (char *)DirectFunctionCall1(textout, name); + + enc = pg_find_encoding(namebuf); + if (enc == NULL) + elog(ERROR, "No such encoding"); + + resultlen = enc->decode_len(datalen); + result = palloc(VARHDRSZ + resultlen); + + res = enc->decode(VARDATA(data), datalen, VARDATA(result)); + if (res > resultlen) + elog(ERROR, "Overflow - decode estimate too small"); + + VARATT_SIZEP(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, +}; + +static unsigned +hex_encode(const uint8 * src, unsigned len, uint8 * dst) +{ + const uint8 *end = src + len; + + while (src < end) + { + *dst++ = hextbl[(*src >> 4) & 0xF]; + *dst++ = hextbl[*src & 0xF]; + src++; + } + return len * 2; +} + +static uint8 +get_hex(unsigned c) +{ + int res = -1; + + if (c > 0 && c < 127) + res = hexlookup[c]; + + if (res < 0) + elog(ERROR, "Bad hex code: '%c'", c); + + return (uint8)res; +} + +static unsigned +hex_decode(const uint8 * src, unsigned len, uint8 * dst) +{ + const uint8 *s, + *srcend; + uint8 v1, + v2, + *p = dst; + + 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) + elog(ERROR, "hex_decode: invalid data"); + v2 = get_hex(*s++); + *p++ = v1 | v2; + } + + return p - dst; +} + +static unsigned +hex_enc_len(unsigned srclen) +{ + return srclen << 1; +} + +static unsigned +hex_dec_len(unsigned srclen) +{ + return srclen >> 1; +} + +/* + * BASE64 + */ + +static const unsigned 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 uint8 * src, unsigned len, uint8 * dst) +{ + uint8 *p, + *lend = dst + 76; + const uint8 *s, + *end = src + len; + int pos = 2; + uint32 buf = 0; + + s = src; + p = dst; + + while (s < end) + { + buf |= *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 uint8 * src, unsigned len, uint8 * dst) +{ + const char *srcend = src + len, + *s = src; + uint8 *p = dst; + unsigned 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 + elog(ERROR, "base64: unexpected '='"); + } + b = 0; + } + else { + b = -1; + if (c > 0 && c < 127) + b = b64lookup[c]; + if (b < 0) + elog(ERROR, "base64: Invalid symbol"); + } + /* 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) + elog(ERROR, "base64: invalid end sequence"); + + return p - dst; +} + + +static unsigned +b64_enc_len(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(unsigned srclen) +{ + return (srclen * 3) >> 2; +} + +/* + * Common + */ + +static struct { + const char *name; + struct pg_encoding enc; +} enclist[] = { + {"hex", { hex_enc_len, hex_dec_len, hex_encode, hex_decode }}, + {"base64", { b64_enc_len, b64_dec_len, b64_encode, b64_decode }}, + {NULL, { NULL, NULL, NULL, NULL } } +}; + +static struct pg_encoding * +pg_find_encoding(const char *name) +{ + int i; + + for (i = 0; enclist[i].name; i++) + if (!strcasecmp(enclist[i].name, name)) + return &enclist[i].enc; + + return NULL; +} |