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