Added base64 support
diff --git a/Modules/binascii.c b/Modules/binascii.c
index 7450349..cd80672 100644
--- a/Modules/binascii.c
+++ b/Modules/binascii.c
@@ -35,6 +35,11 @@
 **	ASCII encoding method is "excess-space": 000000 is encoded as ' ', etc.
 **	short binary data is zero-extended (so the bits are always in the
 **	right place), this does *not* reflect in the length.
+** base64:
+**      Line breaks are insignificant, but lines are at most 76 chars
+**      each char encodes 6 bits, in similar order as uucode/hqx. Encoding
+**      is done via a table.
+**      Short binary data is filled (in ASCII) with '='.
 ** hqx:
 **	File starts with introductory text, real data starts and ends
 **	with colons.
@@ -133,6 +138,25 @@
 static unsigned char table_b2a_hqx[] =
     "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr";
 
+static char table_a2b_base64[] = {
+	-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+	-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+	-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
+	52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1, 0,-1,-1, /* Note PAD->0 */
+	-1, 0, 1, 2,  3, 4, 5, 6,  7, 8, 9,10, 11,12,13,14,
+	15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
+	-1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
+	41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
+};
+
+#define BASE64_PAD '='
+#define BASE64_MAXBIN 57	/* Max binary chunk size (76 char line) */
+
+static unsigned char table_b2a_base64[] =
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+
+
 static unsigned short crctab_hqx[256] = {
     0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
     0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
@@ -290,6 +314,119 @@
 	return rv;
 }
 
+static char doc_a2b_base64[] = "(ascii) -> bin. Decode a line of base64 data";
+
+static PyObject *
+binascii_a2b_base64(self, args)
+	PyObject *self;
+	PyObject *args;
+{
+	unsigned char *ascii_data, *bin_data;
+	int leftbits = 0;
+	unsigned char this_ch;
+	unsigned int leftchar = 0;
+	int npad = 0;
+	PyObject *rv;
+	int ascii_len, bin_len;
+	
+	if ( !PyArg_ParseTuple(args, "s#", &ascii_data, &ascii_len) )
+		return NULL;
+
+	bin_len = ((ascii_len+3)/4)*3; /* Upper bound, corrected later */
+
+	/* Allocate the buffer */
+	if ( (rv=PyString_FromStringAndSize(NULL, bin_len)) == NULL )
+		return NULL;
+	bin_data = (unsigned char *)PyString_AsString(rv);
+	bin_len = 0;
+	for( ; ascii_len > 0 ; ascii_len--, ascii_data++ ) {
+		/*
+		** XXXX I don't do any checks on the chars, ignoring
+		** any illegal chars. Hope this is correct...
+		*/
+		this_ch = (*ascii_data & 0x7f);
+		if ( this_ch == BASE64_PAD )
+			npad++;
+		this_ch = table_a2b_base64[(*ascii_data) & 0x7f];
+		if ( this_ch == -1 ) continue;
+		/*
+		** Shift it in on the low end, and see if there's
+		** a byte ready for output.
+		*/
+		leftchar = (leftchar << 6) | (this_ch);
+		leftbits += 6;
+		if ( leftbits >= 8 ) {
+			leftbits -= 8;
+			*bin_data++ = (leftchar >> leftbits) & 0xff;
+			leftchar &= ((1 << leftbits) - 1);
+			bin_len++;
+		}
+	}
+	/* Check that no bits are left */
+	if ( leftbits ) {
+		PyErr_SetString(Error, "Incorrect padding");
+		Py_DECREF(rv);
+		return NULL;
+	}
+	/* and remove any padding */
+	bin_len -= npad;
+	/* and set string size correctly */
+	_PyString_Resize(&rv, bin_len);
+	return rv;
+}
+
+static char doc_b2a_base64[] = "(bin) -> ascii. Base64-code line of data";
+	
+static PyObject *
+binascii_b2a_base64(self, args)
+	PyObject *self;
+	PyObject *args;
+{
+	unsigned char *ascii_data, *bin_data;
+	int leftbits = 0;
+	unsigned char this_ch;
+	unsigned int leftchar = 0;
+	PyObject *rv;
+	int bin_len;
+	
+	if ( !PyArg_ParseTuple(args, "s#", &bin_data, &bin_len) )
+		return NULL;
+	if ( bin_len > BASE64_MAXBIN ) {
+		PyErr_SetString(Error, "Too much data for base64 line");
+		return NULL;
+	}
+	
+	/* We're lazy and allocate to much (fixed up later) */
+	if ( (rv=PyString_FromStringAndSize(NULL, bin_len*2)) == NULL )
+		return NULL;
+	ascii_data = (unsigned char *)PyString_AsString(rv);
+
+	for( ; bin_len > 0 ; bin_len--, bin_data++ ) {
+		/* Shift the data into our buffer */
+		leftchar = (leftchar << 8) | *bin_data;
+		leftbits += 8;
+
+		/* See if there are 6-bit groups ready */
+		while ( leftbits >= 6 ) {
+			this_ch = (leftchar >> (leftbits-6)) & 0x3f;
+			leftbits -= 6;
+			*ascii_data++ = table_b2a_base64[this_ch];
+		}
+	}
+	if ( leftbits == 2 ) {
+		*ascii_data++ = table_b2a_base64[(leftchar&3) << 4];
+		*ascii_data++ = BASE64_PAD;
+		*ascii_data++ = BASE64_PAD;
+	} else if ( leftbits == 4 ) {
+		*ascii_data++ = table_b2a_base64[(leftchar&0xf) << 2];
+		*ascii_data++ = BASE64_PAD;
+	} 
+	*ascii_data++ = '\n';	/* Append a courtesy newline */
+	
+	_PyString_Resize(&rv, (ascii_data - (unsigned char *)PyString_AsString(rv)));
+	return rv;
+}
+
 static char doc_a2b_hqx[] = "ascii -> bin, done. Decode .hqx coding";
 
 static PyObject *
@@ -562,6 +699,10 @@
 static struct PyMethodDef binascii_module_methods[] = {
 	{"a2b_uu",		binascii_a2b_uu,	1,	doc_a2b_uu},
 	{"b2a_uu",		binascii_b2a_uu,	1,	doc_b2a_uu},
+	{"a2b_base64",		binascii_a2b_base64,	1,
+		 doc_a2b_base64},
+	{"b2a_base64",		binascii_b2a_base64,	1,
+		 doc_b2a_base64},
 	{"a2b_hqx",		binascii_a2b_hqx,	1,	doc_a2b_hqx},
 	{"b2a_hqx",		binascii_b2a_hqx,	1,	doc_b2a_hqx},
 	{"rlecode_hqx",		binascii_rlecode_hqx,	1,