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.
This commit is contained in:
Barry Warsaw 2000-08-15 06:07:13 +00:00
parent 57b808d21a
commit e977c210cb
1 changed files with 126 additions and 22 deletions

View File

@ -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 */
};