[Python-3000-checkins] r53989 - in python/branches/p3yk: Lib/test/test_bytes.py Objects/bytesobject.c

georg.brandl python-3000-checkins at python.org
Tue Feb 27 09:40:55 CET 2007


Author: georg.brandl
Date: Tue Feb 27 09:40:54 2007
New Revision: 53989

Modified:
   python/branches/p3yk/Lib/test/test_bytes.py
   python/branches/p3yk/Objects/bytesobject.c
Log:
Implement bytes.fromhex(), with tests.



Modified: python/branches/p3yk/Lib/test/test_bytes.py
==============================================================================
--- python/branches/p3yk/Lib/test/test_bytes.py	(original)
+++ python/branches/p3yk/Lib/test/test_bytes.py	Tue Feb 27 09:40:54 2007
@@ -396,6 +396,21 @@
                 seq.append(alloc)
         #print seq
 
+    def test_fromhex(self):
+        self.assertRaises(TypeError, bytes.fromhex)
+        self.assertRaises(TypeError, bytes.fromhex, 1)
+        self.assertEquals(bytes.fromhex(''), bytes())
+        b = bytes([0x1a, 0x2b, 0x30])
+        self.assertEquals(bytes.fromhex('1a2B30'), b)
+        self.assertEquals(bytes.fromhex('  1A 2B  30   '), b)
+        self.assertEquals(bytes.fromhex(buffer('')), bytes())
+        self.assertEquals(bytes.fromhex(buffer('0000')), bytes([0, 0]))
+        self.assertRaises(ValueError, bytes.fromhex, 'a')
+        self.assertRaises(ValueError, bytes.fromhex, 'rt')
+        self.assertRaises(ValueError, bytes.fromhex, '1a b cd')
+        self.assertRaises(ValueError, bytes.fromhex, '\x00')
+        self.assertRaises(ValueError, bytes.fromhex, '12   \x00   34')
+
     def test_join(self):
         self.assertEqual(bytes.join([]), bytes())
         self.assertEqual(bytes.join([bytes()]), bytes())

Modified: python/branches/p3yk/Objects/bytesobject.c
==============================================================================
--- python/branches/p3yk/Objects/bytesobject.c	(original)
+++ python/branches/p3yk/Objects/bytesobject.c	Tue Feb 27 09:40:54 2007
@@ -970,17 +970,82 @@
     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 @@
 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 @@
     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 */


More information about the Python-3000-checkins mailing list