Blender  V2.93
idprop.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19 
24 #include <stddef.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #include "BLI_endian_switch.h"
30 #include "BLI_listbase.h"
31 #include "BLI_math.h"
32 #include "BLI_string.h"
33 #include "BLI_utildefines.h"
34 
35 #include "BKE_global.h"
36 #include "BKE_idprop.h"
37 #include "BKE_lib_id.h"
38 
39 #include "CLG_log.h"
40 
41 #include "MEM_guardedalloc.h"
42 
43 #include "BLO_read_write.h"
44 
45 #include "BLI_strict_flags.h"
46 
47 /* IDPropertyTemplate is a union in DNA_ID.h */
48 
53 #define IDP_ARRAY_REALLOC_LIMIT 200
54 
55 static CLG_LogRef LOG = {"bke.idprop"};
56 
57 /*local size table.*/
58 static size_t idp_size_table[] = {
59  1, /*strings*/
60  sizeof(int),
61  sizeof(float),
62  sizeof(float[3]), /*Vector type, deprecated*/
63  sizeof(float[16]), /*Matrix type, deprecated*/
64  0, /*arrays don't have a fixed size*/
65  sizeof(ListBase), /*Group type*/
66  sizeof(void *),
67  sizeof(double),
68 };
69 
70 /* -------------------------------------------------------------------- */
74 #define GETPROP(prop, i) &(IDP_IDPArray(prop)[i])
75 
76 /* --------- property array type -------------*/
77 
82 IDProperty *IDP_NewIDPArray(const char *name)
83 {
84  IDProperty *prop = MEM_callocN(sizeof(IDProperty), "IDProperty prop array");
85  prop->type = IDP_IDPARRAY;
86  prop->len = 0;
87  BLI_strncpy(prop->name, name, MAX_IDPROP_NAME);
88 
89  return prop;
90 }
91 
92 IDProperty *IDP_CopyIDPArray(const IDProperty *array, const int flag)
93 {
94  /* don't use MEM_dupallocN because this may be part of an array */
95  BLI_assert(array->type == IDP_IDPARRAY);
96 
97  IDProperty *narray = MEM_mallocN(sizeof(IDProperty), __func__);
98  *narray = *array;
99 
100  narray->data.pointer = MEM_dupallocN(array->data.pointer);
101  for (int i = 0; i < narray->len; i++) {
102  /* ok, the copy functions always allocate a new structure,
103  * which doesn't work here. instead, simply copy the
104  * contents of the new structure into the array cell,
105  * then free it. this makes for more maintainable
106  * code than simply re-implementing the copy functions
107  * in this loop.*/
108  IDProperty *tmp = IDP_CopyProperty_ex(GETPROP(narray, i), flag);
109  memcpy(GETPROP(narray, i), tmp, sizeof(IDProperty));
110  MEM_freeN(tmp);
111  }
112 
113  return narray;
114 }
115 
116 static void IDP_FreeIDPArray(IDProperty *prop, const bool do_id_user)
117 {
118  BLI_assert(prop->type == IDP_IDPARRAY);
119 
120  for (int i = 0; i < prop->len; i++) {
121  IDP_FreePropertyContent_ex(GETPROP(prop, i), do_id_user);
122  }
123 
124  if (prop->data.pointer) {
125  MEM_freeN(prop->data.pointer);
126  }
127 }
128 
129 /* shallow copies item */
130 void IDP_SetIndexArray(IDProperty *prop, int index, IDProperty *item)
131 {
132  BLI_assert(prop->type == IDP_IDPARRAY);
133 
134  if (index >= prop->len || index < 0) {
135  return;
136  }
137 
138  IDProperty *old = GETPROP(prop, index);
139  if (item != old) {
141 
142  memcpy(old, item, sizeof(IDProperty));
143  }
144 }
145 
147 {
148  BLI_assert(prop->type == IDP_IDPARRAY);
149 
150  return GETPROP(prop, index);
151 }
152 
154 {
155  BLI_assert(prop->type == IDP_IDPARRAY);
156 
157  IDP_ResizeIDPArray(prop, prop->len + 1);
158  IDP_SetIndexArray(prop, prop->len - 1, item);
159 }
160 
161 void IDP_ResizeIDPArray(IDProperty *prop, int newlen)
162 {
163  BLI_assert(prop->type == IDP_IDPARRAY);
164 
165  /* first check if the array buffer size has room */
166  if (newlen <= prop->totallen) {
167  if (newlen < prop->len && prop->totallen - newlen < IDP_ARRAY_REALLOC_LIMIT) {
168  for (int i = newlen; i < prop->len; i++) {
170  }
171 
172  prop->len = newlen;
173  return;
174  }
175  if (newlen >= prop->len) {
176  prop->len = newlen;
177  return;
178  }
179  }
180 
181  /* free trailing items */
182  if (newlen < prop->len) {
183  /* newlen is smaller */
184  for (int i = newlen; i < prop->len; i++) {
186  }
187  }
188 
189  /* - Note: This code comes from python, here's the corresponding comment. - */
190  /* This over-allocates proportional to the list size, making room
191  * for additional growth. The over-allocation is mild, but is
192  * enough to give linear-time amortized behavior over a long
193  * sequence of appends() in the presence of a poorly-performing
194  * system realloc().
195  * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
196  */
197  int newsize = newlen;
198  newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize;
199  prop->data.pointer = MEM_recallocN(prop->data.pointer, sizeof(IDProperty) * (size_t)newsize);
200  prop->len = newlen;
201  prop->totallen = newsize;
202 }
203 
204 /* ----------- Numerical Array Type ----------- */
205 static void idp_resize_group_array(IDProperty *prop, int newlen, void *newarr)
206 {
207  if (prop->subtype != IDP_GROUP) {
208  return;
209  }
210 
211  if (newlen >= prop->len) {
212  /* bigger */
213  IDProperty **array = newarr;
214  IDPropertyTemplate val;
215 
216  for (int a = prop->len; a < newlen; a++) {
217  val.i = 0; /* silence MSVC warning about uninitialized var when debugging */
218  array[a] = IDP_New(IDP_GROUP, &val, "IDP_ResizeArray group");
219  }
220  }
221  else {
222  /* smaller */
223  IDProperty **array = prop->data.pointer;
224 
225  for (int a = newlen; a < prop->len; a++) {
227  }
228  }
229 }
230 
231 /*this function works for strings too!*/
232 void IDP_ResizeArray(IDProperty *prop, int newlen)
233 {
234  const bool is_grow = newlen >= prop->len;
235 
236  /* first check if the array buffer size has room */
237  if (newlen <= prop->totallen && prop->totallen - newlen < IDP_ARRAY_REALLOC_LIMIT) {
238  idp_resize_group_array(prop, newlen, prop->data.pointer);
239  prop->len = newlen;
240  return;
241  }
242 
243  /* - Note: This code comes from python, here's the corresponding comment. - */
244  /* This over-allocates proportional to the list size, making room
245  * for additional growth. The over-allocation is mild, but is
246  * enough to give linear-time amortized behavior over a long
247  * sequence of appends() in the presence of a poorly-performing
248  * system realloc().
249  * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
250  */
251  int newsize = newlen;
252  newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize;
253 
254  if (is_grow == false) {
255  idp_resize_group_array(prop, newlen, prop->data.pointer);
256  }
257 
258  prop->data.pointer = MEM_recallocN(prop->data.pointer,
259  idp_size_table[(int)prop->subtype] * (size_t)newsize);
260 
261  if (is_grow == true) {
262  idp_resize_group_array(prop, newlen, prop->data.pointer);
263  }
264 
265  prop->len = newlen;
266  prop->totallen = newsize;
267 }
268 
270 {
271  if (prop->data.pointer) {
272  idp_resize_group_array(prop, 0, NULL);
273  MEM_freeN(prop->data.pointer);
274  }
275 }
276 
277 static IDProperty *idp_generic_copy(const IDProperty *prop, const int UNUSED(flag))
278 {
279  IDProperty *newp = MEM_callocN(sizeof(IDProperty), __func__);
280 
281  BLI_strncpy(newp->name, prop->name, MAX_IDPROP_NAME);
282  newp->type = prop->type;
283  newp->flag = prop->flag;
284  newp->data.val = prop->data.val;
285  newp->data.val2 = prop->data.val2;
286 
287  return newp;
288 }
289 
290 static IDProperty *IDP_CopyArray(const IDProperty *prop, const int flag)
291 {
292  IDProperty *newp = idp_generic_copy(prop, flag);
293 
294  if (prop->data.pointer) {
295  newp->data.pointer = MEM_dupallocN(prop->data.pointer);
296 
297  if (prop->type == IDP_GROUP) {
298  IDProperty **array = newp->data.pointer;
299  int a;
300 
301  for (a = 0; a < prop->len; a++) {
302  array[a] = IDP_CopyProperty_ex(array[a], flag);
303  }
304  }
305  }
306  newp->len = prop->len;
307  newp->subtype = prop->subtype;
308  newp->totallen = prop->totallen;
309 
310  return newp;
311 }
314 /* -------------------------------------------------------------------- */
325 IDProperty *IDP_NewString(const char *st, const char *name, int maxlen)
326 {
327  IDProperty *prop = MEM_callocN(sizeof(IDProperty), "IDProperty string");
328 
329  if (st == NULL) {
330  prop->data.pointer = MEM_mallocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1");
331  *IDP_String(prop) = '\0';
333  prop->len = 1; /* NULL string, has len of 1 to account for null byte. */
334  }
335  else {
336  /* include null terminator '\0' */
337  int stlen = (int)strlen(st) + 1;
338 
339  if (maxlen > 0 && maxlen < stlen) {
340  stlen = maxlen;
341  }
342 
343  prop->data.pointer = MEM_mallocN((size_t)stlen, "id property string 2");
344  prop->len = prop->totallen = stlen;
345  BLI_strncpy(prop->data.pointer, st, (size_t)stlen);
346  }
347 
348  prop->type = IDP_STRING;
349  BLI_strncpy(prop->name, name, MAX_IDPROP_NAME);
350 
351  return prop;
352 }
353 
354 static IDProperty *IDP_CopyString(const IDProperty *prop, const int flag)
355 {
356  BLI_assert(prop->type == IDP_STRING);
357  IDProperty *newp = idp_generic_copy(prop, flag);
358 
359  if (prop->data.pointer) {
360  newp->data.pointer = MEM_dupallocN(prop->data.pointer);
361  }
362  newp->len = prop->len;
363  newp->subtype = prop->subtype;
364  newp->totallen = prop->totallen;
365 
366  return newp;
367 }
368 
369 void IDP_AssignString(IDProperty *prop, const char *st, int maxlen)
370 {
371  BLI_assert(prop->type == IDP_STRING);
372  int stlen = (int)strlen(st);
373  if (maxlen > 0 && maxlen < stlen) {
374  stlen = maxlen;
375  }
376 
377  if (prop->subtype == IDP_STRING_SUB_BYTE) {
378  IDP_ResizeArray(prop, stlen);
379  memcpy(prop->data.pointer, st, (size_t)stlen);
380  }
381  else {
382  stlen++;
383  IDP_ResizeArray(prop, stlen);
384  BLI_strncpy(prop->data.pointer, st, (size_t)stlen);
385  }
386 }
387 
388 void IDP_ConcatStringC(IDProperty *prop, const char *st)
389 {
390  BLI_assert(prop->type == IDP_STRING);
391 
392  int newlen = prop->len + (int)strlen(st);
393  /* we have to remember that prop->len includes the null byte for strings.
394  * so there's no need to add +1 to the resize function.*/
395  IDP_ResizeArray(prop, newlen);
396  strcat(prop->data.pointer, st);
397 }
398 
400 {
401  BLI_assert(append->type == IDP_STRING);
402 
403  /* since ->len for strings includes the NULL byte, we have to subtract one or
404  * we'll get an extra null byte after each concatenation operation.*/
405  int newlen = str1->len + append->len - 1;
406  IDP_ResizeArray(str1, newlen);
407  strcat(str1->data.pointer, append->data.pointer);
408 }
409 
411 {
412  BLI_assert(prop->type == IDP_STRING);
413 
414  if (prop->data.pointer) {
415  MEM_freeN(prop->data.pointer);
416  }
417 }
420 /* -------------------------------------------------------------------- */
424 static IDProperty *IDP_CopyID(const IDProperty *prop, const int flag)
425 {
426  BLI_assert(prop->type == IDP_ID);
427  IDProperty *newp = idp_generic_copy(prop, flag);
428 
429  newp->data.pointer = prop->data.pointer;
430  if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
431  id_us_plus(IDP_Id(newp));
432  }
433 
434  return newp;
435 }
436 
437 void IDP_AssignID(IDProperty *prop, ID *id, const int flag)
438 {
439  BLI_assert(prop->type == IDP_ID);
440 
441  if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0 && IDP_Id(prop) != NULL) {
442  id_us_min(IDP_Id(prop));
443  }
444 
445  prop->data.pointer = id;
446 
447  if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
448  id_us_plus(IDP_Id(prop));
449  }
450 }
451 
454 /* -------------------------------------------------------------------- */
461 static IDProperty *IDP_CopyGroup(const IDProperty *prop, const int flag)
462 {
463  BLI_assert(prop->type == IDP_GROUP);
464  IDProperty *newp = idp_generic_copy(prop, flag);
465  newp->len = prop->len;
466  newp->subtype = prop->subtype;
467 
468  LISTBASE_FOREACH (IDProperty *, link, &prop->data.group) {
469  BLI_addtail(&newp->data.group, IDP_CopyProperty_ex(link, flag));
470  }
471 
472  return newp;
473 }
474 
475 /* use for syncing proxies.
476  * When values name and types match, copy the values, else ignore */
478 {
479  BLI_assert(dest->type == IDP_GROUP);
480  BLI_assert(src->type == IDP_GROUP);
481 
482  LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) {
483  IDProperty *other = BLI_findstring(&dest->data.group, prop->name, offsetof(IDProperty, name));
484  if (other && prop->type == other->type) {
485  switch (prop->type) {
486  case IDP_INT:
487  case IDP_FLOAT:
488  case IDP_DOUBLE:
489  other->data = prop->data;
490  break;
491  case IDP_GROUP:
492  IDP_SyncGroupValues(other, prop);
493  break;
494  default: {
495  BLI_insertlinkreplace(&dest->data.group, other, IDP_CopyProperty(prop));
496  IDP_FreeProperty(other);
497  break;
498  }
499  }
500  }
501  }
502 }
503 
504 void IDP_SyncGroupTypes(IDProperty *dest, const IDProperty *src, const bool do_arraylen)
505 {
506  LISTBASE_FOREACH_MUTABLE (IDProperty *, prop_dst, &dest->data.group) {
507  const IDProperty *prop_src = IDP_GetPropertyFromGroup((IDProperty *)src, prop_dst->name);
508  if (prop_src != NULL) {
509  /* check of we should replace? */
510  if ((prop_dst->type != prop_src->type || prop_dst->subtype != prop_src->subtype) ||
511  (do_arraylen && ELEM(prop_dst->type, IDP_ARRAY, IDP_IDPARRAY) &&
512  (prop_src->len != prop_dst->len))) {
513  BLI_insertlinkreplace(&dest->data.group, prop_dst, IDP_CopyProperty(prop_src));
514  IDP_FreeProperty(prop_dst);
515  }
516  else if (prop_dst->type == IDP_GROUP) {
517  IDP_SyncGroupTypes(prop_dst, prop_src, do_arraylen);
518  }
519  }
520  else {
521  IDP_FreeFromGroup(dest, prop_dst);
522  }
523  }
524 }
525 
530 {
531  BLI_assert(dest->type == IDP_GROUP);
532  BLI_assert(src->type == IDP_GROUP);
533 
534  LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) {
535  IDProperty *loop;
536  for (loop = dest->data.group.first; loop; loop = loop->next) {
537  if (STREQ(loop->name, prop->name)) {
538  BLI_insertlinkreplace(&dest->data.group, loop, IDP_CopyProperty(prop));
539  IDP_FreeProperty(loop);
540  break;
541  }
542  }
543 
544  /* only add at end if not added yet */
545  if (loop == NULL) {
547  dest->len++;
548  BLI_addtail(&dest->data.group, copy);
549  }
550  }
551 }
552 
557 void IDP_ReplaceInGroup_ex(IDProperty *group, IDProperty *prop, IDProperty *prop_exist)
558 {
559  BLI_assert(group->type == IDP_GROUP);
560  BLI_assert(prop_exist == IDP_GetPropertyFromGroup(group, prop->name));
561 
562  if (prop_exist != NULL) {
563  BLI_insertlinkreplace(&group->data.group, prop_exist, prop);
564  IDP_FreeProperty(prop_exist);
565  }
566  else {
567  group->len++;
568  BLI_addtail(&group->data.group, prop);
569  }
570 }
571 
573 {
574  IDProperty *prop_exist = IDP_GetPropertyFromGroup(group, prop->name);
575 
576  IDP_ReplaceInGroup_ex(group, prop, prop_exist);
577 }
578 
584  const IDProperty *src,
585  const bool do_overwrite,
586  const int flag)
587 {
588  BLI_assert(dest->type == IDP_GROUP);
589  BLI_assert(src->type == IDP_GROUP);
590 
591  if (do_overwrite) {
592  LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) {
593  if (prop->type == IDP_GROUP) {
594  IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name);
595 
596  if (prop_exist != NULL) {
597  IDP_MergeGroup_ex(prop_exist, prop, do_overwrite, flag);
598  continue;
599  }
600  }
601 
602  IDProperty *copy = IDP_CopyProperty_ex(prop, flag);
603  IDP_ReplaceInGroup(dest, copy);
604  }
605  }
606  else {
607  LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) {
608  IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name);
609  if (prop_exist != NULL) {
610  if (prop->type == IDP_GROUP) {
611  IDP_MergeGroup_ex(prop_exist, prop, do_overwrite, flag);
612  continue;
613  }
614  }
615  else {
616  IDProperty *copy = IDP_CopyProperty_ex(prop, flag);
617  dest->len++;
618  BLI_addtail(&dest->data.group, copy);
619  }
620  }
621  }
622 }
623 
628 void IDP_MergeGroup(IDProperty *dest, const IDProperty *src, const bool do_overwrite)
629 {
630  IDP_MergeGroup_ex(dest, src, do_overwrite, 0);
631 }
632 
644 {
645  BLI_assert(group->type == IDP_GROUP);
646 
647  if (IDP_GetPropertyFromGroup(group, prop->name) == NULL) {
648  group->len++;
649  BLI_addtail(&group->data.group, prop);
650  return true;
651  }
652 
653  return false;
654 }
655 
660 bool IDP_InsertToGroup(IDProperty *group, IDProperty *previous, IDProperty *pnew)
661 {
662  BLI_assert(group->type == IDP_GROUP);
663 
664  if (IDP_GetPropertyFromGroup(group, pnew->name) == NULL) {
665  group->len++;
666  BLI_insertlinkafter(&group->data.group, previous, pnew);
667  return true;
668  }
669 
670  return false;
671 }
672 
680 {
681  BLI_assert(group->type == IDP_GROUP);
682 
683  group->len--;
684  BLI_remlink(&group->data.group, prop);
685 }
686 
691 {
692  IDP_RemoveFromGroup(group, prop);
693  IDP_FreeProperty(prop);
694 }
695 
696 IDProperty *IDP_GetPropertyFromGroup(const IDProperty *prop, const char *name)
697 {
698  BLI_assert(prop->type == IDP_GROUP);
699 
700  return (IDProperty *)BLI_findstring(&prop->data.group, name, offsetof(IDProperty, name));
701 }
703 IDProperty *IDP_GetPropertyTypeFromGroup(const IDProperty *prop, const char *name, const char type)
704 {
705  IDProperty *idprop = IDP_GetPropertyFromGroup(prop, name);
706  return (idprop && idprop->type == type) ? idprop : NULL;
707 }
708 
709 /* Ok, the way things work, Groups free the ID Property structs of their children.
710  * This is because all ID Property freeing functions free only direct data (not the ID Property
711  * struct itself), but for Groups the child properties *are* considered
712  * direct data. */
713 static void IDP_FreeGroup(IDProperty *prop, const bool do_id_user)
714 {
715  BLI_assert(prop->type == IDP_GROUP);
716 
717  LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) {
718  IDP_FreePropertyContent_ex(loop, do_id_user);
719  }
720  BLI_freelistN(&prop->data.group);
721 }
724 /* -------------------------------------------------------------------- */
728 IDProperty *IDP_CopyProperty_ex(const IDProperty *prop, const int flag)
729 {
730  switch (prop->type) {
731  case IDP_GROUP:
732  return IDP_CopyGroup(prop, flag);
733  case IDP_STRING:
734  return IDP_CopyString(prop, flag);
735  case IDP_ID:
736  return IDP_CopyID(prop, flag);
737  case IDP_ARRAY:
738  return IDP_CopyArray(prop, flag);
739  case IDP_IDPARRAY:
740  return IDP_CopyIDPArray(prop, flag);
741  default:
742  return idp_generic_copy(prop, flag);
743  }
744 }
745 
747 {
748  return IDP_CopyProperty_ex(prop, 0);
749 }
750 
756 {
757  IDProperty *idprop_tmp = IDP_CopyProperty(src);
758  idprop_tmp->prev = dst->prev;
759  idprop_tmp->next = dst->next;
760  SWAP(IDProperty, *dst, *idprop_tmp);
761  IDP_FreeProperty(idprop_tmp);
762 }
763 
769 IDProperty *IDP_GetProperties(ID *id, const bool create_if_needed)
770 {
771  if (id->properties) {
772  return id->properties;
773  }
774 
775  if (create_if_needed) {
776  id->properties = MEM_callocN(sizeof(IDProperty), "IDProperty");
777  id->properties->type = IDP_GROUP;
778  /* don't overwrite the data's name and type
779  * some functions might need this if they
780  * don't have a real ID, should be named elsewhere - Campbell */
781  /* strcpy(id->name, "top_level_group");*/
782  }
783  return id->properties;
784 }
785 
788 bool IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const bool is_strict)
789 {
790  if (prop1 == NULL && prop2 == NULL) {
791  return true;
792  }
793  if (prop1 == NULL || prop2 == NULL) {
794  return is_strict ? false : true;
795  }
796  if (prop1->type != prop2->type) {
797  return false;
798  }
799 
800  switch (prop1->type) {
801  case IDP_INT:
802  return (IDP_Int(prop1) == IDP_Int(prop2));
803  case IDP_FLOAT:
804 #if !defined(NDEBUG) && defined(WITH_PYTHON)
805  {
806  float p1 = IDP_Float(prop1);
807  float p2 = IDP_Float(prop2);
808  if ((p1 != p2) && ((fabsf(p1 - p2) / max_ff(p1, p2)) < 0.001f)) {
809  printf(
810  "WARNING: Comparing two float properties that have nearly the same value (%f vs. "
811  "%f)\n",
812  p1,
813  p2);
814  printf(" p1: ");
815  IDP_print(prop1);
816  printf(" p2: ");
817  IDP_print(prop2);
818  }
819  }
820 #endif
821  return (IDP_Float(prop1) == IDP_Float(prop2));
822  case IDP_DOUBLE:
823  return (IDP_Double(prop1) == IDP_Double(prop2));
824  case IDP_STRING: {
825  return (((prop1->len == prop2->len) &&
826  STREQLEN(IDP_String(prop1), IDP_String(prop2), (size_t)prop1->len)));
827  }
828  case IDP_ARRAY:
829  if (prop1->len == prop2->len && prop1->subtype == prop2->subtype) {
830  return (memcmp(IDP_Array(prop1),
831  IDP_Array(prop2),
832  idp_size_table[(int)prop1->subtype] * (size_t)prop1->len) == 0);
833  }
834  return false;
835  case IDP_GROUP: {
836  if (is_strict && prop1->len != prop2->len) {
837  return false;
838  }
839 
840  LISTBASE_FOREACH (IDProperty *, link1, &prop1->data.group) {
841  IDProperty *link2 = IDP_GetPropertyFromGroup(prop2, link1->name);
842 
843  if (!IDP_EqualsProperties_ex(link1, link2, is_strict)) {
844  return false;
845  }
846  }
847 
848  return true;
849  }
850  case IDP_IDPARRAY: {
851  IDProperty *array1 = IDP_IDPArray(prop1);
852  IDProperty *array2 = IDP_IDPArray(prop2);
853 
854  if (prop1->len != prop2->len) {
855  return false;
856  }
857 
858  for (int i = 0; i < prop1->len; i++) {
859  if (!IDP_EqualsProperties_ex(&array1[i], &array2[i], is_strict)) {
860  return false;
861  }
862  }
863  return true;
864  }
865  case IDP_ID:
866  return (IDP_Id(prop1) == IDP_Id(prop2));
867  default:
868  BLI_assert(0);
869  break;
870  }
871 
872  return true;
873 }
874 
876 {
877  return IDP_EqualsProperties_ex(prop1, prop2, true);
878 }
879 
907 IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char *name)
908 {
909  IDProperty *prop = NULL;
910 
911  switch (type) {
912  case IDP_INT:
913  prop = MEM_callocN(sizeof(IDProperty), "IDProperty int");
914  prop->data.val = val->i;
915  break;
916  case IDP_FLOAT:
917  prop = MEM_callocN(sizeof(IDProperty), "IDProperty float");
918  *(float *)&prop->data.val = val->f;
919  break;
920  case IDP_DOUBLE:
921  prop = MEM_callocN(sizeof(IDProperty), "IDProperty double");
922  *(double *)&prop->data.val = val->d;
923  break;
924  case IDP_ARRAY: {
925  /* for now, we only support float and int and double arrays */
926  if ((val->array.type == IDP_FLOAT) || (val->array.type == IDP_INT) ||
927  (val->array.type == IDP_DOUBLE) || (val->array.type == IDP_GROUP)) {
928  prop = MEM_callocN(sizeof(IDProperty), "IDProperty array");
929  prop->subtype = val->array.type;
930  if (val->array.len) {
931  prop->data.pointer = MEM_callocN(
932  idp_size_table[val->array.type] * (size_t)val->array.len, "id property array");
933  }
934  prop->len = prop->totallen = val->array.len;
935  break;
936  }
937  CLOG_ERROR(&LOG, "bad array type.");
938  return NULL;
939  }
940  case IDP_STRING: {
941  const char *st = val->string.str;
942 
943  prop = MEM_callocN(sizeof(IDProperty), "IDProperty string");
944  if (val->string.subtype == IDP_STRING_SUB_BYTE) {
945  /* note, intentionally not null terminated */
946  if (st == NULL) {
947  prop->data.pointer = MEM_mallocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1");
948  *IDP_String(prop) = '\0';
950  prop->len = 0;
951  }
952  else {
953  prop->data.pointer = MEM_mallocN((size_t)val->string.len, "id property string 2");
954  prop->len = prop->totallen = val->string.len;
955  memcpy(prop->data.pointer, st, (size_t)val->string.len);
956  }
958  }
959  else {
960  if (st == NULL || val->string.len <= 1) {
961  prop->data.pointer = MEM_mallocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1");
962  *IDP_String(prop) = '\0';
964  /* NULL string, has len of 1 to account for null byte. */
965  prop->len = 1;
966  }
967  else {
968  BLI_assert((int)val->string.len <= (int)strlen(st) + 1);
969  prop->data.pointer = MEM_mallocN((size_t)val->string.len, "id property string 3");
970  memcpy(prop->data.pointer, st, (size_t)val->string.len - 1);
971  IDP_String(prop)[val->string.len - 1] = '\0';
972  prop->len = prop->totallen = val->string.len;
973  }
975  }
976  break;
977  }
978  case IDP_GROUP: {
979  /* Values are set properly by calloc. */
980  prop = MEM_callocN(sizeof(IDProperty), "IDProperty group");
981  break;
982  }
983  case IDP_ID: {
984  prop = MEM_callocN(sizeof(IDProperty), "IDProperty datablock");
985  prop->data.pointer = (void *)val->id;
986  prop->type = IDP_ID;
987  id_us_plus(IDP_Id(prop));
988  break;
989  }
990  default: {
991  prop = MEM_callocN(sizeof(IDProperty), "IDProperty array");
992  break;
993  }
994  }
995 
996  prop->type = type;
997  BLI_strncpy(prop->name, name, MAX_IDPROP_NAME);
998 
999  return prop;
1000 }
1001 
1006 void IDP_FreePropertyContent_ex(IDProperty *prop, const bool do_id_user)
1007 {
1008  switch (prop->type) {
1009  case IDP_ARRAY:
1010  IDP_FreeArray(prop);
1011  break;
1012  case IDP_STRING:
1013  IDP_FreeString(prop);
1014  break;
1015  case IDP_GROUP:
1016  IDP_FreeGroup(prop, do_id_user);
1017  break;
1018  case IDP_IDPARRAY:
1019  IDP_FreeIDPArray(prop, do_id_user);
1020  break;
1021  case IDP_ID:
1022  if (do_id_user) {
1023  id_us_min(IDP_Id(prop));
1024  }
1025  break;
1026  }
1027 }
1028 
1030 {
1031  IDP_FreePropertyContent_ex(prop, true);
1032 }
1033 
1034 void IDP_FreeProperty_ex(IDProperty *prop, const bool do_id_user)
1035 {
1036  IDP_FreePropertyContent_ex(prop, do_id_user);
1037  MEM_freeN(prop);
1038 }
1039 
1041 {
1043  MEM_freeN(prop);
1044 }
1045 
1047 {
1049  prop->data.pointer = NULL;
1050  prop->len = prop->totallen = 0;
1051 }
1052 
1053 void IDP_Reset(IDProperty *prop, const IDProperty *reference)
1054 {
1055  if (prop == NULL) {
1056  return;
1057  }
1058  IDP_ClearProperty(prop);
1059  if (reference != NULL) {
1060  IDP_MergeGroup(prop, reference, true);
1061  }
1062 }
1063 
1072 void IDP_foreach_property(IDProperty *id_property_root,
1073  const int type_filter,
1075  void *user_data)
1076 {
1077  if (!id_property_root) {
1078  return;
1079  }
1080 
1081  if (type_filter == 0 || (1 << id_property_root->type) & type_filter) {
1082  callback(id_property_root, user_data);
1083  }
1084 
1085  /* Recursive call into container types of ID properties. */
1086  switch (id_property_root->type) {
1087  case IDP_GROUP: {
1088  LISTBASE_FOREACH (IDProperty *, loop, &id_property_root->data.group) {
1089  IDP_foreach_property(loop, type_filter, callback, user_data);
1090  }
1091  break;
1092  }
1093  case IDP_IDPARRAY: {
1094  IDProperty *loop = IDP_Array(id_property_root);
1095  for (int i = 0; i < id_property_root->len; i++) {
1096  IDP_foreach_property(&loop[i], type_filter, callback, user_data);
1097  }
1098  break;
1099  }
1100  default:
1101  break; /* Nothing to do here with other types of IDProperties... */
1102  }
1103 }
1104 
1105 void IDP_WriteProperty_OnlyData(const IDProperty *prop, BlendWriter *writer);
1106 
1107 static void IDP_WriteArray(const IDProperty *prop, BlendWriter *writer)
1108 {
1109  /*REMEMBER to set totalen to len in the linking code!!*/
1110  if (prop->data.pointer) {
1111  BLO_write_raw(writer, MEM_allocN_len(prop->data.pointer), prop->data.pointer);
1112 
1113  if (prop->subtype == IDP_GROUP) {
1114  IDProperty **array = prop->data.pointer;
1115  int a;
1116 
1117  for (a = 0; a < prop->len; a++) {
1118  IDP_BlendWrite(writer, array[a]);
1119  }
1120  }
1121  }
1122 }
1123 
1124 static void IDP_WriteIDPArray(const IDProperty *prop, BlendWriter *writer)
1125 {
1126  /*REMEMBER to set totalen to len in the linking code!!*/
1127  if (prop->data.pointer) {
1128  const IDProperty *array = prop->data.pointer;
1129 
1130  BLO_write_struct_array(writer, IDProperty, prop->len, array);
1131 
1132  for (int a = 0; a < prop->len; a++) {
1133  IDP_WriteProperty_OnlyData(&array[a], writer);
1134  }
1135  }
1136 }
1137 
1138 static void IDP_WriteString(const IDProperty *prop, BlendWriter *writer)
1139 {
1140  /*REMEMBER to set totalen to len in the linking code!!*/
1141  BLO_write_raw(writer, (size_t)prop->len, prop->data.pointer);
1142 }
1143 
1144 static void IDP_WriteGroup(const IDProperty *prop, BlendWriter *writer)
1145 {
1146  LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) {
1147  IDP_BlendWrite(writer, loop);
1148  }
1149 }
1150 
1151 /* Functions to read/write ID Properties */
1153 {
1154  switch (prop->type) {
1155  case IDP_GROUP:
1156  IDP_WriteGroup(prop, writer);
1157  break;
1158  case IDP_STRING:
1159  IDP_WriteString(prop, writer);
1160  break;
1161  case IDP_ARRAY:
1162  IDP_WriteArray(prop, writer);
1163  break;
1164  case IDP_IDPARRAY:
1165  IDP_WriteIDPArray(prop, writer);
1166  break;
1167  }
1168 }
1169 
1170 void IDP_BlendWrite(BlendWriter *writer, const IDProperty *prop)
1171 {
1172  BLO_write_struct(writer, IDProperty, prop);
1173  IDP_WriteProperty_OnlyData(prop, writer);
1174 }
1175 
1176 static void IDP_DirectLinkProperty(IDProperty *prop, BlendDataReader *reader);
1177 
1179 {
1180  /* since we didn't save the extra buffer, set totallen to len */
1181  prop->totallen = prop->len;
1182  BLO_read_data_address(reader, &prop->data.pointer);
1183 
1184  IDProperty *array = (IDProperty *)prop->data.pointer;
1185 
1186  /* note!, idp-arrays didn't exist in 2.4x, so the pointer will be cleared
1187  * there's not really anything we can do to correct this, at least don't crash */
1188  if (array == NULL) {
1189  prop->len = 0;
1190  prop->totallen = 0;
1191  }
1192 
1193  for (int i = 0; i < prop->len; i++) {
1194  IDP_DirectLinkProperty(&array[i], reader);
1195  }
1196 }
1197 
1199 {
1200  /* since we didn't save the extra buffer, set totallen to len */
1201  prop->totallen = prop->len;
1202 
1203  if (prop->subtype == IDP_GROUP) {
1204  BLO_read_pointer_array(reader, &prop->data.pointer);
1205  IDProperty **array = prop->data.pointer;
1206 
1207  for (int i = 0; i < prop->len; i++) {
1208  IDP_DirectLinkProperty(array[i], reader);
1209  }
1210  }
1211  else if (prop->subtype == IDP_DOUBLE) {
1212  BLO_read_double_array(reader, prop->len, (double **)&prop->data.pointer);
1213  }
1214  else {
1215  /* also used for floats */
1216  BLO_read_int32_array(reader, prop->len, (int **)&prop->data.pointer);
1217  }
1218 }
1219 
1221 {
1222  /*since we didn't save the extra string buffer, set totallen to len.*/
1223  prop->totallen = prop->len;
1224  BLO_read_data_address(reader, &prop->data.pointer);
1225 }
1226 
1228 {
1229  ListBase *lb = &prop->data.group;
1230 
1231  BLO_read_list(reader, lb);
1232 
1233  /*Link child id properties now*/
1234  LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) {
1235  IDP_DirectLinkProperty(loop, reader);
1236  }
1237 }
1238 
1240 {
1241  switch (prop->type) {
1242  case IDP_GROUP:
1243  IDP_DirectLinkGroup(prop, reader);
1244  break;
1245  case IDP_STRING:
1246  IDP_DirectLinkString(prop, reader);
1247  break;
1248  case IDP_ARRAY:
1249  IDP_DirectLinkArray(prop, reader);
1250  break;
1251  case IDP_IDPARRAY:
1252  IDP_DirectLinkIDPArray(prop, reader);
1253  break;
1254  case IDP_DOUBLE:
1255  /* Workaround for doubles.
1256  * They are stored in the same field as `int val, val2` in the #IDPropertyData struct,
1257  * they have to deal with endianness specifically.
1258  *
1259  * In theory, val and val2 would've already been swapped
1260  * if switch_endian is true, so we have to first un-swap
1261  * them then re-swap them as a single 64-bit entity. */
1262  if (BLO_read_requires_endian_switch(reader)) {
1266  }
1267  break;
1268  case IDP_INT:
1269  case IDP_FLOAT:
1270  case IDP_ID:
1271  break; /* Nothing special to do here. */
1272  default:
1273  /* Unknown IDP type, nuke it (we cannot handle unknown types everywhere in code,
1274  * IDP are way too polymorphic to do it safely. */
1275  printf(
1276  "%s: found unknown IDProperty type %d, reset to Integer one !\n", __func__, prop->type);
1277  /* Note: we do not attempt to free unknown prop, we have no way to know how to do that! */
1278  prop->type = IDP_INT;
1279  prop->subtype = 0;
1280  IDP_Int(prop) = 0;
1281  }
1282 }
1283 
1284 void IDP_BlendReadData_impl(BlendDataReader *reader, IDProperty **prop, const char *caller_func_id)
1285 {
1286  if (*prop) {
1287  if ((*prop)->type == IDP_GROUP) {
1288  IDP_DirectLinkGroup(*prop, reader);
1289  }
1290  else {
1291  /* corrupt file! */
1292  printf("%s: found non group data, freeing type %d!\n", caller_func_id, (*prop)->type);
1293  /* don't risk id, data's likely corrupt. */
1294  // IDP_FreePropertyContent(*prop);
1295  *prop = NULL;
1296  }
1297  }
1298 }
1299 
1301 {
1302  if (!prop) {
1303  return;
1304  }
1305 
1306  switch (prop->type) {
1307  case IDP_ID: /* PointerProperty */
1308  {
1309  void *newaddr = BLO_read_get_new_id_address(reader, NULL, IDP_Id(prop));
1310  if (IDP_Id(prop) && !newaddr && G.debug) {
1311  printf("Error while loading \"%s\". Data not found in file!\n", prop->name);
1312  }
1313  prop->data.pointer = newaddr;
1314  break;
1315  }
1316  case IDP_IDPARRAY: /* CollectionProperty */
1317  {
1318  IDProperty *idp_array = IDP_IDPArray(prop);
1319  for (int i = 0; i < prop->len; i++) {
1320  IDP_BlendReadLib(reader, &(idp_array[i]));
1321  }
1322  break;
1323  }
1324  case IDP_GROUP: /* PointerProperty */
1325  {
1326  LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) {
1327  IDP_BlendReadLib(reader, loop);
1328  }
1329  break;
1330  }
1331  default:
1332  break; /* Nothing to do for other IDProps. */
1333  }
1334 }
1335 
1336 void IDP_BlendReadExpand(struct BlendExpander *expander, IDProperty *prop)
1337 {
1338  if (!prop) {
1339  return;
1340  }
1341 
1342  switch (prop->type) {
1343  case IDP_ID:
1344  BLO_expand(expander, IDP_Id(prop));
1345  break;
1346  case IDP_IDPARRAY: {
1347  IDProperty *idp_array = IDP_IDPArray(prop);
1348  for (int i = 0; i < prop->len; i++) {
1349  IDP_BlendReadExpand(expander, &idp_array[i]);
1350  }
1351  break;
1352  }
1353  case IDP_GROUP:
1354  LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) {
1355  IDP_BlendReadExpand(expander, loop);
1356  }
1357  break;
1358  }
1359 }
1360 
#define IDP_Float(prop)
Definition: BKE_idprop.h:179
#define IDP_IDPArray(prop)
Definition: BKE_idprop.h:182
#define IDP_Int(prop)
Definition: BKE_idprop.h:154
#define IDP_Id(prop)
Definition: BKE_idprop.h:183
void(* IDPForeachPropertyCallback)(struct IDProperty *id_property, void *user_data)
Definition: BKE_idprop.h:190
void IDP_print(const struct IDProperty *prop)
#define IDP_String(prop)
Definition: BKE_idprop.h:181
#define IDP_Double(prop)
Definition: BKE_idprop.h:180
#define IDP_Array(prop)
Definition: BKE_idprop.h:155
void id_us_min(struct ID *id)
Definition: lib_id.c:297
@ LIB_ID_CREATE_NO_USER_REFCOUNT
Definition: BKE_lib_id.h:92
void id_us_plus(struct ID *id)
Definition: lib_id.c:288
#define BLI_assert(a)
Definition: BLI_assert.h:58
BLI_INLINE void BLI_endian_switch_int64(int64_t *val) ATTR_NONNULL(1)
BLI_INLINE void BLI_endian_switch_int32(int *val) ATTR_NONNULL(1)
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
void BLI_insertlinkreplace(ListBase *listbase, void *vreplacelink, void *vnewlink) ATTR_NONNULL(1
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
Definition: BLI_listbase.h:188
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition: listbase.c:352
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:547
void * BLI_findstring(const struct ListBase *listbase, const char *id, const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:133
MINLINE float max_ff(float a, float b)
Strict compiler flags for areas of code we want to ensure don't do conversions without us knowing abo...
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL()
Definition: string.c:108
#define SWAP(type, a, b)
#define STREQLEN(a, b, n)
#define UNUSED(x)
#define ELEM(...)
#define STREQ(a, b)
#define BLO_read_data_address(reader, ptr_p)
ID * BLO_read_get_new_id_address(BlendLibReader *reader, struct Library *lib, struct ID *id)
Definition: readfile.c:5615
void BLO_read_double_array(BlendDataReader *reader, int array_size, double **ptr_p)
Definition: readfile.c:5688
void BLO_read_int32_array(BlendDataReader *reader, int array_size, int32_t **ptr_p)
Definition: readfile.c:5659
#define BLO_write_struct(writer, struct_name, data_ptr)
void BLO_read_list(BlendDataReader *reader, struct ListBase *list)
Definition: readfile.c:5654
#define BLO_write_struct_array(writer, struct_name, array_size, data_ptr)
#define BLO_expand(expander, id)
bool BLO_read_requires_endian_switch(BlendDataReader *reader)
Definition: readfile.c:5620
void BLO_write_raw(BlendWriter *writer, size_t size_in_bytes, const void *data_ptr)
Definition: writefile.c:1286
void BLO_read_pointer_array(BlendDataReader *reader, void **ptr_p)
Definition: readfile.c:5727
typedef double(DMatrix)[4][4]
#define CLOG_ERROR(clg_ref,...)
Definition: CLG_log.h:204
#define DEFAULT_ALLOC_FOR_NULL_STRINGS
Definition: DNA_ID.h:93
@ IDP_DOUBLE
Definition: DNA_ID.h:103
@ IDP_FLOAT
Definition: DNA_ID.h:99
@ IDP_STRING
Definition: DNA_ID.h:97
@ IDP_IDPARRAY
Definition: DNA_ID.h:104
@ IDP_INT
Definition: DNA_ID.h:98
@ IDP_GROUP
Definition: DNA_ID.h:101
@ IDP_ARRAY
Definition: DNA_ID.h:100
@ IDP_ID
Definition: DNA_ID.h:102
#define MAX_IDPROP_NAME
Definition: DNA_ID.h:92
@ IDP_STRING_SUB_UTF8
Definition: DNA_ID.h:124
@ IDP_STRING_SUB_BYTE
Definition: DNA_ID.h:125
struct ListBase ListBase
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
Read Guarded memory(de)allocation.
#define MEM_recallocN(vmemh, len)
T * data()
Definition: util_array.h:208
void * user_data
DEGForeachIDComponentCallback callback
#define IDP_ARRAY_REALLOC_LIMIT
Definition: idprop.c:53
void IDP_SyncGroupTypes(IDProperty *dest, const IDProperty *src, const bool do_arraylen)
Definition: idprop.c:504
void IDP_Reset(IDProperty *prop, const IDProperty *reference)
Definition: idprop.c:1053
bool IDP_InsertToGroup(IDProperty *group, IDProperty *previous, IDProperty *pnew)
Definition: idprop.c:660
bool IDP_AddToGroup(IDProperty *group, IDProperty *prop)
Definition: idprop.c:643
static void IDP_WriteGroup(const IDProperty *prop, BlendWriter *writer)
Definition: idprop.c:1144
IDProperty * IDP_GetProperties(ID *id, const bool create_if_needed)
Definition: idprop.c:769
void IDP_ConcatStringC(IDProperty *prop, const char *st)
Definition: idprop.c:388
void IDP_ConcatString(IDProperty *str1, IDProperty *append)
Definition: idprop.c:399
void IDP_BlendReadExpand(struct BlendExpander *expander, IDProperty *prop)
Definition: idprop.c:1336
bool IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const bool is_strict)
Definition: idprop.c:788
static void idp_resize_group_array(IDProperty *prop, int newlen, void *newarr)
Definition: idprop.c:205
IDProperty * IDP_NewString(const char *st, const char *name, int maxlen)
Definition: idprop.c:325
void IDP_SyncGroupValues(IDProperty *dest, const IDProperty *src)
Definition: idprop.c:477
IDProperty * IDP_CopyProperty(const IDProperty *prop)
Definition: idprop.c:746
void IDP_ReplaceGroupInGroup(IDProperty *dest, const IDProperty *src)
Definition: idprop.c:529
#define GETPROP(prop, i)
Definition: idprop.c:74
void IDP_MergeGroup_ex(IDProperty *dest, const IDProperty *src, const bool do_overwrite, const int flag)
Definition: idprop.c:583
static IDProperty * IDP_CopyArray(const IDProperty *prop, const int flag)
Definition: idprop.c:290
void IDP_foreach_property(IDProperty *id_property_root, const int type_filter, IDPForeachPropertyCallback callback, void *user_data)
Definition: idprop.c:1072
static IDProperty * IDP_CopyID(const IDProperty *prop, const int flag)
Definition: idprop.c:424
static void IDP_FreeIDPArray(IDProperty *prop, const bool do_id_user)
Definition: idprop.c:116
void IDP_BlendReadLib(BlendLibReader *reader, IDProperty *prop)
Definition: idprop.c:1300
void IDP_FreeString(IDProperty *prop)
Definition: idprop.c:410
static IDProperty * IDP_CopyGroup(const IDProperty *prop, const int flag)
Definition: idprop.c:461
static void IDP_DirectLinkIDPArray(IDProperty *prop, BlendDataReader *reader)
Definition: idprop.c:1178
void IDP_WriteProperty_OnlyData(const IDProperty *prop, BlendWriter *writer)
Definition: idprop.c:1152
void IDP_CopyPropertyContent(IDProperty *dst, IDProperty *src)
Definition: idprop.c:755
void IDP_RemoveFromGroup(IDProperty *group, IDProperty *prop)
Definition: idprop.c:679
IDProperty * IDP_NewIDPArray(const char *name)
Definition: idprop.c:82
void IDP_FreeProperty(IDProperty *prop)
Definition: idprop.c:1040
static size_t idp_size_table[]
Definition: idprop.c:58
void IDP_AssignID(IDProperty *prop, ID *id, const int flag)
Definition: idprop.c:437
IDProperty * IDP_CopyProperty_ex(const IDProperty *prop, const int flag)
Definition: idprop.c:728
void IDP_FreeProperty_ex(IDProperty *prop, const bool do_id_user)
Definition: idprop.c:1034
void IDP_AssignString(IDProperty *prop, const char *st, int maxlen)
Definition: idprop.c:369
static IDProperty * IDP_CopyString(const IDProperty *prop, const int flag)
Definition: idprop.c:354
void IDP_FreePropertyContent(IDProperty *prop)
Definition: idprop.c:1029
void IDP_ReplaceInGroup_ex(IDProperty *group, IDProperty *prop, IDProperty *prop_exist)
Definition: idprop.c:557
void IDP_FreePropertyContent_ex(IDProperty *prop, const bool do_id_user)
Definition: idprop.c:1006
static void IDP_DirectLinkGroup(IDProperty *prop, BlendDataReader *reader)
Definition: idprop.c:1227
void IDP_FreeFromGroup(IDProperty *group, IDProperty *prop)
Definition: idprop.c:690
static void IDP_DirectLinkString(IDProperty *prop, BlendDataReader *reader)
Definition: idprop.c:1220
void IDP_ClearProperty(IDProperty *prop)
Definition: idprop.c:1046
static IDProperty * idp_generic_copy(const IDProperty *prop, const int UNUSED(flag))
Definition: idprop.c:277
IDProperty * IDP_GetPropertyFromGroup(const IDProperty *prop, const char *name)
Definition: idprop.c:696
void IDP_ResizeIDPArray(IDProperty *prop, int newlen)
Definition: idprop.c:161
static void IDP_DirectLinkProperty(IDProperty *prop, BlendDataReader *reader)
Definition: idprop.c:1239
static void IDP_FreeGroup(IDProperty *prop, const bool do_id_user)
Definition: idprop.c:713
void IDP_MergeGroup(IDProperty *dest, const IDProperty *src, const bool do_overwrite)
Definition: idprop.c:628
static void IDP_DirectLinkArray(IDProperty *prop, BlendDataReader *reader)
Definition: idprop.c:1198
IDProperty * IDP_GetIndexArray(IDProperty *prop, int index)
Definition: idprop.c:146
void IDP_AppendArray(IDProperty *prop, IDProperty *item)
Definition: idprop.c:153
static void IDP_WriteString(const IDProperty *prop, BlendWriter *writer)
Definition: idprop.c:1138
IDProperty * IDP_GetPropertyTypeFromGroup(const IDProperty *prop, const char *name, const char type)
Definition: idprop.c:703
static CLG_LogRef LOG
Definition: idprop.c:55
void IDP_SetIndexArray(IDProperty *prop, int index, IDProperty *item)
Definition: idprop.c:130
void IDP_ResizeArray(IDProperty *prop, int newlen)
Definition: idprop.c:232
void IDP_ReplaceInGroup(IDProperty *group, IDProperty *prop)
Definition: idprop.c:572
static void IDP_WriteArray(const IDProperty *prop, BlendWriter *writer)
Definition: idprop.c:1107
void IDP_BlendWrite(BlendWriter *writer, const IDProperty *prop)
Definition: idprop.c:1170
IDProperty * IDP_CopyIDPArray(const IDProperty *array, const int flag)
Definition: idprop.c:92
void IDP_FreeArray(IDProperty *prop)
Definition: idprop.c:269
static void IDP_WriteIDPArray(const IDProperty *prop, BlendWriter *writer)
Definition: idprop.c:1124
void IDP_BlendReadData_impl(BlendDataReader *reader, IDProperty **prop, const char *caller_func_id)
Definition: idprop.c:1284
bool IDP_EqualsProperties(IDProperty *prop1, IDProperty *prop2)
Definition: idprop.c:875
IDProperty * IDP_New(const char type, const IDPropertyTemplate *val, const char *name)
Definition: idprop.c:907
#define fabsf(x)
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:42
size_t(* MEM_allocN_len)(const void *vmemh)
Definition: mallocn.c:40
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
static unsigned a[3]
Definition: RandGen.cpp:92
static void copy(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node)
__int64 int64_t
Definition: stdint.h:92
ListBase group
Definition: DNA_ID.h:64
void * pointer
Definition: DNA_ID.h:63
short flag
Definition: DNA_ID.h:72
int len
Definition: DNA_ID.h:84
struct IDProperty * next
Definition: DNA_ID.h:70
char name[64]
Definition: DNA_ID.h:74
IDPropertyData data
Definition: DNA_ID.h:80
struct IDProperty * prev
Definition: DNA_ID.h:70
char subtype
Definition: DNA_ID.h:71
int totallen
Definition: DNA_ID.h:89
char type
Definition: DNA_ID.h:71
Definition: DNA_ID.h:273
IDProperty * properties
Definition: DNA_ID.h:314
void * first
Definition: DNA_listBase.h:47
const char * str
Definition: BKE_idprop.h:41
struct IDPropertyTemplate::@28 array
struct ID * id
Definition: BKE_idprop.h:45
struct IDPropertyTemplate::@27 string
#define G(x, y, z)
uint len