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