Author: Armin Rigo <[email protected]>
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
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit