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