resolve some compiler warnings with intel c/c++ compiler
[blender.git] / source / blender / blenkernel / intern / idprop.c
1 /**
2  * $Id: idprop.c
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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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 #include "DNA_listBase.h"
29 #include "DNA_ID.h"
30
31 #include "BKE_idprop.h"
32 #include "BKE_global.h"
33 #include "BKE_library.h"
34 #include "BKE_utildefines.h"
35
36 #include "BLI_blenlib.h"
37
38 #include "MEM_guardedalloc.h"
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43
44 #define BSTR_EQ(a, b)   (*(a) == *(b) && !strcmp(a, b))
45
46 /* IDPropertyTemplate is a union in DNA_ID.h */
47
48 /*local size table.*/
49 static char idp_size_table[] = {
50         1, /*strings*/
51         sizeof(int),
52         sizeof(float),
53         sizeof(float)*3, /*Vector type, deprecated*/
54         sizeof(float)*16, /*Matrix type, deprecated*/
55         0, /*arrays don't have a fixed size*/
56         sizeof(ListBase), /*Group type*/
57         sizeof(void*),
58         sizeof(double)
59 };
60
61
62 /* ----------- Array Type ----------- */
63
64 /*this function works for strings too!*/
65 void IDP_ResizeArray(IDProperty *prop, int newlen)
66 {
67         void *newarr;
68         int newsize=newlen;
69
70         /*first check if the array buffer size has room*/
71         /*if newlen is 200 chars less then totallen, reallocate anyway*/
72         if (newlen <= prop->totallen && prop->totallen - newlen < 200) {
73                 prop->len = newlen;
74                 return;
75         }
76
77         /* - Note: This code comes from python, here's the corrusponding comment. - */
78         /* This over-allocates proportional to the list size, making room
79          * for additional growth.  The over-allocation is mild, but is
80          * enough to give linear-time amortized behavior over a long
81          * sequence of appends() in the presence of a poorly-performing
82          * system realloc().
83          * The growth pattern is:  0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
84          */
85         newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize;
86
87         newarr = MEM_callocN(idp_size_table[prop->type]*newsize, "idproperty array resized");
88         /*newlen is bigger*/
89         if (newlen >= prop->len) memcpy(newarr, prop->data.pointer, prop->len*idp_size_table[prop->type]);
90         /*newlen is smaller*/
91         else memcpy(newarr, prop->data.pointer, newlen*prop->len*idp_size_table[prop->type]);
92
93         MEM_freeN(prop->data.pointer);
94         prop->data.pointer = newarr;
95         prop->len = newlen;
96         prop->totallen = newsize;
97 }
98
99  void IDP_FreeArray(IDProperty *prop)
100 {
101         if (prop->data.pointer)
102                 MEM_freeN(prop->data.pointer);
103 }
104
105
106  static IDProperty *idp_generic_copy(IDProperty *prop)
107  {
108         IDProperty *newp = MEM_callocN(sizeof(IDProperty), "IDProperty array dup");
109
110         strncpy(newp->name, prop->name, MAX_IDPROP_NAME);
111         newp->type = prop->type;
112         newp->flag = prop->flag;
113         newp->data.val = prop->data.val;
114
115         return newp;
116  }
117
118 IDProperty *IDP_CopyArray(IDProperty *prop)
119 {
120         IDProperty *newp = idp_generic_copy(prop);
121
122         if (prop->data.pointer) newp->data.pointer = MEM_dupallocN(prop->data.pointer);
123         newp->len = prop->len;
124         newp->subtype = prop->subtype;
125         newp->totallen = prop->totallen;
126
127         return newp;
128 }
129
130 /*taken from readfile.c*/
131 #define SWITCH_LONGINT(a) { \
132     char s_i, *p_i; \
133     p_i= (char *)&(a);  \
134     s_i=p_i[0]; p_i[0]=p_i[7]; p_i[7]=s_i; \
135     s_i=p_i[1]; p_i[1]=p_i[6]; p_i[6]=s_i; \
136     s_i=p_i[2]; p_i[2]=p_i[5]; p_i[5]=s_i; \
137     s_i=p_i[3]; p_i[3]=p_i[4]; p_i[4]=s_i; }
138
139
140
141 /* ---------- String Type ------------ */
142 IDProperty *IDP_CopyString(IDProperty *prop)
143 {
144         IDProperty *newp = idp_generic_copy(prop);
145
146         if (prop->data.pointer) newp->data.pointer = MEM_dupallocN(prop->data.pointer);
147         newp->len = prop->len;
148         newp->subtype = prop->subtype;
149         newp->totallen = prop->totallen;
150
151         return newp;
152 }
153
154
155 void IDP_AssignString(IDProperty *prop, char *st)
156 {
157         int stlen;
158
159         stlen = strlen(st);
160
161         IDP_ResizeArray(prop, stlen+1); /*make room for null byte :) */
162         strcpy(prop->data.pointer, st);
163 }
164
165 void IDP_ConcatStringC(IDProperty *prop, char *st)
166 {
167         int newlen;
168
169         newlen = prop->len + strlen(st);
170         /*we have to remember that prop->len includes the null byte for strings.
171          so there's no need to add +1 to the resize function.*/
172         IDP_ResizeArray(prop, newlen);
173         strcat(prop->data.pointer, st);
174 }
175
176 void IDP_ConcatString(IDProperty *str1, IDProperty *append)
177 {
178         int newlen;
179
180         /*since ->len for strings includes the NULL byte, we have to subtract one or
181          we'll get an extra null byte after each concatination operation.*/
182         newlen = str1->len + append->len - 1;
183         IDP_ResizeArray(str1, newlen);
184         strcat(str1->data.pointer, append->data.pointer);
185 }
186
187 void IDP_FreeString(IDProperty *prop)
188 {
189         MEM_freeN(prop->data.pointer);
190 }
191
192
193 /*-------- ID Type, not in use yet -------*/
194
195 void IDP_LinkID(IDProperty *prop, ID *id)
196 {
197         if (prop->data.pointer) ((ID*)prop->data.pointer)->us--;
198         prop->data.pointer = id;
199         id_us_plus(id);
200 }
201
202 void IDP_UnlinkID(IDProperty *prop)
203 {
204         ((ID*)prop->data.pointer)->us--;
205 }
206
207 /*-------- Group Functions -------*/
208
209 /*checks if a property with the same name as prop exists, and if so replaces it.*/
210 IDProperty *IDP_CopyGroup(IDProperty *prop)
211 {
212         IDProperty *newp = idp_generic_copy(prop), *link;
213         newp->len = prop->len;
214         
215         for (link=prop->data.group.first; link; link=link->next) {
216                 BLI_addtail(&newp->data.group, IDP_CopyProperty(link));
217         }
218
219         return newp;
220 }
221
222 void IDP_ReplaceInGroup(IDProperty *group, IDProperty *prop)
223 {
224         IDProperty *loop;
225         for (loop=group->data.group.first; loop; loop=loop->next) {
226                 if (BSTR_EQ(loop->name, prop->name)) {
227                         if (loop->next) BLI_insertlinkbefore(&group->data.group, loop->next, prop);
228                         else BLI_addtail(&group->data.group, prop);
229                         
230                         BLI_remlink(&group->data.group, loop);
231                         IDP_FreeProperty(loop);
232                         MEM_freeN(loop);
233                         
234                         return;
235                 }
236         }
237
238         group->len++;
239         BLI_addtail(&group->data.group, prop);
240 }
241
242 /*returns 0 if an id property with the same name exists and it failed,
243   or 1 if it succeeded in adding to the group.*/
244 int IDP_AddToGroup(IDProperty *group, IDProperty *prop)
245 {
246         IDProperty *loop;
247         for (loop=group->data.group.first; loop; loop=loop->next) {
248                 if (BSTR_EQ(loop->name, prop->name)) return 0;
249         }
250
251         group->len++;
252         BLI_addtail(&group->data.group, prop);
253
254         return 1;
255 }
256
257 int IDP_InsertToGroup(IDProperty *group, IDProperty *previous, IDProperty *pnew)
258 {
259         IDProperty *loop;
260         for (loop=group->data.group.first; loop; loop=loop->next) {
261                 if (BSTR_EQ(loop->name, pnew->name)) return 0;
262         }
263         
264         group->len++;
265         
266         BLI_insertlink(&group->data.group, previous, pnew);
267         return 1;
268 }
269
270 void IDP_RemFromGroup(IDProperty *group, IDProperty *prop)
271 {
272         group->len--;
273         BLI_remlink(&group->data.group, prop);
274 }
275
276 IDProperty *IDP_GetPropertyFromGroup(IDProperty *prop, char *name)
277 {
278         IDProperty *loop;
279         for (loop=prop->data.group.first; loop; loop=loop->next) {
280                 if (strcmp(loop->name, name)==0) return loop;
281         }
282         return NULL;
283 }
284
285 typedef struct IDPIter {
286         void *next;
287         IDProperty *parent;
288 } IDPIter;
289
290 void *IDP_GetGroupIterator(IDProperty *prop)
291 {
292         IDPIter *iter = MEM_callocN(sizeof(IDPIter), "IDPIter");
293         iter->next = prop->data.group.first;
294         iter->parent = prop;
295         return (void*) iter;
296 }
297
298 IDProperty *IDP_GroupIterNext(void *vself)
299 {
300         IDPIter *self = (IDPIter*) vself;
301         Link *next = (Link*) self->next;
302         if (self->next == NULL) {
303                 MEM_freeN(self);
304                 return NULL;
305         }
306
307         self->next = next->next;
308         return (void*) next;
309 }
310
311 void IDP_FreeIterBeforeEnd(void *vself)
312 {
313         MEM_freeN(vself);
314 }
315
316 /*Ok, the way things work, Groups free the ID Property structs of their children.
317   This is because all ID Property freeing functions free only direct data (not the ID Property
318   struct itself), but for Groups the child properties *are* considered
319   direct data.*/
320 static void IDP_FreeGroup(IDProperty *prop)
321 {
322         IDProperty *loop, *next;
323         for (loop=prop->data.group.first; loop; loop=next)
324         {
325                 next = loop->next;
326                 BLI_remlink(&prop->data.group, loop);
327                 IDP_FreeProperty(loop);
328                 MEM_freeN(loop);
329         }
330 }
331
332
333 /*-------- Main Functions --------*/
334 IDProperty *IDP_CopyProperty(IDProperty *prop)
335 {
336         switch (prop->type) {
337                 case IDP_GROUP: return IDP_CopyGroup(prop);
338                 case IDP_STRING: return IDP_CopyString(prop);
339                 case IDP_ARRAY: return IDP_CopyArray(prop);
340                 default: return idp_generic_copy(prop);
341         }
342 }
343
344 IDProperty *IDP_GetProperties(ID *id, int create_if_needed)
345 {
346         if (id->properties) return id->properties;
347         else {
348                 if (create_if_needed) {
349                         id->properties = MEM_callocN(sizeof(IDProperty), "IDProperty");
350                         id->properties->type = IDP_GROUP;
351                 }
352                 return id->properties;
353         }
354 }
355
356 IDProperty *IDP_New(int type, IDPropertyTemplate val, char *name)
357 {
358         IDProperty *prop=NULL;
359
360         switch (type) {
361                 case IDP_INT:
362                         prop = MEM_callocN(sizeof(IDProperty), "IDProperty int");
363                         prop->data.val = val.i;
364                         break;
365                 case IDP_FLOAT:
366                         prop = MEM_callocN(sizeof(IDProperty), "IDProperty float");
367                         *(float*)&prop->data.val = val.f;
368                         break;
369                 case IDP_DOUBLE:
370                         prop = MEM_callocN(sizeof(IDProperty), "IDProperty float");
371                         *(double*)&prop->data.val = val.d;
372                         break;          
373                 case IDP_ARRAY:
374                 {
375                         /*for now, we only support float and int and double arrays*/
376                         if (val.array.type == IDP_FLOAT || val.array.type == IDP_INT || val.array.type == IDP_DOUBLE) {
377                                 prop = MEM_callocN(sizeof(IDProperty), "IDProperty array");
378                                 prop->len = prop->totallen = val.array.len;
379                                 prop->subtype = val.array.type;
380                                 prop->data.pointer = MEM_callocN(idp_size_table[val.array.type]*val.array.len, "id property array");
381                                 break;
382                         } else {
383                                 return NULL;
384                         }
385                 }
386                 case IDP_STRING:
387                 {
388                         char *st = val.str;
389                         int stlen;
390
391                         prop = MEM_callocN(sizeof(IDProperty), "IDProperty string");
392                         if (st == NULL) {
393                                 prop->data.pointer = MEM_callocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1");
394                                 prop->totallen = DEFAULT_ALLOC_FOR_NULL_STRINGS;
395                                 prop->len = 1; /*NULL string, has len of 1 to account for null byte.*/
396                         } else {
397                                 stlen = strlen(st) + 1;
398                                 prop->data.pointer = MEM_callocN(stlen, "id property string 2");
399                                 prop->len = prop->totallen = stlen;
400                                 strcpy(prop->data.pointer, st);
401                         }
402                         break;
403                 }
404                 case IDP_GROUP:
405                 {
406                         prop = MEM_callocN(sizeof(IDProperty), "IDProperty group");
407                         /* heh I think all needed values are set properly by calloc anyway :) */
408                         break;
409                 }
410                 default:
411                 {
412                         prop = MEM_callocN(sizeof(IDProperty), "IDProperty array");
413                         break;
414                 }
415         }
416
417         prop->type = type;
418         strncpy(prop->name, name, MAX_IDPROP_NAME);
419         
420         /*security null byte*/
421         prop->name[MAX_IDPROP_NAME-1] = 0;
422         
423         return prop;
424 }
425
426 /*NOTE: this will free all child properties of list arrays and groups!
427   Also, note that this does NOT unlink anything!  Plus it doesn't free
428   the actual IDProperty struct either.*/
429 void IDP_FreeProperty(IDProperty *prop)
430 {
431         switch (prop->type) {
432                 case IDP_ARRAY:
433                         IDP_FreeArray(prop);
434                         break;
435                 case IDP_STRING:
436                         IDP_FreeString(prop);
437                         break;
438                 case IDP_GROUP:
439                         IDP_FreeGroup(prop);
440                         break;
441         }
442 }
443
444 /*Unlinks any IDProperty<->ID linkage that might be going on.*/
445 void IDP_UnlinkProperty(IDProperty *prop)
446 {
447         switch (prop->type) {
448                 case IDP_ID:
449                         IDP_UnlinkID(prop);
450         }
451 }