X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/mLib/blobdiff_plain/ceba19865c063cf6d2fa5ba3ebcf43674a101549..d04f47331945f4316c495b1a8a034a8dba1862c6:/base64.c diff --git a/base64.c b/base64.c index e5cdcfa..2cefb41 100644 --- a/base64.c +++ b/base64.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: base64.c,v 1.1 1999/05/17 20:35:00 mdw Exp $ + * $Id: base64.c,v 1.5 2002/01/13 13:26:16 mdw Exp $ * * Base64 encoding and decoding. * @@ -30,6 +30,18 @@ /*----- Revision history --------------------------------------------------* * * $Log: base64.c,v $ + * Revision 1.5 2002/01/13 13:26:16 mdw + * Change names for internal tables. + * + * Revision 1.4 1999/10/15 21:08:46 mdw + * Change support for erroneous Base64 streams with length 1 mod 4. + * + * Revision 1.3 1999/05/21 22:14:30 mdw + * Take advantage of the new dynamic string macros. + * + * Revision 1.2 1999/05/18 21:45:27 mdw + * Allow Base64 encode and decode of arbitrary rubbish. + * * Revision 1.1 1999/05/17 20:35:00 mdw * Base64 encoding and decoding support. * @@ -46,11 +58,11 @@ /*----- Important tables --------------------------------------------------*/ -static const char base64_encodeMap[] = { "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/" }; +static const char encodemap[] = { "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/" }; -static const signed char base64_decodeMap[] = { +static const signed char decodemap[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 1x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 2x */ @@ -66,7 +78,7 @@ static const signed char base64_decodeMap[] = { /* --- @base64_encode@ --- * * * Arguments: @base64_ctx *ctx@ = pointer to a context block - * @const unsigned char *src@ = pointer to a source buffer + * @const void *p@ = pointer to a source buffer * @size_t sz@ = size of the source buffer * @dstr *d@ = pointer to destination string * @@ -77,22 +89,23 @@ static const signed char base64_decodeMap[] = { */ void base64_encode(base64_ctx *ctx, - const unsigned char *src, size_t sz, + const void *p, size_t sz, dstr *d) { - if (src) { + if (p) { unsigned long acc = ctx->acc; unsigned qsz = ctx->qsz; + const unsigned char *src = p; while (sz) { acc = (acc << 8) | *src++; qsz++; sz--; if (qsz == 3) { - dstr_putc(d, base64_encodeMap[(acc >> 18) & 0x3f]); - dstr_putc(d, base64_encodeMap[(acc >> 12) & 0x3f]); - dstr_putc(d, base64_encodeMap[(acc >> 6) & 0x3f]); - dstr_putc(d, base64_encodeMap[(acc >> 0) & 0x3f]); + DPUTC(d, encodemap[(acc >> 18) & 0x3f]); + DPUTC(d, encodemap[(acc >> 12) & 0x3f]); + DPUTC(d, encodemap[(acc >> 6) & 0x3f]); + DPUTC(d, encodemap[(acc >> 0) & 0x3f]); ctx->lnlen += 4; if (ctx->maxline && ctx->lnlen >= ctx->maxline) { dstr_puts(d, ctx->indent); @@ -114,18 +127,18 @@ void base64_encode(base64_ctx *ctx, break; case 1: acc <<= 16; - dstr_putc(d, base64_encodeMap[(acc >> 18) & 0x3f]); - dstr_putc(d, base64_encodeMap[(acc >> 12) & 0x3f]); - dstr_putc(d, '='); - dstr_putc(d, '='); + DPUTC(d, encodemap[(acc >> 18) & 0x3f]); + DPUTC(d, encodemap[(acc >> 12) & 0x3f]); + DPUTC(d, '='); + DPUTC(d, '='); ctx->lnlen += 4; break; case 2: acc <<= 8; - dstr_putc(d, base64_encodeMap[(acc >> 18) & 0x3f]); - dstr_putc(d, base64_encodeMap[(acc >> 12) & 0x3f]); - dstr_putc(d, base64_encodeMap[(acc >> 6) & 0x3f]); - dstr_putc(d, '='); + DPUTC(d, encodemap[(acc >> 18) & 0x3f]); + DPUTC(d, encodemap[(acc >> 12) & 0x3f]); + DPUTC(d, encodemap[(acc >> 6) & 0x3f]); + DPUTC(d, '='); ctx->lnlen += 4; break; } @@ -137,7 +150,7 @@ void base64_encode(base64_ctx *ctx, /* --- @base64_decode@ --- * * * Arguments: @base64_ctx *ctx@ = pointer to a context block - * @const unsigned char *src@ = pointer to a source buffer + * @const void *p@ = pointer to a source buffer * @size_t sz@ = size of the source buffer * @dstr *d@ = pointer to destination string * @@ -148,12 +161,13 @@ void base64_encode(base64_ctx *ctx, */ void base64_decode(base64_ctx *ctx, - const unsigned char *src, size_t sz, + const void *p, size_t sz, dstr *d) { - if (src) { + if (p) { unsigned long acc = ctx->acc; unsigned qsz = ctx->qsz; + const char *src = p; int ch; while (sz) { @@ -164,7 +178,7 @@ void base64_decode(base64_ctx *ctx, if (ch >= 128 || ch < 0) ch = -1; else - ch = base64_decodeMap[ch]; + ch = decodemap[ch]; sz--; if (ch == -1) continue; @@ -177,9 +191,9 @@ void base64_decode(base64_ctx *ctx, /* --- Maybe write out a completed triplet --- */ if (qsz == 4) { - dstr_putc(d, (acc >> 16) & 0xff); - dstr_putc(d, (acc >> 8) & 0xff); - dstr_putc(d, (acc >> 0) & 0xff); + DPUTC(d, (acc >> 16) & 0xff); + DPUTC(d, (acc >> 8) & 0xff); + DPUTC(d, (acc >> 0) & 0xff); acc = 0; qsz = 0; } @@ -204,14 +218,24 @@ void base64_decode(base64_ctx *ctx, unsigned long acc = ctx->acc; unsigned qsz = ctx->qsz; - /* --- Now fiddle with everything else --- */ + /* --- Now fiddle with everything else --- * + * + * There's a bodge here for invalid encodings which have only one hextet + * in the final group. I'm not sure this is really worth having, but it + * might save some unexpected behaviour. (Not that you won't still get + * unexpected behaviour if the stream is completely empty, of course.) + */ - acc <<= 6 * (4 - qsz); - qsz *= 6; - while (qsz > 8) { - dstr_putc(d, (acc >> 16) & 0xff); - acc <<= 8; - qsz -= 8; + if (qsz) { + acc <<= 6 * (4 - qsz); + qsz *= 6; + if (qsz < 8) + qsz = 8; + while (qsz >= 8) { + DPUTC(d, (acc >> 16) & 0xff); + acc <<= 8; + qsz -= 8; + } } /* --- That seems to be good enough --- */ @@ -246,12 +270,11 @@ void base64_init(base64_ctx *ctx) int main(int argc, char *argv[]) { unsigned char buf[BUFSIZ]; - dstr d; + dstr d = DSTR_INIT; base64_ctx ctx; void (*proc)(base64_ctx *, const unsigned char *, size_t, dstr *); size_t sz; - dstr_create(&d); base64_init(&ctx); if (argc > 1 && strcmp(argv[1], "-d") == 0)