Committing patch "[#27676] Change window size/resolution in realtime" by me.
[blender-staging.git] / source / blender / python / intern / bpy_rna_array.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s): Arystanbek Dyussenov, Campbell Barton
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/python/intern/bpy_rna_array.c
24  *  \ingroup pythonintern
25  *
26  * This file deals with array access for 'BPy_PropertyArrayRNA' from bpy_rna.c
27  */
28
29 #include <Python.h>
30
31 #include "RNA_types.h"
32
33 #include "bpy_rna.h"
34 #include "BKE_global.h"
35 #include "MEM_guardedalloc.h"
36
37 #include "RNA_access.h"
38
39 #define USE_MATHUTILS
40
41 #ifdef USE_MATHUTILS
42 #  include "../mathutils/mathutils.h" /* so we can have mathutils callbacks */
43 #endif
44
45 #define MAX_ARRAY_DIMENSION 10
46
47 typedef void (*ItemConvertFunc)(PyObject *, char *);
48 typedef int  (*ItemTypeCheckFunc)(PyObject *);
49 typedef void (*RNA_SetArrayFunc)(PointerRNA *, PropertyRNA *, const char *);
50 typedef void (*RNA_SetIndexFunc)(PointerRNA *, PropertyRNA *, int index, void *);
51
52 /*
53   arr[3][4][5]
54           0  1  2  <- dimension index
55 */
56
57 /*
58   arr[2] = x
59
60   py_to_array_index(arraydim=0, arrayoffset=0, index=2)
61         validate_array(lvalue_dim=0)
62         ... make real index ...
63 */
64
65 /* arr[3] = x, self->arraydim is 0, lvalue_dim is 1 */
66 /* Ensures that a python sequence has expected number of items/sub-items and items are of desired type. */
67 static int validate_array_type(PyObject *seq, int dim, int totdim, int dimsize[],
68                                                            ItemTypeCheckFunc check_item_type, const char *item_type_str, const char *error_prefix)
69 {
70         Py_ssize_t i;
71
72         /* not the last dimension */
73         if (dim + 1 < totdim) {
74                 /* check that a sequence contains dimsize[dim] items */
75                 const Py_ssize_t seq_size = PySequence_Size(seq);
76                 if (seq_size == -1) {
77                         PyErr_Format(PyExc_ValueError, "%s sequence expected at dimension %d, not '%s'",
78                                      error_prefix, (int)dim + 1, Py_TYPE(seq)->tp_name);
79                         return -1;
80                 }
81                 for (i = 0; i < seq_size; i++) {
82                         PyObject *item;
83                         int ok = 1;
84                         item = PySequence_GetItem(seq, i);
85
86                         if (item == NULL) {
87                                 PyErr_Format(PyExc_TypeError, "%s sequence type '%s' failed to retrieve index %d",
88                                              error_prefix, Py_TYPE(seq)->tp_name, i);
89                                 ok = 0;
90                         }
91                         else if (!PySequence_Check(item)) {
92                                 /* BLI_snprintf(error_str, error_str_size, "expected a sequence of %s", item_type_str); */
93                                 PyErr_Format(PyExc_TypeError, "%s expected a sequence of %s, not %s",
94                                              error_prefix, item_type_str, Py_TYPE(item)->tp_name);
95                                 ok = 0;
96                         }
97                         /* arr[3][4][5]
98                          * dimsize[1] = 4
99                          * dimsize[2] = 5
100                          *
101                          * dim = 0 */
102                         else if (PySequence_Size(item) != dimsize[dim + 1]) {
103                                 /* BLI_snprintf(error_str, error_str_size,
104                                                 "sequences of dimension %d should contain %d items",
105                                                 (int)dim + 1, (int)dimsize[dim + 1]); */
106                                 PyErr_Format(PyExc_ValueError, "%s sequences of dimension %d should contain %d items",
107                                              error_prefix, (int)dim + 1, (int)dimsize[dim + 1]);
108                                 ok = 0;
109                         }
110                         else if (validate_array_type(item, dim + 1, totdim, dimsize, check_item_type, item_type_str, error_prefix) == -1) {
111                                 ok = 0;
112                         }
113
114                         Py_XDECREF(item);
115
116                         if (!ok) {
117                                 return -1;
118                         }
119                 }
120         }
121         else {
122                 /* check that items are of correct type */
123                 const int seq_size = PySequence_Size(seq);
124                 if (seq_size == -1) {
125                         PyErr_Format(PyExc_ValueError, "%s sequence expected at dimension %d, not '%s'",
126                                      error_prefix, (int)dim + 1, Py_TYPE(seq)->tp_name);
127                         return -1;
128                 }
129                 for (i = 0; i < seq_size; i++) {
130                         PyObject *item = PySequence_GetItem(seq, i);
131
132                         if (item == NULL) {
133                                 PyErr_Format(PyExc_TypeError, "%s sequence type '%s' failed to retrieve index %d",
134                                              error_prefix, Py_TYPE(seq)->tp_name, i);
135                                 return -1;
136                         }
137                         else if (!check_item_type(item)) {
138                                 Py_DECREF(item);
139
140                                 /* BLI_snprintf(error_str, error_str_size, "sequence items should be of type %s", item_type_str); */
141                                 PyErr_Format(PyExc_TypeError, "%s expected sequence items of type %s, not %s",
142                                              error_prefix, item_type_str, Py_TYPE(item)->tp_name);
143                                 return -1;
144                         }
145
146                         Py_DECREF(item);
147                 }
148         }
149
150         return 0; /* ok */
151 }
152
153 /* Returns the number of items in a single- or multi-dimensional sequence. */
154 static int count_items(PyObject *seq, int dim)
155 {
156         int totitem = 0;
157
158         if (dim > 1) {
159                 const Py_ssize_t seq_size = PySequence_Size(seq);
160                 Py_ssize_t i;
161                 for (i = 0; i < seq_size; i++) {
162                         PyObject *item = PySequence_GetItem(seq, i);
163                         if (item) {
164                                 const int tot = count_items(item, dim - 1);
165                                 Py_DECREF(item);
166                                 if (tot != -1) {
167                                         totitem += tot;
168                                 }
169                                 else {
170                                         totitem = -1;
171                                         break;
172                                 }
173                         }
174                         else {
175                                 totitem = -1;
176                                 break;
177                         }
178                 }
179         }
180         else {
181                 totitem = PySequence_Size(seq);
182         }
183
184         return totitem;
185 }
186
187 /* Modifies property array length if needed and PROP_DYNAMIC flag is set. */
188 static int validate_array_length(PyObject *rvalue, PointerRNA *ptr, PropertyRNA *prop,
189                                  int lvalue_dim, int *totitem, const char *error_prefix)
190 {
191         int dimsize[MAX_ARRAY_DIMENSION];
192         int tot, totdim, len;
193
194         totdim = RNA_property_array_dimension(ptr, prop, dimsize);
195         tot = count_items(rvalue, totdim - lvalue_dim);
196
197         if (tot == -1) {
198                 PyErr_Format(PyExc_ValueError, "%s %.200s.%.200s, error validating the sequence length",
199                              error_prefix, RNA_struct_identifier(ptr->type), RNA_property_identifier(prop));
200                 return -1;
201         }
202         else if ((RNA_property_flag(prop) & PROP_DYNAMIC) && lvalue_dim == 0) {
203                 if (RNA_property_array_length(ptr, prop) != tot) {
204 #if 0
205                         /* length is flexible */
206                         if (!RNA_property_dynamic_array_set_length(ptr, prop, tot)) {
207                                 /* BLI_snprintf(error_str, error_str_size,
208                                                 "%s.%s: array length cannot be changed to %d",
209                                                 RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), tot); */
210                                 PyErr_Format(PyExc_ValueError, "%s %s.%s: array length cannot be changed to %d",
211                                              error_prefix, RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), tot);
212                                 return -1;
213                         }
214 #else
215                         *totitem = tot;
216                         return 0;
217
218 #endif
219                 }
220
221                 len = tot;
222         }
223         else {
224                 /* length is a constraint */
225                 if (!lvalue_dim) {
226                         len = RNA_property_array_length(ptr, prop);
227                 }
228                 /* array item assignment */
229                 else {
230                         int i;
231
232                         len = 1;
233
234                         /* arr[3][4][5]
235
236                            arr[2] = x
237                            dimsize = {4, 5}
238                            dimsize[1] = 4
239                            dimsize[2] = 5
240                            lvalue_dim = 0, totdim = 3
241
242                            arr[2][3] = x
243                            lvalue_dim = 1
244
245                            arr[2][3][4] = x
246                            lvalue_dim = 2 */
247                         for (i = lvalue_dim; i < totdim; i++)
248                                 len *= dimsize[i];
249                 }
250
251                 if (tot != len) {
252                         /* BLI_snprintf(error_str, error_str_size, "sequence must have length of %d", len); */
253                         PyErr_Format(PyExc_ValueError, "%s %.200s.%.200s, sequence must have %d items total, not %d",
254                                      error_prefix, RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), len, tot);
255                         return -1;
256                 }
257         }
258
259         *totitem = len;
260
261         return 0;
262 }
263
264 static int validate_array(PyObject *rvalue, PointerRNA *ptr, PropertyRNA *prop,
265                           int lvalue_dim, ItemTypeCheckFunc check_item_type, const char *item_type_str, int *totitem,
266                           const char *error_prefix)
267 {
268         int dimsize[MAX_ARRAY_DIMENSION];
269         int totdim = RNA_property_array_dimension(ptr, prop, dimsize);
270
271         /* validate type first because length validation may modify property array length */
272
273
274 #ifdef USE_MATHUTILS
275         if (lvalue_dim == 0) { /* only valid for first level array */
276                 if (MatrixObject_Check(rvalue)) {
277                         MatrixObject *pymat = (MatrixObject *)rvalue;
278
279                         if (BaseMath_ReadCallback(pymat) == -1)
280                                 return -1;
281
282                         if (RNA_property_type(prop) != PROP_FLOAT) {
283                                 PyErr_Format(PyExc_ValueError, "%s %.200s.%.200s, matrix assign to non float array",
284                                              error_prefix, RNA_struct_identifier(ptr->type), RNA_property_identifier(prop));
285                                 return -1;
286                         }
287                         else if (totdim != 2) {
288                                 PyErr_Format(PyExc_ValueError, "%s %.200s.%.200s, matrix assign array with %d dimensions",
289                                              error_prefix, RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), totdim);
290                                 return -1;
291                         }
292                         else if (pymat->num_col != dimsize[0] || pymat->num_row != dimsize[1]) {
293                                 PyErr_Format(PyExc_ValueError, "%s %.200s.%.200s, matrix assign dimension size mismatch, "
294                                              "is %dx%d, expected be %dx%d",
295                                              error_prefix, RNA_struct_identifier(ptr->type), RNA_property_identifier(prop),
296                                              pymat->num_col, pymat->num_row, dimsize[0], dimsize[1]);
297                                 return -1;
298                         }
299                         else {
300                                 *totitem = dimsize[0] * dimsize[1];
301                                 return 0;
302                         }
303                 }
304         }
305 #endif /* USE_MATHUTILS */
306
307
308         {
309                 if (validate_array_type(rvalue, lvalue_dim, totdim, dimsize, check_item_type, item_type_str, error_prefix) == -1)
310                         return -1;
311
312                 return validate_array_length(rvalue, ptr, prop, lvalue_dim, totitem, error_prefix);
313         }
314 }
315
316 static char *copy_value_single(PyObject *item, PointerRNA *ptr, PropertyRNA *prop,
317                                char *data, unsigned int item_size, int *index,
318                                ItemConvertFunc convert_item, RNA_SetIndexFunc rna_set_index)
319 {
320         if (!data) {
321                 char value[sizeof(int)];
322
323                 convert_item(item, value);
324                 rna_set_index(ptr, prop, *index, value);
325                 *index = *index + 1;
326         }
327         else {
328                 convert_item(item, data);
329                 data += item_size;
330         }
331
332         return data;
333 }
334
335 static char *copy_values(PyObject *seq, PointerRNA *ptr, PropertyRNA *prop,
336                          int dim, char *data, unsigned int item_size, int *index,
337                          ItemConvertFunc convert_item, RNA_SetIndexFunc rna_set_index)
338 {
339         int totdim = RNA_property_array_dimension(ptr, prop, NULL);
340         const Py_ssize_t seq_size = PySequence_Size(seq);
341         Py_ssize_t i;
342
343         /* Regarding PySequence_GetItem() failing.
344          *
345          * This should never be NULL since we validated it, _but_ some triky python
346          * developer could write their own sequence type which succeeds on
347          * validating but fails later somehow, so include checks for safety.
348          */
349
350         /* Note that 'data can be NULL' */
351
352         if (seq_size == -1) {
353                 return NULL;
354         }
355
356
357 #ifdef USE_MATHUTILS
358         if (dim == 0) {
359                 if (MatrixObject_Check(seq)) {
360                         MatrixObject *pymat = (MatrixObject *)seq;
361                         size_t allocsize = pymat->num_col * pymat->num_row * sizeof(float);
362
363                         /* read callback already done by validate */
364                         /* since this is the first iteration we can assume data is allocated */
365                         memcpy(data, pymat->matrix, allocsize);
366
367                         /* not really needed but do for completeness */
368                         data += allocsize;
369
370                         return data;
371                 }
372         }
373 #endif /* USE_MATHUTILS */
374
375
376         for (i = 0; i < seq_size; i++) {
377                 PyObject *item = PySequence_GetItem(seq, i);
378                 if (item) {
379                         if (dim + 1 < totdim) {
380                                 data = copy_values(item, ptr, prop, dim + 1, data, item_size, index, convert_item, rna_set_index);
381                         }
382                         else {
383                                 data = copy_value_single(item, ptr, prop, data, item_size, index, convert_item, rna_set_index);
384                         }
385
386                         Py_DECREF(item);
387
388                         /* data may be NULL, but the for loop checks */
389                 }
390                 else {
391                         return NULL;
392                 }
393         }
394
395         return data;
396 }
397
398 static int py_to_array(PyObject *seq, PointerRNA *ptr, PropertyRNA *prop,
399                        char *param_data, ItemTypeCheckFunc check_item_type, const char *item_type_str, int item_size,
400                        ItemConvertFunc convert_item, RNA_SetArrayFunc rna_set_array, const char *error_prefix)
401 {
402         /*int totdim, dim_size[MAX_ARRAY_DIMENSION];*/
403         int totitem;
404         char *data = NULL;
405
406         /*totdim = RNA_property_array_dimension(ptr, prop, dim_size);*/ /*UNUSED*/
407
408         if (validate_array(seq, ptr, prop, 0, check_item_type, item_type_str, &totitem, error_prefix) == -1) {
409                 return -1;
410         }
411
412         if (totitem) {
413                 /* note: this code is confusing */
414                 if (param_data && RNA_property_flag(prop) & PROP_DYNAMIC) {
415                         /* not freeing allocated mem, RNA_parameter_list_free() will do this */
416                         ParameterDynAlloc *param_alloc = (ParameterDynAlloc *)param_data;
417                         param_alloc->array_tot = (int)totitem;
418                         param_alloc->array = MEM_callocN(item_size * totitem, "py_to_array dyn"); /* freeing param list will free */
419
420                         data = param_alloc->array;
421                 }
422                 else if (param_data) {
423                         data = param_data;
424                 }
425                 else {
426                         data = PyMem_MALLOC(item_size * totitem);
427                 }
428
429                 /* will only fail in very rare cases since we already validated the
430                  * python data, the check here is mainly for completeness. */
431                 if (copy_values(seq, ptr, prop, 0, data, item_size, NULL, convert_item, NULL) != NULL) {
432                         if (param_data == NULL) {
433                                 /* NULL can only pass through in case RNA property arraylength is 0 (impossible?) */
434                                 rna_set_array(ptr, prop, data);
435                                 PyMem_FREE(data);
436                         }
437                 }
438                 else {
439                         if (param_data == NULL) {
440                                 PyMem_FREE(data);
441                         }
442
443                         PyErr_Format(PyExc_TypeError, "%s internal error parsing sequence of type '%s' after successful validation",
444                                      error_prefix, Py_TYPE(seq)->tp_name);
445                         return -1;
446                 }
447         }
448
449         return 0;
450 }
451
452 static int py_to_array_index(PyObject *py, PointerRNA *ptr, PropertyRNA *prop,
453                              int lvalue_dim, int arrayoffset, int index,
454                              ItemTypeCheckFunc check_item_type, const char *item_type_str,
455                              ItemConvertFunc convert_item, RNA_SetIndexFunc rna_set_index, const char *error_prefix)
456 {
457         int totdim, dimsize[MAX_ARRAY_DIMENSION];
458         int totitem, i;
459
460         totdim = RNA_property_array_dimension(ptr, prop, dimsize);
461
462         /* convert index */
463
464         /* arr[3][4][5]
465
466            arr[2] = x
467            lvalue_dim = 0, index = 0 + 2 * 4 * 5
468
469            arr[2][3] = x
470            lvalue_dim = 1, index = 40 + 3 * 5 */
471
472         lvalue_dim++;
473
474         for (i = lvalue_dim; i < totdim; i++)
475                 index *= dimsize[i];
476
477         index += arrayoffset;
478
479         if (lvalue_dim == totdim) { /* single item, assign directly */
480                 if (!check_item_type(py)) {
481                         PyErr_Format(PyExc_TypeError, "%s %.200s.%.200s, expected a %s type, not %s",
482                                      error_prefix, RNA_struct_identifier(ptr->type),
483                                      RNA_property_identifier(prop), item_type_str,
484                                      Py_TYPE(py)->tp_name);
485                         return -1;
486                 }
487                 copy_value_single(py, ptr, prop, NULL, 0, &index, convert_item, rna_set_index);
488         }
489         else {
490                 if (validate_array(py, ptr, prop, lvalue_dim, check_item_type, item_type_str, &totitem, error_prefix) == -1) {
491                         return -1;
492                 }
493
494                 if (totitem) {
495                         copy_values(py, ptr, prop, lvalue_dim, NULL, 0, &index, convert_item, rna_set_index);
496                 }
497         }
498         return 0;
499 }
500
501 static void py_to_float(PyObject *py, char *data)
502 {
503         *(float *)data = (float)PyFloat_AsDouble(py);
504 }
505
506 static void py_to_int(PyObject *py, char *data)
507 {
508         *(int *)data = (int)PyLong_AsSsize_t(py);
509 }
510
511 static void py_to_bool(PyObject *py, char *data)
512 {
513         *(int *)data = (int)PyObject_IsTrue(py);
514 }
515
516 static int py_float_check(PyObject *py)
517 {
518         /* accept both floats and integers */
519         return PyNumber_Check(py);
520 }
521
522 static int py_int_check(PyObject *py)
523 {
524         /* accept only integers */
525         return PyLong_Check(py);
526 }
527
528 static int py_bool_check(PyObject *py)
529 {
530         return PyBool_Check(py);
531 }
532
533 static void float_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value)
534 {
535         RNA_property_float_set_index(ptr, prop, index, *(float *)value);
536 }
537
538 static void int_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value)
539 {
540         RNA_property_int_set_index(ptr, prop, index, *(int *)value);
541 }
542
543 static void bool_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value)
544 {
545         RNA_property_boolean_set_index(ptr, prop, index, *(int *)value);
546 }
547
548 int pyrna_py_to_array(PointerRNA *ptr, PropertyRNA *prop, char *param_data,
549                       PyObject *py, const char *error_prefix)
550 {
551         int ret;
552         switch (RNA_property_type(prop)) {
553         case PROP_FLOAT:
554                 ret = py_to_array(py, ptr, prop, param_data, py_float_check, "float", sizeof(float),
555                                  py_to_float, (RNA_SetArrayFunc)RNA_property_float_set_array, error_prefix);
556                 break;
557         case PROP_INT:
558                 ret = py_to_array(py, ptr, prop, param_data, py_int_check, "int", sizeof(int),
559                                  py_to_int, (RNA_SetArrayFunc)RNA_property_int_set_array, error_prefix);
560                 break;
561         case PROP_BOOLEAN:
562                 ret = py_to_array(py, ptr, prop, param_data, py_bool_check, "boolean", sizeof(int),
563                                  py_to_bool, (RNA_SetArrayFunc)RNA_property_boolean_set_array, error_prefix);
564                 break;
565         default:
566                 PyErr_SetString(PyExc_TypeError, "not an array type");
567                 ret = -1;
568         }
569
570         return ret;
571 }
572
573 int pyrna_py_to_array_index(PointerRNA *ptr, PropertyRNA *prop, int arraydim, int arrayoffset, int index,
574                             PyObject *py, const char *error_prefix)
575 {
576         int ret;
577         switch (RNA_property_type(prop)) {
578         case PROP_FLOAT:
579                 ret = py_to_array_index(py, ptr, prop, arraydim, arrayoffset, index,
580                                        py_float_check, "float", py_to_float, float_set_index, error_prefix);
581                 break;
582         case PROP_INT:
583                 ret = py_to_array_index(py, ptr, prop, arraydim, arrayoffset, index,
584                                        py_int_check, "int", py_to_int, int_set_index, error_prefix);
585                 break;
586         case PROP_BOOLEAN:
587                 ret = py_to_array_index(py, ptr, prop, arraydim, arrayoffset, index,
588                                        py_bool_check, "boolean", py_to_bool, bool_set_index, error_prefix);
589                 break;
590         default:
591                 PyErr_SetString(PyExc_TypeError, "not an array type");
592                 ret = -1;
593         }
594
595         return ret;
596 }
597
598 PyObject *pyrna_array_index(PointerRNA *ptr, PropertyRNA *prop, int index)
599 {
600         PyObject *item;
601
602         switch (RNA_property_type(prop)) {
603         case PROP_FLOAT:
604                 item = PyFloat_FromDouble(RNA_property_float_get_index(ptr, prop, index));
605                 break;
606         case PROP_BOOLEAN:
607                 item = PyBool_FromLong(RNA_property_boolean_get_index(ptr, prop, index));
608                 break;
609         case PROP_INT:
610                 item = PyLong_FromSsize_t(RNA_property_int_get_index(ptr, prop, index));
611                 break;
612         default:
613                 PyErr_SetString(PyExc_TypeError, "not an array type");
614                 item = NULL;
615         }
616
617         return item;
618 }
619
620 #if 0
621 /* XXX this is not used (and never will?) */
622 /* Given an array property, creates an N-dimensional tuple of values. */
623 static PyObject *pyrna_py_from_array_internal(PointerRNA *ptr, PropertyRNA *prop, int dim, int *index)
624 {
625         PyObject *tuple;
626         int i, len;
627         int totdim = RNA_property_array_dimension(ptr, prop, NULL);
628
629         len = RNA_property_multi_array_length(ptr, prop, dim);
630
631         tuple = PyTuple_New(len);
632
633         for (i = 0; i < len; i++) {
634                 PyObject *item;
635
636                 if (dim + 1 < totdim)
637                         item = pyrna_py_from_array_internal(ptr, prop, dim + 1, index);
638                 else {
639                         item = pyrna_array_index(ptr, prop, *index);
640                         *index = *index + 1;
641                 }
642
643                 if (!item) {
644                         Py_DECREF(tuple);
645                         return NULL;
646                 }
647
648                 PyTuple_SET_ITEM(tuple, i, item);
649         }
650
651         return tuple;
652 }
653 #endif
654
655 PyObject *pyrna_py_from_array_index(BPy_PropertyArrayRNA *self, PointerRNA *ptr, PropertyRNA *prop, int index)
656 {
657         int totdim, arraydim, arrayoffset, dimsize[MAX_ARRAY_DIMENSION], i, len;
658         BPy_PropertyArrayRNA *ret = NULL;
659
660         arraydim = self ? self->arraydim : 0;
661         arrayoffset = self ? self->arrayoffset : 0;
662
663         /* just in case check */
664         len = RNA_property_multi_array_length(ptr, prop, arraydim);
665         if (index >= len || index < 0) {
666                 /* this shouldn't happen because higher level funcs must check for invalid index */
667                 if (G.f & G_DEBUG) printf("pyrna_py_from_array_index: invalid index %d for array with length=%d\n", index, len);
668
669                 PyErr_SetString(PyExc_IndexError, "out of range");
670                 return NULL;
671         }
672
673         totdim = RNA_property_array_dimension(ptr, prop, dimsize);
674
675         if (arraydim + 1 < totdim) {
676                 ret = (BPy_PropertyArrayRNA *)pyrna_prop_CreatePyObject(ptr, prop);
677                 ret->arraydim = arraydim + 1;
678
679                 /* arr[3][4][5]
680
681                    x = arr[2]
682                    index = 0 + 2 * 4 * 5
683
684                    x = arr[2][3]
685                    index = offset + 3 * 5 */
686
687                 for (i = arraydim + 1; i < totdim; i++)
688                         index *= dimsize[i];
689
690                 ret->arrayoffset = arrayoffset + index;
691         }
692         else {
693                 index = arrayoffset + index;
694                 ret = (BPy_PropertyArrayRNA *)pyrna_array_index(ptr, prop, index);
695         }
696
697         return (PyObject *)ret;
698 }
699
700 PyObject *pyrna_py_from_array(PointerRNA *ptr, PropertyRNA *prop)
701 {
702         PyObject *ret;
703
704         ret = pyrna_math_object_from_array(ptr, prop);
705
706         /* is this a maths object? */
707         if (ret) return ret;
708
709         return pyrna_prop_CreatePyObject(ptr, prop);
710 }
711
712 /* TODO, multi-dimensional arrays */
713 int pyrna_array_contains_py(PointerRNA *ptr, PropertyRNA *prop, PyObject *value)
714 {
715         int len = RNA_property_array_length(ptr, prop);
716         int type;
717         int i;
718
719         if (len == 0) /* possible with dynamic arrays */
720                 return 0;
721
722         if (RNA_property_array_dimension(ptr, prop, NULL) > 1) {
723                 PyErr_SetString(PyExc_TypeError, "PropertyRNA - multi dimensional arrays not supported yet");
724                 return -1;
725         }
726
727         type = RNA_property_type(prop);
728
729         switch (type) {
730                 case PROP_FLOAT:
731                 {
732                         float value_f = PyFloat_AsDouble(value);
733                         if (value_f == -1 && PyErr_Occurred()) {
734                                 PyErr_Clear();
735                                 return 0;
736                         }
737                         else {
738                                 float tmp[32];
739                                 float *tmp_arr;
740
741                                 if (len * sizeof(float) > sizeof(tmp)) {
742                                         tmp_arr = PyMem_MALLOC(len * sizeof(float));
743                                 }
744                                 else {
745                                         tmp_arr = tmp;
746                                 }
747
748                                 RNA_property_float_get_array(ptr, prop, tmp_arr);
749
750                                 for (i = 0; i < len; i++) {
751                                         if (tmp_arr[i] == value_f) {
752                                                 break;
753                                         }
754                                 }
755
756                                 if (tmp_arr != tmp)
757                                         PyMem_FREE(tmp_arr);
758
759                                 return i < len ? 1 : 0;
760                         }
761                         break;
762                 }
763                 case PROP_BOOLEAN:
764                 case PROP_INT:
765                 {
766                         int value_i = PyLong_AsSsize_t(value);
767                         if (value_i == -1 && PyErr_Occurred()) {
768                                 PyErr_Clear();
769                                 return 0;
770                         }
771                         else {
772                                 int tmp[32];
773                                 int *tmp_arr;
774
775                                 if (len * sizeof(int) > sizeof(tmp)) {
776                                         tmp_arr = PyMem_MALLOC(len * sizeof(int));
777                                 }
778                                 else {
779                                         tmp_arr = tmp;
780                                 }
781
782                                 if (type == PROP_BOOLEAN)
783                                         RNA_property_boolean_get_array(ptr, prop, tmp_arr);
784                                 else
785                                         RNA_property_int_get_array(ptr, prop, tmp_arr);
786
787                                 for (i = 0; i < len; i++) {
788                                         if (tmp_arr[i] == value_i) {
789                                                 break;
790                                         }
791                                 }
792
793                                 if (tmp_arr != tmp)
794                                         PyMem_FREE(tmp_arr);
795
796                                 return i < len ? 1 : 0;
797                         }
798                         break;
799                 }
800         }
801
802         /* should never reach this */
803         PyErr_SetString(PyExc_TypeError, "PropertyRNA - type not in float/bool/int");
804         return -1;
805 }