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