Patch #34204: [Render Animation] Fails with "Error: Specified sample_fmt is not suppo...
[blender.git] / source / blender / blenkernel / intern / idprop.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * Contributor(s): Joseph Eagar
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/blenkernel/intern/idprop.c
27  *  \ingroup bke
28  */
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <stddef.h>
33 #include <string.h>
34
35 #include "BLI_utildefines.h"
36 #include "BLI_string.h"
37 #include "BLI_listbase.h"
38
39 #include "BKE_idprop.h"
40 #include "BKE_library.h"
41
42 #include "MEM_guardedalloc.h"
43
44 /* IDPropertyTemplate is a union in DNA_ID.h */
45
46 /*local size table.*/
47 static char idp_size_table[] = {
48         1, /*strings*/
49         sizeof(int),
50         sizeof(float),
51         sizeof(float) * 3, /*Vector type, deprecated*/
52         sizeof(float) * 16, /*Matrix type, deprecated*/
53         0, /*arrays don't have a fixed size*/
54         sizeof(ListBase), /*Group type*/
55         sizeof(void *),
56         sizeof(double)
57 };
58
59 /* ------------Property Array Type ----------- */
60 #define GETPROP(prop, i) (((IDProperty *)(prop)->data.pointer) + (i))
61
62 /* --------- property array type -------------*/
63
64 /* note: as a start to move away from the stupid IDP_New function, this type
65  * has it's own allocation function.*/
66 IDProperty *IDP_NewIDPArray(const char *name)
67 {
68         IDProperty *prop = MEM_callocN(sizeof(IDProperty), "IDProperty prop array");
69         prop->type = IDP_IDPARRAY;
70         prop->len = 0;
71         BLI_strncpy(prop->name, name, MAX_IDPROP_NAME);
72         
73         return prop;
74 }
75
76 IDProperty *IDP_CopyIDPArray(IDProperty *array)
77 {
78         /* don't use MEM_dupallocN because this may be part of an array */
79         IDProperty *narray = MEM_mallocN(sizeof(IDProperty), "IDP_CopyIDPArray"), *tmp;
80         int i;
81
82         *narray = *array;
83
84         narray->data.pointer = MEM_dupallocN(array->data.pointer);
85         for (i = 0; i < narray->len; i++) {
86                 /* ok, the copy functions always allocate a new structure,
87                  * which doesn't work here.  instead, simply copy the
88                  * contents of the new structure into the array cell,
89                  * then free it.  this makes for more maintainable
90                  * code than simply reimplementing the copy functions
91                  * in this loop.*/
92                 tmp = IDP_CopyProperty(GETPROP(narray, i));
93                 memcpy(GETPROP(narray, i), tmp, sizeof(IDProperty));
94                 MEM_freeN(tmp);
95         }
96         
97         return narray;
98 }
99
100 void IDP_FreeIDPArray(IDProperty *prop)
101 {
102         int i;
103         
104         for (i = 0; i < prop->len; i++)
105                 IDP_FreeProperty(GETPROP(prop, i));
106
107         if (prop->data.pointer)
108                 MEM_freeN(prop->data.pointer);
109 }
110
111 /*shallow copies item*/
112 void IDP_SetIndexArray(IDProperty *prop, int index, IDProperty *item)
113 {
114         IDProperty *old = GETPROP(prop, index);
115         if (index >= prop->len || index < 0) return;
116         if (item != old) IDP_FreeProperty(old);
117         
118         memcpy(GETPROP(prop, index), item, sizeof(IDProperty));
119 }
120
121 IDProperty *IDP_GetIndexArray(IDProperty *prop, int index)
122 {
123         return GETPROP(prop, index);
124 }
125
126 void IDP_AppendArray(IDProperty *prop, IDProperty *item)
127 {
128         IDP_ResizeIDPArray(prop, prop->len + 1);
129         IDP_SetIndexArray(prop, prop->len - 1, item);
130 }
131
132 void IDP_ResizeIDPArray(IDProperty *prop, int newlen)
133 {
134         void *newarr;
135         int newsize = newlen;
136
137         /*first check if the array buffer size has room*/
138         /*if newlen is 200 chars less then totallen, reallocate anyway*/
139         if (newlen <= prop->totallen && prop->totallen - newlen < 200) {
140                 int i;
141
142                 for (i = newlen; i < prop->len; i++)
143                         IDP_FreeProperty(GETPROP(prop, i));
144
145                 prop->len = newlen;
146                 return;
147         }
148
149         /* - Note: This code comes from python, here's the corresponding comment. - */
150         /* This over-allocates proportional to the list size, making room
151          * for additional growth.  The over-allocation is mild, but is
152          * enough to give linear-time amortized behavior over a long
153          * sequence of appends() in the presence of a poorly-performing
154          * system realloc().
155          * The growth pattern is:  0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
156          */
157         newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize;
158
159         newarr = MEM_callocN(sizeof(IDProperty) * newsize, "idproperty array resized");
160         if (newlen >= prop->len) {
161                 /* newlen is bigger */
162                 memcpy(newarr, prop->data.pointer, prop->len * sizeof(IDProperty));
163         }
164         else {
165                 int i;
166                 /* newlen is smaller */
167                 for (i = newlen; i < prop->len; i++) {
168                         IDP_FreeProperty(GETPROP(prop, i));
169                 }
170                 memcpy(newarr, prop->data.pointer, newlen * sizeof(IDProperty));
171         }
172
173         if (prop->data.pointer)
174                 MEM_freeN(prop->data.pointer);
175         prop->data.pointer = newarr;
176         prop->len = newlen;
177         prop->totallen = newsize;
178 }
179
180 /* ----------- Numerical Array Type ----------- */
181 static void idp_resize_group_array(IDProperty *prop, int newlen, void *newarr)
182 {
183         if (prop->subtype != IDP_GROUP)
184                 return;
185
186         if (newlen >= prop->len) {
187                 /* bigger */
188                 IDProperty **array = newarr;
189                 IDPropertyTemplate val;
190                 int a;
191
192                 for (a = prop->len; a < newlen; a++) {
193                         val.i = 0; /* silence MSVC warning about uninitialized var when debugging */
194                         array[a] = IDP_New(IDP_GROUP, &val, "IDP_ResizeArray group");
195                 }
196         }
197         else {
198                 /* smaller */
199                 IDProperty **array = prop->data.pointer;
200                 int a;
201
202                 for (a = newlen; a < prop->len; a++) {
203                         IDP_FreeProperty(array[a]);
204                         MEM_freeN(array[a]);
205                 }
206         }
207 }
208
209 /*this function works for strings too!*/
210 void IDP_ResizeArray(IDProperty *prop, int newlen)
211 {
212         void *newarr;
213         int newsize = newlen;
214
215         /*first check if the array buffer size has room*/
216         /*if newlen is 200 chars less then totallen, reallocate anyway*/
217         if (newlen <= prop->totallen && prop->totallen - newlen < 200) {
218                 idp_resize_group_array(prop, newlen, prop->data.pointer);
219                 prop->len = newlen;
220                 return;
221         }
222
223         /* - Note: This code comes from python, here's the corresponding comment. - */
224         /* This over-allocates proportional to the list size, making room
225          * for additional growth.  The over-allocation is mild, but is
226          * enough to give linear-time amortized behavior over a long
227          * sequence of appends() in the presence of a poorly-performing
228          * system realloc().
229          * The growth pattern is:  0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
230          */
231         newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize;
232
233         newarr = MEM_callocN(idp_size_table[(int)prop->subtype] * newsize, "idproperty array resized");
234         if (newlen >= prop->len) {
235                 /* newlen is bigger */
236                 memcpy(newarr, prop->data.pointer, prop->len * idp_size_table[(int)prop->subtype]);
237                 idp_resize_group_array(prop, newlen, newarr);
238         }
239         else {
240                 /* newlen is smaller */
241                 idp_resize_group_array(prop, newlen, newarr);
242                 memcpy(newarr, prop->data.pointer, newlen * idp_size_table[(int)prop->subtype]);
243         }
244
245         MEM_freeN(prop->data.pointer);
246         prop->data.pointer = newarr;
247         prop->len = newlen;
248         prop->totallen = newsize;
249 }
250
251 void IDP_FreeArray(IDProperty *prop)
252 {
253         if (prop->data.pointer) {
254                 idp_resize_group_array(prop, 0, NULL);
255                 MEM_freeN(prop->data.pointer);
256         }
257 }
258
259
260 static IDProperty *idp_generic_copy(IDProperty *prop)
261 {
262         IDProperty *newp = MEM_callocN(sizeof(IDProperty), "IDProperty array dup");
263
264         BLI_strncpy(newp->name, prop->name, MAX_IDPROP_NAME);
265         newp->type = prop->type;
266         newp->flag = prop->flag;
267         newp->data.val = prop->data.val;
268         newp->data.val2 = prop->data.val2;
269
270         return newp;
271 }
272
273 static IDProperty *IDP_CopyArray(IDProperty *prop)
274 {
275         IDProperty *newp = idp_generic_copy(prop);
276
277         if (prop->data.pointer) {
278                 newp->data.pointer = MEM_dupallocN(prop->data.pointer);
279
280                 if (prop->type == IDP_GROUP) {
281                         IDProperty **array = newp->data.pointer;
282                         int a;
283
284                         for (a = 0; a < prop->len; a++)
285                                 array[a] = IDP_CopyProperty(array[a]);
286                 }
287         }
288         newp->len = prop->len;
289         newp->subtype = prop->subtype;
290         newp->totallen = prop->totallen;
291
292         return newp;
293 }
294
295 /* ---------- String Type ------------ */
296 IDProperty *IDP_NewString(const char *st, const char *name, int maxlen)
297 {
298         IDProperty *prop = MEM_callocN(sizeof(IDProperty), "IDProperty string");
299
300         if (st == NULL) {
301                 prop->data.pointer = MEM_callocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1");
302                 prop->totallen = DEFAULT_ALLOC_FOR_NULL_STRINGS;
303                 prop->len = 1; /*NULL string, has len of 1 to account for null byte.*/
304         }
305         else {
306                 int stlen = strlen(st);
307
308                 if (maxlen > 0 && maxlen < stlen)
309                         stlen = maxlen;
310
311                 stlen++; /* null terminator '\0' */
312
313                 prop->data.pointer = MEM_callocN(stlen, "id property string 2");
314                 prop->len = prop->totallen = stlen;
315                 BLI_strncpy(prop->data.pointer, st, stlen);
316         }
317
318         prop->type = IDP_STRING;
319         BLI_strncpy(prop->name, name, MAX_IDPROP_NAME);
320
321         return prop;
322 }
323
324 static IDProperty *IDP_CopyString(IDProperty *prop)
325 {
326         IDProperty *newp = idp_generic_copy(prop);
327
328         if (prop->data.pointer) newp->data.pointer = MEM_dupallocN(prop->data.pointer);
329         newp->len = prop->len;
330         newp->subtype = prop->subtype;
331         newp->totallen = prop->totallen;
332
333         return newp;
334 }
335
336
337 void IDP_AssignString(IDProperty *prop, const char *st, int maxlen)
338 {
339         int stlen = strlen(st);
340
341         if (maxlen > 0 && maxlen < stlen)
342                 stlen = maxlen;
343
344         if (prop->subtype == IDP_STRING_SUB_BYTE) {
345                 IDP_ResizeArray(prop, stlen);
346                 memcpy(prop->data.pointer, st, stlen);
347         }
348         else {
349                 stlen++; /* make room for null byte */
350                 IDP_ResizeArray(prop, stlen);
351                 BLI_strncpy(prop->data.pointer, st, stlen);
352         }
353 }
354
355 void IDP_ConcatStringC(IDProperty *prop, const char *st)
356 {
357         int newlen;
358
359         newlen = prop->len + strlen(st);
360         /* we have to remember that prop->len includes the null byte for strings.
361          * so there's no need to add +1 to the resize function.*/
362         IDP_ResizeArray(prop, newlen);
363         strcat(prop->data.pointer, st);
364 }
365
366 void IDP_ConcatString(IDProperty *str1, IDProperty *append)
367 {
368         int newlen;
369
370         /* since ->len for strings includes the NULL byte, we have to subtract one or
371          * we'll get an extra null byte after each concatenation operation.*/
372         newlen = str1->len + append->len - 1;
373         IDP_ResizeArray(str1, newlen);
374         strcat(str1->data.pointer, append->data.pointer);
375 }
376
377 void IDP_FreeString(IDProperty *prop)
378 {
379         if (prop->data.pointer)
380                 MEM_freeN(prop->data.pointer);
381 }
382
383
384 /*-------- ID Type, not in use yet -------*/
385
386 void IDP_LinkID(IDProperty *prop, ID *id)
387 {
388         if (prop->data.pointer) ((ID *)prop->data.pointer)->us--;
389         prop->data.pointer = id;
390         id_us_plus(id);
391 }
392
393 void IDP_UnlinkID(IDProperty *prop)
394 {
395         ((ID *)prop->data.pointer)->us--;
396 }
397
398 /*-------- Group Functions -------*/
399
400 /*checks if a property with the same name as prop exists, and if so replaces it.*/
401 static IDProperty *IDP_CopyGroup(IDProperty *prop)
402 {
403         IDProperty *newp = idp_generic_copy(prop), *link;
404         newp->len = prop->len;
405         
406         for (link = prop->data.group.first; link; link = link->next) {
407                 BLI_addtail(&newp->data.group, IDP_CopyProperty(link));
408         }
409
410         return newp;
411 }
412
413 /* use for syncing proxies.
414  * When values name and types match, copy the values, else ignore */
415 void IDP_SyncGroupValues(IDProperty *dest, IDProperty *src)
416 {
417         IDProperty *other, *prop;
418         for (prop = src->data.group.first; prop; prop = prop->next) {
419                 other = BLI_findstring(&dest->data.group, prop->name, offsetof(IDProperty, name));
420                 if (other && prop->type == other->type) {
421                         switch (prop->type) {
422                                 case IDP_INT:
423                                 case IDP_FLOAT:
424                                 case IDP_DOUBLE:
425                                         other->data = prop->data;
426                                         break;
427                                 case IDP_GROUP:
428                                         IDP_SyncGroupValues(other, prop);
429                                         break;
430                                 default:
431                                 {
432                                         IDProperty *tmp = other;
433                                         IDProperty *copy = IDP_CopyProperty(prop);
434
435                                         BLI_insertlinkafter(&dest->data.group, other, copy);
436                                         BLI_remlink(&dest->data.group, tmp);
437
438                                         IDP_FreeProperty(tmp);
439                                         MEM_freeN(tmp);
440                                 }
441                         }
442                 }
443         }
444 }
445
446 /*
447  * replaces all properties with the same name in a destination group from a source group.
448  */
449 void IDP_ReplaceGroupInGroup(IDProperty *dest, IDProperty *src)
450 {
451         IDProperty *loop, *prop;
452         for (prop = src->data.group.first; prop; prop = prop->next) {
453                 for (loop = dest->data.group.first; loop; loop = loop->next) {
454                         if (STREQ(loop->name, prop->name)) {
455                                 IDProperty *copy = IDP_CopyProperty(prop);
456
457                                 BLI_insertlinkafter(&dest->data.group, loop, copy);
458
459                                 BLI_remlink(&dest->data.group, loop);
460                                 IDP_FreeProperty(loop);
461                                 MEM_freeN(loop);
462                                 break;
463                         }
464                 }
465
466                 /* only add at end if not added yet */
467                 if (loop == NULL) {
468                         IDProperty *copy = IDP_CopyProperty(prop);
469                         dest->len++;
470                         BLI_addtail(&dest->data.group, copy);
471                 }
472         }
473 }
474 /*
475  * replaces a property with the same name in a group, or adds 
476  * it if the properly doesn't exist.
477  */
478 void IDP_ReplaceInGroup(IDProperty *group, IDProperty *prop)
479 {
480         IDProperty *loop;
481         if ((loop = IDP_GetPropertyFromGroup(group, prop->name))) {
482                 BLI_insertlinkafter(&group->data.group, loop, prop);
483                 
484                 BLI_remlink(&group->data.group, loop);
485                 IDP_FreeProperty(loop);
486                 MEM_freeN(loop);
487         }
488         else {
489                 group->len++;
490                 BLI_addtail(&group->data.group, prop);
491         }
492 }
493
494 /*
495  * If a property is missing in \a dest, add it.
496  */
497 void IDP_MergeGroup(IDProperty *dest, IDProperty *src, const int do_overwrite)
498 {
499         IDProperty *prop;
500
501         if (do_overwrite) {
502                 for (prop = src->data.group.first; prop; prop = prop->next) {
503                         IDProperty *copy = IDP_CopyProperty(prop);
504                         IDP_ReplaceInGroup(dest, copy);
505                 }
506         }
507         else {
508                 for (prop = src->data.group.first; prop; prop = prop->next) {
509                         if (IDP_GetPropertyFromGroup(dest, prop->name) == NULL) {
510                                 IDProperty *copy = IDP_CopyProperty(prop);
511                                 dest->len++;
512                                 BLI_addtail(&dest->data.group, copy);
513                         }
514                 }
515         }
516 }
517
518 /* returns 0 if an id property with the same name exists and it failed,
519  * or 1 if it succeeded in adding to the group.*/
520 int IDP_AddToGroup(IDProperty *group, IDProperty *prop)
521 {
522         if (IDP_GetPropertyFromGroup(group, prop->name) == NULL) {
523                 group->len++;
524                 BLI_addtail(&group->data.group, prop);
525                 return 1;
526         }
527
528         return 0;
529 }
530
531 int IDP_InsertToGroup(IDProperty *group, IDProperty *previous, IDProperty *pnew)
532 {
533         if (IDP_GetPropertyFromGroup(group, pnew->name) == NULL) {
534                 group->len++;
535                 BLI_insertlinkafter(&group->data.group, previous, pnew);
536                 return 1;
537         }
538
539         return 0;
540 }
541
542 void IDP_RemFromGroup(IDProperty *group, IDProperty *prop)
543 {
544         group->len--;
545         BLI_remlink(&group->data.group, prop);
546 }
547
548 IDProperty *IDP_GetPropertyFromGroup(IDProperty *prop, const char *name)
549 {
550         return (IDProperty *)BLI_findstring(&prop->data.group, name, offsetof(IDProperty, name));
551 }
552
553 IDProperty *IDP_GetPropertyTypeFromGroup(IDProperty *prop, const char *name, const char type)
554 {
555         IDProperty *idprop = IDP_GetPropertyFromGroup(prop, name);
556         return (idprop && idprop->type == type) ? idprop : NULL;
557 }
558
559 typedef struct IDPIter {
560         void *next;
561         IDProperty *parent;
562 } IDPIter;
563
564 void *IDP_GetGroupIterator(IDProperty *prop)
565 {
566         IDPIter *iter = MEM_callocN(sizeof(IDPIter), "IDPIter");
567         iter->next = prop->data.group.first;
568         iter->parent = prop;
569         return (void *) iter;
570 }
571
572 IDProperty *IDP_GroupIterNext(void *vself)
573 {
574         IDPIter *self = (IDPIter *) vself;
575         Link *next = (Link *) self->next;
576         if (self->next == NULL) {
577                 MEM_freeN(self);
578                 return NULL;
579         }
580
581         self->next = next->next;
582         return (void *) next;
583 }
584
585 void IDP_FreeIterBeforeEnd(void *vself)
586 {
587         MEM_freeN(vself);
588 }
589
590 /* Ok, the way things work, Groups free the ID Property structs of their children.
591  * This is because all ID Property freeing functions free only direct data (not the ID Property
592  * struct itself), but for Groups the child properties *are* considered
593  * direct data. */
594 static void IDP_FreeGroup(IDProperty *prop)
595 {
596         IDProperty *loop;
597         for (loop = prop->data.group.first; loop; loop = loop->next) {
598                 IDP_FreeProperty(loop);
599         }
600         BLI_freelistN(&prop->data.group);
601 }
602
603
604 /*-------- Main Functions --------*/
605 IDProperty *IDP_CopyProperty(IDProperty *prop)
606 {
607         switch (prop->type) {
608                 case IDP_GROUP: return IDP_CopyGroup(prop);
609                 case IDP_STRING: return IDP_CopyString(prop);
610                 case IDP_ARRAY: return IDP_CopyArray(prop);
611                 case IDP_IDPARRAY: return IDP_CopyIDPArray(prop);
612                 default: return idp_generic_copy(prop);
613         }
614 }
615
616 IDProperty *IDP_GetProperties(ID *id, int create_if_needed)
617 {
618         if (id->properties) {
619                 return id->properties;
620         }
621         else {
622                 if (create_if_needed) {
623                         id->properties = MEM_callocN(sizeof(IDProperty), "IDProperty");
624                         id->properties->type = IDP_GROUP;
625                         /* don't overwrite the data's name and type
626                          * some functions might need this if they
627                          * don't have a real ID, should be named elsewhere - Campbell */
628                         /* strcpy(id->name, "top_level_group");*/
629                 }
630                 return id->properties;
631         }
632 }
633
634 /**
635  * \param is_strict When FALSE treat missing items as a match */
636 int IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const int is_strict)
637 {
638         if (prop1 == NULL && prop2 == NULL)
639                 return 1;
640         else if (prop1 == NULL || prop2 == NULL)
641                 return is_strict ? 0 : 1;
642         else if (prop1->type != prop2->type)
643                 return 0;
644
645         switch (prop1->type) {
646                 case IDP_INT:
647                         return (IDP_Int(prop1) == IDP_Int(prop2));
648                 case IDP_FLOAT:
649                         return (IDP_Float(prop1) == IDP_Float(prop2));
650                 case IDP_DOUBLE:
651                         return (IDP_Double(prop1) == IDP_Double(prop2));
652                 case IDP_STRING:
653                         return ((prop1->len == prop2->len) && strncmp(IDP_String(prop1), IDP_String(prop2), prop1->len) == 0);
654                 case IDP_ARRAY:
655                         if (prop1->len == prop2->len && prop1->subtype == prop2->subtype) {
656                                 return memcmp(IDP_Array(prop1), IDP_Array(prop2), idp_size_table[(int)prop1->subtype] * prop1->len);
657                         }
658                         else {
659                                 return 0;
660                         }
661                 case IDP_GROUP:
662                 {
663                         IDProperty *link1, *link2;
664
665                         if (is_strict && prop1->len != prop2->len)
666                                 return 0;
667
668                         for (link1 = prop1->data.group.first; link1; link1 = link1->next) {
669                                 link2 = IDP_GetPropertyFromGroup(prop2, link1->name);
670
671                                 if (!IDP_EqualsProperties_ex(link1, link2, is_strict))
672                                         return 0;
673                         }
674
675                         return 1;
676                 }
677                 case IDP_IDPARRAY:
678                 {
679                         IDProperty *array1 = IDP_IDPArray(prop1);
680                         IDProperty *array2 = IDP_IDPArray(prop2);
681                         int i;
682
683                         if (prop1->len != prop2->len)
684                                 return 0;
685
686                         for (i = 0; i < prop1->len; i++)
687                                 if (!IDP_EqualsProperties(&array1[i], &array2[i]))
688                                         return 0;
689                         return 1;
690                 }
691                 default:
692                         /* should never get here */
693                         BLI_assert(0);
694                         break;
695         }
696
697         return 1;
698 }
699
700 int IDP_EqualsProperties(IDProperty *prop1, IDProperty *prop2)
701 {
702         return IDP_EqualsProperties_ex(prop1, prop2, TRUE);
703 }
704
705 /* 'val' is never NULL, don't check */
706 IDProperty *IDP_New(const int type, const IDPropertyTemplate *val, const char *name)
707 {
708         IDProperty *prop = NULL;
709
710         switch (type) {
711                 case IDP_INT:
712                         prop = MEM_callocN(sizeof(IDProperty), "IDProperty int");
713                         prop->data.val = val->i;
714                         break;
715                 case IDP_FLOAT:
716                         prop = MEM_callocN(sizeof(IDProperty), "IDProperty float");
717                         *(float *)&prop->data.val = val->f;
718                         break;
719                 case IDP_DOUBLE:
720                         prop = MEM_callocN(sizeof(IDProperty), "IDProperty float");
721                         *(double *)&prop->data.val = val->d;
722                         break;
723                 case IDP_ARRAY:
724                 {
725                         /* for now, we only support float and int and double arrays */
726                         if ( (val->array.type == IDP_FLOAT) ||
727                              (val->array.type == IDP_INT) ||
728                              (val->array.type == IDP_DOUBLE) ||
729                              (val->array.type == IDP_GROUP) )
730                         {
731                                 prop = MEM_callocN(sizeof(IDProperty), "IDProperty array");
732                                 prop->subtype = val->array.type;
733                                 if (val->array.len)
734                                         prop->data.pointer = MEM_callocN(idp_size_table[val->array.type] * val->array.len, "id property array");
735                                 prop->len = prop->totallen = val->array.len;
736                                 break;
737                         }
738                         else {
739                                 return NULL;
740                         }
741                 }
742                 case IDP_STRING:
743                 {
744                         const char *st = val->string.str;
745
746                         prop = MEM_callocN(sizeof(IDProperty), "IDProperty string");
747                         if (val->string.subtype == IDP_STRING_SUB_BYTE) {
748                                 /* note, intentionally not null terminated */
749                                 if (st == NULL) {
750                                         prop->data.pointer = MEM_callocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1");
751                                         prop->totallen = DEFAULT_ALLOC_FOR_NULL_STRINGS;
752                                         prop->len = 0;
753                                 }
754                                 else {
755                                         prop->data.pointer = MEM_mallocN(val->string.len, "id property string 2");
756                                         prop->len = prop->totallen = val->string.len;
757                                         memcpy(prop->data.pointer, st, val->string.len);
758                                 }
759                                 prop->subtype = IDP_STRING_SUB_BYTE;
760                         }
761                         else {
762                                 if (st == NULL) {
763                                         prop->data.pointer = MEM_callocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1");
764                                         prop->totallen = DEFAULT_ALLOC_FOR_NULL_STRINGS;
765                                         prop->len = 1; /*NULL string, has len of 1 to account for null byte.*/
766                                 }
767                                 else {
768                                         int stlen = strlen(st) + 1;
769                                         prop->data.pointer = MEM_mallocN(stlen, "id property string 3");
770                                         prop->len = prop->totallen = stlen;
771                                         memcpy(prop->data.pointer, st, stlen);
772                                 }
773                                 prop->subtype = IDP_STRING_SUB_UTF8;
774                         }
775                         break;
776                 }
777                 case IDP_GROUP:
778                 {
779                         prop = MEM_callocN(sizeof(IDProperty), "IDProperty group");
780                         /* heh I think all needed values are set properly by calloc anyway :) */
781                         break;
782                 }
783                 default:
784                 {
785                         prop = MEM_callocN(sizeof(IDProperty), "IDProperty array");
786                         break;
787                 }
788         }
789
790         prop->type = type;
791         BLI_strncpy(prop->name, name, MAX_IDPROP_NAME);
792         
793         return prop;
794 }
795
796 /* NOTE: this will free all child properties including list arrays and groups!
797  * Also, note that this does NOT unlink anything!  Plus it doesn't free
798  * the actual IDProperty struct either.*/
799 void IDP_FreeProperty(IDProperty *prop)
800 {
801         switch (prop->type) {
802                 case IDP_ARRAY:
803                         IDP_FreeArray(prop);
804                         break;
805                 case IDP_STRING:
806                         IDP_FreeString(prop);
807                         break;
808                 case IDP_GROUP:
809                         IDP_FreeGroup(prop);
810                         break;
811                 case IDP_IDPARRAY:
812                         IDP_FreeIDPArray(prop);
813                         break;
814         }
815 }
816
817 void IDP_ClearProperty(IDProperty *prop)
818 {
819         IDP_FreeProperty(prop);
820         prop->data.pointer = NULL;
821         prop->len = prop->totallen = 0;
822 }
823
824 /* Unlinks any IDProperty<->ID linkage that might be going on.
825  * note: currently unused.*/
826 void IDP_UnlinkProperty(IDProperty *prop)
827 {
828         switch (prop->type) {
829                 case IDP_ID:
830                         IDP_UnlinkID(prop);
831         }
832 }