diff --git a/base64.c b/base64.c index 4ec6c6af500ba2004a0a4bba8114cdbce50f5f08..7124060e9236707f7fc22ec400e3fe0a6e8776fe 100644 --- a/base64.c +++ b/base64.c @@ -26,6 +26,7 @@ #include "base64.h" #include <assert.h> +#include <stdlib.h> #define TABLE_INVALID -1 #define TABLE_SPACE -2 @@ -56,42 +57,55 @@ static const signed char decode_table[256] = -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }; +#define ENCODE(x) (encode_table[0x3F & (x)]) + unsigned base64_encode(uint8_t *dst, unsigned src_length, const uint8_t *src) { - uint8_t *out = dst; + unsigned dst_length = BASE64_ENCODE_LENGTH(src_length); + const uint8_t *in = src + src_length; + uint8_t *out = dst + dst_length; + unsigned left_over = src_length % 3; - while (src_length >= 3) + if (left_over) { - *out++ = encode_table[0x3F & (src[0] >> 2)]; - *out++ = encode_table[0x3F & ((src[0] << 4) | (src[1] >> 4))]; - *out++ = encode_table[0x3F & ((src[1] << 2) | (src[2] >> 6))]; - *out++ = encode_table[0x3F & src[2]]; - src += 3; - src_length -= 3; - } + switch(left_over) + { + case 1: + in--; + *--out = '='; + *--out = '='; + *--out = ENCODE(in[0] << 4); + *--out = ENCODE(in[0] >> 2); + break; + + case 2: + in-= 2; + *--out = '='; + *--out = ENCODE( in[1] << 2); + *--out = ENCODE((in[0] << 4) | (in[1] >> 4)); + *--out = ENCODE( in[0] >> 2); + break; - switch (src_length) + default: + abort(); + } + } + + while (in > src) { - case 2: - *out++ = encode_table[0x3F & (src[0] >> 2)]; - *out++ = encode_table[0x3F & ((src[0] << 4) | (src[1] >> 4))]; - *out++ = encode_table[0x3F & (src[1] << 2)]; - *out++ = '='; - break; - case 1: - *out++ = encode_table[0x3F & (src[0] >> 2)]; - *out++ = encode_table[0x3F & (src[0] << 4)]; - *out++ = '='; - *out++ = '='; - break; - case 0: - break; + in -= 3; + *--out = ENCODE( in[2]); + *--out = ENCODE((in[1] << 2) | (in[2] >> 6)); + *--out = ENCODE((in[0] << 4) | (in[1] >> 4)); + *--out = ENCODE( in[0] >> 2); } - return out - dst; + assert(out == dst); + + return dst_length; } void diff --git a/base64.h b/base64.h index e0f3c5f3c7eead5449d70f95e0126cdf4713b39f..d69c9ccdb72c2014ed601c412668066b69fe2357 100644 --- a/base64.h +++ b/base64.h @@ -33,6 +33,9 @@ #define BASE64_BINARY_BLOCK_SIZE 3 #define BASE64_TEXT_BLOCK_SIZE 4 +/* Overlapping source and destination is allowed, as long as the start + * of the source area is not later than the start of the destination + * area. */ unsigned /* Returns the length of encoded data */ base64_encode(uint8_t *dst, unsigned src_length, @@ -53,6 +56,9 @@ struct base64_ctx /* Internal, do not modify */ void base64_decode_init(struct base64_ctx *ctx); +/* Overlapping source and destination is allowed, as long as the start + * of the source area is not before the start of the destination + * area. */ unsigned /* Returns the length of decoded data */ base64_decode_update(struct base64_ctx *ctx, uint8_t *dst,