Blender V2.61 - r43446

bpy_rna_array.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * Contributor(s): Arystanbek Dyussenov, Campbell Barton
00019  *
00020  * ***** END GPL LICENSE BLOCK *****
00021  */
00022 
00029 #include <Python.h>
00030 
00031 #include "RNA_types.h"
00032 
00033 #include "bpy_rna.h"
00034 #include "BKE_global.h"
00035 #include "MEM_guardedalloc.h"
00036 
00037 #include "RNA_access.h"
00038 
00039 #define USE_MATHUTILS
00040 
00041 #ifdef USE_MATHUTILS
00042 #  include "../mathutils/mathutils.h" /* so we can have mathutils callbacks */
00043 #endif
00044 
00045 #define MAX_ARRAY_DIMENSION 10
00046 
00047 typedef void (*ItemConvertFunc)(PyObject *, char *);
00048 typedef int  (*ItemTypeCheckFunc)(PyObject *);
00049 typedef void (*RNA_SetArrayFunc)(PointerRNA *, PropertyRNA *, const char *);
00050 typedef void (*RNA_SetIndexFunc)(PointerRNA *, PropertyRNA *, int index, void *);
00051 
00052 /*
00053   arr[3][4][5]
00054       0  1  2  <- dimension index
00055 */
00056 
00057 /*
00058   arr[2] = x
00059 
00060   py_to_array_index(arraydim=0, arrayoffset=0, index=2)
00061     validate_array(lvalue_dim=0)
00062     ... make real index ...
00063 */
00064 
00065 /* arr[3] = x, self->arraydim is 0, lvalue_dim is 1 */
00066 /* Ensures that a python sequence has expected number of items/sub-items and items are of desired type. */
00067 static int validate_array_type(PyObject *seq, int dim, int totdim, int dimsize[],
00068                                ItemTypeCheckFunc check_item_type, const char *item_type_str, const char *error_prefix)
00069 {
00070     Py_ssize_t i;
00071 
00072     /* not the last dimension */
00073     if (dim + 1 < totdim) {
00074         /* check that a sequence contains dimsize[dim] items */
00075         const Py_ssize_t seq_size = PySequence_Size(seq);
00076         if (seq_size == -1) {
00077             PyErr_Format(PyExc_ValueError, "%s sequence expected at dimension %d, not '%s'",
00078                          error_prefix, (int)dim + 1, Py_TYPE(seq)->tp_name);
00079             return -1;
00080         }
00081         for (i = 0; i < seq_size; i++) {
00082             PyObject *item;
00083             int ok = 1;
00084             item = PySequence_GetItem(seq, i);
00085 
00086             if (item == NULL) {
00087                 PyErr_Format(PyExc_TypeError, "%s sequence type '%s' failed to retrieve index %d",
00088                              error_prefix, Py_TYPE(seq)->tp_name, i);
00089                 ok = 0;
00090             }
00091             else if (!PySequence_Check(item)) {
00092                 /* BLI_snprintf(error_str, error_str_size, "expected a sequence of %s", item_type_str); */
00093                 PyErr_Format(PyExc_TypeError, "%s expected a sequence of %s, not %s",
00094                              error_prefix, item_type_str, Py_TYPE(item)->tp_name);
00095                 ok = 0;
00096             }
00097             /* arr[3][4][5]
00098              * dimsize[1] = 4
00099              * dimsize[2] = 5
00100              *
00101              * dim = 0 */
00102             else if (PySequence_Size(item) != dimsize[dim + 1]) {
00103                 /* BLI_snprintf(error_str, error_str_size,
00104                                 "sequences of dimension %d should contain %d items",
00105                                 (int)dim + 1, (int)dimsize[dim + 1]); */
00106                 PyErr_Format(PyExc_ValueError, "%s sequences of dimension %d should contain %d items",
00107                              error_prefix, (int)dim + 1, (int)dimsize[dim + 1]);
00108                 ok = 0;
00109             }
00110             else if (validate_array_type(item, dim + 1, totdim, dimsize, check_item_type, item_type_str, error_prefix) == -1) {
00111                 ok = 0;
00112             }
00113 
00114             Py_XDECREF(item);
00115 
00116             if (!ok) {
00117                 return -1;
00118             }
00119         }
00120     }
00121     else {
00122         /* check that items are of correct type */
00123         const int seq_size = PySequence_Size(seq);
00124         if (seq_size == -1) {
00125             PyErr_Format(PyExc_ValueError, "%s sequence expected at dimension %d, not '%s'",
00126                          error_prefix, (int)dim + 1, Py_TYPE(seq)->tp_name);
00127             return -1;
00128         }
00129         for (i = 0; i < seq_size; i++) {
00130             PyObject *item = PySequence_GetItem(seq, i);
00131 
00132             if (item == NULL) {
00133                 PyErr_Format(PyExc_TypeError, "%s sequence type '%s' failed to retrieve index %d",
00134                              error_prefix, Py_TYPE(seq)->tp_name, i);
00135                 return -1;
00136             }
00137             else if (!check_item_type(item)) {
00138                 Py_DECREF(item);
00139 
00140                 /* BLI_snprintf(error_str, error_str_size, "sequence items should be of type %s", item_type_str); */
00141                 PyErr_Format(PyExc_TypeError, "%s expected sequence items of type %s, not %s",
00142                              error_prefix, item_type_str, Py_TYPE(item)->tp_name);
00143                 return -1;
00144             }
00145 
00146             Py_DECREF(item);
00147         }
00148     }
00149 
00150     return 0; /* ok */
00151 }
00152 
00153 /* Returns the number of items in a single- or multi-dimensional sequence. */
00154 static int count_items(PyObject *seq, int dim)
00155 {
00156     int totitem = 0;
00157 
00158     if (dim > 1) {
00159         const Py_ssize_t seq_size = PySequence_Size(seq);
00160         Py_ssize_t i;
00161         for (i = 0; i < seq_size; i++) {
00162             PyObject *item = PySequence_GetItem(seq, i);
00163             if (item) {
00164                 const int tot = count_items(item, dim - 1);
00165                 Py_DECREF(item);
00166                 if (tot != -1) {
00167                     totitem += tot;
00168                 }
00169                 else {
00170                     totitem = -1;
00171                     break;
00172                 }
00173             }
00174             else {
00175                 totitem = -1;
00176                 break;
00177             }
00178         }
00179     }
00180     else {
00181         totitem = PySequence_Size(seq);
00182     }
00183 
00184     return totitem;
00185 }
00186 
00187 /* Modifies property array length if needed and PROP_DYNAMIC flag is set. */
00188 static int validate_array_length(PyObject *rvalue, PointerRNA *ptr, PropertyRNA *prop,
00189                                  int lvalue_dim, int *totitem, const char *error_prefix)
00190 {
00191     int dimsize[MAX_ARRAY_DIMENSION];
00192     int tot, totdim, len;
00193 
00194     totdim = RNA_property_array_dimension(ptr, prop, dimsize);
00195     tot = count_items(rvalue, totdim - lvalue_dim);
00196 
00197     if (tot == -1) {
00198         PyErr_Format(PyExc_ValueError, "%s %.200s.%.200s, error validating the sequence length",
00199                      error_prefix, RNA_struct_identifier(ptr->type), RNA_property_identifier(prop));
00200         return -1;
00201     }
00202     else if ((RNA_property_flag(prop) & PROP_DYNAMIC) && lvalue_dim == 0) {
00203         if (RNA_property_array_length(ptr, prop) != tot) {
00204 #if 0
00205             /* length is flexible */
00206             if (!RNA_property_dynamic_array_set_length(ptr, prop, tot)) {
00207                 /* BLI_snprintf(error_str, error_str_size,
00208                                 "%s.%s: array length cannot be changed to %d",
00209                                 RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), tot); */
00210                 PyErr_Format(PyExc_ValueError, "%s %s.%s: array length cannot be changed to %d",
00211                              error_prefix, RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), tot);
00212                 return -1;
00213             }
00214 #else
00215             *totitem = tot;
00216             return 0;
00217 
00218 #endif
00219         }
00220 
00221         len = tot;
00222     }
00223     else {
00224         /* length is a constraint */
00225         if (!lvalue_dim) {
00226             len = RNA_property_array_length(ptr, prop);
00227         }
00228         /* array item assignment */
00229         else {
00230             int i;
00231 
00232             len = 1;
00233 
00234             /* arr[3][4][5]
00235 
00236                arr[2] = x
00237                dimsize = {4, 5}
00238                dimsize[1] = 4
00239                dimsize[2] = 5
00240                lvalue_dim = 0, totdim = 3
00241 
00242                arr[2][3] = x
00243                lvalue_dim = 1
00244 
00245                arr[2][3][4] = x
00246                lvalue_dim = 2 */
00247             for (i = lvalue_dim; i < totdim; i++)
00248                 len *= dimsize[i];
00249         }
00250 
00251         if (tot != len) {
00252             /* BLI_snprintf(error_str, error_str_size, "sequence must have length of %d", len); */
00253             PyErr_Format(PyExc_ValueError, "%s %.200s.%.200s, sequence must have %d items total, not %d",
00254                          error_prefix, RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), len, tot);
00255             return -1;
00256         }
00257     }
00258 
00259     *totitem = len;
00260 
00261     return 0;
00262 }
00263 
00264 static int validate_array(PyObject *rvalue, PointerRNA *ptr, PropertyRNA *prop,
00265                           int lvalue_dim, ItemTypeCheckFunc check_item_type, const char *item_type_str, int *totitem,
00266                           const char *error_prefix)
00267 {
00268     int dimsize[MAX_ARRAY_DIMENSION];
00269     int totdim = RNA_property_array_dimension(ptr, prop, dimsize);
00270 
00271     /* validate type first because length validation may modify property array length */
00272 
00273 
00274 #ifdef USE_MATHUTILS
00275     if (lvalue_dim == 0) { /* only valid for first level array */
00276         if (MatrixObject_Check(rvalue)) {
00277             MatrixObject *pymat = (MatrixObject *)rvalue;
00278 
00279             if (BaseMath_ReadCallback(pymat) == -1)
00280                 return -1;
00281 
00282             if (RNA_property_type(prop) != PROP_FLOAT) {
00283                 PyErr_Format(PyExc_ValueError, "%s %.200s.%.200s, matrix assign to non float array",
00284                              error_prefix, RNA_struct_identifier(ptr->type), RNA_property_identifier(prop));
00285                 return -1;
00286             }
00287             else if (totdim != 2) {
00288                 PyErr_Format(PyExc_ValueError, "%s %.200s.%.200s, matrix assign array with %d dimensions",
00289                              error_prefix, RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), totdim);
00290                 return -1;
00291             }
00292             else if (pymat->num_col != dimsize[0] || pymat->num_row != dimsize[1]) {
00293                 PyErr_Format(PyExc_ValueError, "%s %.200s.%.200s, matrix assign dimension size mismatch, "
00294                              "is %dx%d, expected be %dx%d",
00295                              error_prefix, RNA_struct_identifier(ptr->type), RNA_property_identifier(prop),
00296                              pymat->num_col, pymat->num_row, dimsize[0], dimsize[1]);
00297                 return -1;
00298             }
00299             else {
00300                 *totitem = dimsize[0] * dimsize[1];
00301                 return 0;
00302             }
00303         }
00304     }
00305 #endif /* USE_MATHUTILS */
00306 
00307 
00308     {
00309         if (validate_array_type(rvalue, lvalue_dim, totdim, dimsize, check_item_type, item_type_str, error_prefix) == -1)
00310             return -1;
00311 
00312         return validate_array_length(rvalue, ptr, prop, lvalue_dim, totitem, error_prefix);
00313     }
00314 }
00315 
00316 static char *copy_value_single(PyObject *item, PointerRNA *ptr, PropertyRNA *prop,
00317                                char *data, unsigned int item_size, int *index,
00318                                ItemConvertFunc convert_item, RNA_SetIndexFunc rna_set_index)
00319 {
00320     if (!data) {
00321         char value[sizeof(int)];
00322 
00323         convert_item(item, value);
00324         rna_set_index(ptr, prop, *index, value);
00325         *index = *index + 1;
00326     }
00327     else {
00328         convert_item(item, data);
00329         data += item_size;
00330     }
00331 
00332     return data;
00333 }
00334 
00335 static char *copy_values(PyObject *seq, PointerRNA *ptr, PropertyRNA *prop,
00336                          int dim, char *data, unsigned int item_size, int *index,
00337                          ItemConvertFunc convert_item, RNA_SetIndexFunc rna_set_index)
00338 {
00339     int totdim = RNA_property_array_dimension(ptr, prop, NULL);
00340     const Py_ssize_t seq_size = PySequence_Size(seq);
00341     Py_ssize_t i;
00342 
00343     /* Regarding PySequence_GetItem() failing.
00344      *
00345      * This should never be NULL since we validated it, _but_ some triky python
00346      * developer could write their own sequence type which succeeds on
00347      * validating but fails later somehow, so include checks for safety.
00348      */
00349 
00350     /* Note that 'data can be NULL' */
00351 
00352     if (seq_size == -1) {
00353         return NULL;
00354     }
00355 
00356 
00357 #ifdef USE_MATHUTILS
00358     if (dim == 0) {
00359         if (MatrixObject_Check(seq)) {
00360             MatrixObject *pymat = (MatrixObject *)seq;
00361             size_t allocsize = pymat->num_col * pymat->num_row * sizeof(float);
00362 
00363             /* read callback already done by validate */
00364             /* since this is the first iteration we can assume data is allocated */
00365             memcpy(data, pymat->matrix, allocsize);
00366 
00367             /* not really needed but do for completeness */
00368             data += allocsize;
00369 
00370             return data;
00371         }
00372     }
00373 #endif /* USE_MATHUTILS */
00374 
00375 
00376     for (i = 0; i < seq_size; i++) {
00377         PyObject *item = PySequence_GetItem(seq, i);
00378         if (item) {
00379             if (dim + 1 < totdim) {
00380                 data = copy_values(item, ptr, prop, dim + 1, data, item_size, index, convert_item, rna_set_index);
00381             }
00382             else {
00383                 data = copy_value_single(item, ptr, prop, data, item_size, index, convert_item, rna_set_index);
00384             }
00385 
00386             Py_DECREF(item);
00387 
00388             /* data may be NULL, but the for loop checks */
00389         }
00390         else {
00391             return NULL;
00392         }
00393     }
00394 
00395     return data;
00396 }
00397 
00398 static int py_to_array(PyObject *seq, PointerRNA *ptr, PropertyRNA *prop,
00399                        char *param_data, ItemTypeCheckFunc check_item_type, const char *item_type_str, int item_size,
00400                        ItemConvertFunc convert_item, RNA_SetArrayFunc rna_set_array, const char *error_prefix)
00401 {
00402     /*int totdim, dim_size[MAX_ARRAY_DIMENSION];*/
00403     int totitem;
00404     char *data = NULL;
00405 
00406     /*totdim = RNA_property_array_dimension(ptr, prop, dim_size);*/ /*UNUSED*/
00407 
00408     if (validate_array(seq, ptr, prop, 0, check_item_type, item_type_str, &totitem, error_prefix) == -1) {
00409         return -1;
00410     }
00411 
00412     if (totitem) {
00413         /* note: this code is confusing */
00414         if (param_data && RNA_property_flag(prop) & PROP_DYNAMIC) {
00415             /* not freeing allocated mem, RNA_parameter_list_free() will do this */
00416             ParameterDynAlloc *param_alloc = (ParameterDynAlloc *)param_data;
00417             param_alloc->array_tot = (int)totitem;
00418             param_alloc->array = MEM_callocN(item_size * totitem, "py_to_array dyn"); /* freeing param list will free */
00419 
00420             data = param_alloc->array;
00421         }
00422         else if (param_data) {
00423             data = param_data;
00424         }
00425         else {
00426             data = PyMem_MALLOC(item_size * totitem);
00427         }
00428 
00429         /* will only fail in very rare cases since we already validated the
00430          * python data, the check here is mainly for completeness. */
00431         if (copy_values(seq, ptr, prop, 0, data, item_size, NULL, convert_item, NULL) != NULL) {
00432             if (param_data == NULL) {
00433                 /* NULL can only pass through in case RNA property arraylength is 0 (impossible?) */
00434                 rna_set_array(ptr, prop, data);
00435                 PyMem_FREE(data);
00436             }
00437         }
00438         else {
00439             if (param_data == NULL) {
00440                 PyMem_FREE(data);
00441             }
00442 
00443             PyErr_Format(PyExc_TypeError, "%s internal error parsing sequence of type '%s' after successful validation",
00444                          error_prefix, Py_TYPE(seq)->tp_name);
00445             return -1;
00446         }
00447     }
00448 
00449     return 0;
00450 }
00451 
00452 static int py_to_array_index(PyObject *py, PointerRNA *ptr, PropertyRNA *prop,
00453                              int lvalue_dim, int arrayoffset, int index,
00454                              ItemTypeCheckFunc check_item_type, const char *item_type_str,
00455                              ItemConvertFunc convert_item, RNA_SetIndexFunc rna_set_index, const char *error_prefix)
00456 {
00457     int totdim, dimsize[MAX_ARRAY_DIMENSION];
00458     int totitem, i;
00459 
00460     totdim = RNA_property_array_dimension(ptr, prop, dimsize);
00461 
00462     /* convert index */
00463 
00464     /* arr[3][4][5]
00465 
00466        arr[2] = x
00467        lvalue_dim = 0, index = 0 + 2 * 4 * 5
00468 
00469        arr[2][3] = x
00470        lvalue_dim = 1, index = 40 + 3 * 5 */
00471 
00472     lvalue_dim++;
00473 
00474     for (i = lvalue_dim; i < totdim; i++)
00475         index *= dimsize[i];
00476 
00477     index += arrayoffset;
00478 
00479     if (lvalue_dim == totdim) { /* single item, assign directly */
00480         if (!check_item_type(py)) {
00481             PyErr_Format(PyExc_TypeError, "%s %.200s.%.200s, expected a %s type, not %s",
00482                          error_prefix, RNA_struct_identifier(ptr->type),
00483                          RNA_property_identifier(prop), item_type_str,
00484                          Py_TYPE(py)->tp_name);
00485             return -1;
00486         }
00487         copy_value_single(py, ptr, prop, NULL, 0, &index, convert_item, rna_set_index);
00488     }
00489     else {
00490         if (validate_array(py, ptr, prop, lvalue_dim, check_item_type, item_type_str, &totitem, error_prefix) == -1) {
00491             return -1;
00492         }
00493 
00494         if (totitem) {
00495             copy_values(py, ptr, prop, lvalue_dim, NULL, 0, &index, convert_item, rna_set_index);
00496         }
00497     }
00498     return 0;
00499 }
00500 
00501 static void py_to_float(PyObject *py, char *data)
00502 {
00503     *(float *)data = (float)PyFloat_AsDouble(py);
00504 }
00505 
00506 static void py_to_int(PyObject *py, char *data)
00507 {
00508     *(int *)data = (int)PyLong_AsSsize_t(py);
00509 }
00510 
00511 static void py_to_bool(PyObject *py, char *data)
00512 {
00513     *(int *)data = (int)PyObject_IsTrue(py);
00514 }
00515 
00516 static int py_float_check(PyObject *py)
00517 {
00518     /* accept both floats and integers */
00519     return PyNumber_Check(py);
00520 }
00521 
00522 static int py_int_check(PyObject *py)
00523 {
00524     /* accept only integers */
00525     return PyLong_Check(py);
00526 }
00527 
00528 static int py_bool_check(PyObject *py)
00529 {
00530     return PyBool_Check(py);
00531 }
00532 
00533 static void float_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value)
00534 {
00535     RNA_property_float_set_index(ptr, prop, index, *(float *)value);
00536 }
00537 
00538 static void int_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value)
00539 {
00540     RNA_property_int_set_index(ptr, prop, index, *(int *)value);
00541 }
00542 
00543 static void bool_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value)
00544 {
00545     RNA_property_boolean_set_index(ptr, prop, index, *(int *)value);
00546 }
00547 
00548 int pyrna_py_to_array(PointerRNA *ptr, PropertyRNA *prop, char *param_data,
00549                       PyObject *py, const char *error_prefix)
00550 {
00551     int ret;
00552     switch (RNA_property_type(prop)) {
00553     case PROP_FLOAT:
00554         ret = py_to_array(py, ptr, prop, param_data, py_float_check, "float", sizeof(float),
00555                          py_to_float, (RNA_SetArrayFunc)RNA_property_float_set_array, error_prefix);
00556         break;
00557     case PROP_INT:
00558         ret = py_to_array(py, ptr, prop, param_data, py_int_check, "int", sizeof(int),
00559                          py_to_int, (RNA_SetArrayFunc)RNA_property_int_set_array, error_prefix);
00560         break;
00561     case PROP_BOOLEAN:
00562         ret = py_to_array(py, ptr, prop, param_data, py_bool_check, "boolean", sizeof(int),
00563                          py_to_bool, (RNA_SetArrayFunc)RNA_property_boolean_set_array, error_prefix);
00564         break;
00565     default:
00566         PyErr_SetString(PyExc_TypeError, "not an array type");
00567         ret = -1;
00568     }
00569 
00570     return ret;
00571 }
00572 
00573 int pyrna_py_to_array_index(PointerRNA *ptr, PropertyRNA *prop, int arraydim, int arrayoffset, int index,
00574                             PyObject *py, const char *error_prefix)
00575 {
00576     int ret;
00577     switch (RNA_property_type(prop)) {
00578     case PROP_FLOAT:
00579         ret = py_to_array_index(py, ptr, prop, arraydim, arrayoffset, index,
00580                                py_float_check, "float", py_to_float, float_set_index, error_prefix);
00581         break;
00582     case PROP_INT:
00583         ret = py_to_array_index(py, ptr, prop, arraydim, arrayoffset, index,
00584                                py_int_check, "int", py_to_int, int_set_index, error_prefix);
00585         break;
00586     case PROP_BOOLEAN:
00587         ret = py_to_array_index(py, ptr, prop, arraydim, arrayoffset, index,
00588                                py_bool_check, "boolean", py_to_bool, bool_set_index, error_prefix);
00589         break;
00590     default:
00591         PyErr_SetString(PyExc_TypeError, "not an array type");
00592         ret = -1;
00593     }
00594 
00595     return ret;
00596 }
00597 
00598 PyObject *pyrna_array_index(PointerRNA *ptr, PropertyRNA *prop, int index)
00599 {
00600     PyObject *item;
00601 
00602     switch (RNA_property_type(prop)) {
00603     case PROP_FLOAT:
00604         item = PyFloat_FromDouble(RNA_property_float_get_index(ptr, prop, index));
00605         break;
00606     case PROP_BOOLEAN:
00607         item = PyBool_FromLong(RNA_property_boolean_get_index(ptr, prop, index));
00608         break;
00609     case PROP_INT:
00610         item = PyLong_FromSsize_t(RNA_property_int_get_index(ptr, prop, index));
00611         break;
00612     default:
00613         PyErr_SetString(PyExc_TypeError, "not an array type");
00614         item = NULL;
00615     }
00616 
00617     return item;
00618 }
00619 
00620 #if 0
00621 /* XXX this is not used (and never will?) */
00622 /* Given an array property, creates an N-dimensional tuple of values. */
00623 static PyObject *pyrna_py_from_array_internal(PointerRNA *ptr, PropertyRNA *prop, int dim, int *index)
00624 {
00625     PyObject *tuple;
00626     int i, len;
00627     int totdim = RNA_property_array_dimension(ptr, prop, NULL);
00628 
00629     len = RNA_property_multi_array_length(ptr, prop, dim);
00630 
00631     tuple = PyTuple_New(len);
00632 
00633     for (i = 0; i < len; i++) {
00634         PyObject *item;
00635 
00636         if (dim + 1 < totdim)
00637             item = pyrna_py_from_array_internal(ptr, prop, dim + 1, index);
00638         else {
00639             item = pyrna_array_index(ptr, prop, *index);
00640             *index = *index + 1;
00641         }
00642 
00643         if (!item) {
00644             Py_DECREF(tuple);
00645             return NULL;
00646         }
00647 
00648         PyTuple_SET_ITEM(tuple, i, item);
00649     }
00650 
00651     return tuple;
00652 }
00653 #endif
00654 
00655 PyObject *pyrna_py_from_array_index(BPy_PropertyArrayRNA *self, PointerRNA *ptr, PropertyRNA *prop, int index)
00656 {
00657     int totdim, arraydim, arrayoffset, dimsize[MAX_ARRAY_DIMENSION], i, len;
00658     BPy_PropertyArrayRNA *ret = NULL;
00659 
00660     arraydim = self ? self->arraydim : 0;
00661     arrayoffset = self ? self->arrayoffset : 0;
00662 
00663     /* just in case check */
00664     len = RNA_property_multi_array_length(ptr, prop, arraydim);
00665     if (index >= len || index < 0) {
00666         /* this shouldn't happen because higher level funcs must check for invalid index */
00667         if (G.f & G_DEBUG) printf("pyrna_py_from_array_index: invalid index %d for array with length=%d\n", index, len);
00668 
00669         PyErr_SetString(PyExc_IndexError, "out of range");
00670         return NULL;
00671     }
00672 
00673     totdim = RNA_property_array_dimension(ptr, prop, dimsize);
00674 
00675     if (arraydim + 1 < totdim) {
00676         ret = (BPy_PropertyArrayRNA *)pyrna_prop_CreatePyObject(ptr, prop);
00677         ret->arraydim = arraydim + 1;
00678 
00679         /* arr[3][4][5]
00680 
00681            x = arr[2]
00682            index = 0 + 2 * 4 * 5
00683 
00684            x = arr[2][3]
00685            index = offset + 3 * 5 */
00686 
00687         for (i = arraydim + 1; i < totdim; i++)
00688             index *= dimsize[i];
00689 
00690         ret->arrayoffset = arrayoffset + index;
00691     }
00692     else {
00693         index = arrayoffset + index;
00694         ret = (BPy_PropertyArrayRNA *)pyrna_array_index(ptr, prop, index);
00695     }
00696 
00697     return (PyObject *)ret;
00698 }
00699 
00700 PyObject *pyrna_py_from_array(PointerRNA *ptr, PropertyRNA *prop)
00701 {
00702     PyObject *ret;
00703 
00704     ret = pyrna_math_object_from_array(ptr, prop);
00705 
00706     /* is this a maths object? */
00707     if (ret) return ret;
00708 
00709     return pyrna_prop_CreatePyObject(ptr, prop);
00710 }
00711 
00712 /* TODO, multi-dimensional arrays */
00713 int pyrna_array_contains_py(PointerRNA *ptr, PropertyRNA *prop, PyObject *value)
00714 {
00715     int len = RNA_property_array_length(ptr, prop);
00716     int type;
00717     int i;
00718 
00719     if (len == 0) /* possible with dynamic arrays */
00720         return 0;
00721 
00722     if (RNA_property_array_dimension(ptr, prop, NULL) > 1) {
00723         PyErr_SetString(PyExc_TypeError, "PropertyRNA - multi dimensional arrays not supported yet");
00724         return -1;
00725     }
00726 
00727     type = RNA_property_type(prop);
00728 
00729     switch (type) {
00730         case PROP_FLOAT:
00731         {
00732             float value_f = PyFloat_AsDouble(value);
00733             if (value_f == -1 && PyErr_Occurred()) {
00734                 PyErr_Clear();
00735                 return 0;
00736             }
00737             else {
00738                 float tmp[32];
00739                 float *tmp_arr;
00740 
00741                 if (len * sizeof(float) > sizeof(tmp)) {
00742                     tmp_arr = PyMem_MALLOC(len * sizeof(float));
00743                 }
00744                 else {
00745                     tmp_arr = tmp;
00746                 }
00747 
00748                 RNA_property_float_get_array(ptr, prop, tmp_arr);
00749 
00750                 for (i = 0; i < len; i++) {
00751                     if (tmp_arr[i] == value_f) {
00752                         break;
00753                     }
00754                 }
00755 
00756                 if (tmp_arr != tmp)
00757                     PyMem_FREE(tmp_arr);
00758 
00759                 return i < len ? 1 : 0;
00760             }
00761             break;
00762         }
00763         case PROP_BOOLEAN:
00764         case PROP_INT:
00765         {
00766             int value_i = PyLong_AsSsize_t(value);
00767             if (value_i == -1 && PyErr_Occurred()) {
00768                 PyErr_Clear();
00769                 return 0;
00770             }
00771             else {
00772                 int tmp[32];
00773                 int *tmp_arr;
00774 
00775                 if (len * sizeof(int) > sizeof(tmp)) {
00776                     tmp_arr = PyMem_MALLOC(len * sizeof(int));
00777                 }
00778                 else {
00779                     tmp_arr = tmp;
00780                 }
00781 
00782                 if (type == PROP_BOOLEAN)
00783                     RNA_property_boolean_get_array(ptr, prop, tmp_arr);
00784                 else
00785                     RNA_property_int_get_array(ptr, prop, tmp_arr);
00786 
00787                 for (i = 0; i < len; i++) {
00788                     if (tmp_arr[i] == value_i) {
00789                         break;
00790                     }
00791                 }
00792 
00793                 if (tmp_arr != tmp)
00794                     PyMem_FREE(tmp_arr);
00795 
00796                 return i < len ? 1 : 0;
00797             }
00798             break;
00799         }
00800     }
00801 
00802     /* should never reach this */
00803     PyErr_SetString(PyExc_TypeError, "PropertyRNA - type not in float/bool/int");
00804     return -1;
00805 }