Support old Python 2 buffer protocol in PTA and Texture ram_image

This enables passing eg. str and array.array objects in Python 2
This commit is contained in:
rdb 2017-12-20 01:23:00 +01:00
parent 096d54de00
commit f0b21ee969
2 changed files with 43 additions and 17 deletions

View File

@ -203,34 +203,37 @@ set_data(PyObject *data) {
}
PyBuffer_Release(&view);
} else {
Dtool_Raise_TypeError("PointerToArray.set_data() requires a buffer object");
return;
}
#else
// In Python 2.5 we didn't have the new buffer protocol, only str.
if (PyString_CheckExact(data)) {
int size = PyString_Size(data);
if (size % sizeof(Element) != 0) {
#endif
// In Python 2, there was also an older buffer protocol, supported by eg.
// str and array objects.
#if PY_MAJOR_VERSION < 3
// The old, deprecated buffer interface, as used by eg. the array module.
const void *buffer;
Py_ssize_t buffer_len;
if (!PyUnicode_CheckExact(data) &&
PyObject_AsReadBuffer(data, &buffer, &buffer_len) == 0) {
if (buffer_len % sizeof(Element) != 0) {
PyErr_Format(PyExc_ValueError,
"str object is not a multiple of %zu bytes",
"byte buffer is not a multiple of %zu bytes",
sizeof(Element));
return;
}
int num_elements = size / sizeof(Element);
this->_this->insert(this->_this->begin(), num_elements, Element());
// Hope there aren't any constructors or destructors involved here.
if (size != 0) {
const char *ptr = PyString_AsString(data);
memcpy(this->_this->p(), ptr, size);
if (buffer_len > 0) {
this->_this->resize(buffer_len / sizeof(Element));
memcpy(this->_this->p(), buffer, buffer_len);
} else {
this->_this->clear();
}
} else {
Dtool_Raise_TypeError("PointerToArray.set_data() requires a str");
return;
}
#endif
Dtool_Raise_TypeError("PointerToArray.set_data() requires a buffer object");
}
/**

View File

@ -84,6 +84,29 @@ set_ram_image(PyObject *image, Texture::CompressionMode compression,
}
#endif
#if PY_MAJOR_VERSION < 3
// The old, deprecated buffer interface, as used by eg. the array module.
const void *buffer;
Py_ssize_t buffer_len;
if (!PyUnicode_CheckExact(image) &&
PyObject_AsReadBuffer(image, &buffer, &buffer_len) == 0) {
if (compression == Texture::CM_off) {
int component_width = _this->get_component_width();
if (buffer_len % component_width != 0) {
PyErr_Format(PyExc_ValueError,
"byte buffer is not a multiple of %d bytes",
component_width);
return;
}
}
PTA_uchar data = PTA_uchar::empty_array(buffer_len, Texture::get_class_type());
memcpy(data.p(), buffer, buffer_len);
_this->set_ram_image(MOVE(data), compression, page_size);
return;
}
#endif
Dtool_Raise_ArgTypeError(image, 0, "Texture.set_ram_image", "CPTA_uchar or buffer");
}