diff options
author | Georg Brandl <georg@python.org> | 2007-02-27 08:40:54 (GMT) |
---|---|---|
committer | Georg Brandl <georg@python.org> | 2007-02-27 08:40:54 (GMT) |
commit | 0b9b9e04830c40c7866b4ba23d6fa1a0aa80f039 (patch) | |
tree | b91b2c5de74b0941a4accd806b5d956a603e71a9 /Objects/bytesobject.c | |
parent | 88d65bd3e2229e38b4720bdc19493da17d851b62 (diff) | |
download | cpython-0b9b9e04830c40c7866b4ba23d6fa1a0aa80f039.zip cpython-0b9b9e04830c40c7866b4ba23d6fa1a0aa80f039.tar.gz cpython-0b9b9e04830c40c7866b4ba23d6fa1a0aa80f039.tar.bz2 |
Implement bytes.fromhex(), with tests.
Diffstat (limited to 'Objects/bytesobject.c')
-rw-r--r-- | Objects/bytesobject.c | 86 |
1 files changed, 76 insertions, 10 deletions
diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 88e6585..f2befed 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -970,17 +970,82 @@ bytes_join(PyObject *cls, PyObject *it) return NULL; } +PyDoc_STRVAR(fromhex_doc, +"bytes.fromhex(string) -> bytes\n\ +\n\ +Create a bytes object from a string of hexadecimal numbers.\n\ +Spaces between two numbers are accepted. Example:\n\ +bytes.fromhex('10 2030') -> bytes([0x10, 0x20, 0x30])."); + +static int +hex_digit_to_int(int 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 * +bytes_fromhex(PyObject *cls, PyObject *args) +{ + PyObject *newbytes; + char *hex, *buf; + Py_ssize_t len, byteslen, i, j; + int top, bot; + + if (!PyArg_ParseTuple(args, "s#:fromhex", &hex, &len)) + return NULL; + + byteslen = len / 2; /* max length if there are no spaces */ + + newbytes = PyBytes_FromStringAndSize(NULL, byteslen); + if (!newbytes) + return NULL; + buf = PyBytes_AS_STRING(newbytes); + + for (i = j = 0; ; i += 2) { + /* skip over spaces in the input */ + while (Py_CHARMASK(hex[i]) == ' ') + i++; + if (i >= len) + break; + top = hex_digit_to_int(Py_CHARMASK(hex[i])); + bot = hex_digit_to_int(Py_CHARMASK(hex[i+1])); + if (top == -1 || bot == -1) { + PyErr_Format(PyExc_ValueError, + "non-hexadecimal number string '%c%c' found in " + "fromhex() arg at position %zd", + hex[i], hex[i+1], i); + goto error; + } + buf[j++] = (top << 4) + bot; + } + if (PyBytes_Resize(newbytes, j) < 0) + goto error; + return newbytes; + + error: + Py_DECREF(newbytes); + return NULL; +} + static PySequenceMethods bytes_as_sequence = { - (lenfunc)bytes_length, /*sq_length*/ - (binaryfunc)bytes_concat, /*sq_concat*/ - (ssizeargfunc)bytes_repeat, /*sq_repeat*/ - (ssizeargfunc)bytes_getitem, /*sq_item*/ - 0, /*sq_slice*/ - (ssizeobjargproc)bytes_setitem, /*sq_ass_item*/ - 0, /* sq_ass_slice */ + (lenfunc)bytes_length, /* sq_length */ + (binaryfunc)bytes_concat, /* sq_concat */ + (ssizeargfunc)bytes_repeat, /* sq_repeat */ + (ssizeargfunc)bytes_getitem, /* sq_item */ + 0, /* sq_slice */ + (ssizeobjargproc)bytes_setitem, /* sq_ass_item */ + 0, /* sq_ass_slice */ (objobjproc)bytes_contains, /* sq_contains */ - (binaryfunc)bytes_iconcat, /* sq_inplace_concat */ - (ssizeargfunc)bytes_irepeat, /* sq_inplace_repeat */ + (binaryfunc)bytes_iconcat, /* sq_inplace_concat */ + (ssizeargfunc)bytes_irepeat, /* sq_inplace_repeat */ }; static PyMappingMethods bytes_as_mapping = { @@ -1002,6 +1067,7 @@ static PyMethodDef bytes_methods[] = { {"decode", (PyCFunction)bytes_decode, METH_VARARGS, decode_doc}, {"__alloc__", (PyCFunction)bytes_alloc, METH_NOARGS, alloc_doc}, + {"fromhex", (PyCFunction)bytes_fromhex, METH_VARARGS|METH_CLASS, fromhex_doc}, {"join", (PyCFunction)bytes_join, METH_O|METH_CLASS, join_doc}, {NULL} }; @@ -1032,7 +1098,7 @@ PyTypeObject PyBytes_Type = { PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ &bytes_as_buffer, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ /* bytes is 'final' or 'sealed' */ bytes_doc, /* tp_doc */ 0, /* tp_traverse */ |