diff options
Diffstat (limited to 'source/blender/python/generic')
-rw-r--r-- | source/blender/python/generic/bpy_internal_import.c | 13 | ||||
-rw-r--r-- | source/blender/python/generic/idprop_py_api.c | 6 | ||||
-rw-r--r-- | source/blender/python/generic/py_capi_utils.c | 187 | ||||
-rw-r--r-- | source/blender/python/generic/py_capi_utils.h | 43 | ||||
-rw-r--r-- | source/blender/python/generic/python_utildefines.h | 6 |
5 files changed, 203 insertions, 52 deletions
diff --git a/source/blender/python/generic/bpy_internal_import.c b/source/blender/python/generic/bpy_internal_import.c index ed2752d8372..7ab6447d21a 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 = (char *)_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); 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..053250a2a95 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_variadic_defines.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); |