diff options
Diffstat (limited to 'Modules/binascii.c')
-rw-r--r-- | Modules/binascii.c | 141 |
1 files changed, 141 insertions, 0 deletions
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 @@ 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, |