Author: Armin Rigo <ar...@tunes.org>
Branch: 
Changeset: r2658:21bef1a21d1b
Date: 2016-04-15 18:23 +0200
http://bitbucket.org/cffi/cffi/changeset/21bef1a21d1b/

Log:    ffi.rawstring(), with a minimal interface

diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -5582,6 +5582,36 @@
     return NULL;
 }
 
+static PyObject *b_rawstring(PyObject *self, PyObject *arg)
+{
+    CDataObject *cd;
+    Py_ssize_t length;
+
+    if (!CData_Check(arg)) {
+        PyErr_SetString(PyExc_TypeError, "expected a 'cdata' object");
+        return NULL;
+    }
+    cd = (CDataObject *)arg;
+    if (!(cd->c_type->ct_flags & CT_ARRAY) ||
+        !(cd->c_type->ct_itemdescr->ct_flags & CT_PRIMITIVE_CHAR)) {
+        PyErr_Format(PyExc_TypeError,
+                     "expected an array of 'char' or 'wchar_t', got '%s'",
+                     cd->c_type->ct_name);
+        return NULL;
+    }
+
+    length = get_array_length(cd);
+    if (cd->c_type->ct_itemdescr->ct_size == sizeof(char))
+        return PyBytes_FromStringAndSize(cd->c_data, length);
+#ifdef HAVE_WCHAR_H
+    else if (cd->c_type->ct_itemdescr->ct_size == sizeof(wchar_t))
+        return _my_PyUnicode_FromWideChar((wchar_t *)cd->c_data, length);
+#endif
+
+    PyErr_SetString(PyExc_SystemError, "bad size for char-like");
+    return NULL;
+}
+
 static PyObject *b_buffer(PyObject *self, PyObject *args, PyObject *kwds)
 {
     CDataObject *cd;
@@ -6225,6 +6255,7 @@
     {"rawaddressof", b_rawaddressof, METH_VARARGS},
     {"getcname", b_getcname, METH_VARARGS},
     {"string", (PyCFunction)b_string, METH_VARARGS | METH_KEYWORDS},
+    {"rawstring", b_rawstring, METH_O},
     {"buffer", (PyCFunction)b_buffer, METH_VARARGS | METH_KEYWORDS},
     {"get_errno", b_get_errno, METH_NOARGS},
     {"set_errno", b_set_errno, METH_O},
diff --git a/c/ffi_obj.c b/c/ffi_obj.c
--- a/c/ffi_obj.c
+++ b/c/ffi_obj.c
@@ -459,6 +459,19 @@
 #define ffi_string  b_string     /* ffi_string() => b_string()
                                     from _cffi_backend.c */
 
+PyDoc_STRVAR(ffi_rawstring_doc,
+"Convert a cdata that is an array of 'char' or 'wchar_t' to\n"
+"a byte or unicode string.  Unlike ffi.string(), it does not stop\n"
+"at the first null.\n"
+"\n"
+"Note that if you have a pointer and an explicit length, you\n"
+"can use 'p[0:length]' to make an array view.  This is similar to\n"
+"the construct 'list(p[0:length])', which returns a list of chars/\n"
+"unichars/ints/floats.");
+
+#define ffi_rawstring  b_rawstring     /* ffi_rawstring() => b_rawstring()
+                                          from _cffi_backend.c */
+
 PyDoc_STRVAR(ffi_buffer_doc,
 "Return a read-write buffer object that references the raw C data\n"
 "pointed to by the given 'cdata'.  The 'cdata' must be a pointer or an\n"
@@ -1090,6 +1103,7 @@
 
{"new_allocator",(PyCFunction)ffi_new_allocator,METH_VKW,ffi_new_allocator_doc},
  {"new_handle", (PyCFunction)ffi_new_handle, METH_O,       ffi_new_handle_doc},
  {"offsetof",   (PyCFunction)ffi_offsetof,   METH_VARARGS, ffi_offsetof_doc},
+ {"rawstring",  (PyCFunction)ffi_rawstring,  METH_O,       ffi_rawstring_doc},
  {"sizeof",     (PyCFunction)ffi_sizeof,     METH_O,       ffi_sizeof_doc},
  {"string",     (PyCFunction)ffi_string,     METH_VKW,     ffi_string_doc},
  {"typeof",     (PyCFunction)ffi_typeof,     METH_O,       ffi_typeof_doc},
diff --git a/cffi/api.py b/cffi/api.py
--- a/cffi/api.py
+++ b/cffi/api.py
@@ -299,6 +299,18 @@
         """
         return self._backend.string(cdata, maxlen)
 
+    def rawstring(self, cdata):
+        """Convert a cdata that is an array of 'char' or 'wchar_t' to
+        a byte or unicode string.  Unlike ffi.string(), it does not stop
+        at the first null.
+
+        Note that if you have a pointer and an explicit length, you
+        can use 'p[0:length]' to make an array view.  This is similar to
+        the construct 'list(p[0:length])', which returns a list of chars/
+        unichars/ints/floats.
+        """
+        return self._backend.rawstring(cdata)
+
     def buffer(self, cdata, size=-1):
         """Return a read-write buffer object that references the raw C data
         pointed to by the given 'cdata'.  The 'cdata' must be a pointer or
diff --git a/testing/cffi0/test_ffi_backend.py 
b/testing/cffi0/test_ffi_backend.py
--- a/testing/cffi0/test_ffi_backend.py
+++ b/testing/cffi0/test_ffi_backend.py
@@ -472,3 +472,12 @@
         assert ffi.list_types() == (['b', 'bb', 'bbb'],
                                     ['a', 'cc', 'ccc'],
                                     ['aa', 'aaa', 'g'])
+
+    def test_rawstring(self):
+        ffi = FFI()
+        p = ffi.new("char[]", "abc\x00def")
+        assert ffi.rawstring(p) == "abc\x00def\x00"
+        assert ffi.rawstring(p[1:6]) == "bc\x00de"
+        p = ffi.new("wchar_t[]", u"abc\x00def")
+        assert ffi.rawstring(p) == u"abc\x00def\x00"
+        assert ffi.rawstring(p[1:6]) == u"bc\x00de"
diff --git a/testing/cffi1/test_ffi_obj.py b/testing/cffi1/test_ffi_obj.py
--- a/testing/cffi1/test_ffi_obj.py
+++ b/testing/cffi1/test_ffi_obj.py
@@ -495,3 +495,15 @@
         assert i < 20
         time.sleep(0.51)
     assert seen == ['init!', 'oops'] * 3
+
+def test_rawstring():
+    ffi = _cffi1_backend.FFI()
+    p = ffi.new("char[]", "abc\x00def")
+    assert ffi.rawstring(p) == "abc\x00def\x00"
+    assert ffi.rawstring(p[1:6]) == "bc\x00de"
+    p = ffi.new("wchar_t[]", u"abc\x00def")
+    assert ffi.rawstring(p) == u"abc\x00def\x00"
+    assert ffi.rawstring(p[1:6]) == u"bc\x00de"
+    #
+    py.test.raises(TypeError, ffi.rawstring, "foobar")
+    py.test.raises(TypeError, ffi.rawstring, p + 1)
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to