Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/idprop.c
| Show First 20 Lines • Show All 86 Lines • ▼ Show 20 Lines | IDProperty *IDP_NewIDPArray(const char *name) | ||||
| BLI_strncpy(prop->name, name, MAX_IDPROP_NAME); | BLI_strncpy(prop->name, name, MAX_IDPROP_NAME); | ||||
| return prop; | return prop; | ||||
| } | } | ||||
| IDProperty *IDP_CopyIDPArray(const IDProperty *array, const int flag) | IDProperty *IDP_CopyIDPArray(const IDProperty *array, const int flag) | ||||
| { | { | ||||
| /* don't use MEM_dupallocN because this may be part of an array */ | /* don't use MEM_dupallocN because this may be part of an array */ | ||||
| IDProperty *narray, *tmp; | |||||
| BLI_assert(array->type == IDP_IDPARRAY); | BLI_assert(array->type == IDP_IDPARRAY); | ||||
| narray = MEM_mallocN(sizeof(IDProperty), __func__); | IDProperty *narray = MEM_mallocN(sizeof(IDProperty), __func__); | ||||
| *narray = *array; | *narray = *array; | ||||
| narray->data.pointer = MEM_dupallocN(array->data.pointer); | narray->data.pointer = MEM_dupallocN(array->data.pointer); | ||||
| for (int i = 0; i < narray->len; i++) { | for (int i = 0; i < narray->len; i++) { | ||||
| /* ok, the copy functions always allocate a new structure, | /* ok, the copy functions always allocate a new structure, | ||||
| * which doesn't work here. instead, simply copy the | * which doesn't work here. instead, simply copy the | ||||
| * contents of the new structure into the array cell, | * contents of the new structure into the array cell, | ||||
| * then free it. this makes for more maintainable | * then free it. this makes for more maintainable | ||||
| * code than simply re-implementing the copy functions | * code than simply re-implementing the copy functions | ||||
| * in this loop.*/ | * in this loop.*/ | ||||
| tmp = IDP_CopyProperty_ex(GETPROP(narray, i), flag); | IDProperty *tmp = IDP_CopyProperty_ex(GETPROP(narray, i), flag); | ||||
| memcpy(GETPROP(narray, i), tmp, sizeof(IDProperty)); | memcpy(GETPROP(narray, i), tmp, sizeof(IDProperty)); | ||||
| MEM_freeN(tmp); | MEM_freeN(tmp); | ||||
| } | } | ||||
| return narray; | return narray; | ||||
| } | } | ||||
| static void IDP_FreeIDPArray(IDProperty *prop, const bool do_id_user) | static void IDP_FreeIDPArray(IDProperty *prop, const bool do_id_user) | ||||
| { | { | ||||
| BLI_assert(prop->type == IDP_IDPARRAY); | BLI_assert(prop->type == IDP_IDPARRAY); | ||||
| for (int i = 0; i < prop->len; i++) { | for (int i = 0; i < prop->len; i++) { | ||||
| IDP_FreePropertyContent_ex(GETPROP(prop, i), do_id_user); | IDP_FreePropertyContent_ex(GETPROP(prop, i), do_id_user); | ||||
| } | } | ||||
| if (prop->data.pointer) { | if (prop->data.pointer) { | ||||
| MEM_freeN(prop->data.pointer); | MEM_freeN(prop->data.pointer); | ||||
| } | } | ||||
| } | } | ||||
| /* shallow copies item */ | /* shallow copies item */ | ||||
| void IDP_SetIndexArray(IDProperty *prop, int index, IDProperty *item) | void IDP_SetIndexArray(IDProperty *prop, int index, IDProperty *item) | ||||
| { | { | ||||
| IDProperty *old; | |||||
| BLI_assert(prop->type == IDP_IDPARRAY); | BLI_assert(prop->type == IDP_IDPARRAY); | ||||
| if (index >= prop->len || index < 0) { | if (index >= prop->len || index < 0) { | ||||
| return; | return; | ||||
| } | } | ||||
| old = GETPROP(prop, index); | IDProperty *old = GETPROP(prop, index); | ||||
| if (item != old) { | if (item != old) { | ||||
| IDP_FreePropertyContent(old); | IDP_FreePropertyContent(old); | ||||
| memcpy(old, item, sizeof(IDProperty)); | memcpy(old, item, sizeof(IDProperty)); | ||||
| } | } | ||||
| } | } | ||||
| IDProperty *IDP_GetIndexArray(IDProperty *prop, int index) | IDProperty *IDP_GetIndexArray(IDProperty *prop, int index) | ||||
| { | { | ||||
| BLI_assert(prop->type == IDP_IDPARRAY); | BLI_assert(prop->type == IDP_IDPARRAY); | ||||
| return GETPROP(prop, index); | return GETPROP(prop, index); | ||||
| } | } | ||||
| void IDP_AppendArray(IDProperty *prop, IDProperty *item) | void IDP_AppendArray(IDProperty *prop, IDProperty *item) | ||||
| { | { | ||||
| BLI_assert(prop->type == IDP_IDPARRAY); | BLI_assert(prop->type == IDP_IDPARRAY); | ||||
| IDP_ResizeIDPArray(prop, prop->len + 1); | IDP_ResizeIDPArray(prop, prop->len + 1); | ||||
| IDP_SetIndexArray(prop, prop->len - 1, item); | IDP_SetIndexArray(prop, prop->len - 1, item); | ||||
| } | } | ||||
| void IDP_ResizeIDPArray(IDProperty *prop, int newlen) | void IDP_ResizeIDPArray(IDProperty *prop, int newlen) | ||||
| { | { | ||||
| int newsize; | |||||
| BLI_assert(prop->type == IDP_IDPARRAY); | BLI_assert(prop->type == IDP_IDPARRAY); | ||||
| /* first check if the array buffer size has room */ | /* first check if the array buffer size has room */ | ||||
| if (newlen <= prop->totallen) { | if (newlen <= prop->totallen) { | ||||
| if (newlen < prop->len && prop->totallen - newlen < IDP_ARRAY_REALLOC_LIMIT) { | if (newlen < prop->len && prop->totallen - newlen < IDP_ARRAY_REALLOC_LIMIT) { | ||||
| for (int i = newlen; i < prop->len; i++) { | for (int i = newlen; i < prop->len; i++) { | ||||
| IDP_FreePropertyContent(GETPROP(prop, i)); | IDP_FreePropertyContent(GETPROP(prop, i)); | ||||
| } | } | ||||
| Show All 18 Lines | void IDP_ResizeIDPArray(IDProperty *prop, int newlen) | ||||
| /* - Note: This code comes from python, here's the corresponding comment. - */ | /* - Note: This code comes from python, here's the corresponding comment. - */ | ||||
| /* This over-allocates proportional to the list size, making room | /* This over-allocates proportional to the list size, making room | ||||
| * for additional growth. The over-allocation is mild, but is | * for additional growth. The over-allocation is mild, but is | ||||
| * enough to give linear-time amortized behavior over a long | * enough to give linear-time amortized behavior over a long | ||||
| * sequence of appends() in the presence of a poorly-performing | * sequence of appends() in the presence of a poorly-performing | ||||
| * system realloc(). | * system realloc(). | ||||
| * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ... | * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ... | ||||
| */ | */ | ||||
| newsize = newlen; | int newsize = newlen; | ||||
| newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize; | newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize; | ||||
| prop->data.pointer = MEM_recallocN(prop->data.pointer, sizeof(IDProperty) * (size_t)newsize); | prop->data.pointer = MEM_recallocN(prop->data.pointer, sizeof(IDProperty) * (size_t)newsize); | ||||
| prop->len = newlen; | prop->len = newlen; | ||||
| prop->totallen = newsize; | prop->totallen = newsize; | ||||
| } | } | ||||
| /* ----------- Numerical Array Type ----------- */ | /* ----------- Numerical Array Type ----------- */ | ||||
| static void idp_resize_group_array(IDProperty *prop, int newlen, void *newarr) | static void idp_resize_group_array(IDProperty *prop, int newlen, void *newarr) | ||||
| { | { | ||||
| if (prop->subtype != IDP_GROUP) { | if (prop->subtype != IDP_GROUP) { | ||||
| return; | return; | ||||
| } | } | ||||
| if (newlen >= prop->len) { | if (newlen >= prop->len) { | ||||
| /* bigger */ | /* bigger */ | ||||
| IDProperty **array = newarr; | IDProperty **array = newarr; | ||||
| IDPropertyTemplate val; | IDPropertyTemplate val; | ||||
| int a; | |||||
| for (a = prop->len; a < newlen; a++) { | for (int a = prop->len; a < newlen; a++) { | ||||
| val.i = 0; /* silence MSVC warning about uninitialized var when debugging */ | val.i = 0; /* silence MSVC warning about uninitialized var when debugging */ | ||||
| array[a] = IDP_New(IDP_GROUP, &val, "IDP_ResizeArray group"); | array[a] = IDP_New(IDP_GROUP, &val, "IDP_ResizeArray group"); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| /* smaller */ | /* smaller */ | ||||
| IDProperty **array = prop->data.pointer; | IDProperty **array = prop->data.pointer; | ||||
| int a; | |||||
| for (a = newlen; a < prop->len; a++) { | for (int a = newlen; a < prop->len; a++) { | ||||
| IDP_FreeProperty(array[a]); | IDP_FreeProperty(array[a]); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /*this function works for strings too!*/ | /*this function works for strings too!*/ | ||||
| void IDP_ResizeArray(IDProperty *prop, int newlen) | void IDP_ResizeArray(IDProperty *prop, int newlen) | ||||
| { | { | ||||
| int newsize; | |||||
| const bool is_grow = newlen >= prop->len; | const bool is_grow = newlen >= prop->len; | ||||
| /* first check if the array buffer size has room */ | /* first check if the array buffer size has room */ | ||||
| if (newlen <= prop->totallen && prop->totallen - newlen < IDP_ARRAY_REALLOC_LIMIT) { | if (newlen <= prop->totallen && prop->totallen - newlen < IDP_ARRAY_REALLOC_LIMIT) { | ||||
| idp_resize_group_array(prop, newlen, prop->data.pointer); | idp_resize_group_array(prop, newlen, prop->data.pointer); | ||||
| prop->len = newlen; | prop->len = newlen; | ||||
| return; | return; | ||||
| } | } | ||||
| /* - Note: This code comes from python, here's the corresponding comment. - */ | /* - Note: This code comes from python, here's the corresponding comment. - */ | ||||
| /* This over-allocates proportional to the list size, making room | /* This over-allocates proportional to the list size, making room | ||||
| * for additional growth. The over-allocation is mild, but is | * for additional growth. The over-allocation is mild, but is | ||||
| * enough to give linear-time amortized behavior over a long | * enough to give linear-time amortized behavior over a long | ||||
| * sequence of appends() in the presence of a poorly-performing | * sequence of appends() in the presence of a poorly-performing | ||||
| * system realloc(). | * system realloc(). | ||||
| * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ... | * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ... | ||||
| */ | */ | ||||
| newsize = newlen; | int newsize = newlen; | ||||
| newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize; | newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize; | ||||
| if (is_grow == false) { | if (is_grow == false) { | ||||
| idp_resize_group_array(prop, newlen, prop->data.pointer); | idp_resize_group_array(prop, newlen, prop->data.pointer); | ||||
| } | } | ||||
| prop->data.pointer = MEM_recallocN(prop->data.pointer, | prop->data.pointer = MEM_recallocN(prop->data.pointer, | ||||
| idp_size_table[(int)prop->subtype] * (size_t)newsize); | idp_size_table[(int)prop->subtype] * (size_t)newsize); | ||||
| ▲ Show 20 Lines • Show All 88 Lines • ▼ Show 20 Lines | IDProperty *IDP_NewString(const char *st, const char *name, int maxlen) | ||||
| prop->type = IDP_STRING; | prop->type = IDP_STRING; | ||||
| BLI_strncpy(prop->name, name, MAX_IDPROP_NAME); | BLI_strncpy(prop->name, name, MAX_IDPROP_NAME); | ||||
| return prop; | return prop; | ||||
| } | } | ||||
| static IDProperty *IDP_CopyString(const IDProperty *prop, const int flag) | static IDProperty *IDP_CopyString(const IDProperty *prop, const int flag) | ||||
| { | { | ||||
| IDProperty *newp; | |||||
| BLI_assert(prop->type == IDP_STRING); | BLI_assert(prop->type == IDP_STRING); | ||||
| newp = idp_generic_copy(prop, flag); | IDProperty *newp = idp_generic_copy(prop, flag); | ||||
| if (prop->data.pointer) { | if (prop->data.pointer) { | ||||
| newp->data.pointer = MEM_dupallocN(prop->data.pointer); | newp->data.pointer = MEM_dupallocN(prop->data.pointer); | ||||
| } | } | ||||
| newp->len = prop->len; | newp->len = prop->len; | ||||
| newp->subtype = prop->subtype; | newp->subtype = prop->subtype; | ||||
| newp->totallen = prop->totallen; | newp->totallen = prop->totallen; | ||||
| return newp; | return newp; | ||||
| } | } | ||||
| void IDP_AssignString(IDProperty *prop, const char *st, int maxlen) | void IDP_AssignString(IDProperty *prop, const char *st, int maxlen) | ||||
| { | { | ||||
| int stlen; | |||||
| BLI_assert(prop->type == IDP_STRING); | BLI_assert(prop->type == IDP_STRING); | ||||
| stlen = (int)strlen(st); | int stlen = (int)strlen(st); | ||||
| if (maxlen > 0 && maxlen < stlen) { | if (maxlen > 0 && maxlen < stlen) { | ||||
| stlen = maxlen; | stlen = maxlen; | ||||
| } | } | ||||
| if (prop->subtype == IDP_STRING_SUB_BYTE) { | if (prop->subtype == IDP_STRING_SUB_BYTE) { | ||||
| IDP_ResizeArray(prop, stlen); | IDP_ResizeArray(prop, stlen); | ||||
| memcpy(prop->data.pointer, st, (size_t)stlen); | memcpy(prop->data.pointer, st, (size_t)stlen); | ||||
| } | } | ||||
| else { | else { | ||||
| stlen++; | stlen++; | ||||
| IDP_ResizeArray(prop, stlen); | IDP_ResizeArray(prop, stlen); | ||||
| BLI_strncpy(prop->data.pointer, st, (size_t)stlen); | BLI_strncpy(prop->data.pointer, st, (size_t)stlen); | ||||
| } | } | ||||
| } | } | ||||
| void IDP_ConcatStringC(IDProperty *prop, const char *st) | void IDP_ConcatStringC(IDProperty *prop, const char *st) | ||||
| { | { | ||||
| int newlen; | |||||
| BLI_assert(prop->type == IDP_STRING); | BLI_assert(prop->type == IDP_STRING); | ||||
| newlen = prop->len + (int)strlen(st); | int newlen = prop->len + (int)strlen(st); | ||||
| /* we have to remember that prop->len includes the null byte for strings. | /* we have to remember that prop->len includes the null byte for strings. | ||||
| * so there's no need to add +1 to the resize function.*/ | * so there's no need to add +1 to the resize function.*/ | ||||
| IDP_ResizeArray(prop, newlen); | IDP_ResizeArray(prop, newlen); | ||||
| strcat(prop->data.pointer, st); | strcat(prop->data.pointer, st); | ||||
| } | } | ||||
| void IDP_ConcatString(IDProperty *str1, IDProperty *append) | void IDP_ConcatString(IDProperty *str1, IDProperty *append) | ||||
| { | { | ||||
| int newlen; | |||||
| BLI_assert(append->type == IDP_STRING); | BLI_assert(append->type == IDP_STRING); | ||||
| /* since ->len for strings includes the NULL byte, we have to subtract one or | /* since ->len for strings includes the NULL byte, we have to subtract one or | ||||
| * we'll get an extra null byte after each concatenation operation.*/ | * we'll get an extra null byte after each concatenation operation.*/ | ||||
| newlen = str1->len + append->len - 1; | int newlen = str1->len + append->len - 1; | ||||
| IDP_ResizeArray(str1, newlen); | IDP_ResizeArray(str1, newlen); | ||||
| strcat(str1->data.pointer, append->data.pointer); | strcat(str1->data.pointer, append->data.pointer); | ||||
| } | } | ||||
| void IDP_FreeString(IDProperty *prop) | void IDP_FreeString(IDProperty *prop) | ||||
| { | { | ||||
| BLI_assert(prop->type == IDP_STRING); | BLI_assert(prop->type == IDP_STRING); | ||||
| if (prop->data.pointer) { | if (prop->data.pointer) { | ||||
| MEM_freeN(prop->data.pointer); | MEM_freeN(prop->data.pointer); | ||||
| } | } | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name ID Type (IDProperty ID API) | /** \name ID Type (IDProperty ID API) | ||||
| * \{ */ | * \{ */ | ||||
| static IDProperty *IDP_CopyID(const IDProperty *prop, const int flag) | static IDProperty *IDP_CopyID(const IDProperty *prop, const int flag) | ||||
| { | { | ||||
| IDProperty *newp; | |||||
| BLI_assert(prop->type == IDP_ID); | BLI_assert(prop->type == IDP_ID); | ||||
| newp = idp_generic_copy(prop, flag); | IDProperty *newp = idp_generic_copy(prop, flag); | ||||
| newp->data.pointer = prop->data.pointer; | newp->data.pointer = prop->data.pointer; | ||||
| if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { | if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { | ||||
| id_us_plus(IDP_Id(newp)); | id_us_plus(IDP_Id(newp)); | ||||
| } | } | ||||
| return newp; | return newp; | ||||
| } | } | ||||
| Show All 19 Lines | |||||
| /** \name Group Functions (IDProperty Group API) | /** \name Group Functions (IDProperty Group API) | ||||
| * \{ */ | * \{ */ | ||||
| /** | /** | ||||
| * Checks if a property with the same name as prop exists, and if so replaces it. | * Checks if a property with the same name as prop exists, and if so replaces it. | ||||
| */ | */ | ||||
| static IDProperty *IDP_CopyGroup(const IDProperty *prop, const int flag) | static IDProperty *IDP_CopyGroup(const IDProperty *prop, const int flag) | ||||
| { | { | ||||
| IDProperty *newp, *link; | |||||
| BLI_assert(prop->type == IDP_GROUP); | BLI_assert(prop->type == IDP_GROUP); | ||||
| newp = idp_generic_copy(prop, flag); | IDProperty *newp = idp_generic_copy(prop, flag); | ||||
| newp->len = prop->len; | newp->len = prop->len; | ||||
| newp->subtype = prop->subtype; | newp->subtype = prop->subtype; | ||||
| for (link = prop->data.group.first; link; link = link->next) { | LISTBASE_FOREACH (IDProperty *, link, &prop->data.group) { | ||||
| BLI_addtail(&newp->data.group, IDP_CopyProperty_ex(link, flag)); | BLI_addtail(&newp->data.group, IDP_CopyProperty_ex(link, flag)); | ||||
| } | } | ||||
| return newp; | return newp; | ||||
| } | } | ||||
| /* use for syncing proxies. | /* use for syncing proxies. | ||||
| * When values name and types match, copy the values, else ignore */ | * When values name and types match, copy the values, else ignore */ | ||||
| void IDP_SyncGroupValues(IDProperty *dest, const IDProperty *src) | void IDP_SyncGroupValues(IDProperty *dest, const IDProperty *src) | ||||
| { | { | ||||
| IDProperty *other, *prop; | |||||
| BLI_assert(dest->type == IDP_GROUP); | BLI_assert(dest->type == IDP_GROUP); | ||||
| BLI_assert(src->type == IDP_GROUP); | BLI_assert(src->type == IDP_GROUP); | ||||
| for (prop = src->data.group.first; prop; prop = prop->next) { | LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) { | ||||
| other = BLI_findstring(&dest->data.group, prop->name, offsetof(IDProperty, name)); | IDProperty *other = BLI_findstring(&dest->data.group, prop->name, offsetof(IDProperty, name)); | ||||
| if (other && prop->type == other->type) { | if (other && prop->type == other->type) { | ||||
| switch (prop->type) { | switch (prop->type) { | ||||
| case IDP_INT: | case IDP_INT: | ||||
| case IDP_FLOAT: | case IDP_FLOAT: | ||||
| case IDP_DOUBLE: | case IDP_DOUBLE: | ||||
| other->data = prop->data; | other->data = prop->data; | ||||
| break; | break; | ||||
| case IDP_GROUP: | case IDP_GROUP: | ||||
| IDP_SyncGroupValues(other, prop); | IDP_SyncGroupValues(other, prop); | ||||
| break; | break; | ||||
| default: { | default: { | ||||
| BLI_insertlinkreplace(&dest->data.group, other, IDP_CopyProperty(prop)); | BLI_insertlinkreplace(&dest->data.group, other, IDP_CopyProperty(prop)); | ||||
| IDP_FreeProperty(other); | IDP_FreeProperty(other); | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void IDP_SyncGroupTypes(IDProperty *dest, const IDProperty *src, const bool do_arraylen) | void IDP_SyncGroupTypes(IDProperty *dest, const IDProperty *src, const bool do_arraylen) | ||||
| { | { | ||||
| IDProperty *prop_dst, *prop_dst_next; | LISTBASE_FOREACH_MUTABLE (IDProperty *, prop_dst, &src->data.group) { | ||||
| const IDProperty *prop_src; | const IDProperty *prop_src = IDP_GetPropertyFromGroup((IDProperty *)src, prop_dst->name); | ||||
| if (prop_src != NULL) { | |||||
| for (prop_dst = dest->data.group.first; prop_dst; prop_dst = prop_dst_next) { | |||||
| prop_dst_next = prop_dst->next; | |||||
| if ((prop_src = IDP_GetPropertyFromGroup((IDProperty *)src, prop_dst->name))) { | |||||
| /* check of we should replace? */ | /* check of we should replace? */ | ||||
| if ((prop_dst->type != prop_src->type || prop_dst->subtype != prop_src->subtype) || | if ((prop_dst->type != prop_src->type || prop_dst->subtype != prop_src->subtype) || | ||||
| (do_arraylen && ELEM(prop_dst->type, IDP_ARRAY, IDP_IDPARRAY) && | (do_arraylen && ELEM(prop_dst->type, IDP_ARRAY, IDP_IDPARRAY) && | ||||
| (prop_src->len != prop_dst->len))) { | (prop_src->len != prop_dst->len))) { | ||||
| BLI_insertlinkreplace(&dest->data.group, prop_dst, IDP_CopyProperty(prop_src)); | BLI_insertlinkreplace(&dest->data.group, prop_dst, IDP_CopyProperty(prop_src)); | ||||
| IDP_FreeProperty(prop_dst); | IDP_FreeProperty(prop_dst); | ||||
| } | } | ||||
| else if (prop_dst->type == IDP_GROUP) { | else if (prop_dst->type == IDP_GROUP) { | ||||
| IDP_SyncGroupTypes(prop_dst, prop_src, do_arraylen); | IDP_SyncGroupTypes(prop_dst, prop_src, do_arraylen); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| IDP_FreeFromGroup(dest, prop_dst); | IDP_FreeFromGroup(dest, prop_dst); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * Replaces all properties with the same name in a destination group from a source group. | * Replaces all properties with the same name in a destination group from a source group. | ||||
| */ | */ | ||||
| void IDP_ReplaceGroupInGroup(IDProperty *dest, const IDProperty *src) | void IDP_ReplaceGroupInGroup(IDProperty *dest, const IDProperty *src) | ||||
| { | { | ||||
| IDProperty *loop, *prop; | |||||
| BLI_assert(dest->type == IDP_GROUP); | BLI_assert(dest->type == IDP_GROUP); | ||||
| BLI_assert(src->type == IDP_GROUP); | BLI_assert(src->type == IDP_GROUP); | ||||
| for (prop = src->data.group.first; prop; prop = prop->next) { | LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) { | ||||
| IDProperty *loop; | |||||
| for (loop = dest->data.group.first; loop; loop = loop->next) { | for (loop = dest->data.group.first; loop; loop = loop->next) { | ||||
| if (STREQ(loop->name, prop->name)) { | if (STREQ(loop->name, prop->name)) { | ||||
| BLI_insertlinkreplace(&dest->data.group, loop, IDP_CopyProperty(prop)); | BLI_insertlinkreplace(&dest->data.group, loop, IDP_CopyProperty(prop)); | ||||
| IDP_FreeProperty(loop); | IDP_FreeProperty(loop); | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| Show All 36 Lines | |||||
| * If a property is missing in \a dest, add it. | * If a property is missing in \a dest, add it. | ||||
| * Do it recursively. | * Do it recursively. | ||||
| */ | */ | ||||
| void IDP_MergeGroup_ex(IDProperty *dest, | void IDP_MergeGroup_ex(IDProperty *dest, | ||||
| const IDProperty *src, | const IDProperty *src, | ||||
| const bool do_overwrite, | const bool do_overwrite, | ||||
| const int flag) | const int flag) | ||||
| { | { | ||||
| IDProperty *prop; | |||||
| BLI_assert(dest->type == IDP_GROUP); | BLI_assert(dest->type == IDP_GROUP); | ||||
| BLI_assert(src->type == IDP_GROUP); | BLI_assert(src->type == IDP_GROUP); | ||||
| if (do_overwrite) { | if (do_overwrite) { | ||||
| for (prop = src->data.group.first; prop; prop = prop->next) { | LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) { | ||||
| if (prop->type == IDP_GROUP) { | if (prop->type == IDP_GROUP) { | ||||
| IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name); | IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name); | ||||
| if (prop_exist != NULL) { | if (prop_exist != NULL) { | ||||
| IDP_MergeGroup_ex(prop_exist, prop, do_overwrite, flag); | IDP_MergeGroup_ex(prop_exist, prop, do_overwrite, flag); | ||||
| continue; | continue; | ||||
| } | } | ||||
| } | } | ||||
| IDProperty *copy = IDP_CopyProperty_ex(prop, flag); | IDProperty *copy = IDP_CopyProperty_ex(prop, flag); | ||||
| IDP_ReplaceInGroup(dest, copy); | IDP_ReplaceInGroup(dest, copy); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| for (prop = src->data.group.first; prop; prop = prop->next) { | LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) { | ||||
| IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name); | IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name); | ||||
| if (prop_exist != NULL) { | if (prop_exist != NULL) { | ||||
| if (prop->type == IDP_GROUP) { | if (prop->type == IDP_GROUP) { | ||||
| IDP_MergeGroup_ex(prop_exist, prop, do_overwrite, flag); | IDP_MergeGroup_ex(prop_exist, prop, do_overwrite, flag); | ||||
| continue; | continue; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| ▲ Show 20 Lines • Show All 91 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| /* Ok, the way things work, Groups free the ID Property structs of their children. | /* Ok, the way things work, Groups free the ID Property structs of their children. | ||||
| * This is because all ID Property freeing functions free only direct data (not the ID Property | * This is because all ID Property freeing functions free only direct data (not the ID Property | ||||
| * struct itself), but for Groups the child properties *are* considered | * struct itself), but for Groups the child properties *are* considered | ||||
| * direct data. */ | * direct data. */ | ||||
| static void IDP_FreeGroup(IDProperty *prop, const bool do_id_user) | static void IDP_FreeGroup(IDProperty *prop, const bool do_id_user) | ||||
| { | { | ||||
| IDProperty *loop; | |||||
| BLI_assert(prop->type == IDP_GROUP); | BLI_assert(prop->type == IDP_GROUP); | ||||
| for (loop = prop->data.group.first; loop; loop = loop->next) { | |||||
| LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) { | |||||
| IDP_FreePropertyContent_ex(loop, do_id_user); | IDP_FreePropertyContent_ex(loop, do_id_user); | ||||
| } | } | ||||
| BLI_freelistN(&prop->data.group); | BLI_freelistN(&prop->data.group); | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Main Functions (IDProperty Main API) | /** \name Main Functions (IDProperty Main API) | ||||
| ▲ Show 20 Lines • Show All 102 Lines • ▼ Show 20 Lines | #endif | ||||
| case IDP_ARRAY: | case IDP_ARRAY: | ||||
| if (prop1->len == prop2->len && prop1->subtype == prop2->subtype) { | if (prop1->len == prop2->len && prop1->subtype == prop2->subtype) { | ||||
| return (memcmp(IDP_Array(prop1), | return (memcmp(IDP_Array(prop1), | ||||
| IDP_Array(prop2), | IDP_Array(prop2), | ||||
| idp_size_table[(int)prop1->subtype] * (size_t)prop1->len) == 0); | idp_size_table[(int)prop1->subtype] * (size_t)prop1->len) == 0); | ||||
| } | } | ||||
| return false; | return false; | ||||
| case IDP_GROUP: { | case IDP_GROUP: { | ||||
| IDProperty *link1, *link2; | |||||
| if (is_strict && prop1->len != prop2->len) { | if (is_strict && prop1->len != prop2->len) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| for (link1 = prop1->data.group.first; link1; link1 = link1->next) { | LISTBASE_FOREACH (IDProperty *, link1, &prop1->data.group) { | ||||
| link2 = IDP_GetPropertyFromGroup(prop2, link1->name); | IDProperty *link2 = IDP_GetPropertyFromGroup(prop2, link1->name); | ||||
| if (!IDP_EqualsProperties_ex(link1, link2, is_strict)) { | if (!IDP_EqualsProperties_ex(link1, link2, is_strict)) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 271 Lines • ▼ Show 20 Lines | static void IDP_WriteArray(const IDProperty *prop, BlendWriter *writer) | ||||
| } | } | ||||
| } | } | ||||
| static void IDP_WriteIDPArray(const IDProperty *prop, BlendWriter *writer) | static void IDP_WriteIDPArray(const IDProperty *prop, BlendWriter *writer) | ||||
| { | { | ||||
| /*REMEMBER to set totalen to len in the linking code!!*/ | /*REMEMBER to set totalen to len in the linking code!!*/ | ||||
| if (prop->data.pointer) { | if (prop->data.pointer) { | ||||
| const IDProperty *array = prop->data.pointer; | const IDProperty *array = prop->data.pointer; | ||||
| int a; | |||||
| BLO_write_struct_array(writer, IDProperty, prop->len, array); | BLO_write_struct_array(writer, IDProperty, prop->len, array); | ||||
| for (a = 0; a < prop->len; a++) { | for (int a = 0; a < prop->len; a++) { | ||||
| IDP_WriteProperty_OnlyData(&array[a], writer); | IDP_WriteProperty_OnlyData(&array[a], writer); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| static void IDP_WriteString(const IDProperty *prop, BlendWriter *writer) | static void IDP_WriteString(const IDProperty *prop, BlendWriter *writer) | ||||
| { | { | ||||
| /*REMEMBER to set totalen to len in the linking code!!*/ | /*REMEMBER to set totalen to len in the linking code!!*/ | ||||
| BLO_write_raw(writer, (size_t)prop->len, prop->data.pointer); | BLO_write_raw(writer, (size_t)prop->len, prop->data.pointer); | ||||
| } | } | ||||
| static void IDP_WriteGroup(const IDProperty *prop, BlendWriter *writer) | static void IDP_WriteGroup(const IDProperty *prop, BlendWriter *writer) | ||||
| { | { | ||||
| IDProperty *loop; | LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) { | ||||
| for (loop = prop->data.group.first; loop; loop = loop->next) { | |||||
| IDP_BlendWrite(writer, loop); | IDP_BlendWrite(writer, loop); | ||||
| } | } | ||||
| } | } | ||||
| /* Functions to read/write ID Properties */ | /* Functions to read/write ID Properties */ | ||||
| void IDP_WriteProperty_OnlyData(const IDProperty *prop, BlendWriter *writer) | void IDP_WriteProperty_OnlyData(const IDProperty *prop, BlendWriter *writer) | ||||
| { | { | ||||
| switch (prop->type) { | switch (prop->type) { | ||||
| Show All 17 Lines | void IDP_BlendWrite(BlendWriter *writer, const IDProperty *prop) | ||||
| BLO_write_struct(writer, IDProperty, prop); | BLO_write_struct(writer, IDProperty, prop); | ||||
| IDP_WriteProperty_OnlyData(prop, writer); | IDP_WriteProperty_OnlyData(prop, writer); | ||||
| } | } | ||||
| static void IDP_DirectLinkProperty(IDProperty *prop, BlendDataReader *reader); | static void IDP_DirectLinkProperty(IDProperty *prop, BlendDataReader *reader); | ||||
| static void IDP_DirectLinkIDPArray(IDProperty *prop, BlendDataReader *reader) | static void IDP_DirectLinkIDPArray(IDProperty *prop, BlendDataReader *reader) | ||||
| { | { | ||||
| IDProperty *array; | |||||
| /* since we didn't save the extra buffer, set totallen to len */ | /* since we didn't save the extra buffer, set totallen to len */ | ||||
| prop->totallen = prop->len; | prop->totallen = prop->len; | ||||
| BLO_read_data_address(reader, &prop->data.pointer); | BLO_read_data_address(reader, &prop->data.pointer); | ||||
| array = (IDProperty *)prop->data.pointer; | IDProperty *array = (IDProperty *)prop->data.pointer; | ||||
| /* note!, idp-arrays didn't exist in 2.4x, so the pointer will be cleared | /* note!, idp-arrays didn't exist in 2.4x, so the pointer will be cleared | ||||
| * there's not really anything we can do to correct this, at least don't crash */ | * there's not really anything we can do to correct this, at least don't crash */ | ||||
| if (array == NULL) { | if (array == NULL) { | ||||
| prop->len = 0; | prop->len = 0; | ||||
| prop->totallen = 0; | prop->totallen = 0; | ||||
| } | } | ||||
| for (int i = 0; i < prop->len; i++) { | for (int i = 0; i < prop->len; i++) { | ||||
| IDP_DirectLinkProperty(&array[i], reader); | IDP_DirectLinkProperty(&array[i], reader); | ||||
| } | } | ||||
| } | } | ||||
| static void IDP_DirectLinkArray(IDProperty *prop, BlendDataReader *reader) | static void IDP_DirectLinkArray(IDProperty *prop, BlendDataReader *reader) | ||||
| { | { | ||||
| IDProperty **array; | |||||
| /* since we didn't save the extra buffer, set totallen to len */ | /* since we didn't save the extra buffer, set totallen to len */ | ||||
| prop->totallen = prop->len; | prop->totallen = prop->len; | ||||
| if (prop->subtype == IDP_GROUP) { | if (prop->subtype == IDP_GROUP) { | ||||
| BLO_read_pointer_array(reader, &prop->data.pointer); | BLO_read_pointer_array(reader, &prop->data.pointer); | ||||
| array = prop->data.pointer; | IDProperty **array = prop->data.pointer; | ||||
| for (int i = 0; i < prop->len; i++) { | for (int i = 0; i < prop->len; i++) { | ||||
| IDP_DirectLinkProperty(array[i], reader); | IDP_DirectLinkProperty(array[i], reader); | ||||
| } | } | ||||
| } | } | ||||
| else if (prop->subtype == IDP_DOUBLE) { | else if (prop->subtype == IDP_DOUBLE) { | ||||
| BLO_read_double_array(reader, prop->len, (double **)&prop->data.pointer); | BLO_read_double_array(reader, prop->len, (double **)&prop->data.pointer); | ||||
| } | } | ||||
| else { | else { | ||||
| /* also used for floats */ | /* also used for floats */ | ||||
| BLO_read_int32_array(reader, prop->len, (int **)&prop->data.pointer); | BLO_read_int32_array(reader, prop->len, (int **)&prop->data.pointer); | ||||
| } | } | ||||
| } | } | ||||
| static void IDP_DirectLinkString(IDProperty *prop, BlendDataReader *reader) | static void IDP_DirectLinkString(IDProperty *prop, BlendDataReader *reader) | ||||
| { | { | ||||
| /*since we didn't save the extra string buffer, set totallen to len.*/ | /*since we didn't save the extra string buffer, set totallen to len.*/ | ||||
| prop->totallen = prop->len; | prop->totallen = prop->len; | ||||
| BLO_read_data_address(reader, &prop->data.pointer); | BLO_read_data_address(reader, &prop->data.pointer); | ||||
| } | } | ||||
| static void IDP_DirectLinkGroup(IDProperty *prop, BlendDataReader *reader) | static void IDP_DirectLinkGroup(IDProperty *prop, BlendDataReader *reader) | ||||
| { | { | ||||
| ListBase *lb = &prop->data.group; | ListBase *lb = &prop->data.group; | ||||
| IDProperty *loop; | |||||
| BLO_read_list(reader, lb); | BLO_read_list(reader, lb); | ||||
| /*Link child id properties now*/ | /*Link child id properties now*/ | ||||
| for (loop = prop->data.group.first; loop; loop = loop->next) { | LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) { | ||||
| IDP_DirectLinkProperty(loop, reader); | IDP_DirectLinkProperty(loop, reader); | ||||
| } | } | ||||
| } | } | ||||
| static void IDP_DirectLinkProperty(IDProperty *prop, BlendDataReader *reader) | static void IDP_DirectLinkProperty(IDProperty *prop, BlendDataReader *reader) | ||||
| { | { | ||||
| switch (prop->type) { | switch (prop->type) { | ||||
| case IDP_GROUP: | case IDP_GROUP: | ||||
| ▲ Show 20 Lines • Show All 119 Lines • Show Last 20 Lines | |||||