]> granicus.if.org Git - neomutt/commitdiff
refactor: create a generic base64 encode/decode
authorDamien Riegel <damien.riegel@savoirfairelinux.com>
Sun, 5 Feb 2017 01:51:17 +0000 (20:51 -0500)
committerRichard Russon <rich@flatcap.org>
Fri, 10 Feb 2017 03:22:57 +0000 (03:22 +0000)
- 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
mime.h
rfc2047.c
sendlib.c

index 0245a7a6a785af3f3836b53769e2b0104c107fff..2e59f33ab4fc2d8e2b48ac19be084e8da28a6dfe 100644 (file)
--- a/base64.c
+++ b/base64.c
 
 #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 c1e441e41250c82df58d35d52b60c9d99f5498e4..30348726c0ccf9caf2b847b1e6b309590d616c8f 100644 (file)
--- 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)]
index 8506425450c1ad197b2f87cbd98f67942b0f5630..a25132bc4e4fc8037881571439539c6decbfeb3e 100644 (file)
--- 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;
 }
index c2db246c9d46383b4654084989c8fff8d3692a11..e482b062c76ffd2959f1f816b32195003bcb4b4b 100644 (file)
--- 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);
 }