Blender  V2.59
idprop.c
Go to the documentation of this file.
00001 /*
00002  * $Id: idprop.c 36403 2011-05-01 06:34:40Z campbellbarton $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00021  * All rights reserved.
00022  *
00023  * Contributor(s): Joseph Eagar
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00033 #include <stdio.h>
00034 #include <stdlib.h>
00035 #include <stddef.h>
00036 #include <string.h>
00037 
00038 #include "BKE_idprop.h"
00039 #include "BKE_library.h"
00040 
00041 #include "BLI_blenlib.h"
00042 
00043 #include "MEM_guardedalloc.h"
00044 
00045 #define BSTR_EQ(a, b)   (*(a) == *(b) && !strcmp(a, b))
00046 
00047 /* IDPropertyTemplate is a union in DNA_ID.h */
00048 
00049 /*local size table.*/
00050 static char idp_size_table[] = {
00051         1, /*strings*/
00052         sizeof(int),
00053         sizeof(float),
00054         sizeof(float)*3, /*Vector type, deprecated*/
00055         sizeof(float)*16, /*Matrix type, deprecated*/
00056         0, /*arrays don't have a fixed size*/
00057         sizeof(ListBase), /*Group type*/
00058         sizeof(void*),
00059         sizeof(double)
00060 };
00061 
00062 /* ------------Property Array Type ----------- */
00063 #define GETPROP(prop, i) (((IDProperty*)(prop)->data.pointer)+(i))
00064 
00065 /* --------- property array type -------------*/
00066 
00067 /*note: as a start to move away from the stupid IDP_New function, this type
00068   has it's own allocation function.*/
00069 IDProperty *IDP_NewIDPArray(const char *name)
00070 {
00071         IDProperty *prop = MEM_callocN(sizeof(IDProperty), "IDProperty prop array");
00072         prop->type = IDP_IDPARRAY;
00073         prop->len = 0;
00074         BLI_strncpy(prop->name, name, MAX_IDPROP_NAME);
00075         
00076         return prop;
00077 }
00078 
00079 IDProperty *IDP_CopyIDPArray(IDProperty *array)
00080 {
00081         /* dont use MEM_dupallocN because this may be part of an array */
00082         IDProperty *narray = MEM_mallocN(sizeof(IDProperty), "IDP_CopyIDPArray"), *tmp;
00083         int i;
00084 
00085         *narray= *array;
00086 
00087         narray->data.pointer = MEM_dupallocN(array->data.pointer);
00088         for (i=0; i<narray->len; i++) {
00089                 /*ok, the copy functions always allocate a new structure,
00090                   which doesn't work here.  instead, simply copy the
00091                   contents of the new structure into the array cell,
00092                   then free it.  this makes for more maintainable
00093                   code than simply reimplementing the copy functions
00094                   in this loop.*/
00095                 tmp = IDP_CopyProperty(GETPROP(narray, i));
00096                 memcpy(GETPROP(narray, i), tmp, sizeof(IDProperty));
00097                 MEM_freeN(tmp);
00098         }
00099         
00100         return narray;
00101 }
00102 
00103 void IDP_FreeIDPArray(IDProperty *prop)
00104 {
00105         int i;
00106         
00107         for (i=0; i<prop->len; i++)
00108                 IDP_FreeProperty(GETPROP(prop, i));
00109 
00110         if(prop->data.pointer)
00111                 MEM_freeN(prop->data.pointer);
00112 }
00113 
00114 /*shallow copies item*/
00115 void IDP_SetIndexArray(IDProperty *prop, int index, IDProperty *item)
00116 {
00117         IDProperty *old = GETPROP(prop, index);
00118         if (index >= prop->len || index < 0) return;
00119         if (item != old) IDP_FreeProperty(old);
00120         
00121         memcpy(GETPROP(prop, index), item, sizeof(IDProperty));
00122 }
00123 
00124 IDProperty *IDP_GetIndexArray(IDProperty *prop, int index)
00125 {
00126         return GETPROP(prop, index);
00127 }
00128 
00129 IDProperty *IDP_AppendArray(IDProperty *prop, IDProperty *item)
00130 {
00131         IDP_ResizeIDPArray(prop, prop->len+1);
00132         IDP_SetIndexArray(prop, prop->len-1, item);
00133         return item;
00134 }
00135 
00136 void IDP_ResizeIDPArray(IDProperty *prop, int newlen)
00137 {
00138         void *newarr;
00139         int newsize=newlen;
00140 
00141         /*first check if the array buffer size has room*/
00142         /*if newlen is 200 chars less then totallen, reallocate anyway*/
00143         if (newlen <= prop->totallen && prop->totallen - newlen < 200) {
00144                 int i;
00145 
00146                 for(i=newlen; i<prop->len; i++)
00147                         IDP_FreeProperty(GETPROP(prop, i));
00148 
00149                 prop->len = newlen;
00150                 return;
00151         }
00152 
00153         /* - Note: This code comes from python, here's the corrusponding comment. - */
00154         /* This over-allocates proportional to the list size, making room
00155          * for additional growth.  The over-allocation is mild, but is
00156          * enough to give linear-time amortized behavior over a long
00157          * sequence of appends() in the presence of a poorly-performing
00158          * system realloc().
00159          * The growth pattern is:  0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
00160          */
00161         newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize;
00162 
00163         newarr = MEM_callocN(sizeof(IDProperty)*newsize, "idproperty array resized");
00164         if (newlen >= prop->len) {
00165                 /* newlen is bigger*/
00166                 memcpy(newarr, prop->data.pointer, prop->len*sizeof(IDProperty));
00167         }
00168         else {
00169                 int i;
00170                 /* newlen is smaller*/
00171                 for (i=newlen; i<prop->len; i++) {
00172                         IDP_FreeProperty(GETPROP(prop, i));
00173                 }
00174                 memcpy(newarr, prop->data.pointer, newlen*sizeof(IDProperty));
00175         }
00176 
00177         if(prop->data.pointer)
00178                 MEM_freeN(prop->data.pointer);
00179         prop->data.pointer = newarr;
00180         prop->len = newlen;
00181         prop->totallen = newsize;
00182 }
00183 
00184 /* ----------- Numerical Array Type ----------- */
00185 static void idp_resize_group_array(IDProperty *prop, int newlen, void *newarr)
00186 {
00187         if(prop->subtype != IDP_GROUP)
00188                 return;
00189 
00190         if(newlen >= prop->len) {
00191                 /* bigger */
00192                 IDProperty **array= newarr;
00193                 IDPropertyTemplate val;
00194                 int a;
00195 
00196                 for(a=prop->len; a<newlen; a++) {
00197                         val.i = 0; /* silence MSVC warning about uninitialized var when debugging */
00198                         array[a]= IDP_New(IDP_GROUP, val, "IDP_ResizeArray group");
00199                 }
00200         }
00201         else {
00202                 /* smaller */
00203                 IDProperty **array= prop->data.pointer;
00204                 int a;
00205 
00206                 for(a=newlen; a<prop->len; a++) {
00207                         IDP_FreeProperty(array[a]);
00208                         MEM_freeN(array[a]);
00209                 }
00210         }
00211 }
00212 
00213 /*this function works for strings too!*/
00214 void IDP_ResizeArray(IDProperty *prop, int newlen)
00215 {
00216         void *newarr;
00217         int newsize=newlen;
00218 
00219         /*first check if the array buffer size has room*/
00220         /*if newlen is 200 chars less then totallen, reallocate anyway*/
00221         if (newlen <= prop->totallen && prop->totallen - newlen < 200) {
00222                 idp_resize_group_array(prop, newlen, prop->data.pointer);
00223                 prop->len = newlen;
00224                 return;
00225         }
00226 
00227         /* - Note: This code comes from python, here's the corrusponding comment. - */
00228         /* This over-allocates proportional to the list size, making room
00229          * for additional growth.  The over-allocation is mild, but is
00230          * enough to give linear-time amortized behavior over a long
00231          * sequence of appends() in the presence of a poorly-performing
00232          * system realloc().
00233          * The growth pattern is:  0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
00234          */
00235         newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize;
00236 
00237         newarr = MEM_callocN(idp_size_table[(int)prop->subtype]*newsize, "idproperty array resized");
00238         if (newlen >= prop->len) {
00239                 /* newlen is bigger*/
00240                 memcpy(newarr, prop->data.pointer, prop->len*idp_size_table[(int)prop->subtype]);
00241                 idp_resize_group_array(prop, newlen, newarr);
00242         }
00243         else {
00244                 /* newlen is smaller*/
00245                 idp_resize_group_array(prop, newlen, newarr);
00246                 memcpy(newarr, prop->data.pointer, newlen*idp_size_table[(int)prop->subtype]);
00247         }
00248 
00249         MEM_freeN(prop->data.pointer);
00250         prop->data.pointer = newarr;
00251         prop->len = newlen;
00252         prop->totallen = newsize;
00253 }
00254 
00255 void IDP_FreeArray(IDProperty *prop)
00256 {
00257         if (prop->data.pointer) {
00258                 idp_resize_group_array(prop, 0, NULL);
00259                 MEM_freeN(prop->data.pointer);
00260         }
00261 }
00262 
00263 
00264  static IDProperty *idp_generic_copy(IDProperty *prop)
00265  {
00266         IDProperty *newp = MEM_callocN(sizeof(IDProperty), "IDProperty array dup");
00267 
00268         BLI_strncpy(newp->name, prop->name, MAX_IDPROP_NAME);
00269         newp->type = prop->type;
00270         newp->flag = prop->flag;
00271         newp->data.val = prop->data.val;
00272         newp->data.val2 = prop->data.val2;
00273 
00274         return newp;
00275  }
00276 
00277 static IDProperty *IDP_CopyArray(IDProperty *prop)
00278 {
00279         IDProperty *newp = idp_generic_copy(prop);
00280 
00281         if (prop->data.pointer) {
00282                 newp->data.pointer = MEM_dupallocN(prop->data.pointer);
00283 
00284                 if(prop->type == IDP_GROUP) {
00285                         IDProperty **array= newp->data.pointer;
00286                         int a;
00287 
00288                         for(a=0; a<prop->len; a++)
00289                                 array[a]= IDP_CopyProperty(array[a]);
00290                 }
00291         }
00292         newp->len = prop->len;
00293         newp->subtype = prop->subtype;
00294         newp->totallen = prop->totallen;
00295 
00296         return newp;
00297 }
00298 
00299 /*taken from readfile.c*/
00300 #define SWITCH_LONGINT(a) { \
00301         char s_i, *p_i; \
00302         p_i= (char *)&(a);  \
00303         s_i=p_i[0]; p_i[0]=p_i[7]; p_i[7]=s_i; \
00304         s_i=p_i[1]; p_i[1]=p_i[6]; p_i[6]=s_i; \
00305         s_i=p_i[2]; p_i[2]=p_i[5]; p_i[5]=s_i; \
00306         s_i=p_i[3]; p_i[3]=p_i[4]; p_i[4]=s_i; }
00307 
00308 
00309 
00310 /* ---------- String Type ------------ */
00311 IDProperty *IDP_NewString(const char *st, const char *name, int maxlen)
00312 {
00313         IDProperty *prop = MEM_callocN(sizeof(IDProperty), "IDProperty string");
00314 
00315         if (st == NULL) {
00316                 prop->data.pointer = MEM_callocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1");
00317                 prop->totallen = DEFAULT_ALLOC_FOR_NULL_STRINGS;
00318                 prop->len = 1; /*NULL string, has len of 1 to account for null byte.*/
00319         }
00320         else {
00321                 int stlen = strlen(st);
00322 
00323                 if(maxlen > 0 && maxlen < stlen)
00324                         stlen = maxlen;
00325 
00326                 stlen++; /* null terminator '\0' */
00327 
00328                 prop->data.pointer = MEM_callocN(stlen, "id property string 2");
00329                 prop->len = prop->totallen = stlen;
00330                 BLI_strncpy(prop->data.pointer, st, stlen);
00331         }
00332 
00333         prop->type = IDP_STRING;
00334         BLI_strncpy(prop->name, name, MAX_IDPROP_NAME);
00335 
00336         return prop;
00337 }
00338 
00339 static IDProperty *IDP_CopyString(IDProperty *prop)
00340 {
00341         IDProperty *newp = idp_generic_copy(prop);
00342 
00343         if (prop->data.pointer) newp->data.pointer = MEM_dupallocN(prop->data.pointer);
00344         newp->len = prop->len;
00345         newp->subtype = prop->subtype;
00346         newp->totallen = prop->totallen;
00347 
00348         return newp;
00349 }
00350 
00351 
00352 void IDP_AssignString(IDProperty *prop, const char *st, int maxlen)
00353 {
00354         int stlen;
00355 
00356         stlen = strlen(st);
00357 
00358         if(maxlen > 0 && maxlen < stlen)
00359                 stlen= maxlen;
00360 
00361         stlen++; /* make room for null byte */
00362 
00363         IDP_ResizeArray(prop, stlen);
00364         BLI_strncpy(prop->data.pointer, st, stlen);
00365 }
00366 
00367 void IDP_ConcatStringC(IDProperty *prop, const char *st)
00368 {
00369         int newlen;
00370 
00371         newlen = prop->len + strlen(st);
00372         /*we have to remember that prop->len includes the null byte for strings.
00373          so there's no need to add +1 to the resize function.*/
00374         IDP_ResizeArray(prop, newlen);
00375         strcat(prop->data.pointer, st);
00376 }
00377 
00378 void IDP_ConcatString(IDProperty *str1, IDProperty *append)
00379 {
00380         int newlen;
00381 
00382         /*since ->len for strings includes the NULL byte, we have to subtract one or
00383          we'll get an extra null byte after each concatination operation.*/
00384         newlen = str1->len + append->len - 1;
00385         IDP_ResizeArray(str1, newlen);
00386         strcat(str1->data.pointer, append->data.pointer);
00387 }
00388 
00389 void IDP_FreeString(IDProperty *prop)
00390 {
00391         if(prop->data.pointer)
00392                 MEM_freeN(prop->data.pointer);
00393 }
00394 
00395 
00396 /*-------- ID Type, not in use yet -------*/
00397 
00398 void IDP_LinkID(IDProperty *prop, ID *id)
00399 {
00400         if (prop->data.pointer) ((ID*)prop->data.pointer)->us--;
00401         prop->data.pointer = id;
00402         id_us_plus(id);
00403 }
00404 
00405 void IDP_UnlinkID(IDProperty *prop)
00406 {
00407         ((ID*)prop->data.pointer)->us--;
00408 }
00409 
00410 /*-------- Group Functions -------*/
00411 
00412 /*checks if a property with the same name as prop exists, and if so replaces it.*/
00413 static IDProperty *IDP_CopyGroup(IDProperty *prop)
00414 {
00415         IDProperty *newp = idp_generic_copy(prop), *link;
00416         newp->len = prop->len;
00417         
00418         for (link=prop->data.group.first; link; link=link->next) {
00419                 BLI_addtail(&newp->data.group, IDP_CopyProperty(link));
00420         }
00421 
00422         return newp;
00423 }
00424 
00425 /* use for syncing proxies.
00426  * When values name and types match, copy the values, else ignore */
00427 void IDP_SyncGroupValues(IDProperty *dest, IDProperty *src)
00428 {
00429         IDProperty *other, *prop;
00430         for (prop=src->data.group.first; prop; prop=prop->next) {
00431                 other= BLI_findstring(&dest->data.group, prop->name, offsetof(IDProperty, name));
00432                 if (other && prop->type==other->type) {
00433                         switch (prop->type) {
00434                                 case IDP_INT:
00435                                 case IDP_FLOAT:
00436                                 case IDP_DOUBLE:
00437                                         other->data= prop->data;
00438                                         break;
00439                                 case IDP_GROUP:
00440                                         IDP_SyncGroupValues(other, prop);
00441                                         break;
00442                                 default:
00443                                 {
00444                                         IDProperty *tmp= other;
00445                                         IDProperty *copy= IDP_CopyProperty(prop);
00446 
00447                                         BLI_insertlinkafter(&dest->data.group, other, copy);
00448                                         BLI_remlink(&dest->data.group, tmp);
00449 
00450                                         IDP_FreeProperty(tmp);
00451                                         MEM_freeN(tmp);
00452                                 }
00453                         }
00454                 }
00455         }
00456 }
00457 
00458 /*
00459  replaces all properties with the same name in a destination group from a source group.
00460 */
00461 void IDP_ReplaceGroupInGroup(IDProperty *dest, IDProperty *src)
00462 {
00463         IDProperty *loop, *prop;
00464         for (prop=src->data.group.first; prop; prop=prop->next) {
00465                 for (loop=dest->data.group.first; loop; loop=loop->next) {
00466                         if (BSTR_EQ(loop->name, prop->name)) {
00467                                 IDProperty *copy = IDP_CopyProperty(prop);
00468 
00469                                 BLI_insertlink(&dest->data.group, loop, copy);
00470 
00471                                 BLI_remlink(&dest->data.group, loop);
00472                                 IDP_FreeProperty(loop);
00473                                 MEM_freeN(loop);
00474                                 break;
00475                         }
00476                 }
00477 
00478                 /* only add at end if not added yet */
00479                 if (loop == NULL) {
00480                         IDProperty *copy = IDP_CopyProperty(prop);
00481                         dest->len++;
00482                         BLI_addtail(&dest->data.group, copy);
00483                 }
00484         }
00485 }
00486 /*
00487  replaces a property with the same name in a group, or adds 
00488  it if the propery doesn't exist.
00489 */
00490 void IDP_ReplaceInGroup(IDProperty *group, IDProperty *prop)
00491 {
00492         IDProperty *loop;
00493         if((loop= IDP_GetPropertyFromGroup(group, prop->name)))  {
00494                 BLI_insertlink(&group->data.group, loop, prop);
00495                 
00496                 BLI_remlink(&group->data.group, loop);
00497                 IDP_FreeProperty(loop);
00498                 MEM_freeN(loop);                        
00499         }
00500         else {
00501                 group->len++;
00502                 BLI_addtail(&group->data.group, prop);
00503         }
00504 }
00505 
00506 /*returns 0 if an id property with the same name exists and it failed,
00507   or 1 if it succeeded in adding to the group.*/
00508 int IDP_AddToGroup(IDProperty *group, IDProperty *prop)
00509 {
00510         if(IDP_GetPropertyFromGroup(group, prop->name) == NULL)  {
00511                 group->len++;
00512                 BLI_addtail(&group->data.group, prop);
00513                 return 1;
00514         }
00515 
00516         return 0;
00517 }
00518 
00519 int IDP_InsertToGroup(IDProperty *group, IDProperty *previous, IDProperty *pnew)
00520 {
00521         if(IDP_GetPropertyFromGroup(group, pnew->name) == NULL)  {
00522                 group->len++;
00523                 BLI_insertlink(&group->data.group, previous, pnew);
00524                 return 1;
00525         }
00526 
00527         return 0;
00528 }
00529 
00530 void IDP_RemFromGroup(IDProperty *group, IDProperty *prop)
00531 {
00532         group->len--;
00533         BLI_remlink(&group->data.group, prop);
00534 }
00535 
00536 IDProperty *IDP_GetPropertyFromGroup(IDProperty *prop, const char *name)
00537 {
00538         return (IDProperty *)BLI_findstring(&prop->data.group, name, offsetof(IDProperty, name));
00539 }
00540 
00541 IDProperty *IDP_GetPropertyTypeFromGroup(IDProperty *prop, const char *name, const char type)
00542 {
00543         IDProperty *idprop= IDP_GetPropertyFromGroup(prop, name);
00544         return (idprop && idprop->type == type) ? idprop : NULL;
00545 }
00546 
00547 typedef struct IDPIter {
00548         void *next;
00549         IDProperty *parent;
00550 } IDPIter;
00551 
00552 void *IDP_GetGroupIterator(IDProperty *prop)
00553 {
00554         IDPIter *iter = MEM_callocN(sizeof(IDPIter), "IDPIter");
00555         iter->next = prop->data.group.first;
00556         iter->parent = prop;
00557         return (void*) iter;
00558 }
00559 
00560 IDProperty *IDP_GroupIterNext(void *vself)
00561 {
00562         IDPIter *self = (IDPIter*) vself;
00563         Link *next = (Link*) self->next;
00564         if (self->next == NULL) {
00565                 MEM_freeN(self);
00566                 return NULL;
00567         }
00568 
00569         self->next = next->next;
00570         return (void*) next;
00571 }
00572 
00573 void IDP_FreeIterBeforeEnd(void *vself)
00574 {
00575         MEM_freeN(vself);
00576 }
00577 
00578 /*Ok, the way things work, Groups free the ID Property structs of their children.
00579   This is because all ID Property freeing functions free only direct data (not the ID Property
00580   struct itself), but for Groups the child properties *are* considered
00581   direct data.*/
00582 static void IDP_FreeGroup(IDProperty *prop)
00583 {
00584         IDProperty *loop;
00585         for (loop=prop->data.group.first; loop; loop=loop->next)
00586         {
00587                 IDP_FreeProperty(loop);
00588         }
00589         BLI_freelistN(&prop->data.group);
00590 }
00591 
00592 
00593 /*-------- Main Functions --------*/
00594 IDProperty *IDP_CopyProperty(IDProperty *prop)
00595 {
00596         switch (prop->type) {
00597                 case IDP_GROUP: return IDP_CopyGroup(prop);
00598                 case IDP_STRING: return IDP_CopyString(prop);
00599                 case IDP_ARRAY: return IDP_CopyArray(prop);
00600                 case IDP_IDPARRAY: return IDP_CopyIDPArray(prop);
00601                 default: return idp_generic_copy(prop);
00602         }
00603 }
00604 
00605 IDProperty *IDP_GetProperties(ID *id, int create_if_needed)
00606 {
00607         if (id->properties) return id->properties;
00608         else {
00609                 if (create_if_needed) {
00610                         id->properties = MEM_callocN(sizeof(IDProperty), "IDProperty");
00611                         id->properties->type = IDP_GROUP;
00612                         /* dont overwite the data's name and type
00613                          * some functions might need this if they
00614                          * dont have a real ID, should be named elsewhere - Campbell */
00615                         /* strcpy(id->name, "top_level_group");*/
00616                 }
00617                 return id->properties;
00618         }
00619 }
00620 
00621 int IDP_EqualsProperties(IDProperty *prop1, IDProperty *prop2)
00622 {
00623         if(prop1 == NULL && prop2 == NULL)
00624                 return 1;
00625         else if(prop1 == NULL || prop2 == NULL)
00626                 return 0;
00627         else if(prop1->type != prop2->type)
00628                 return 0;
00629 
00630         if(prop1->type == IDP_INT)
00631                 return (IDP_Int(prop1) == IDP_Int(prop2));
00632         else if(prop1->type == IDP_FLOAT)
00633                 return (IDP_Float(prop1) == IDP_Float(prop2));
00634         else if(prop1->type == IDP_DOUBLE)
00635                 return (IDP_Double(prop1) == IDP_Double(prop2));
00636         else if(prop1->type == IDP_STRING)
00637                 return BSTR_EQ(IDP_String(prop1), IDP_String(prop2));
00638         else if(prop1->type == IDP_ARRAY) {
00639                 if(prop1->len == prop2->len && prop1->subtype == prop2->subtype)
00640                         return memcmp(IDP_Array(prop1), IDP_Array(prop2), idp_size_table[(int)prop1->subtype]*prop1->len);
00641                 else
00642                         return 0;
00643         }
00644         else if(prop1->type == IDP_GROUP) {
00645                 IDProperty *link1, *link2;
00646 
00647                 if(BLI_countlist(&prop1->data.group) != BLI_countlist(&prop2->data.group))
00648                         return 0;
00649 
00650                 for(link1=prop1->data.group.first; link1; link1=link1->next) {
00651                         link2= IDP_GetPropertyFromGroup(prop2, link1->name);
00652 
00653                         if(!IDP_EqualsProperties(link1, link2))
00654                                 return 0;
00655                 }
00656 
00657                 return 1;
00658         }
00659         else if(prop1->type == IDP_IDPARRAY) {
00660                 IDProperty *array1= IDP_IDPArray(prop1);
00661                 IDProperty *array2= IDP_IDPArray(prop2);
00662                 int i;
00663 
00664                 if(prop1->len != prop2->len)
00665                         return 0;
00666                 
00667                 for(i=0; i<prop1->len; i++)
00668                         if(!IDP_EqualsProperties(&array1[i], &array2[i]))
00669                                 return 0;
00670         }
00671         
00672         return 1;
00673 }
00674 
00675 IDProperty *IDP_New(int type, IDPropertyTemplate val, const char *name)
00676 {
00677         IDProperty *prop=NULL;
00678 
00679         switch (type) {
00680                 case IDP_INT:
00681                         prop = MEM_callocN(sizeof(IDProperty), "IDProperty int");
00682                         prop->data.val = val.i;
00683                         break;
00684                 case IDP_FLOAT:
00685                         prop = MEM_callocN(sizeof(IDProperty), "IDProperty float");
00686                         *(float*)&prop->data.val = val.f;
00687                         break;
00688                 case IDP_DOUBLE:
00689                         prop = MEM_callocN(sizeof(IDProperty), "IDProperty float");
00690                         *(double*)&prop->data.val = val.d;
00691                         break;          
00692                 case IDP_ARRAY:
00693                 {
00694                         /*for now, we only support float and int and double arrays*/
00695                         if (val.array.type == IDP_FLOAT || val.array.type == IDP_INT || val.array.type == IDP_DOUBLE || val.array.type == IDP_GROUP) {
00696                                 prop = MEM_callocN(sizeof(IDProperty), "IDProperty array");
00697                                 prop->subtype = val.array.type;
00698                                 if (val.array.len)
00699                                         prop->data.pointer = MEM_callocN(idp_size_table[val.array.type]*val.array.len, "id property array");
00700                                 prop->len = prop->totallen = val.array.len;
00701                                 break;
00702                         } else {
00703                                 return NULL;
00704                         }
00705                 }
00706                 case IDP_STRING:
00707                 {
00708                         char *st = val.str;
00709 
00710                         prop = MEM_callocN(sizeof(IDProperty), "IDProperty string");
00711                         if (st == NULL) {
00712                                 prop->data.pointer = MEM_callocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1");
00713                                 prop->totallen = DEFAULT_ALLOC_FOR_NULL_STRINGS;
00714                                 prop->len = 1; /*NULL string, has len of 1 to account for null byte.*/
00715                         } else {
00716                                 int stlen = strlen(st) + 1;
00717                                 prop->data.pointer = MEM_mallocN(stlen, "id property string 2");
00718                                 prop->len = prop->totallen = stlen;
00719                                 memcpy(prop->data.pointer, st, stlen);
00720                         }
00721                         break;
00722                 }
00723                 case IDP_GROUP:
00724                 {
00725                         prop = MEM_callocN(sizeof(IDProperty), "IDProperty group");
00726                         /* heh I think all needed values are set properly by calloc anyway :) */
00727                         break;
00728                 }
00729                 default:
00730                 {
00731                         prop = MEM_callocN(sizeof(IDProperty), "IDProperty array");
00732                         break;
00733                 }
00734         }
00735 
00736         prop->type = type;
00737         BLI_strncpy(prop->name, name, MAX_IDPROP_NAME);
00738         
00739         return prop;
00740 }
00741 
00742 /*NOTE: this will free all child properties including list arrays and groups!
00743   Also, note that this does NOT unlink anything!  Plus it doesn't free
00744   the actual IDProperty struct either.*/
00745 void IDP_FreeProperty(IDProperty *prop)
00746 {
00747         switch (prop->type) {
00748                 case IDP_ARRAY:
00749                         IDP_FreeArray(prop);
00750                         break;
00751                 case IDP_STRING:
00752                         IDP_FreeString(prop);
00753                         break;
00754                 case IDP_GROUP:
00755                         IDP_FreeGroup(prop);
00756                         break;
00757                 case IDP_IDPARRAY:
00758                         IDP_FreeIDPArray(prop);
00759                         break;
00760         }
00761 }
00762 
00763 /*Unlinks any IDProperty<->ID linkage that might be going on.
00764   note: currently unused.*/
00765 void IDP_UnlinkProperty(IDProperty *prop)
00766 {
00767         switch (prop->type) {
00768                 case IDP_ID:
00769                         IDP_UnlinkID(prop);
00770         }
00771 }