From e977c210cbadf5d4a91eefa94b9b10da484f6ef1 Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Tue, 15 Aug 2000 06:07:13 +0000 Subject: [PATCH] After a brief conversation and code review with TP, adding two very commonly used functions to convert an arbitrary binary string into a hexadecimal digit representation and back again. These are often (and often differently) implemented in Python. Best to have one common fast implementation. Specifically, binascii_hexlify(): a.k.a. b2a_hex() to return the hex representation of binary data. binascii_unhexlify(): a.k.a. a2b_hex() to do the inverse conversion (hex digits to binary data). The argument must have an even length, and must contain only hex digits, otherwise a TypeError is raised. --- Modules/binascii.c | 148 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 126 insertions(+), 22 deletions(-) diff --git a/Modules/binascii.c b/Modules/binascii.c index 50f8b76044b5..89ccc79c6eb0 100644 --- a/Modules/binascii.c +++ b/Modules/binascii.c @@ -874,31 +874,135 @@ binascii_crc32(PyObject *self, PyObject *args) return Py_BuildValue("l", crc ^ 0xFFFFFFFFUL); } + +static PyObject * +binascii_hexlify(PyObject *self, PyObject *args) +{ + char* argbuf; + int arglen; + PyObject *retval; + char* retbuf; + int i, j; + + if (!PyArg_ParseTuple(args, "t#:b2a_hex", &argbuf, &arglen)) + return NULL; + + retval = PyString_FromStringAndSize(NULL, arglen*2); + if (!retval) + return NULL; + retbuf = PyString_AsString(retval); + if (!retbuf) + goto finally; + + /* make hex version of string, taken from shamodule.c */ + for (i=j=0; i < arglen; i++) { + char c; + c = (argbuf[i] >> 4) & 0xf; + c = (c>9) ? c+'a'-10 : c + '0'; + retbuf[j++] = c; + c = argbuf[i] & 0xf; + c = (c>9) ? c+'a'-10 : c + '0'; + retbuf[j++] = c; + } + return retval; + + finally: + Py_DECREF(retval); + return NULL; +} + +static char doc_hexlify[] = +"b2a_hex(data) -> s; Hexadecimal representation of binary data.\n\ +\n\ +This function is also available as \"hexlify()\"."; + + +static int +to_int(char c) +{ + if (isdigit(c)) + return c - '0'; + else { + if (isupper(c)) + c = tolower(c); + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + } + return -1; +} + + +static PyObject * +binascii_unhexlify(PyObject *self, PyObject *args) +{ + char* argbuf; + int arglen; + PyObject *retval; + char* retbuf; + int i, j; + + if (!PyArg_ParseTuple(args, "s#:a2b_hex", &argbuf, &arglen)) + return NULL; + + /* XXX What should we do about odd-lengthed strings? Should we add + * an implicit leading zero, or a trailing zero? For now, raise an + * exception. + */ + if (arglen % 2) { + PyErr_SetString(PyExc_TypeError, "odd lengthed string"); + return NULL; + } + + retval = PyString_FromStringAndSize(NULL, (arglen/2)); + if (!retval) + return NULL; + retbuf = PyString_AsString(retval); + if (!retbuf) + goto finally; + + for (i=j=0; i < arglen; i += 2) { + int top = to_int(Py_CHARMASK(argbuf[i])); + int bot = to_int(Py_CHARMASK(argbuf[i+1])); + if (top == -1 || bot == -1) { + PyErr_SetString(PyExc_TypeError, + "non-hexadecimal digit found"); + goto finally; + } + retbuf[j++] = (top << 4) + bot; + } + return retval; + + finally: + Py_DECREF(retval); + return NULL; +} + +static char doc_unhexlify[] = +"a2b_hex(hexstr) -> s; Binary data of hexadecimal representation.\n\ +\n\ +hexstr must contain an even number of hex digits (upper or lower case).\n\ +This function is also available as \"unhexlify()\""; + + /* List of functions defined in the module */ static struct PyMethodDef binascii_module_methods[] = { - {"a2b_uu", binascii_a2b_uu, - METH_VARARGS, doc_a2b_uu}, - {"b2a_uu", binascii_b2a_uu, - METH_VARARGS, doc_b2a_uu}, - {"a2b_base64", binascii_a2b_base64, - METH_VARARGS, - doc_a2b_base64}, - {"b2a_base64", binascii_b2a_base64, - METH_VARARGS, doc_b2a_base64}, - {"a2b_hqx", binascii_a2b_hqx, - METH_VARARGS, doc_a2b_hqx}, - {"b2a_hqx", binascii_b2a_hqx, - METH_VARARGS, doc_b2a_hqx}, - {"rlecode_hqx", binascii_rlecode_hqx, - METH_VARARGS, doc_rlecode_hqx}, - {"rledecode_hqx", binascii_rledecode_hqx, - METH_VARARGS, doc_rledecode_hqx}, - {"crc_hqx", binascii_crc_hqx, - METH_VARARGS, doc_crc_hqx}, - {"crc32", binascii_crc32, - METH_VARARGS, doc_crc32}, - {NULL, NULL} /* sentinel */ + {"a2b_uu", binascii_a2b_uu, METH_VARARGS, doc_a2b_uu}, + {"b2a_uu", binascii_b2a_uu, METH_VARARGS, doc_b2a_uu}, + {"a2b_base64", binascii_a2b_base64, METH_VARARGS, doc_a2b_base64}, + {"b2a_base64", binascii_b2a_base64, METH_VARARGS, doc_b2a_base64}, + {"a2b_hqx", binascii_a2b_hqx, METH_VARARGS, doc_a2b_hqx}, + {"b2a_hqx", binascii_b2a_hqx, METH_VARARGS, doc_b2a_hqx}, + {"b2a_hex", binascii_hexlify, METH_VARARGS, doc_hexlify}, + {"a2b_hex", binascii_unhexlify, METH_VARARGS, doc_unhexlify}, + {"hexlify", binascii_hexlify, METH_VARARGS, doc_hexlify}, + {"unhexlify", binascii_unhexlify, METH_VARARGS, doc_unhexlify}, + {"rlecode_hqx", binascii_rlecode_hqx, METH_VARARGS, doc_rlecode_hqx}, + {"rledecode_hqx", binascii_rledecode_hqx, METH_VARARGS, + doc_rledecode_hqx}, + {"crc_hqx", binascii_crc_hqx, METH_VARARGS, doc_crc_hqx}, + {"crc32", binascii_crc32, METH_VARARGS, doc_crc32}, + {NULL, NULL} /* sentinel */ };