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