From 69c579ed9e8e845b286c3f7a291ea5fba5101d60 Mon Sep 17 00:00:00 2001 From: Damien Riegel Date: Sat, 4 Feb 2017 20:51:17 -0500 Subject: [PATCH] refactor: create a generic base64 encode/decode - make sendlib use generic base64 encode function Sendlib had its own implementation for base64 encoding, so change it to make use of the generic one defined in base64.c. While we're at it, move the B64Chars where it belongs, and remove some global variables by creating a b64_context structure to hold all necessary information. - make rfc2047 use generic base64 encode function This was another source of a custom base64 encode function. Let's keep the same logic as before: encode 3 bytes (or less) at a time. Also, switch from a `for` to a `while` loop as `dlen` can simply be used as a stop condition. - B64Chars can now be made static to base64.c. closes #360 --- base64.c | 8 ++++++ mime.h | 1 - rfc2047.c | 40 +++++++++----------------- sendlib.c | 86 +++++++++++++++++++++++++------------------------------ 4 files changed, 60 insertions(+), 75 deletions(-) diff --git a/base64.c b/base64.c index 0245a7a6a..2e59f33ab 100644 --- a/base64.c +++ b/base64.c @@ -48,6 +48,14 @@ #define BAD -1 +static const char B64Chars[64] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', + 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', '+', '/' +}; + /** * mutt_to_base64 - convert raw bytes to null-terminated base64 string. * diff --git a/mime.h b/mime.h index c1e441e41..30348726c 100644 --- a/mime.h +++ b/mime.h @@ -57,7 +57,6 @@ enum #ifndef _SENDLIB_C extern const int Index_hex[]; extern const int Index_64[]; -extern const char B64Chars[]; #endif #define hexval(c) Index_hex[(unsigned int)(c)] diff --git a/rfc2047.c b/rfc2047.c index 850642545..a25132bc4 100644 --- a/rfc2047.c +++ b/rfc2047.c @@ -197,35 +197,21 @@ static size_t b_encoder (char *s, ICONV_CONST char *d, size_t dlen, memcpy (s, "=?", 2), s += 2; memcpy (s, tocode, strlen (tocode)), s += strlen (tocode); memcpy (s, "?B?", 3), s += 3; - for (;;) + + while (dlen) { - if (!dlen) - break; - else if (dlen == 1) - { - *s++ = B64Chars[(*d >> 2) & 0x3f]; - *s++ = B64Chars[(*d & 0x03) << 4]; - *s++ = '='; - *s++ = '='; - break; - } - else if (dlen == 2) - { - *s++ = B64Chars[(*d >> 2) & 0x3f]; - *s++ = B64Chars[((*d & 0x03) << 4) | ((d[1] >> 4) & 0x0f)]; - *s++ = B64Chars[(d[1] & 0x0f) << 2]; - *s++ = '='; - break; - } - else - { - *s++ = B64Chars[(*d >> 2) & 0x3f]; - *s++ = B64Chars[((*d & 0x03) << 4) | ((d[1] >> 4) & 0x0f)]; - *s++ = B64Chars[((d[1] & 0x0f) << 2) | ((d[2] >> 6) & 0x03)]; - *s++ = B64Chars[d[2] & 0x3f]; - d += 3, dlen -= 3; - } + char encoded[11]; + size_t ret, i; + size_t in_len = MIN(3, dlen); + + ret = mutt_to_base64 (encoded, d, in_len, sizeof(encoded)); + for (i = 0; i < ret; i++) + *s++ = encoded[i]; + + dlen -= in_len; + d += in_len; } + memcpy (s, "?=", 2), s += 2; return s - s0; } diff --git a/sendlib.c b/sendlib.c index c2db246c9..e482b062c 100644 --- a/sendlib.c +++ b/sendlib.c @@ -69,14 +69,6 @@ extern char RFC822Specials[]; const char MimeSpecials[] = "@.,;:<>[]\\\"()?/= \t"; -const char B64Chars[64] = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', - 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', - 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', '+', '/' -}; - static void transform_to_7bit (BODY *a, FILE *fpin); static void encode_quoted (FGETCONV * fc, FILE *fout, int istext) @@ -211,66 +203,66 @@ static void encode_quoted (FGETCONV * fc, FILE *fout, int istext) } } -static char b64_buffer[3]; -static short b64_num; -static short b64_linelen; +struct b64_context { + char buffer[3]; + short size; + short linelen; +}; -static void b64_flush(FILE *fout) +static int b64_init(struct b64_context *ctx) { - short i; - - if(!b64_num) - return; + memset(ctx->buffer, '\0', sizeof(ctx->buffer)); + ctx->size = 0; + ctx->linelen = 0; - if(b64_linelen >= 72) - { - fputc('\n', fout); - b64_linelen = 0; - } + return 0; +} - for(i = b64_num; i < 3; i++) - b64_buffer[i] = '\0'; +static void b64_flush(struct b64_context *ctx, FILE *fout) +{ + /* for some reasons, mutt_to_base64 expects the + * output buffer to be larger than 10B */ + char encoded[11]; + size_t ret, i; - fputc(B64Chars[(b64_buffer[0] >> 2) & 0x3f], fout); - b64_linelen++; - fputc(B64Chars[((b64_buffer[0] & 0x3) << 4) | ((b64_buffer[1] >> 4) & 0xf) ], fout); - b64_linelen++; + if (!ctx->size) + return; - if(b64_num > 1) + if (ctx->linelen >= 72) { - fputc(B64Chars[((b64_buffer[1] & 0xf) << 2) | ((b64_buffer[2] >> 6) & 0x3) ], fout); - b64_linelen++; - if(b64_num > 2) - { - fputc(B64Chars[b64_buffer[2] & 0x3f], fout); - b64_linelen++; - } + fputc('\n', fout); + ctx->linelen = 0; } - while(b64_linelen % 4) + /* ret should always be equal to 4 here, because ctx->size + * is a value between 1 and 3 (included), but let's not hardcode it + * and prefer the return value of the function */ + ret = mutt_to_base64 (encoded, ctx->buffer, ctx->size, sizeof(encoded)); + for(i = 0; i < ret; i++) { - fputc('=', fout); - b64_linelen++; + fputc(encoded[i], fout); + ctx->linelen++; } - b64_num = 0; + ctx->size = 0; } -static void b64_putc(char c, FILE *fout) +static void b64_putc(struct b64_context *ctx, char c, FILE *fout) { - if(b64_num == 3) - b64_flush(fout); + if(ctx->size == 3) + b64_flush(ctx, fout); - b64_buffer[b64_num++] = c; + ctx->buffer[ctx->size++] = c; } static void encode_base64 (FGETCONV * fc, FILE *fout, int istext) { + struct b64_context ctx; int ch, ch1 = EOF; - b64_num = b64_linelen = 0; + b64_init(&ctx); while ((ch = fgetconv (fc)) != EOF) { @@ -279,11 +271,11 @@ static void encode_base64 (FGETCONV * fc, FILE *fout, int istext) return; } if (istext && ch == '\n' && ch1 != '\r') - b64_putc('\r', fout); - b64_putc(ch, fout); + b64_putc(&ctx, '\r', fout); + b64_putc(&ctx, ch, fout); ch1 = ch; } - b64_flush(fout); + b64_flush(&ctx, fout); fputc('\n', fout); } -- 2.40.0