X-Git-Url: https://git.toastfreeware.priv.at/debian/iodine.git/blobdiff_plain/cf812f1d2258d434d6c75362a1f9e66170f0aabf..81f2f4b5b93cecc84dcf6f3c80723baefc0a07aa:/src/base64.c diff --git a/src/base64.c b/src/base64.c index 7da2d2a..71bbcf1 100644 --- a/src/base64.c +++ b/src/base64.c @@ -1,5 +1,7 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson + * Mostly rewritten 2009 J.A.Bezemer@opensourcepartners.nl * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -19,15 +21,16 @@ #include #include "encoding.h" -#include "common.h" #include "base64.h" #define BLKSIZE_RAW 3 #define BLKSIZE_ENC 4 -static const char cb64[] = +/* Note: the "unofficial" char is last here, which means that the \377 pattern + in DOWNCODECCHECK1 ('Y' request) will properly test it. */ +static const char cb64[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789+"; -static unsigned char rev64[128]; +static unsigned char rev64[256]; static int reverse_init = 0; static int base64_encode(char *, size_t *, const void *, size_t); @@ -36,8 +39,6 @@ static int base64_handles_dots(); static int base64_blksize_raw(); static int base64_blksize_enc(); -#define REV64(x) rev64[(int) (x)] - static struct encoder base64_encoder = { "Base64", @@ -55,140 +56,151 @@ struct encoder return &base64_encoder; } -static int +static int base64_handles_dots() { return 0; } -static int +static int base64_blksize_raw() { return BLKSIZE_RAW; } -static int +static int base64_blksize_enc() { return BLKSIZE_ENC; } -static int -base64_encode(char *buf, size_t *buflen, const void *data, size_t size) +inline static void +base64_reverse_init() { - size_t newsize; - size_t maxsize; - unsigned char *s; - unsigned char *p; - unsigned char *q; int i; + unsigned char c; - memset(buf, 0, *buflen); - - /* how many chars can we encode within the buf */ - maxsize = BLKSIZE_RAW * (*buflen / BLKSIZE_ENC); - /* how big will the encoded data be */ - newsize = BLKSIZE_ENC * (size / BLKSIZE_RAW); - if (size % BLKSIZE_RAW) { - newsize += BLKSIZE_ENC; - } - - /* if the buffer is too small, eat some of the data */ - if (*buflen < newsize) { - size = maxsize; + if (!reverse_init) { + memset (rev64, 0, 256); + for (i = 0; i < 64; i++) { + c = cb64[i]; + rev64[(int) c] = i; + } + reverse_init = 1; } - - p = s = (unsigned char *) buf; - q = (unsigned char *)data; - - for(i=0;i> 2)]; - p[1] = cb64[(((q[0] & 0x03) << 4) | ((q[1] & 0xf0) >> 4))]; - p[2] = (i+1 < size) ? cb64[((q[1] & 0x0f) << 2 ) | ((q[2] & 0xc0) >> 6)] : '\0'; - p[3] = (i+2 < size) ? cb64[(q[2] & 0x3f)] : '\0'; - - q += BLKSIZE_RAW; - p += BLKSIZE_ENC; - } - *p = 0; - - /* store number of bytes from data that was used */ - *buflen = size; - - return strlen(buf); } -#define DECODE_ERROR 0xffffffff - static int -decode_token(const unsigned char *t, unsigned char *data, size_t len) +base64_encode(char *buf, size_t *buflen, const void *data, size_t size) +/* + * Fills *buf with max. *buflen characters, encoding size bytes of *data. + * + * NOTE: *buf space should be at least 1 byte _more_ than *buflen + * to hold the trailing '\0'. + * + * return value : #bytes filled in buf (excluding \0) + * sets *buflen to : #bytes encoded from data + */ { - if (len < 2) - return 0; + unsigned char *udata = (unsigned char *) data; + int iout = 0; /* to-be-filled output char */ + int iin = 0; /* one more than last input byte that can be + successfully decoded */ + + /* Note: Don't bother to optimize manually. GCC optimizes + better(!) when using simplistic array indexing. */ - data[0] = ((REV64(t[0]) & 0x3f) << 2) | - ((REV64(t[1]) & 0x30) >> 4); + while (1) { + if (iout >= *buflen || iin >= size) + break; + buf[iout] = cb64[((udata[iin] & 0xfc) >> 2)]; + iout++; + + if (iout >= *buflen || iin >= size) { + iout--; /* previous char is useless */ + break; + } + buf[iout] = cb64[((udata[iin] & 0x03) << 4) | + ((iin + 1 < size) ? + ((udata[iin + 1] & 0xf0) >> 4) : 0)]; + iin++; /* 0 complete, iin=1 */ + iout++; - if (len < 3) - return 1; + if (iout >= *buflen || iin >= size) + break; + buf[iout] = cb64[((udata[iin] & 0x0f) << 2 ) | + ((iin + 1 < size) ? + ((udata[iin + 1] & 0xc0) >> 6) : 0)]; + iin++; /* 1 complete, iin=2 */ + iout++; - data[1] = ((REV64(t[1]) & 0x0f) << 4) | - ((REV64(t[2]) & 0x3c) >> 2); + if (iout >= *buflen || iin >= size) + break; + buf[iout] = cb64[(udata[iin] & 0x3f)]; + iin++; /* 2 complete, iin=3 */ + iout++; + } - if (len < 4) - return 2; + buf[iout] = '\0'; - data[2] = ((REV64(t[2]) & 0x03) << 6) | - (REV64(t[3]) & 0x3f); + /* store number of bytes from data that was used */ + *buflen = iin; - return 3; + return iout; } +#define REV64(x) rev64[(int) (x)] + static int base64_decode(void *buf, size_t *buflen, const char *str, size_t slen) +/* + * Fills *buf with max. *buflen bytes, decoded from slen chars in *str. + * Decoding stops early when *str contains \0. + * Illegal encoded chars are assumed to decode to zero. + * + * NOTE: *buf space should be at least 1 byte _more_ than *buflen + * to hold a trailing '\0' that is added (though *buf will usually + * contain full-binary data). + * + * return value : #bytes filled in buf (excluding \0) + */ { - unsigned char *q; - size_t newsize; - size_t maxsize; - const char *p; - unsigned char c; - unsigned char block[BLKSIZE_ENC]; - int len; - int i; + unsigned char *ubuf = (unsigned char *) buf; + int iout = 0; /* to-be-filled output byte */ + int iin = 0; /* next input char to use in decoding */ - if (!reverse_init) { - for (i = 0; i < 64; i++) { - c = cb64[i]; - rev64[(int) c] = i; - } - reverse_init = 1; - } - - /* chars needed to decode slen */ - newsize = BLKSIZE_RAW * (slen / BLKSIZE_ENC + 1) + 1; - /* encoded chars that fit in buf */ - maxsize = BLKSIZE_ENC * (*buflen / BLKSIZE_RAW + 1) + 1; - /* if the buffer is too small, eat some of the data */ - if (*buflen < newsize) { - slen = maxsize; - } - + base64_reverse_init (); - q = buf; - for (p = str; *p; p += BLKSIZE_ENC) { - /* since the str is const, we unescape in another buf */ - for (i = 0; i < BLKSIZE_ENC; i++) { - block[i] = p[i]; - } - len = decode_token(block, (unsigned char *) q, slen); - q += len; - slen -= BLKSIZE_ENC; - - if (len < BLKSIZE_RAW) + /* Note: Don't bother to optimize manually. GCC optimizes + better(!) when using simplistic array indexing. */ + + while (1) { + if (iout >= *buflen || iin + 1 >= slen || + str[iin] == '\0' || str[iin + 1] == '\0') break; + ubuf[iout] = ((REV64(str[iin]) & 0x3f) << 2) | + ((REV64(str[iin + 1]) & 0x30) >> 4); + iin++; /* 0 used up, iin=1 */ + iout++; + + if (iout >= *buflen || iin + 1 >= slen || + str[iin] == '\0' || str[iin + 1] == '\0') + break; + ubuf[iout] = ((REV64(str[iin]) & 0x0f) << 4) | + ((REV64(str[iin + 1]) & 0x3c) >> 2); + iin++; /* 1 used up, iin=2 */ + iout++; + + if (iout >= *buflen || iin + 1 >= slen || + str[iin] == '\0' || str[iin + 1] == '\0') + break; + ubuf[iout] = ((REV64(str[iin]) & 0x03) << 6) | + (REV64(str[iin + 1]) & 0x3f); + iin += 2; /* 2,3 used up, iin=4 */ + iout++; } - *q = '\0'; - - return q - (unsigned char *) buf; -} + ubuf[iout] = '\0'; + + return iout; +}