Blender V2.61 - r43446

idprop.c

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