code cleanup: typos and set gcc attributes for string formatting.
[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 "BKE_idprop.h"
37 #include "BKE_library.h"
38
39 #include "BLI_blenlib.h"
40
41 #include "MEM_guardedalloc.h"
42
43 /* IDPropertyTemplate is a union in DNA_ID.h */
44
45 /*local size table.*/
46 static char idp_size_table[] = {
47         1, /*strings*/
48         sizeof(int),
49         sizeof(float),
50         sizeof(float)*3, /*Vector type, deprecated*/
51         sizeof(float)*16, /*Matrix type, deprecated*/
52         0, /*arrays don't have a fixed size*/
53         sizeof(ListBase), /*Group type*/
54         sizeof(void*),
55         sizeof(double)
56 };
57
58 /* ------------Property Array Type ----------- */
59 #define GETPROP(prop, i) (((IDProperty*)(prop)->data.pointer)+(i))
60
61 /* --------- property array type -------------*/
62
63 /* note: as a start to move away from the stupid IDP_New function, this type
64  * has it's own allocation function.*/
65 IDProperty *IDP_NewIDPArray(const char *name)
66 {
67         IDProperty *prop = MEM_callocN(sizeof(IDProperty), "IDProperty prop array");
68         prop->type = IDP_IDPARRAY;
69         prop->len = 0;
70         BLI_strncpy(prop->name, name, MAX_IDPROP_NAME);
71         
72         return prop;
73 }
74
75 IDProperty *IDP_CopyIDPArray(IDProperty *array)
76 {
77         /* don't use MEM_dupallocN because this may be part of an array */
78         IDProperty *narray = MEM_mallocN(sizeof(IDProperty), "IDP_CopyIDPArray"), *tmp;
79         int i;
80
81         *narray= *array;
82
83         narray->data.pointer = MEM_dupallocN(array->data.pointer);
84         for (i=0; i<narray->len; i++) {
85                 /* ok, the copy functions always allocate a new structure,
86                  * which doesn't work here.  instead, simply copy the
87                  * contents of the new structure into the array cell,
88                  * then free it.  this makes for more maintainable
89                  * code than simply reimplementing the copy functions
90                  * in this loop.*/
91                 tmp = IDP_CopyProperty(GETPROP(narray, i));
92                 memcpy(GETPROP(narray, i), tmp, sizeof(IDProperty));
93                 MEM_freeN(tmp);
94         }
95         
96         return narray;
97 }
98
99 void IDP_FreeIDPArray(IDProperty *prop)
100 {
101         int i;
102         
103         for (i=0; i<prop->len; i++)
104                 IDP_FreeProperty(GETPROP(prop, i));
105
106         if (prop->data.pointer)
107                 MEM_freeN(prop->data.pointer);
108 }
109
110 /*shallow copies item*/
111 void IDP_SetIndexArray(IDProperty *prop, int index, IDProperty *item)
112 {
113         IDProperty *old = GETPROP(prop, index);
114         if (index >= prop->len || index < 0) return;
115         if (item != old) IDP_FreeProperty(old);
116         
117         memcpy(GETPROP(prop, index), item, sizeof(IDProperty));
118 }
119
120 IDProperty *IDP_GetIndexArray(IDProperty *prop, int index)
121 {
122         return GETPROP(prop, index);
123 }
124
125 IDProperty *IDP_AppendArray(IDProperty *prop, IDProperty *item)
126 {
127         IDP_ResizeIDPArray(prop, prop->len+1);
128         IDP_SetIndexArray(prop, prop->len-1, item);
129         return 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 /*taken from readfile.c*/
296 #define SWITCH_LONGINT(a) { \
297         char s_i, *p_i; \
298         p_i= (char *)&(a);  \
299         s_i=p_i[0]; p_i[0]=p_i[7]; p_i[7]=s_i; \
300         s_i=p_i[1]; p_i[1]=p_i[6]; p_i[6]=s_i; \
301         s_i=p_i[2]; p_i[2]=p_i[5]; p_i[5]=s_i; \
302         s_i=p_i[3]; p_i[3]=p_i[4]; p_i[4]=s_i; }
303
304
305
306 /* ---------- String Type ------------ */
307 IDProperty *IDP_NewString(const char *st, const char *name, int maxlen)
308 {
309         IDProperty *prop = MEM_callocN(sizeof(IDProperty), "IDProperty string");
310
311         if (st == NULL) {
312                 prop->data.pointer = MEM_callocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1");
313                 prop->totallen = DEFAULT_ALLOC_FOR_NULL_STRINGS;
314                 prop->len = 1; /*NULL string, has len of 1 to account for null byte.*/
315         }
316         else {
317                 int stlen = strlen(st);
318
319                 if (maxlen > 0 && maxlen < stlen)
320                         stlen = maxlen;
321
322                 stlen++; /* null terminator '\0' */
323
324                 prop->data.pointer = MEM_callocN(stlen, "id property string 2");
325                 prop->len = prop->totallen = stlen;
326                 BLI_strncpy(prop->data.pointer, st, stlen);
327         }
328
329         prop->type = IDP_STRING;
330         BLI_strncpy(prop->name, name, MAX_IDPROP_NAME);
331
332         return prop;
333 }
334
335 static IDProperty *IDP_CopyString(IDProperty *prop)
336 {
337         IDProperty *newp = idp_generic_copy(prop);
338
339         if (prop->data.pointer) newp->data.pointer = MEM_dupallocN(prop->data.pointer);
340         newp->len = prop->len;
341         newp->subtype = prop->subtype;
342         newp->totallen = prop->totallen;
343
344         return newp;
345 }
346
347
348 void IDP_AssignString(IDProperty *prop, const char *st, int maxlen)
349 {
350         int stlen = strlen(st);
351
352         if (maxlen > 0 && maxlen < stlen)
353                 stlen= maxlen;
354
355         if (prop->subtype == IDP_STRING_SUB_BYTE) {
356                 IDP_ResizeArray(prop, stlen);
357                 memcpy(prop->data.pointer, st, stlen);
358         }
359         else {
360                 stlen++; /* make room for null byte */
361                 IDP_ResizeArray(prop, stlen);
362                 BLI_strncpy(prop->data.pointer, st, stlen);
363         }
364 }
365
366 void IDP_ConcatStringC(IDProperty *prop, const char *st)
367 {
368         int newlen;
369
370         newlen = prop->len + strlen(st);
371         /* we have to remember that prop->len includes the null byte for strings.
372          * so there's no need to add +1 to the resize function.*/
373         IDP_ResizeArray(prop, newlen);
374         strcat(prop->data.pointer, st);
375 }
376
377 void IDP_ConcatString(IDProperty *str1, IDProperty *append)
378 {
379         int newlen;
380
381         /* since ->len for strings includes the NULL byte, we have to subtract one or
382          * we'll get an extra null byte after each concatenation operation.*/
383         newlen = str1->len + append->len - 1;
384         IDP_ResizeArray(str1, newlen);
385         strcat(str1->data.pointer, append->data.pointer);
386 }
387
388 void IDP_FreeString(IDProperty *prop)
389 {
390         if (prop->data.pointer)
391                 MEM_freeN(prop->data.pointer);
392 }
393
394
395 /*-------- ID Type, not in use yet -------*/
396
397 void IDP_LinkID(IDProperty *prop, ID *id)
398 {
399         if (prop->data.pointer) ((ID*)prop->data.pointer)->us--;
400         prop->data.pointer = id;
401         id_us_plus(id);
402 }
403
404 void IDP_UnlinkID(IDProperty *prop)
405 {
406         ((ID*)prop->data.pointer)->us--;
407 }
408
409 /*-------- Group Functions -------*/
410
411 /*checks if a property with the same name as prop exists, and if so replaces it.*/
412 static IDProperty *IDP_CopyGroup(IDProperty *prop)
413 {
414         IDProperty *newp = idp_generic_copy(prop), *link;
415         newp->len = prop->len;
416         
417         for (link=prop->data.group.first; link; link=link->next) {
418                 BLI_addtail(&newp->data.group, IDP_CopyProperty(link));
419         }
420
421         return newp;
422 }
423
424 /* use for syncing proxies.
425  * When values name and types match, copy the values, else ignore */
426 void IDP_SyncGroupValues(IDProperty *dest, IDProperty *src)
427 {
428         IDProperty *other, *prop;
429         for (prop=src->data.group.first; prop; prop=prop->next) {
430                 other= BLI_findstring(&dest->data.group, prop->name, offsetof(IDProperty, name));
431                 if (other && prop->type==other->type) {
432                         switch (prop->type) {
433                                 case IDP_INT:
434                                 case IDP_FLOAT:
435                                 case IDP_DOUBLE:
436                                         other->data= prop->data;
437                                         break;
438                                 case IDP_GROUP:
439                                         IDP_SyncGroupValues(other, prop);
440                                         break;
441                                 default:
442                                 {
443                                         IDProperty *tmp= other;
444                                         IDProperty *copy= IDP_CopyProperty(prop);
445
446                                         BLI_insertlinkafter(&dest->data.group, other, copy);
447                                         BLI_remlink(&dest->data.group, tmp);
448
449                                         IDP_FreeProperty(tmp);
450                                         MEM_freeN(tmp);
451                                 }
452                         }
453                 }
454         }
455 }
456
457 /*
458  * replaces all properties with the same name in a destination group from a source group.
459  */
460 void IDP_ReplaceGroupInGroup(IDProperty *dest, IDProperty *src)
461 {
462         IDProperty *loop, *prop;
463         for (prop=src->data.group.first; prop; prop=prop->next) {
464                 for (loop=dest->data.group.first; loop; loop=loop->next) {
465                         if (strcmp(loop->name, prop->name) == 0) {
466                                 IDProperty *copy = IDP_CopyProperty(prop);
467
468                                 BLI_insertlink(&dest->data.group, loop, copy);
469
470                                 BLI_remlink(&dest->data.group, loop);
471                                 IDP_FreeProperty(loop);
472                                 MEM_freeN(loop);
473                                 break;
474                         }
475                 }
476
477                 /* only add at end if not added yet */
478                 if (loop == NULL) {
479                         IDProperty *copy = IDP_CopyProperty(prop);
480                         dest->len++;
481                         BLI_addtail(&dest->data.group, copy);
482                 }
483         }
484 }
485 /*
486  * replaces a property with the same name in a group, or adds 
487  * it if the properly doesn't exist.
488  */
489 void IDP_ReplaceInGroup(IDProperty *group, IDProperty *prop)
490 {
491         IDProperty *loop;
492         if ((loop= IDP_GetPropertyFromGroup(group, prop->name))) {
493                 BLI_insertlink(&group->data.group, loop, prop);
494                 
495                 BLI_remlink(&group->data.group, loop);
496                 IDP_FreeProperty(loop);
497                 MEM_freeN(loop);                        
498         }
499         else {
500                 group->len++;
501                 BLI_addtail(&group->data.group, prop);
502         }
503 }
504
505 /* returns 0 if an id property with the same name exists and it failed,
506  * or 1 if it succeeded in adding to the group.*/
507 int IDP_AddToGroup(IDProperty *group, IDProperty *prop)
508 {
509         if (IDP_GetPropertyFromGroup(group, prop->name) == NULL) {
510                 group->len++;
511                 BLI_addtail(&group->data.group, prop);
512                 return 1;
513         }
514
515         return 0;
516 }
517
518 int IDP_InsertToGroup(IDProperty *group, IDProperty *previous, IDProperty *pnew)
519 {
520         if (IDP_GetPropertyFromGroup(group, pnew->name) == NULL) {
521                 group->len++;
522                 BLI_insertlink(&group->data.group, previous, pnew);
523                 return 1;
524         }
525
526         return 0;
527 }
528
529 void IDP_RemFromGroup(IDProperty *group, IDProperty *prop)
530 {
531         group->len--;
532         BLI_remlink(&group->data.group, prop);
533 }
534
535 IDProperty *IDP_GetPropertyFromGroup(IDProperty *prop, const char *name)
536 {
537         return (IDProperty *)BLI_findstring(&prop->data.group, name, offsetof(IDProperty, name));
538 }
539
540 IDProperty *IDP_GetPropertyTypeFromGroup(IDProperty *prop, const char *name, const char type)
541 {
542         IDProperty *idprop= IDP_GetPropertyFromGroup(prop, name);
543         return (idprop && idprop->type == type) ? idprop : NULL;
544 }
545
546 typedef struct IDPIter {
547         void *next;
548         IDProperty *parent;
549 } IDPIter;
550
551 void *IDP_GetGroupIterator(IDProperty *prop)
552 {
553         IDPIter *iter = MEM_callocN(sizeof(IDPIter), "IDPIter");
554         iter->next = prop->data.group.first;
555         iter->parent = prop;
556         return (void*) iter;
557 }
558
559 IDProperty *IDP_GroupIterNext(void *vself)
560 {
561         IDPIter *self = (IDPIter*) vself;
562         Link *next = (Link*) self->next;
563         if (self->next == NULL) {
564                 MEM_freeN(self);
565                 return NULL;
566         }
567
568         self->next = next->next;
569         return (void*) next;
570 }
571
572 void IDP_FreeIterBeforeEnd(void *vself)
573 {
574         MEM_freeN(vself);
575 }
576
577 /* Ok, the way things work, Groups free the ID Property structs of their children.
578  * This is because all ID Property freeing functions free only direct data (not the ID Property
579  * struct itself), but for Groups the child properties *are* considered
580  * direct data. */
581 static void IDP_FreeGroup(IDProperty *prop)
582 {
583         IDProperty *loop;
584         for (loop=prop->data.group.first; loop; loop=loop->next)
585         {
586                 IDP_FreeProperty(loop);
587         }
588         BLI_freelistN(&prop->data.group);
589 }
590
591
592 /*-------- Main Functions --------*/
593 IDProperty *IDP_CopyProperty(IDProperty *prop)
594 {
595         switch (prop->type) {
596                 case IDP_GROUP: return IDP_CopyGroup(prop);
597                 case IDP_STRING: return IDP_CopyString(prop);
598                 case IDP_ARRAY: return IDP_CopyArray(prop);
599                 case IDP_IDPARRAY: return IDP_CopyIDPArray(prop);
600                 default: return idp_generic_copy(prop);
601         }
602 }
603
604 IDProperty *IDP_GetProperties(ID *id, int create_if_needed)
605 {
606         if (id->properties) return id->properties;
607         else {
608                 if (create_if_needed) {
609                         id->properties = MEM_callocN(sizeof(IDProperty), "IDProperty");
610                         id->properties->type = IDP_GROUP;
611                         /* don't overwrite the data's name and type
612                          * some functions might need this if they
613                          * don't have a real ID, should be named elsewhere - Campbell */
614                         /* strcpy(id->name, "top_level_group");*/
615                 }
616                 return id->properties;
617         }
618 }
619
620 int IDP_EqualsProperties(IDProperty *prop1, IDProperty *prop2)
621 {
622         if (prop1 == NULL && prop2 == NULL)
623                 return 1;
624         else if (prop1 == NULL || prop2 == NULL)
625                 return 0;
626         else if (prop1->type != prop2->type)
627                 return 0;
628
629         if (prop1->type == IDP_INT)
630                 return (IDP_Int(prop1) == IDP_Int(prop2));
631         else if (prop1->type == IDP_FLOAT)
632                 return (IDP_Float(prop1) == IDP_Float(prop2));
633         else if (prop1->type == IDP_DOUBLE)
634                 return (IDP_Double(prop1) == IDP_Double(prop2));
635         else if (prop1->type == IDP_STRING)
636                 return ((prop1->len == prop2->len) && strncmp(IDP_String(prop1), IDP_String(prop2), prop1->len) == 0);
637         else if (prop1->type == IDP_ARRAY) {
638                 if (prop1->len == prop2->len && prop1->subtype == prop2->subtype)
639                         return memcmp(IDP_Array(prop1), IDP_Array(prop2), idp_size_table[(int)prop1->subtype]*prop1->len);
640                 else
641                         return 0;
642         }
643         else if (prop1->type == IDP_GROUP) {
644                 IDProperty *link1, *link2;
645
646                 if (BLI_countlist(&prop1->data.group) != BLI_countlist(&prop2->data.group))
647                         return 0;
648
649                 for (link1=prop1->data.group.first; link1; link1=link1->next) {
650                         link2= IDP_GetPropertyFromGroup(prop2, link1->name);
651
652                         if (!IDP_EqualsProperties(link1, link2))
653                                 return 0;
654                 }
655
656                 return 1;
657         }
658         else if (prop1->type == IDP_IDPARRAY) {
659                 IDProperty *array1= IDP_IDPArray(prop1);
660                 IDProperty *array2= IDP_IDPArray(prop2);
661                 int i;
662
663                 if (prop1->len != prop2->len)
664                         return 0;
665                 
666                 for (i=0; i<prop1->len; i++)
667                         if (!IDP_EqualsProperties(&array1[i], &array2[i]))
668                                 return 0;
669         }
670         
671         return 1;
672 }
673
674 /* 'val' is never NULL, don't check */
675 IDProperty *IDP_New(const int type, const IDPropertyTemplate *val, const char *name)
676 {
677         IDProperty *prop=NULL;
678
679         switch (type) {
680                 case IDP_INT:
681                         prop = MEM_callocN(sizeof(IDProperty), "IDProperty int");
682                         prop->data.val = val->i;
683                         break;
684                 case IDP_FLOAT:
685                         prop = MEM_callocN(sizeof(IDProperty), "IDProperty float");
686                         *(float*)&prop->data.val = val->f;
687                         break;
688                 case IDP_DOUBLE:
689                         prop = MEM_callocN(sizeof(IDProperty), "IDProperty float");
690                         *(double*)&prop->data.val = val->d;
691                         break;          
692                 case IDP_ARRAY:
693                 {
694                         /*for now, we only support float and int and double arrays*/
695                         if ( (val->array.type == IDP_FLOAT) ||
696                              (val->array.type == IDP_INT) ||
697                              (val->array.type == IDP_DOUBLE) ||
698                              (val->array.type == IDP_GROUP) )
699                         {
700                                 prop = MEM_callocN(sizeof(IDProperty), "IDProperty array");
701                                 prop->subtype = val->array.type;
702                                 if (val->array.len)
703                                         prop->data.pointer = MEM_callocN(idp_size_table[val->array.type]*val->array.len, "id property array");
704                                 prop->len = prop->totallen = val->array.len;
705                                 break;
706                         }
707                         else {
708                                 return NULL;
709                         }
710                 }
711                 case IDP_STRING:
712                 {
713                         const char *st = val->string.str;
714
715                         prop = MEM_callocN(sizeof(IDProperty), "IDProperty string");
716                         if (val->string.subtype == IDP_STRING_SUB_BYTE) {
717                                 /* note, intentionally not null terminated */
718                                 if (st == NULL) {
719                                         prop->data.pointer = MEM_callocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1");
720                                         prop->totallen = DEFAULT_ALLOC_FOR_NULL_STRINGS;
721                                         prop->len = 0;
722                                 }
723                                 else {
724                                         prop->data.pointer = MEM_mallocN(val->string.len, "id property string 2");
725                                         prop->len = prop->totallen = val->string.len;
726                                         memcpy(prop->data.pointer, st, val->string.len);
727                                 }
728                                 prop->subtype= IDP_STRING_SUB_BYTE;
729                         }
730                         else {
731                                 if (st == NULL) {
732                                         prop->data.pointer = MEM_callocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1");
733                                         prop->totallen = DEFAULT_ALLOC_FOR_NULL_STRINGS;
734                                         prop->len = 1; /*NULL string, has len of 1 to account for null byte.*/
735                                 }
736                                 else {
737                                         int stlen = strlen(st) + 1;
738                                         prop->data.pointer = MEM_mallocN(stlen, "id property string 3");
739                                         prop->len = prop->totallen = stlen;
740                                         memcpy(prop->data.pointer, st, stlen);
741                                 }
742                                 prop->subtype= IDP_STRING_SUB_UTF8;
743                         }
744                         break;
745                 }
746                 case IDP_GROUP:
747                 {
748                         prop = MEM_callocN(sizeof(IDProperty), "IDProperty group");
749                         /* heh I think all needed values are set properly by calloc anyway :) */
750                         break;
751                 }
752                 default:
753                 {
754                         prop = MEM_callocN(sizeof(IDProperty), "IDProperty array");
755                         break;
756                 }
757         }
758
759         prop->type = type;
760         BLI_strncpy(prop->name, name, MAX_IDPROP_NAME);
761         
762         return prop;
763 }
764
765 /* NOTE: this will free all child properties including list arrays and groups!
766  * Also, note that this does NOT unlink anything!  Plus it doesn't free
767  * the actual IDProperty struct either.*/
768 void IDP_FreeProperty(IDProperty *prop)
769 {
770         switch (prop->type) {
771                 case IDP_ARRAY:
772                         IDP_FreeArray(prop);
773                         break;
774                 case IDP_STRING:
775                         IDP_FreeString(prop);
776                         break;
777                 case IDP_GROUP:
778                         IDP_FreeGroup(prop);
779                         break;
780                 case IDP_IDPARRAY:
781                         IDP_FreeIDPArray(prop);
782                         break;
783         }
784 }
785
786 /* Unlinks any IDProperty<->ID linkage that might be going on.
787  * note: currently unused.*/
788 void IDP_UnlinkProperty(IDProperty *prop)
789 {
790         switch (prop->type) {
791                 case IDP_ID:
792                         IDP_UnlinkID(prop);
793         }
794 }