summaryrefslogtreecommitdiffstats
path: root/Objects/bytesobject.c
diff options
context:
space:
mode:
authorGeorg Brandl <georg@python.org>2007-02-27 08:40:54 (GMT)
committerGeorg Brandl <georg@python.org>2007-02-27 08:40:54 (GMT)
commit0b9b9e04830c40c7866b4ba23d6fa1a0aa80f039 (patch)
treeb91b2c5de74b0941a4accd806b5d956a603e71a9 /Objects/bytesobject.c
parent88d65bd3e2229e38b4720bdc19493da17d851b62 (diff)
downloadcpython-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.c86
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 */