[MINOR] Base64 decode

Implement Base64 decoding with a reverse table.

The function accepts and decodes classic base64 strings, which
can be composed from many streams as long each one is properly
padded, for example: SGVsbG8=IEhBUHJveHk=IQ==
diff --git a/src/base64.c b/src/base64.c
index e012622..ea244a2 100644
--- a/src/base64.c
+++ b/src/base64.c
@@ -1,7 +1,8 @@
 /*
- * Ascii to Base64 conversion as described in RFC1421.
+ * ASCII <-> Base64 conversion as described in RFC1421.
  *
  * Copyright 2006-2008 Willy Tarreau <w@1wt.eu>
+ * Copyright 2009-2010 Krzysztof Piotr Oledzki <ole@ans.pl>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -10,10 +11,19 @@
  *
  */
 
+#include <stdlib.h>
+#include <string.h>
+
 #include <common/base64.h>
 #include <common/config.h>
 
+#define B64BASE	'#'		/* arbitrary chosen base value */
+#define B64CMIN	'+'
+#define B64CMAX	'z'
+#define B64PADV	64		/* Base64 chosen special pad value */
+
 const char base64tab[65]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+const char base64rev[]="b###cXYZ[\\]^_`a###d###$%&'()*+,-./0123456789:;<=######>?@ABCDEFGHIJKLMNOPQRSTUVW";
 
 /* Encodes <ilen> bytes from <in> to <out> for at most <olen> chars (including
  * the trailing zero). Returns the number of bytes written. No check is made
@@ -57,3 +67,71 @@
 
 	return convlen;
 }
+
+/* Decodes <ilen> bytes from <in> to <out> for at most <olen> chars.
+ * Returns the number of bytes converted. No check is made for
+ * <in> or <out> to be NULL. Returns -1 if <in> is invalid or ilen
+ * has wrong size, -2 if <olen> is too short.
+ * 1 to 3 output bytes are produced for 4 input bytes.
+ */
+int base64dec(const char *in, size_t ilen, char *out, size_t olen) {
+
+	unsigned char t[4];
+	signed char b;
+	int convlen = 0, i = 0, pad = 0;
+
+	if (ilen % 4)
+		return -1;
+
+	if (olen < ilen / 4 * 3)
+		return -2;
+
+	while (ilen) {
+
+		/* if (*p < B64CMIN || *p > B64CMAX) */
+		b = (signed char)*in - B64CMIN;
+		if ((unsigned char)b > (B64CMAX-B64CMIN))
+			return -1;
+
+		b = base64rev[b] - B64BASE - 1;
+
+		/* b == -1: invalid character */
+		if (b < 0)
+			return -1;
+
+		/* padding has to be continous */
+		if (pad && b != B64PADV)
+			return -1;
+
+		/* valid padding: "XX==" or "XXX=", but never "X===" or "====" */
+		if (pad && i < 2)
+			return -1;
+
+		if (b == B64PADV)
+			pad++;
+
+		t[i++] = b;
+
+		if (i == 4) {
+			/*
+			 * WARNING: we allow to write little more data than we
+			 * should, but the checks from the beginning of the
+			 * functions guarantee that we can safely do that.
+			 */
+
+			/* xx000000 xx001111 xx111122 xx222222 */
+			out[convlen]   = ((t[0] << 2) + (t[1] >> 4));
+			out[convlen+1] = ((t[1] << 4) + (t[2] >> 2));
+			out[convlen+2] = ((t[2] << 6) + (t[3] >> 0));
+
+			convlen += 3-pad;
+
+			pad = i = 0;
+		}
+
+		in++;
+		ilen--;
+	}
+
+	return convlen;
+}