doxygen: prevent GPL license block from being parsed as doxygen comment.
[blender.git] / source / blender / python / intern / bpy_rna_array.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * Contributor(s): Arystanbek Dyussenov
21  *
22  * ***** END GPL LICENSE BLOCK *****
23  */
24 #include <Python.h>
25
26 #include "bpy_rna.h"
27 #include "BKE_global.h"
28 #include "MEM_guardedalloc.h"
29
30 #define MAX_ARRAY_DIMENSION 10
31
32 typedef void (*ItemConvertFunc)(PyObject *, char *);
33 typedef int  (*ItemTypeCheckFunc)(PyObject *);
34 typedef void (*RNA_SetArrayFunc)(PointerRNA *, PropertyRNA *, const char *);
35 typedef void (*RNA_SetIndexFunc)(PointerRNA *, PropertyRNA *, int index, void *);
36
37 /*
38   arr[3][4][5]
39           0  1  2  <- dimension index
40 */
41
42 /*
43   arr[2] = x
44
45   py_to_array_index(arraydim=0, arrayoffset=0, index=2)
46         validate_array(lvalue_dim=0)
47         ... make real index ...
48 */
49
50 /* arr[3]=x, self->arraydim is 0, lvalue_dim is 1 */
51 /* Ensures that a python sequence has expected number of items/sub-items and items are of desired type. */
52 static int validate_array_type(PyObject *seq, int dim, int totdim, int dimsize[],
53                                                            ItemTypeCheckFunc check_item_type, const char *item_type_str, const char *error_prefix)
54 {
55         int i;
56
57         /* not the last dimension */
58         if (dim + 1 < totdim) {
59                 /* check that a sequence contains dimsize[dim] items */
60                 const int seq_size= PySequence_Size(seq);
61                 for (i= 0; i < seq_size; i++) {
62                         PyObject *item;
63                         int ok= 1;
64                         item= PySequence_GetItem(seq, i);
65
66                         if (!PySequence_Check(item)) {
67                                 /* BLI_snprintf(error_str, error_str_size, "expected a sequence of %s", item_type_str); */
68                                 PyErr_Format(PyExc_TypeError, "%s expected a sequence of %s, not %s", error_prefix, item_type_str, Py_TYPE(item)->tp_name);
69                                 ok= 0;
70                         }
71                         /* arr[3][4][5]
72                            dimsize[1]=4
73                            dimsize[2]=5
74                    
75                            dim=0 */
76                         else if (PySequence_Size(item) != dimsize[dim + 1]) {
77                                 /* BLI_snprintf(error_str, error_str_size, "sequences of dimension %d should contain %d items", (int)dim + 1, (int)dimsize[dim + 1]); */
78                                 PyErr_Format(PyExc_ValueError, "%s sequences of dimension %d should contain %d items", error_prefix, (int)dim + 1, (int)dimsize[dim + 1]);
79                                 ok= 0;
80                         }
81                         else if (!validate_array_type(item, dim + 1, totdim, dimsize, check_item_type, item_type_str, error_prefix)) {
82                                 ok= 0;
83                         }
84
85                         Py_DECREF(item);
86
87                         if (!ok)
88                                 return 0;
89                 }
90         }
91         else {
92                 /* check that items are of correct type */
93                 const int seq_size= PySequence_Size(seq);
94                 for (i= 0; i < seq_size; i++) {
95                         PyObject *item= PySequence_GetItem(seq, i);
96
97                         if (!check_item_type(item)) {
98                                 Py_DECREF(item);
99
100                                 /* BLI_snprintf(error_str, error_str_size, "sequence items should be of type %s", item_type_str); */
101                                 PyErr_Format(PyExc_TypeError, "expected sequence items of type %s, not %s", item_type_str, Py_TYPE(item)->tp_name);
102                                 return 0;
103                         }
104
105                         Py_DECREF(item);
106                 }
107         }
108
109         return 1;
110 }
111
112 /* Returns the number of items in a single- or multi-dimensional sequence. */
113 static int count_items(PyObject *seq)
114 {
115         int totitem= 0;
116
117         if (PySequence_Check(seq)) {
118                 const int seq_size= PySequence_Size(seq);
119                 int i;
120                 for (i= 0; i < seq_size; i++) {
121                         PyObject *item= PySequence_GetItem(seq, i);
122                         totitem += count_items(item);
123                         Py_DECREF(item);
124                 }
125         }
126         else
127                 totitem= 1;
128
129         return totitem;
130 }
131
132 /* Modifies property array length if needed and PROP_DYNAMIC flag is set. */
133 static int validate_array_length(PyObject *rvalue, PointerRNA *ptr, PropertyRNA *prop, int lvalue_dim, int *totitem, const char *error_prefix)
134 {
135         int dimsize[MAX_ARRAY_DIMENSION];
136         int tot, totdim, len;
137
138         tot= count_items(rvalue);
139         totdim= RNA_property_array_dimension(ptr, prop, dimsize);
140
141         if ((RNA_property_flag(prop) & PROP_DYNAMIC) && lvalue_dim == 0) {
142                 if (RNA_property_array_length(ptr, prop) != tot) {
143 #if 0
144                         /* length is flexible */
145                         if (!RNA_property_dynamic_array_set_length(ptr, prop, tot)) {
146                                 /* BLI_snprintf(error_str, error_str_size, "%s.%s: array length cannot be changed to %d", RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), tot); */
147                                 PyErr_Format(PyExc_ValueError, "%s %s.%s: array length cannot be changed to %d", error_prefix, RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), tot);
148                                 return 0;
149                         }
150 #else
151                         *totitem= tot;
152                         return 1;
153
154 #endif
155                 }
156
157                 len= tot;
158         }
159         else {
160                 /* length is a constraint */
161                 if (!lvalue_dim) {
162                         len= RNA_property_array_length(ptr, prop);
163                 }
164                 /* array item assignment */
165                 else {
166                         int i;
167
168                         len= 1;
169
170                         /* arr[3][4][5]
171
172                            arr[2] = x
173                            dimsize={4, 5}
174                            dimsize[1] = 4
175                            dimsize[2] = 5
176                            lvalue_dim=0, totdim=3
177
178                            arr[2][3] = x
179                            lvalue_dim=1
180
181                            arr[2][3][4] = x
182                            lvalue_dim=2 */
183                         for (i= lvalue_dim; i < totdim; i++)
184                                 len *= dimsize[i];
185                 }
186
187                 if (tot != len) {
188                         /* BLI_snprintf(error_str, error_str_size, "sequence must have length of %d", len); */
189                         PyErr_Format(PyExc_ValueError, "%s sequence must have %d items total, not %d", error_prefix, len, tot);
190                         return 0;
191                 }
192         }
193
194         *totitem= len;
195
196         return 1;
197 }
198
199 static int validate_array(PyObject *rvalue, PointerRNA *ptr, PropertyRNA *prop, int lvalue_dim, ItemTypeCheckFunc check_item_type, const char *item_type_str, int *totitem, const char *error_prefix)
200 {
201         int dimsize[MAX_ARRAY_DIMENSION];
202         int totdim= RNA_property_array_dimension(ptr, prop, dimsize);
203
204         /* validate type first because length validation may modify property array length */
205
206         if (!validate_array_type(rvalue, lvalue_dim, totdim, dimsize, check_item_type, item_type_str, error_prefix))
207                 return 0;
208
209         return validate_array_length(rvalue, ptr, prop, lvalue_dim, totitem, error_prefix);
210 }
211
212 static char *copy_value_single(PyObject *item, PointerRNA *ptr, PropertyRNA *prop, char *data, unsigned int item_size, int *index, ItemConvertFunc convert_item, RNA_SetIndexFunc rna_set_index)
213 {
214         if (!data) {
215                 char value[sizeof(int)];
216
217                 convert_item(item, value);
218                 rna_set_index(ptr, prop, *index, value);
219                 *index = *index + 1;
220         }
221         else {
222                 convert_item(item, data);
223                 data += item_size;
224         }
225
226         return data;
227 }
228
229 static char *copy_values(PyObject *seq, PointerRNA *ptr, PropertyRNA *prop, int dim, char *data, unsigned int item_size, int *index, ItemConvertFunc convert_item, RNA_SetIndexFunc rna_set_index)
230 {
231         unsigned int i;
232         int totdim= RNA_property_array_dimension(ptr, prop, NULL);
233         const int seq_size= PySequence_Size(seq);
234
235         for (i= 0; i < seq_size; i++) {
236                 PyObject *item= PySequence_GetItem(seq, i);
237
238                 if (dim + 1 < totdim) {
239                         data= copy_values(item, ptr, prop, dim + 1, data, item_size, index, convert_item, rna_set_index);
240                 }
241                 else {
242                         data= copy_value_single(item, ptr, prop, data, item_size, index, convert_item, rna_set_index);
243                 }
244
245                 Py_DECREF(item);
246         }
247
248         return data;
249 }
250
251 static int py_to_array(PyObject *py, PointerRNA *ptr, PropertyRNA *prop, char *param_data, ItemTypeCheckFunc check_item_type, const char *item_type_str, int item_size, ItemConvertFunc convert_item, RNA_SetArrayFunc rna_set_array, const char *error_prefix)
252 {
253         /*int totdim, dim_size[MAX_ARRAY_DIMENSION];*/
254         int totitem;
255         char *data= NULL;
256
257         /*totdim= RNA_property_array_dimension(ptr, prop, dim_size);*/ /*UNUSED*/
258
259         if (!validate_array(py, ptr, prop, 0, check_item_type, item_type_str, &totitem, error_prefix)) {
260                 return 0;
261         }
262
263         if (totitem) {
264                 /* note: this code is confusing */
265                 if(param_data && RNA_property_flag(prop) & PROP_DYNAMIC) {
266                         /* not freeing allocated mem, RNA_parameter_list_free() will do this */
267                         ParameterDynAlloc *param_alloc= (ParameterDynAlloc *)param_data;
268                         param_alloc->array_tot= (int)totitem;
269                         param_alloc->array= MEM_callocN(item_size * totitem, "py_to_array dyn"); /* freeing param list will free */
270
271                         data= param_alloc->array;
272                 }
273                 else if (param_data) {
274                         data= param_data;
275                 }
276                 else {
277                         data= PyMem_MALLOC(item_size * totitem);
278                 }
279
280                 copy_values(py, ptr, prop, 0, data, item_size, NULL, convert_item, NULL);
281
282                 if (param_data==NULL) {
283                         /* NULL can only pass through in case RNA property arraylength is 0 (impossible?) */
284                         rna_set_array(ptr, prop, data);
285                         PyMem_FREE(data);
286                 }
287         }
288
289         return 1;
290 }
291
292 static int 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, ItemConvertFunc convert_item, RNA_SetIndexFunc rna_set_index, const char *error_prefix)
293 {
294         int totdim, dimsize[MAX_ARRAY_DIMENSION];
295         int totitem, i;
296
297         totdim= RNA_property_array_dimension(ptr, prop, dimsize);
298
299         /* convert index */
300
301         /* arr[3][4][5]
302
303            arr[2] = x
304            lvalue_dim=0, index = 0 + 2 * 4 * 5
305
306            arr[2][3] = x
307            lvalue_dim=1, index = 40 + 3 * 5 */
308
309         lvalue_dim++;
310
311         for (i= lvalue_dim; i < totdim; i++)
312                 index *= dimsize[i];
313
314         index += arrayoffset;
315
316         if(lvalue_dim == totdim) { /* single item, assign directly */
317                 if(!check_item_type(py)) {
318                         PyErr_Format(PyExc_TypeError, "%s expected a %s type, not %s", error_prefix, item_type_str, Py_TYPE(py)->tp_name);
319                         return 0;
320                 }
321                 copy_value_single(py, ptr, prop, NULL, 0, &index, convert_item, rna_set_index);
322         }
323         else {
324                 if (!validate_array(py, ptr, prop, lvalue_dim, check_item_type, item_type_str, &totitem, error_prefix)) {
325                         return 0;
326                 }
327
328                 if (totitem) {
329                         copy_values(py, ptr, prop, lvalue_dim, NULL, 0, &index, convert_item, rna_set_index);
330                 }
331         }
332         return 1;
333 }
334
335 static void py_to_float(PyObject *py, char *data)
336 {
337         *(float*)data= (float)PyFloat_AsDouble(py);
338 }
339
340 static void py_to_int(PyObject *py, char *data)
341 {
342         *(int*)data= (int)PyLong_AsSsize_t(py);
343 }
344
345 static void py_to_bool(PyObject *py, char *data)
346 {
347         *(int*)data= (int)PyObject_IsTrue(py);
348 }
349
350 static int py_float_check(PyObject *py)
351 {
352         /* accept both floats and integers */
353         return PyNumber_Check(py);
354 }
355
356 static int py_int_check(PyObject *py)
357 {
358         /* accept only integers */
359         return PyLong_Check(py);
360 }
361
362 static int py_bool_check(PyObject *py)
363 {
364         return PyBool_Check(py);
365 }
366
367 static void float_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value)
368 {
369         RNA_property_float_set_index(ptr, prop, index, *(float*)value);
370 }
371
372 static void int_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value)
373 {
374         RNA_property_int_set_index(ptr, prop, index, *(int*)value);
375 }
376
377 static void bool_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value)
378 {
379         RNA_property_boolean_set_index(ptr, prop, index, *(int*)value);
380 }
381
382 int pyrna_py_to_array(PointerRNA *ptr, PropertyRNA *prop, char *param_data, PyObject *py, const char *error_prefix)
383 {
384         int ret;
385         switch (RNA_property_type(prop)) {
386         case PROP_FLOAT:
387                 ret= py_to_array(py, ptr, prop, param_data, py_float_check, "float", sizeof(float), py_to_float, (RNA_SetArrayFunc)RNA_property_float_set_array, error_prefix);
388                 break;
389         case PROP_INT:
390                 ret= py_to_array(py, ptr, prop, param_data, py_int_check, "int", sizeof(int), py_to_int, (RNA_SetArrayFunc)RNA_property_int_set_array, error_prefix);
391                 break;
392         case PROP_BOOLEAN:
393                 ret= py_to_array(py, ptr, prop, param_data, py_bool_check, "boolean", sizeof(int), py_to_bool, (RNA_SetArrayFunc)RNA_property_boolean_set_array, error_prefix);
394                 break;
395         default:
396                 PyErr_SetString(PyExc_TypeError, "not an array type");
397                 ret= 0;
398         }
399
400         return ret;
401 }
402
403 int pyrna_py_to_array_index(PointerRNA *ptr, PropertyRNA *prop, int arraydim, int arrayoffset, int index, PyObject *py, const char *error_prefix)
404 {
405         int ret;
406         switch (RNA_property_type(prop)) {
407         case PROP_FLOAT:
408                 ret= py_to_array_index(py, ptr, prop, arraydim, arrayoffset, index, py_float_check, "float", py_to_float, float_set_index, error_prefix);
409                 break;
410         case PROP_INT:
411                 ret= py_to_array_index(py, ptr, prop, arraydim, arrayoffset, index, py_int_check, "int", py_to_int, int_set_index, error_prefix);
412                 break;
413         case PROP_BOOLEAN:
414                 ret= py_to_array_index(py, ptr, prop, arraydim, arrayoffset, index, py_bool_check, "boolean", py_to_bool, bool_set_index, error_prefix);
415                 break;
416         default:
417                 PyErr_SetString(PyExc_TypeError, "not an array type");
418                 ret= 0;
419         }
420
421         return ret;
422 }
423
424 PyObject *pyrna_array_index(PointerRNA *ptr, PropertyRNA *prop, int index)
425 {
426         PyObject *item;
427
428         switch (RNA_property_type(prop)) {
429         case PROP_FLOAT:
430                 item= PyFloat_FromDouble(RNA_property_float_get_index(ptr, prop, index));
431                 break;
432         case PROP_BOOLEAN:
433                 item= PyBool_FromLong(RNA_property_boolean_get_index(ptr, prop, index));
434                 break;
435         case PROP_INT:
436                 item= PyLong_FromSsize_t(RNA_property_int_get_index(ptr, prop, index));
437                 break;
438         default:
439                 PyErr_SetString(PyExc_TypeError, "not an array type");
440                 item= NULL;
441         }
442
443         return item;
444 }
445
446 #if 0
447 /* XXX this is not used (and never will?) */
448 /* Given an array property, creates an N-dimensional tuple of values. */
449 static PyObject *pyrna_py_from_array_internal(PointerRNA *ptr, PropertyRNA *prop, int dim, int *index)
450 {
451         PyObject *tuple;
452         int i, len;
453         int totdim= RNA_property_array_dimension(ptr, prop, NULL);
454
455         len= RNA_property_multi_array_length(ptr, prop, dim);
456
457         tuple= PyTuple_New(len);
458
459         for (i= 0; i < len; i++) {
460                 PyObject *item;
461
462                 if (dim + 1 < totdim)
463                         item= pyrna_py_from_array_internal(ptr, prop, dim + 1, index);
464                 else {
465                         item= pyrna_array_index(ptr, prop, *index);
466                         *index= *index + 1;
467                 }
468
469                 if (!item) {
470                         Py_DECREF(tuple);
471                         return NULL;
472                 }
473
474                 PyTuple_SET_ITEM(tuple, i, item);
475         }
476
477         return tuple;
478 }
479 #endif
480
481 PyObject *pyrna_py_from_array_index(BPy_PropertyArrayRNA *self, PointerRNA *ptr, PropertyRNA *prop, int index)
482 {
483         int totdim, arraydim, arrayoffset, dimsize[MAX_ARRAY_DIMENSION], i, len;
484         BPy_PropertyArrayRNA *ret= NULL;
485
486         arraydim= self ? self->arraydim : 0;
487         arrayoffset = self ? self->arrayoffset : 0;
488
489         /* just in case check */
490         len= RNA_property_multi_array_length(ptr, prop, arraydim);
491         if (index >= len || index < 0) {
492                 /* this shouldn't happen because higher level funcs must check for invalid index */
493                 if (G.f & G_DEBUG) printf("pyrna_py_from_array_index: invalid index %d for array with length=%d\n", index, len);
494
495                 PyErr_SetString(PyExc_IndexError, "out of range");
496                 return NULL;
497         }
498
499         totdim= RNA_property_array_dimension(ptr, prop, dimsize);
500
501         if (arraydim + 1 < totdim) {
502                 ret= (BPy_PropertyArrayRNA*)pyrna_prop_CreatePyObject(ptr, prop);
503                 ret->arraydim= arraydim + 1;
504
505                 /* arr[3][4][5]
506
507                    x = arr[2]
508                    index = 0 + 2 * 4 * 5
509
510                    x = arr[2][3]
511                    index = offset + 3 * 5 */
512
513                 for (i= arraydim + 1; i < totdim; i++)
514                         index *= dimsize[i];
515
516                 ret->arrayoffset= arrayoffset + index;
517         }
518         else {
519                 index = arrayoffset + index;
520                 ret= (BPy_PropertyArrayRNA *)pyrna_array_index(ptr, prop, index);
521         }
522
523         return (PyObject*)ret;
524 }
525
526 PyObject *pyrna_py_from_array(PointerRNA *ptr, PropertyRNA *prop)
527 {
528         PyObject *ret;
529
530         ret= pyrna_math_object_from_array(ptr, prop);
531
532         /* is this a maths object? */
533         if (ret) return ret;
534
535         return pyrna_prop_CreatePyObject(ptr, prop);
536 }
537
538 /* TODO, multi-dimensional arrays */
539 int pyrna_array_contains_py(PointerRNA *ptr, PropertyRNA *prop, PyObject *value)
540 {
541         int len= RNA_property_array_length(ptr, prop);
542         int type;
543         int i;
544
545         if(len==0) /* possible with dynamic arrays */
546                 return 0;
547
548         if (RNA_property_array_dimension(ptr, prop, NULL) > 1) {
549                 PyErr_SetString(PyExc_TypeError, "PropertyRNA - multi dimensional arrays not supported yet");
550                 return -1;
551         }
552
553         type= RNA_property_type(prop);
554
555         switch (type) {
556                 case PROP_FLOAT:
557                 {
558                         float value_f= PyFloat_AsDouble(value);
559                         if(value_f==-1 && PyErr_Occurred()) {
560                                 PyErr_Clear();
561                                 return 0;
562                         }
563                         else {
564                                 float tmp[32];
565                                 float *tmp_arr;
566
567                                 if(len * sizeof(float) > sizeof(tmp)) {
568                                         tmp_arr= PyMem_MALLOC(len * sizeof(float));
569                                 }
570                                 else {
571                                         tmp_arr= tmp;
572                                 }
573
574                                 RNA_property_float_get_array(ptr, prop, tmp_arr);
575
576                                 for(i=0; i<len; i++)
577                                         if(tmp_arr[i] == value_f)
578                                                 break;
579
580                                 if(tmp_arr != tmp)
581                                         PyMem_FREE(tmp_arr);
582
583                                 return i<len ? 1 : 0;
584                         }
585                         break;
586                 }
587                 case PROP_BOOLEAN:
588                 case PROP_INT:
589                 {
590                         int value_i= PyLong_AsSsize_t(value);
591                         if(value_i==-1 && PyErr_Occurred()) {
592                                 PyErr_Clear();
593                                 return 0;
594                         }
595                         else {
596                                 int tmp[32];
597                                 int *tmp_arr;
598
599                                 if(len * sizeof(int) > sizeof(tmp)) {
600                                         tmp_arr= PyMem_MALLOC(len * sizeof(int));
601                                 }
602                                 else {
603                                         tmp_arr= tmp;
604                                 }
605
606                                 if(type==PROP_BOOLEAN)
607                                         RNA_property_boolean_get_array(ptr, prop, tmp_arr);
608                                 else
609                                         RNA_property_int_get_array(ptr, prop, tmp_arr);
610
611                                 for(i=0; i<len; i++)
612                                         if(tmp_arr[i] == value_i)
613                                                 break;
614
615                                 if(tmp_arr != tmp)
616                                         PyMem_FREE(tmp_arr);
617
618                                 return i<len ? 1 : 0;
619                         }
620                         break;
621                 }
622         }
623
624         /* should never reach this */
625         PyErr_SetString(PyExc_TypeError, "PropertyRNA - type not in float/bool/int");
626         return -1;
627 }