summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--base64.c64
-rw-r--r--base64.h6
2 files changed, 45 insertions, 25 deletions
diff --git a/base64.c b/base64.c
index 4ec6c6af..7124060e 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 e0f3c5f3..d69c9ccd 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,