]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Added base64 support
authorJack Jansen <jack.jansen@cwi.nl>
Wed, 4 Oct 1995 16:38:44 +0000 (16:38 +0000)
committerJack Jansen <jack.jansen@cwi.nl>
Wed, 4 Oct 1995 16:38:44 +0000 (16:38 +0000)
Modules/binascii.c

index 7450349d8999dc5098771f070eaf14f85dfde739..cd806723d4978f1b898a4bceb73aa652be1394f7 100644 (file)
@@ -35,6 +35,11 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 **     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_a2b_hqx[256] = {
 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 @@ binascii_b2a_uu(self, args)
        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 @@ binascii_crc_hqx(self, args)
 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,