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