Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/python/generic')
-rw-r--r--source/blender/python/generic/bgl.c135
-rw-r--r--source/blender/python/generic/bpy_internal_import.c25
-rw-r--r--source/blender/python/generic/idprop_py_api.c6
-rw-r--r--source/blender/python/generic/py_capi_utils.c187
-rw-r--r--source/blender/python/generic/py_capi_utils.h43
-rw-r--r--source/blender/python/generic/python_utildefines.h6
6 files changed, 308 insertions, 94 deletions
diff --git a/source/blender/python/generic/bgl.c b/source/blender/python/generic/bgl.c
index ed4726e2ab7..5c938ef2ee3 100644
--- a/source/blender/python/generic/bgl.c
+++ b/source/blender/python/generic/bgl.c
@@ -476,6 +476,49 @@ int BGL_typeSize(int type)
return -1;
}
+static int gl_buffer_type_from_py_format_char(char *typestr)
+{
+ if (ELEM(typestr[0], '<', '>', '|')) {
+ typestr += 1;
+ }
+ char format = typestr[0];
+ char byte_num = typestr[1];
+
+ switch (format) {
+ case 't':
+ case 'b':
+ case 'h':
+ if (!byte_num) return GL_BYTE;
+ ATTR_FALLTHROUGH;
+ case 'i':
+ if (!byte_num) return GL_SHORT;
+ ATTR_FALLTHROUGH;
+ case 'l':
+ if (!byte_num || byte_num == '4') return GL_INT;
+ if (byte_num == '1') return GL_BYTE;
+ if (byte_num == '2') return GL_SHORT;
+ break;
+ case 'f':
+ if (!byte_num) return GL_FLOAT;
+ ATTR_FALLTHROUGH;
+ case 'd':
+ if (!byte_num || byte_num == '8') return GL_DOUBLE;
+ if (byte_num == '4') return GL_FLOAT;
+ break;
+ }
+ return -1; /* UNKNOWN */
+}
+
+static bool compare_dimensions(int ndim, int *dim1, Py_ssize_t *dim2)
+{
+ for (int i = 0; i < ndim; i++) {
+ if (dim1[i] != dim2[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
/** \} */
@@ -634,6 +677,22 @@ PyTypeObject BGL_bufferType = {
NULL /*tp_del*/
};
+
+static Buffer *BGL_MakeBuffer_FromData(PyObject *parent, int type, int ndimensions, int *dimensions, void *buf)
+{
+ Buffer *buffer = (Buffer *)PyObject_NEW(Buffer, &BGL_bufferType);
+
+ Py_XINCREF(parent);
+ buffer->parent = parent;
+ buffer->ndimensions = ndimensions;
+ buffer->dimensions = MEM_mallocN(ndimensions * sizeof(int), "Buffer dimensions");
+ memcpy(buffer->dimensions, dimensions, ndimensions * sizeof(int));
+ buffer->type = type;
+ buffer->buf.asvoid = buf;
+
+ return buffer;
+}
+
/**
* Create a buffer object
*
@@ -645,30 +704,21 @@ Buffer *BGL_MakeBuffer(int type, int ndimensions, int *dimensions, void *initbuf
{
Buffer *buffer;
void *buf = NULL;
- int i, size, length;
+ int i, size = BGL_typeSize(type);
- length = 1;
for (i = 0; i < ndimensions; i++) {
- length *= dimensions[i];
+ size *= dimensions[i];
}
- size = BGL_typeSize(type);
+ buf = MEM_mallocN(size, "Buffer buffer");
- buf = MEM_mallocN(length * size, "Buffer buffer");
-
- buffer = (Buffer *)PyObject_NEW(Buffer, &BGL_bufferType);
- buffer->parent = NULL;
- buffer->ndimensions = ndimensions;
- buffer->dimensions = MEM_mallocN(ndimensions * sizeof(int), "Buffer dimensions");
- memcpy(buffer->dimensions, dimensions, ndimensions * sizeof(int));
- buffer->type = type;
- buffer->buf.asvoid = buf;
+ buffer = BGL_MakeBuffer_FromData(NULL, type, ndimensions, dimensions, buf);
if (initbuffer) {
- memcpy(buffer->buf.asvoid, initbuffer, length * size);
+ memcpy(buffer->buf.asvoid, initbuffer, size);
}
else {
- memset(buffer->buf.asvoid, 0, length * size);
+ memset(buffer->buf.asvoid, 0, size);
}
return buffer;
}
@@ -678,7 +728,7 @@ Buffer *BGL_MakeBuffer(int type, int ndimensions, int *dimensions, void *initbuf
static PyObject *Buffer_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds)
{
PyObject *length_ob = NULL, *init = NULL;
- Buffer *buffer;
+ Buffer *buffer = NULL;
int dimensions[MAX_DIMENSIONS];
int type;
@@ -743,9 +793,32 @@ static PyObject *Buffer_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject
return NULL;
}
- buffer = BGL_MakeBuffer(type, ndimensions, dimensions, NULL);
- if (init && ndimensions) {
- if (Buffer_ass_slice(buffer, 0, dimensions[0], init)) {
+ if (init && PyObject_CheckBuffer(init)) {
+ Py_buffer pybuffer;
+
+ if (PyObject_GetBuffer(init, &pybuffer, PyBUF_ND | PyBUF_FORMAT) == -1) {
+ /* PyObject_GetBuffer raise a PyExc_BufferError */
+ return NULL;
+ }
+
+ if (type != gl_buffer_type_from_py_format_char(pybuffer.format)) {
+ PyErr_Format(PyExc_TypeError,
+ "`GL_TYPE` and `typestr` of object with buffer interface do not match. '%s'", pybuffer.format);
+ }
+ else if (ndimensions != pybuffer.ndim ||
+ !compare_dimensions(ndimensions, dimensions, pybuffer.shape))
+ {
+ PyErr_Format(PyExc_TypeError, "array size does not match");
+ }
+ else {
+ buffer = BGL_MakeBuffer_FromData(init, type, pybuffer.ndim, dimensions, pybuffer.buf);
+ }
+
+ PyBuffer_Release(&pybuffer);
+ }
+ else {
+ buffer = BGL_MakeBuffer(type, ndimensions, dimensions, NULL);
+ if (init && Buffer_ass_slice(buffer, 0, dimensions[0], init)) {
Py_DECREF(buffer);
return NULL;
}
@@ -778,27 +851,17 @@ static PyObject *Buffer_item(Buffer *self, int i)
}
}
else {
- Buffer *newbuf;
- int j, length, size;
+ int j, offset = i * BGL_typeSize(self->type);
- length = 1;
for (j = 1; j < self->ndimensions; j++) {
- length *= self->dimensions[j];
+ offset *= self->dimensions[j];
}
- size = BGL_typeSize(self->type);
-
- newbuf = (Buffer *)PyObject_NEW(Buffer, &BGL_bufferType);
-
- Py_INCREF(self);
- newbuf->parent = (PyObject *)self;
-
- newbuf->ndimensions = self->ndimensions - 1;
- newbuf->type = self->type;
- newbuf->buf.asvoid = self->buf.asbyte + i * length * size;
- newbuf->dimensions = MEM_mallocN(newbuf->ndimensions * sizeof(int), "Buffer dimensions");
- memcpy(newbuf->dimensions, self->dimensions + 1, newbuf->ndimensions * sizeof(int));
- return (PyObject *)newbuf;
+ return (PyObject *)BGL_MakeBuffer_FromData(
+ (PyObject *)self, self->type,
+ self->ndimensions - 1,
+ self->dimensions + 1,
+ self->buf.asbyte + offset);
}
return NULL;
diff --git a/source/blender/python/generic/bpy_internal_import.c b/source/blender/python/generic/bpy_internal_import.c
index ed2752d8372..ffac09efdde 100644
--- a/source/blender/python/generic/bpy_internal_import.c
+++ b/source/blender/python/generic/bpy_internal_import.c
@@ -248,8 +248,17 @@ PyObject *bpy_text_reimport(PyObject *module, int *found)
if ((name = PyModule_GetName(module)) == NULL)
return NULL;
- if ((filepath = (char *)PyModule_GetFilename(module)) == NULL)
- return NULL;
+ {
+ PyObject *module_file = PyModule_GetFilenameObject(module);
+ if (module_file == NULL) {
+ return NULL;
+ }
+ filepath = _PyUnicode_AsString(module_file);
+ Py_DECREF(module_file);
+ if (filepath == NULL) {
+ return NULL;
+ }
+ }
/* look up the text object */
text = BLI_findstring(&maggie->text, BLI_path_basename(filepath), offsetof(ID, name) + 2);
@@ -276,13 +285,13 @@ static PyObject *blender_import(PyObject *UNUSED(self), PyObject *args, PyObject
int found = 0;
PyObject *globals = NULL, *locals = NULL, *fromlist = NULL;
int level = 0; /* relative imports */
-
PyObject *newmodule;
- //PyObject_Print(args, stderr, 0);
- static const char *kwlist[] = {"name", "globals", "locals", "fromlist", "level", NULL};
-
- if (!PyArg_ParseTupleAndKeywords(args, kw, "s|OOOi:bpy_import_meth", (char **)kwlist,
- &name, &globals, &locals, &fromlist, &level))
+
+ static const char *_keywords[] = {"name", "globals", "locals", "fromlist", "level", NULL};
+ static _PyArg_Parser _parser = {"s|OOOi:bpy_import_meth", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser,
+ &name, &globals, &locals, &fromlist, &level))
{
return NULL;
}
diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c
index 5d6a7c578a2..1153e0176df 100644
--- a/source/blender/python/generic/idprop_py_api.c
+++ b/source/blender/python/generic/idprop_py_api.c
@@ -386,7 +386,7 @@ static IDProperty *idp_from_PyFloat(const char *name, PyObject *ob)
static IDProperty *idp_from_PyLong(const char *name, PyObject *ob)
{
IDPropertyTemplate val = {0};
- val.i = _PyLong_AsInt(ob);
+ val.i = PyC_Long_AsI32(ob);
if (val.i == -1 && PyErr_Occurred()) {
return NULL;
}
@@ -499,7 +499,7 @@ static IDProperty *idp_from_PySequence_Fast(const char *name, PyObject *ob)
prop_data = IDP_Array(prop);
for (i = 0; i < val.array.len; i++) {
item = ob_seq_fast_items[i];
- if (((prop_data[i] = _PyLong_AsInt(item)) == -1) && PyErr_Occurred()) {
+ if (((prop_data[i] = PyC_Long_AsI32(item)) == -1) && PyErr_Occurred()) {
return NULL;
}
}
@@ -1337,7 +1337,7 @@ static int BPy_IDArray_SetItem(BPy_IDArray *self, int index, PyObject *value)
}
case IDP_INT:
{
- const int i = _PyLong_AsInt(value);
+ const int i = PyC_Long_AsI32(value);
if (i == -1 && PyErr_Occurred()) {
return -1;
}
diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c
index 2e789d6d4b3..d49f9514b8c 100644
--- a/source/blender/python/generic/py_capi_utils.c
+++ b/source/blender/python/generic/py_capi_utils.c
@@ -85,7 +85,7 @@ int PyC_AsArray_FAST(
/* could use is_double for 'long int' but no use now */
int *array_int = array;
for (i = 0; i < length; i++) {
- array_int[i] = PyLong_AsLong(value_fast_items[i]);
+ array_int[i] = PyC_Long_AsI32(value_fast_items[i]);
}
}
else if (type == &PyBool_Type) {
@@ -127,54 +127,52 @@ int PyC_AsArray(
return ret;
}
+/* -------------------------------------------------------------------- */
+/** \name Typed Tuple Packing
+ *
+ * \note See #PyC_Tuple_Pack_* macros that take multiple arguments.
+ *
+ * \{ */
+
/* array utility function */
-PyObject *PyC_FromArray(const void *array, int length, const PyTypeObject *type,
- const bool is_double, const char *error_prefix)
+PyObject *PyC_Tuple_PackArray_F32(const float *array, uint len)
{
- PyObject *tuple;
- int i;
-
- tuple = PyTuple_New(length);
-
- /* for each type */
- if (type == &PyFloat_Type) {
- if (is_double) {
- const double *array_double = array;
- for (i = 0; i < length; ++i) {
- PyTuple_SET_ITEM(tuple, i, PyFloat_FromDouble(array_double[i]));
- }
- }
- else {
- const float *array_float = array;
- for (i = 0; i < length; ++i) {
- PyTuple_SET_ITEM(tuple, i, PyFloat_FromDouble(array_float[i]));
- }
- }
- }
- else if (type == &PyLong_Type) {
- /* could use is_double for 'long int' but no use now */
- const int *array_int = array;
- for (i = 0; i < length; ++i) {
- PyTuple_SET_ITEM(tuple, i, PyLong_FromLong(array_int[i]));
- }
+ PyObject *tuple = PyTuple_New(len);
+ for (uint i = 0; i < len; i++) {
+ PyTuple_SET_ITEM(tuple, i, PyFloat_FromDouble(array[i]));
}
- else if (type == &PyBool_Type) {
- const int *array_bool = array;
- for (i = 0; i < length; ++i) {
- PyTuple_SET_ITEM(tuple, i, PyBool_FromLong(array_bool[i]));
- }
+ return tuple;
+}
+
+PyObject *PyC_Tuple_PackArray_I32(const int *array, uint len)
+{
+ PyObject *tuple = PyTuple_New(len);
+ for (uint i = 0; i < len; i++) {
+ PyTuple_SET_ITEM(tuple, i, PyLong_FromLong(array[i]));
}
- else {
- Py_DECREF(tuple);
- PyErr_Format(PyExc_TypeError,
- "%s: internal error %s is invalid",
- error_prefix, type->tp_name);
- return NULL;
+ return tuple;
+}
+
+PyObject *PyC_Tuple_PackArray_I32FromBool(const int *array, uint len)
+{
+ PyObject *tuple = PyTuple_New(len);
+ for (uint i = 0; i < len; i++) {
+ PyTuple_SET_ITEM(tuple, i, PyBool_FromLong(array[i]));
}
+ return tuple;
+}
+PyObject *PyC_Tuple_PackArray_Bool(const bool *array, uint len)
+{
+ PyObject *tuple = PyTuple_New(len);
+ for (uint i = 0; i < len; i++) {
+ PyTuple_SET_ITEM(tuple, i, PyBool_FromLong(array[i]));
+ }
return tuple;
}
+/** \} */
+
/**
* Caller needs to ensure tuple is uninitialized.
* Handy for filling a tuple with None for eg.
@@ -203,6 +201,8 @@ void PyC_List_Fill(PyObject *list, PyObject *value)
/**
* Use with PyArg_ParseTuple's "O&" formatting.
+ *
+ * \see #PyC_Long_AsBool for a similar function to use outside of argument parsing.
*/
int PyC_ParseBool(PyObject *o, void *p)
{
@@ -300,7 +300,14 @@ void PyC_FileAndNum(const char **filename, int *lineno)
if (mod_name) {
PyObject *mod = PyDict_GetItem(PyImport_GetModuleDict(), mod_name);
if (mod) {
- *filename = PyModule_GetFilename(mod);
+ PyObject *mod_file = PyModule_GetFilenameObject(mod);
+ if (mod_file) {
+ *filename = _PyUnicode_AsString(mod_name);
+ Py_DECREF(mod_file);
+ }
+ else {
+ PyErr_Clear();
+ }
}
/* unlikely, fallback */
@@ -1108,3 +1115,101 @@ bool PyC_RunString_AsString(const char *expr, const char *filename, char **r_val
}
#endif /* #ifndef MATH_STANDALONE */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Int Conversion
+ *
+ * \note Python doesn't provide overflow checks for specific bit-widths.
+ *
+ * \{ */
+
+/* Compiler optimizes out redundant checks. */
+#ifdef __GNUC__
+# pragma warning(push)
+# pragma GCC diagnostic ignored "-Wtype-limits"
+#endif
+
+/**
+ * Don't use `bool` return type, so -1 can be used as an error value.
+ */
+int PyC_Long_AsBool(PyObject *value)
+{
+ int test = _PyLong_AsInt(value);
+ if (UNLIKELY((uint)test > 1)) {
+ PyErr_SetString(PyExc_TypeError,
+ "Python number not a bool (0/1)");
+ return -1;
+ }
+ return test;
+}
+
+int8_t PyC_Long_AsI8(PyObject *value)
+{
+ int test = _PyLong_AsInt(value);
+ if (UNLIKELY(test < INT8_MIN || test > INT8_MAX)) {
+ PyErr_SetString(PyExc_OverflowError,
+ "Python int too large to convert to C int8");
+ return -1;
+ }
+ return (int8_t)test;
+}
+
+int16_t PyC_Long_AsI16(PyObject *value)
+{
+ int test = _PyLong_AsInt(value);
+ if (UNLIKELY(test < INT16_MIN || test > INT16_MAX)) {
+ PyErr_SetString(PyExc_OverflowError,
+ "Python int too large to convert to C int16");
+ return -1;
+ }
+ return (int16_t)test;
+}
+
+/* Inlined in header:
+ * PyC_Long_AsI32
+ * PyC_Long_AsI64
+ */
+
+uint8_t PyC_Long_AsU8(PyObject *value)
+{
+ ulong test = PyLong_AsUnsignedLong(value);
+ if (UNLIKELY(test > UINT8_MAX)) {
+ PyErr_SetString(PyExc_OverflowError,
+ "Python int too large to convert to C uint8");
+ return (uint8_t)-1;
+ }
+ return (uint8_t)test;
+}
+
+uint16_t PyC_Long_AsU16(PyObject *value)
+{
+ ulong test = PyLong_AsUnsignedLong(value);
+ if (UNLIKELY(test > UINT16_MAX)) {
+ PyErr_SetString(PyExc_OverflowError,
+ "Python int too large to convert to C uint16");
+ return (uint16_t)-1;
+ }
+ return (uint16_t)test;
+}
+
+uint32_t PyC_Long_AsU32(PyObject *value)
+{
+ ulong test = PyLong_AsUnsignedLong(value);
+ if (UNLIKELY(test > UINT32_MAX)) {
+ PyErr_SetString(PyExc_OverflowError,
+ "Python int too large to convert to C uint32");
+ return (uint32_t)-1;
+ }
+ return (uint32_t)test;
+}
+
+/* Inlined in header:
+ * PyC_Long_AsU64
+ */
+
+#ifdef __GNUC__
+# pragma warning(pop)
+#endif
+
+/** \} */
diff --git a/source/blender/python/generic/py_capi_utils.h b/source/blender/python/generic/py_capi_utils.h
index 3f89e1d82a0..327d4e60954 100644
--- a/source/blender/python/generic/py_capi_utils.h
+++ b/source/blender/python/generic/py_capi_utils.h
@@ -24,10 +24,12 @@
* \ingroup pygen
*/
-
#ifndef __PY_CAPI_UTILS_H__
#define __PY_CAPI_UTILS_H__
+#include "BLI_sys_types.h"
+#include "BLI_utildefines_variadic.h"
+
void PyC_ObSpit(const char *name, PyObject *var);
void PyC_LineSpit(void);
void PyC_StackSpit(void);
@@ -44,8 +46,21 @@ int PyC_AsArray_FAST(
int PyC_AsArray(
void *array, PyObject *value, const Py_ssize_t length,
const PyTypeObject *type, const bool is_double, const char *error_prefix);
-PyObject * PyC_FromArray(const void *array, int length, const PyTypeObject *type,
- const bool is_double, const char *error_prefix);
+
+PyObject *PyC_Tuple_PackArray_F32(const float *array, uint len);
+PyObject *PyC_Tuple_PackArray_I32(const int *array, uint len);
+PyObject *PyC_Tuple_PackArray_I32FromBool(const int *array, uint len);
+PyObject *PyC_Tuple_PackArray_Bool(const bool *array, uint len);
+
+#define PyC_Tuple_Pack_F32(...) \
+ PyC_Tuple_PackArray_F32(((const float []){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__))
+#define PyC_Tuple_Pack_I32(...) \
+ PyC_Tuple_PackArray_I32(((const int []){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__))
+#define PyC_Tuple_Pack_I32FromBool(...) \
+ PyC_Tuple_PackArray_I32FromBool(((const int []){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__))
+#define PyC_Tuple_Pack_Bool(...) \
+ PyC_Tuple_PackArray_Bool(((const bool []){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__))
+
void PyC_Tuple_Fill(PyObject *tuple, PyObject *value);
void PyC_List_Fill(PyObject *list, PyObject *value);
@@ -85,4 +100,26 @@ bool PyC_RunString_AsString(const char *expr, const char *filename, char **r_val
int PyC_ParseBool(PyObject *o, void *p);
+
+/* Integer parsing (with overflow checks), -1 on error. */
+int PyC_Long_AsBool(PyObject *value);
+int8_t PyC_Long_AsI8(PyObject *value);
+int16_t PyC_Long_AsI16(PyObject *value);
+#if 0 /* inline */
+int32_t PyC_Long_AsI32(PyObject *value);
+int64_t PyC_Long_AsI64(PyObject *value);
+#endif
+
+uint8_t PyC_Long_AsU8(PyObject *value);
+uint16_t PyC_Long_AsU16(PyObject *value);
+uint32_t PyC_Long_AsU32(PyObject *value);
+#if 0 /* inline */
+uint64_t PyC_Long_AsU64(PyObject *value);
+#endif
+
+/* inline so type signatures match as expected */
+Py_LOCAL_INLINE(int32_t) PyC_Long_AsI32(PyObject *value) { return (int32_t)_PyLong_AsInt(value); }
+Py_LOCAL_INLINE(int64_t) PyC_Long_AsI64(PyObject *value) { return (int64_t)PyLong_AsLongLong(value); }
+Py_LOCAL_INLINE(uint64_t) PyC_Long_AsU64(PyObject *value) { return (uint64_t)PyLong_AsUnsignedLongLong(value); }
+
#endif /* __PY_CAPI_UTILS_H__ */
diff --git a/source/blender/python/generic/python_utildefines.h b/source/blender/python/generic/python_utildefines.h
index f7d3e7a8b4a..2d2d19c05f5 100644
--- a/source/blender/python/generic/python_utildefines.h
+++ b/source/blender/python/generic/python_utildefines.h
@@ -36,16 +36,16 @@ extern "C" {
PyTupleObject *op = (PyTupleObject *)op_arg; \
PyObject **ob_items = op->ob_item; \
CHECK_TYPE_ANY(op_arg, PyObject *, PyTupleObject *); \
- BLI_assert(_VA_NARGS_COUNT(__VA_ARGS__) == PyTuple_GET_SIZE(op)); \
+ BLI_assert(VA_NARGS_COUNT(__VA_ARGS__) == PyTuple_GET_SIZE(op)); \
ARRAY_SET_ITEMS(ob_items, __VA_ARGS__); \
} (void)0
/* wrap Py_INCREF & return the result,
* use sparingly to avoid comma operator or temp var assignment */
-BLI_INLINE PyObject *Py_INCREF_RET(PyObject *op) { Py_INCREF(op); return op; }
+Py_LOCAL_INLINE(PyObject *)Py_INCREF_RET(PyObject *op) { Py_INCREF(op); return op; }
/* append & transfer ownership to the list, avoids inline Py_DECREF all over (which is quite a large macro) */
-BLI_INLINE int PyList_APPEND(PyObject *op, PyObject *v)
+Py_LOCAL_INLINE(int) PyList_APPEND(PyObject *op, PyObject *v)
{
int ret = PyList_Append(op, v);
Py_DecRef(v);