|
Blender
V2.59
|
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 }