Blender  V3.3
idprop.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2001-2002 NaN Holding BV. All rights reserved. */
3 
8 #include <limits.h>
9 #include <stddef.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 
14 #include "BLI_endian_switch.h"
15 #include "BLI_listbase.h"
16 #include "BLI_math.h"
17 #include "BLI_string.h"
18 #include "BLI_utildefines.h"
19 
20 #include "BKE_global.h"
21 #include "BKE_idprop.h"
22 #include "BKE_lib_id.h"
23 
24 #include "CLG_log.h"
25 
26 #include "MEM_guardedalloc.h"
27 
28 #include "BLO_read_write.h"
29 
30 #include "BLI_strict_flags.h"
31 
32 /* IDPropertyTemplate is a union in DNA_ID.h */
33 
38 #define IDP_ARRAY_REALLOC_LIMIT 200
39 
40 static CLG_LogRef LOG = {"bke.idprop"};
41 
42 /* Local size table. */
43 static size_t idp_size_table[] = {
44  1, /*strings*/
45  sizeof(int),
46  sizeof(float),
47  sizeof(float[3]), /* Vector type, deprecated. */
48  sizeof(float[16]), /* Matrix type, deprecated. */
49  0, /* Arrays don't have a fixed size. */
50  sizeof(ListBase), /* Group type. */
51  sizeof(void *),
52  sizeof(double),
53 };
54 
55 /* -------------------------------------------------------------------- */
59 #define GETPROP(prop, i) &(IDP_IDPArray(prop)[i])
60 
61 /* --------- property array type -------------*/
62 
63 IDProperty *IDP_NewIDPArray(const char *name)
64 {
65  IDProperty *prop = MEM_callocN(sizeof(IDProperty), "IDProperty prop array");
66  prop->type = IDP_IDPARRAY;
67  prop->len = 0;
68  BLI_strncpy(prop->name, name, MAX_IDPROP_NAME);
69 
70  return prop;
71 }
72 
73 IDProperty *IDP_CopyIDPArray(const IDProperty *array, const int flag)
74 {
75  /* don't use MEM_dupallocN because this may be part of an array */
76  BLI_assert(array->type == IDP_IDPARRAY);
77 
78  IDProperty *narray = MEM_mallocN(sizeof(IDProperty), __func__);
79  *narray = *array;
80 
81  narray->data.pointer = MEM_dupallocN(array->data.pointer);
82  for (int i = 0; i < narray->len; i++) {
83  /* OK, the copy functions always allocate a new structure,
84  * which doesn't work here. instead, simply copy the
85  * contents of the new structure into the array cell,
86  * then free it. this makes for more maintainable
87  * code than simply re-implementing the copy functions
88  * in this loop. */
89  IDProperty *tmp = IDP_CopyProperty_ex(GETPROP(narray, i), flag);
90  memcpy(GETPROP(narray, i), tmp, sizeof(IDProperty));
91  MEM_freeN(tmp);
92  }
93 
94  return narray;
95 }
96 
97 static void IDP_FreeIDPArray(IDProperty *prop, const bool do_id_user)
98 {
99  BLI_assert(prop->type == IDP_IDPARRAY);
100 
101  for (int i = 0; i < prop->len; i++) {
102  IDP_FreePropertyContent_ex(GETPROP(prop, i), do_id_user);
103  }
104 
105  if (prop->data.pointer) {
106  MEM_freeN(prop->data.pointer);
107  }
108 }
109 
110 void IDP_SetIndexArray(IDProperty *prop, int index, IDProperty *item)
111 {
112  BLI_assert(prop->type == IDP_IDPARRAY);
113 
114  if (index >= prop->len || index < 0) {
115  return;
116  }
117 
118  IDProperty *old = GETPROP(prop, index);
119  if (item != old) {
121 
122  memcpy(old, item, sizeof(IDProperty));
123  }
124 }
125 
127 {
128  BLI_assert(prop->type == IDP_IDPARRAY);
129 
130  return GETPROP(prop, index);
131 }
132 
134 {
135  BLI_assert(prop->type == IDP_IDPARRAY);
136 
137  IDP_ResizeIDPArray(prop, prop->len + 1);
138  IDP_SetIndexArray(prop, prop->len - 1, item);
139 }
140 
141 void IDP_ResizeIDPArray(IDProperty *prop, int newlen)
142 {
143  BLI_assert(prop->type == IDP_IDPARRAY);
144 
145  /* first check if the array buffer size has room */
146  if (newlen <= prop->totallen) {
147  if (newlen < prop->len && prop->totallen - newlen < IDP_ARRAY_REALLOC_LIMIT) {
148  for (int i = newlen; i < prop->len; i++) {
150  }
151 
152  prop->len = newlen;
153  return;
154  }
155  if (newlen >= prop->len) {
156  prop->len = newlen;
157  return;
158  }
159  }
160 
161  /* free trailing items */
162  if (newlen < prop->len) {
163  /* newlen is smaller */
164  for (int i = newlen; i < prop->len; i++) {
166  }
167  }
168 
169  /* NOTE: This code comes from python, here's the corresponding comment. */
170  /* This over-allocates proportional to the list size, making room
171  * for additional growth. The over-allocation is mild, but is
172  * enough to give linear-time amortized behavior over a long
173  * sequence of appends() in the presence of a poorly-performing
174  * system realloc().
175  * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
176  */
177  int newsize = newlen;
178  newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize;
179  prop->data.pointer = MEM_recallocN(prop->data.pointer, sizeof(IDProperty) * (size_t)newsize);
180  prop->len = newlen;
181  prop->totallen = newsize;
182 }
183 
184 /* ----------- Numerical Array Type ----------- */
185 static void idp_resize_group_array(IDProperty *prop, int newlen, void *newarr)
186 {
187  if (prop->subtype != IDP_GROUP) {
188  return;
189  }
190 
191  if (newlen >= prop->len) {
192  /* bigger */
193  IDProperty **array = newarr;
194  IDPropertyTemplate val;
195 
196  for (int a = prop->len; a < newlen; a++) {
197  val.i = 0; /* silence MSVC warning about uninitialized var when debugging */
198  array[a] = IDP_New(IDP_GROUP, &val, "IDP_ResizeArray group");
199  }
200  }
201  else {
202  /* smaller */
203  IDProperty **array = prop->data.pointer;
204 
205  for (int a = newlen; a < prop->len; a++) {
207  }
208  }
209 }
210 
211 void IDP_ResizeArray(IDProperty *prop, int newlen)
212 {
213  const bool is_grow = newlen >= prop->len;
214 
215  /* first check if the array buffer size has room */
216  if (newlen <= prop->totallen && prop->totallen - newlen < IDP_ARRAY_REALLOC_LIMIT) {
217  idp_resize_group_array(prop, newlen, prop->data.pointer);
218  prop->len = newlen;
219  return;
220  }
221 
222  /* NOTE: This code comes from python, here's the corresponding comment. */
223  /* This over-allocates proportional to the list size, making room
224  * for additional growth. The over-allocation is mild, but is
225  * enough to give linear-time amortized behavior over a long
226  * sequence of appends() in the presence of a poorly-performing
227  * system realloc().
228  * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
229  */
230  int newsize = newlen;
231  newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize;
232 
233  if (is_grow == false) {
234  idp_resize_group_array(prop, newlen, prop->data.pointer);
235  }
236 
237  prop->data.pointer = MEM_recallocN(prop->data.pointer,
238  idp_size_table[(int)prop->subtype] * (size_t)newsize);
239 
240  if (is_grow == true) {
241  idp_resize_group_array(prop, newlen, prop->data.pointer);
242  }
243 
244  prop->len = newlen;
245  prop->totallen = newsize;
246 }
247 
249 {
250  if (prop->data.pointer) {
251  idp_resize_group_array(prop, 0, NULL);
252  MEM_freeN(prop->data.pointer);
253  }
254 }
255 
257 {
258  IDPropertyUIData *dst_ui_data = MEM_dupallocN(prop->ui_data);
259 
260  /* Copy extra type specific data. */
261  switch (IDP_ui_data_type(prop)) {
264  IDPropertyUIDataString *dst = (IDPropertyUIDataString *)dst_ui_data;
265  dst->default_value = MEM_dupallocN(src->default_value);
266  break;
267  }
268  case IDP_UI_DATA_TYPE_ID: {
269  break;
270  }
271  case IDP_UI_DATA_TYPE_INT: {
272  const IDPropertyUIDataInt *src = (const IDPropertyUIDataInt *)prop->ui_data;
273  IDPropertyUIDataInt *dst = (IDPropertyUIDataInt *)dst_ui_data;
274  dst->default_array = MEM_dupallocN(src->default_array);
275  break;
276  }
277  case IDP_UI_DATA_TYPE_FLOAT: {
278  const IDPropertyUIDataFloat *src = (const IDPropertyUIDataFloat *)prop->ui_data;
279  IDPropertyUIDataFloat *dst = (IDPropertyUIDataFloat *)dst_ui_data;
280  dst->default_array = MEM_dupallocN(src->default_array);
281  break;
282  }
284  break;
285  }
286  }
287 
288  dst_ui_data->description = MEM_dupallocN(prop->ui_data->description);
289 
290  return dst_ui_data;
291 }
292 
293 static IDProperty *idp_generic_copy(const IDProperty *prop, const int UNUSED(flag))
294 {
295  IDProperty *newp = MEM_callocN(sizeof(IDProperty), __func__);
296 
297  BLI_strncpy(newp->name, prop->name, MAX_IDPROP_NAME);
298  newp->type = prop->type;
299  newp->flag = prop->flag;
300  newp->data.val = prop->data.val;
301  newp->data.val2 = prop->data.val2;
302 
303  if (prop->ui_data != NULL) {
304  newp->ui_data = IDP_ui_data_copy(prop);
305  }
306 
307  return newp;
308 }
309 
310 static IDProperty *IDP_CopyArray(const IDProperty *prop, const int flag)
311 {
312  IDProperty *newp = idp_generic_copy(prop, flag);
313 
314  if (prop->data.pointer) {
315  newp->data.pointer = MEM_dupallocN(prop->data.pointer);
316 
317  if (prop->type == IDP_GROUP) {
318  IDProperty **array = newp->data.pointer;
319  int a;
320 
321  for (a = 0; a < prop->len; a++) {
322  array[a] = IDP_CopyProperty_ex(array[a], flag);
323  }
324  }
325  }
326  newp->len = prop->len;
327  newp->subtype = prop->subtype;
328  newp->totallen = prop->totallen;
329 
330  return newp;
331 }
332 
335 /* -------------------------------------------------------------------- */
339 IDProperty *IDP_NewString(const char *st, const char *name, int maxlen)
340 {
341  IDProperty *prop = MEM_callocN(sizeof(IDProperty), "IDProperty string");
342 
343  if (st == NULL) {
344  prop->data.pointer = MEM_mallocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1");
345  *IDP_String(prop) = '\0';
347  prop->len = 1; /* NULL string, has len of 1 to account for null byte. */
348  }
349  else {
350  /* include null terminator '\0' */
351  int stlen = (int)strlen(st) + 1;
352 
353  if (maxlen > 0 && maxlen < stlen) {
354  stlen = maxlen;
355  }
356 
357  prop->data.pointer = MEM_mallocN((size_t)stlen, "id property string 2");
358  prop->len = prop->totallen = stlen;
359  BLI_strncpy(prop->data.pointer, st, (size_t)stlen);
360  }
361 
362  prop->type = IDP_STRING;
363  BLI_strncpy(prop->name, name, MAX_IDPROP_NAME);
364 
365  return prop;
366 }
367 
368 static IDProperty *IDP_CopyString(const IDProperty *prop, const int flag)
369 {
370  BLI_assert(prop->type == IDP_STRING);
371  IDProperty *newp = idp_generic_copy(prop, flag);
372 
373  if (prop->data.pointer) {
374  newp->data.pointer = MEM_dupallocN(prop->data.pointer);
375  }
376  newp->len = prop->len;
377  newp->subtype = prop->subtype;
378  newp->totallen = prop->totallen;
379 
380  return newp;
381 }
382 
383 void IDP_AssignString(IDProperty *prop, const char *st, int maxlen)
384 {
385  BLI_assert(prop->type == IDP_STRING);
386  int stlen = (int)strlen(st);
387  if (maxlen > 0 && maxlen < stlen) {
388  stlen = maxlen;
389  }
390 
391  if (prop->subtype == IDP_STRING_SUB_BYTE) {
392  IDP_ResizeArray(prop, stlen);
393  memcpy(prop->data.pointer, st, (size_t)stlen);
394  }
395  else {
396  stlen++;
397  IDP_ResizeArray(prop, stlen);
398  BLI_strncpy(prop->data.pointer, st, (size_t)stlen);
399  }
400 }
401 
402 void IDP_ConcatStringC(IDProperty *prop, const char *st)
403 {
404  BLI_assert(prop->type == IDP_STRING);
405 
406  int newlen = prop->len + (int)strlen(st);
407  /* We have to remember that prop->len includes the null byte for strings.
408  * so there's no need to add +1 to the resize function. */
409  IDP_ResizeArray(prop, newlen);
410  strcat(prop->data.pointer, st);
411 }
412 
414 {
415  BLI_assert(append->type == IDP_STRING);
416 
417  /* Since ->len for strings includes the NULL byte, we have to subtract one or
418  * we'll get an extra null byte after each concatenation operation. */
419  int newlen = str1->len + append->len - 1;
420  IDP_ResizeArray(str1, newlen);
421  strcat(str1->data.pointer, append->data.pointer);
422 }
423 
425 {
426  BLI_assert(prop->type == IDP_STRING);
427 
428  if (prop->data.pointer) {
429  MEM_freeN(prop->data.pointer);
430  }
431 }
432 
435 /* -------------------------------------------------------------------- */
439 static IDProperty *IDP_CopyID(const IDProperty *prop, const int flag)
440 {
441  BLI_assert(prop->type == IDP_ID);
442  IDProperty *newp = idp_generic_copy(prop, flag);
443 
444  newp->data.pointer = prop->data.pointer;
445  if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
446  id_us_plus(IDP_Id(newp));
447  }
448 
449  return newp;
450 }
451 
452 void IDP_AssignID(IDProperty *prop, ID *id, const int flag)
453 {
454  BLI_assert(prop->type == IDP_ID);
455 
456  if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0 && IDP_Id(prop) != NULL) {
457  id_us_min(IDP_Id(prop));
458  }
459 
460  prop->data.pointer = id;
461 
462  if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
463  id_us_plus(IDP_Id(prop));
464  }
465 }
466 
469 /* -------------------------------------------------------------------- */
476 static IDProperty *IDP_CopyGroup(const IDProperty *prop, const int flag)
477 {
478  BLI_assert(prop->type == IDP_GROUP);
479  IDProperty *newp = idp_generic_copy(prop, flag);
480  newp->len = prop->len;
481  newp->subtype = prop->subtype;
482 
483  LISTBASE_FOREACH (IDProperty *, link, &prop->data.group) {
484  BLI_addtail(&newp->data.group, IDP_CopyProperty_ex(link, flag));
485  }
486 
487  return newp;
488 }
489 
491 {
492  BLI_assert(dest->type == IDP_GROUP);
493  BLI_assert(src->type == IDP_GROUP);
494 
495  LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) {
496  IDProperty *other = BLI_findstring(&dest->data.group, prop->name, offsetof(IDProperty, name));
497  if (other && prop->type == other->type) {
498  switch (prop->type) {
499  case IDP_INT:
500  case IDP_FLOAT:
501  case IDP_DOUBLE:
502  other->data = prop->data;
503  break;
504  case IDP_GROUP:
505  IDP_SyncGroupValues(other, prop);
506  break;
507  default: {
508  BLI_insertlinkreplace(&dest->data.group, other, IDP_CopyProperty(prop));
509  IDP_FreeProperty(other);
510  break;
511  }
512  }
513  }
514  }
515 }
516 
517 void IDP_SyncGroupTypes(IDProperty *dest, const IDProperty *src, const bool do_arraylen)
518 {
519  LISTBASE_FOREACH_MUTABLE (IDProperty *, prop_dst, &dest->data.group) {
520  const IDProperty *prop_src = IDP_GetPropertyFromGroup((IDProperty *)src, prop_dst->name);
521  if (prop_src != NULL) {
522  /* check of we should replace? */
523  if ((prop_dst->type != prop_src->type || prop_dst->subtype != prop_src->subtype) ||
524  (do_arraylen && ELEM(prop_dst->type, IDP_ARRAY, IDP_IDPARRAY) &&
525  (prop_src->len != prop_dst->len))) {
526  BLI_insertlinkreplace(&dest->data.group, prop_dst, IDP_CopyProperty(prop_src));
527  IDP_FreeProperty(prop_dst);
528  }
529  else if (prop_dst->type == IDP_GROUP) {
530  IDP_SyncGroupTypes(prop_dst, prop_src, do_arraylen);
531  }
532  }
533  else {
534  IDP_FreeFromGroup(dest, prop_dst);
535  }
536  }
537 }
538 
540 {
541  BLI_assert(dest->type == IDP_GROUP);
542  BLI_assert(src->type == IDP_GROUP);
543 
544  LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) {
545  IDProperty *loop;
546  for (loop = dest->data.group.first; loop; loop = loop->next) {
547  if (STREQ(loop->name, prop->name)) {
548  BLI_insertlinkreplace(&dest->data.group, loop, IDP_CopyProperty(prop));
549  IDP_FreeProperty(loop);
550  break;
551  }
552  }
553 
554  /* only add at end if not added yet */
555  if (loop == NULL) {
557  dest->len++;
558  BLI_addtail(&dest->data.group, copy);
559  }
560  }
561 }
562 
563 void IDP_ReplaceInGroup_ex(IDProperty *group, IDProperty *prop, IDProperty *prop_exist)
564 {
565  BLI_assert(group->type == IDP_GROUP);
566  BLI_assert(prop_exist == IDP_GetPropertyFromGroup(group, prop->name));
567 
568  if (prop_exist != NULL) {
569  BLI_insertlinkreplace(&group->data.group, prop_exist, prop);
570  IDP_FreeProperty(prop_exist);
571  }
572  else {
573  group->len++;
574  BLI_addtail(&group->data.group, prop);
575  }
576 }
577 
579 {
580  IDProperty *prop_exist = IDP_GetPropertyFromGroup(group, prop->name);
581 
582  IDP_ReplaceInGroup_ex(group, prop, prop_exist);
583 }
584 
586  const IDProperty *src,
587  const bool do_overwrite,
588  const int flag)
589 {
590  BLI_assert(dest->type == IDP_GROUP);
591  BLI_assert(src->type == IDP_GROUP);
592 
593  if (do_overwrite) {
594  LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) {
595  if (prop->type == IDP_GROUP) {
596  IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name);
597 
598  if (prop_exist != NULL) {
599  IDP_MergeGroup_ex(prop_exist, prop, do_overwrite, flag);
600  continue;
601  }
602  }
603 
604  IDProperty *copy = IDP_CopyProperty_ex(prop, flag);
606  }
607  }
608  else {
609  LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) {
610  IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name);
611  if (prop_exist != NULL) {
612  if (prop->type == IDP_GROUP) {
613  IDP_MergeGroup_ex(prop_exist, prop, do_overwrite, flag);
614  continue;
615  }
616  }
617  else {
618  IDProperty *copy = IDP_CopyProperty_ex(prop, flag);
619  dest->len++;
620  BLI_addtail(&dest->data.group, copy);
621  }
622  }
623  }
624 }
625 
626 void IDP_MergeGroup(IDProperty *dest, const IDProperty *src, const bool do_overwrite)
627 {
628  IDP_MergeGroup_ex(dest, src, do_overwrite, 0);
629 }
630 
632 {
633  BLI_assert(group->type == IDP_GROUP);
634 
635  if (IDP_GetPropertyFromGroup(group, prop->name) == NULL) {
636  group->len++;
637  BLI_addtail(&group->data.group, prop);
638  return true;
639  }
640 
641  return false;
642 }
643 
644 bool IDP_InsertToGroup(IDProperty *group, IDProperty *previous, IDProperty *pnew)
645 {
646  BLI_assert(group->type == IDP_GROUP);
647 
648  if (IDP_GetPropertyFromGroup(group, pnew->name) == NULL) {
649  group->len++;
650  BLI_insertlinkafter(&group->data.group, previous, pnew);
651  return true;
652  }
653 
654  return false;
655 }
656 
658 {
659  BLI_assert(group->type == IDP_GROUP);
660  BLI_assert(BLI_findindex(&group->data.group, prop) != -1);
661 
662  group->len--;
663  BLI_remlink(&group->data.group, prop);
664 }
665 
667 {
668  IDP_RemoveFromGroup(group, prop);
669  IDP_FreeProperty(prop);
670 }
671 
672 IDProperty *IDP_GetPropertyFromGroup(const IDProperty *prop, const char *name)
673 {
674  BLI_assert(prop->type == IDP_GROUP);
675 
676  return (IDProperty *)BLI_findstring(&prop->data.group, name, offsetof(IDProperty, name));
677 }
678 IDProperty *IDP_GetPropertyTypeFromGroup(const IDProperty *prop, const char *name, const char type)
679 {
680  IDProperty *idprop = IDP_GetPropertyFromGroup(prop, name);
681  return (idprop && idprop->type == type) ? idprop : NULL;
682 }
683 
684 /* Ok, the way things work, Groups free the ID Property structs of their children.
685  * This is because all ID Property freeing functions free only direct data (not the ID Property
686  * struct itself), but for Groups the child properties *are* considered
687  * direct data. */
688 static void IDP_FreeGroup(IDProperty *prop, const bool do_id_user)
689 {
690  BLI_assert(prop->type == IDP_GROUP);
691 
692  LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) {
693  IDP_FreePropertyContent_ex(loop, do_id_user);
694  }
695  BLI_freelistN(&prop->data.group);
696 }
697 
700 /* -------------------------------------------------------------------- */
705 {
706  switch (prop->type) {
707  case IDP_INT:
708  return IDP_Int(prop);
709  case IDP_DOUBLE:
710  return (int)IDP_Double(prop);
711  case IDP_FLOAT:
712  return (int)IDP_Float(prop);
713  default:
714  return 0;
715  }
716 }
717 
719 {
720  switch (prop->type) {
721  case IDP_DOUBLE:
722  return IDP_Double(prop);
723  case IDP_FLOAT:
724  return (double)IDP_Float(prop);
725  case IDP_INT:
726  return (double)IDP_Int(prop);
727  default:
728  return 0.0;
729  }
730 }
731 
733 {
734  switch (prop->type) {
735  case IDP_FLOAT:
736  return IDP_Float(prop);
737  case IDP_DOUBLE:
738  return (float)IDP_Double(prop);
739  case IDP_INT:
740  return (float)IDP_Int(prop);
741  default:
742  return 0.0f;
743  }
744 }
745 
746 IDProperty *IDP_CopyProperty_ex(const IDProperty *prop, const int flag)
747 {
748  switch (prop->type) {
749  case IDP_GROUP:
750  return IDP_CopyGroup(prop, flag);
751  case IDP_STRING:
752  return IDP_CopyString(prop, flag);
753  case IDP_ID:
754  return IDP_CopyID(prop, flag);
755  case IDP_ARRAY:
756  return IDP_CopyArray(prop, flag);
757  case IDP_IDPARRAY:
758  return IDP_CopyIDPArray(prop, flag);
759  default:
760  return idp_generic_copy(prop, flag);
761  }
762 }
763 
765 {
766  return IDP_CopyProperty_ex(prop, 0);
767 }
768 
770 {
771  IDProperty *idprop_tmp = IDP_CopyProperty(src);
772  idprop_tmp->prev = dst->prev;
773  idprop_tmp->next = dst->next;
774  SWAP(IDProperty, *dst, *idprop_tmp);
775  IDP_FreeProperty(idprop_tmp);
776 }
777 
778 IDProperty *IDP_GetProperties(ID *id, const bool create_if_needed)
779 {
780  if (id->properties) {
781  return id->properties;
782  }
783 
784  if (create_if_needed) {
785  id->properties = MEM_callocN(sizeof(IDProperty), "IDProperty");
786  id->properties->type = IDP_GROUP;
787  /* NOTE(campbell): Don't overwrite the data's name and type
788  * some functions might need this if they
789  * don't have a real ID, should be named elsewhere. */
790  // strcpy(id->name, "top_level_group");
791  }
792  return id->properties;
793 }
794 
795 bool IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const bool is_strict)
796 {
797  if (prop1 == NULL && prop2 == NULL) {
798  return true;
799  }
800  if (prop1 == NULL || prop2 == NULL) {
801  return is_strict ? false : true;
802  }
803  if (prop1->type != prop2->type) {
804  return false;
805  }
806 
807  switch (prop1->type) {
808  case IDP_INT:
809  return (IDP_Int(prop1) == IDP_Int(prop2));
810  case IDP_FLOAT:
811 #if !defined(NDEBUG) && defined(WITH_PYTHON)
812  {
813  float p1 = IDP_Float(prop1);
814  float p2 = IDP_Float(prop2);
815  if ((p1 != p2) && ((fabsf(p1 - p2) / max_ff(p1, p2)) < 0.001f)) {
816  printf(
817  "WARNING: Comparing two float properties that have nearly the same value (%f vs. "
818  "%f)\n",
819  p1,
820  p2);
821  printf(" p1: ");
822  IDP_print(prop1);
823  printf(" p2: ");
824  IDP_print(prop2);
825  }
826  }
827 #endif
828  return (IDP_Float(prop1) == IDP_Float(prop2));
829  case IDP_DOUBLE:
830  return (IDP_Double(prop1) == IDP_Double(prop2));
831  case IDP_STRING: {
832  return (((prop1->len == prop2->len) &&
833  STREQLEN(IDP_String(prop1), IDP_String(prop2), (size_t)prop1->len)));
834  }
835  case IDP_ARRAY:
836  if (prop1->len == prop2->len && prop1->subtype == prop2->subtype) {
837  return (memcmp(IDP_Array(prop1),
838  IDP_Array(prop2),
839  idp_size_table[(int)prop1->subtype] * (size_t)prop1->len) == 0);
840  }
841  return false;
842  case IDP_GROUP: {
843  if (is_strict && prop1->len != prop2->len) {
844  return false;
845  }
846 
847  LISTBASE_FOREACH (IDProperty *, link1, &prop1->data.group) {
848  IDProperty *link2 = IDP_GetPropertyFromGroup(prop2, link1->name);
849 
850  if (!IDP_EqualsProperties_ex(link1, link2, is_strict)) {
851  return false;
852  }
853  }
854 
855  return true;
856  }
857  case IDP_IDPARRAY: {
858  IDProperty *array1 = IDP_IDPArray(prop1);
859  IDProperty *array2 = IDP_IDPArray(prop2);
860 
861  if (prop1->len != prop2->len) {
862  return false;
863  }
864 
865  for (int i = 0; i < prop1->len; i++) {
866  if (!IDP_EqualsProperties_ex(&array1[i], &array2[i], is_strict)) {
867  return false;
868  }
869  }
870  return true;
871  }
872  case IDP_ID:
873  return (IDP_Id(prop1) == IDP_Id(prop2));
874  default:
876  break;
877  }
878 
879  return true;
880 }
881 
883 {
884  return IDP_EqualsProperties_ex(prop1, prop2, true);
885 }
886 
887 IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char *name)
888 {
889  IDProperty *prop = NULL;
890 
891  switch (type) {
892  case IDP_INT:
893  prop = MEM_callocN(sizeof(IDProperty), "IDProperty int");
894  prop->data.val = val->i;
895  break;
896  case IDP_FLOAT:
897  prop = MEM_callocN(sizeof(IDProperty), "IDProperty float");
898  *(float *)&prop->data.val = val->f;
899  break;
900  case IDP_DOUBLE:
901  prop = MEM_callocN(sizeof(IDProperty), "IDProperty double");
902  *(double *)&prop->data.val = val->d;
903  break;
904  case IDP_ARRAY: {
905  /* for now, we only support float and int and double arrays */
907  prop = MEM_callocN(sizeof(IDProperty), "IDProperty array");
908  prop->subtype = val->array.type;
909  if (val->array.len) {
910  prop->data.pointer = MEM_callocN(
911  idp_size_table[val->array.type] * (size_t)val->array.len, "id property array");
912  }
913  prop->len = prop->totallen = val->array.len;
914  break;
915  }
916  CLOG_ERROR(&LOG, "bad array type.");
917  return NULL;
918  }
919  case IDP_STRING: {
920  const char *st = val->string.str;
921 
922  prop = MEM_callocN(sizeof(IDProperty), "IDProperty string");
923  if (val->string.subtype == IDP_STRING_SUB_BYTE) {
924  /* NOTE: Intentionally not null terminated. */
925  if (st == NULL) {
926  prop->data.pointer = MEM_mallocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1");
927  *IDP_String(prop) = '\0';
929  prop->len = 0;
930  }
931  else {
932  prop->data.pointer = MEM_mallocN((size_t)val->string.len, "id property string 2");
933  prop->len = prop->totallen = val->string.len;
934  memcpy(prop->data.pointer, st, (size_t)val->string.len);
935  }
937  }
938  else {
939  if (st == NULL || val->string.len <= 1) {
940  prop->data.pointer = MEM_mallocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1");
941  *IDP_String(prop) = '\0';
943  /* NULL string, has len of 1 to account for null byte. */
944  prop->len = 1;
945  }
946  else {
947  BLI_assert((int)val->string.len <= (int)strlen(st) + 1);
948  prop->data.pointer = MEM_mallocN((size_t)val->string.len, "id property string 3");
949  memcpy(prop->data.pointer, st, (size_t)val->string.len - 1);
950  IDP_String(prop)[val->string.len - 1] = '\0';
951  prop->len = prop->totallen = val->string.len;
952  }
954  }
955  break;
956  }
957  case IDP_GROUP: {
958  /* Values are set properly by calloc. */
959  prop = MEM_callocN(sizeof(IDProperty), "IDProperty group");
960  break;
961  }
962  case IDP_ID: {
963  prop = MEM_callocN(sizeof(IDProperty), "IDProperty datablock");
964  prop->data.pointer = (void *)val->id;
965  prop->type = IDP_ID;
966  id_us_plus(IDP_Id(prop));
967  break;
968  }
969  default: {
970  prop = MEM_callocN(sizeof(IDProperty), "IDProperty array");
971  break;
972  }
973  }
974 
975  prop->type = type;
976  BLI_strncpy(prop->name, name, MAX_IDPROP_NAME);
977 
978  return prop;
979 }
980 
983  const IDPropertyUIData *other)
984 {
985  if (ui_data->description != other->description) {
986  MEM_SAFE_FREE(ui_data->description);
987  }
988 
989  switch (type) {
991  const IDPropertyUIDataString *other_string = (const IDPropertyUIDataString *)other;
992  IDPropertyUIDataString *ui_data_string = (IDPropertyUIDataString *)ui_data;
993  if (ui_data_string->default_value != other_string->default_value) {
994  MEM_SAFE_FREE(ui_data_string->default_value);
995  }
996  break;
997  }
998  case IDP_UI_DATA_TYPE_ID: {
999  break;
1000  }
1001  case IDP_UI_DATA_TYPE_INT: {
1002  const IDPropertyUIDataInt *other_int = (const IDPropertyUIDataInt *)other;
1003  IDPropertyUIDataInt *ui_data_int = (IDPropertyUIDataInt *)ui_data;
1004  if (ui_data_int->default_array != other_int->default_array) {
1005  MEM_SAFE_FREE(ui_data_int->default_array);
1006  }
1007  break;
1008  }
1009  case IDP_UI_DATA_TYPE_FLOAT: {
1010  const IDPropertyUIDataFloat *other_float = (const IDPropertyUIDataFloat *)other;
1011  IDPropertyUIDataFloat *ui_data_float = (IDPropertyUIDataFloat *)ui_data;
1012  if (ui_data_float->default_array != other_float->default_array) {
1013  MEM_SAFE_FREE(ui_data_float->default_array);
1014  }
1015  break;
1016  }
1018  break;
1019  }
1020  }
1021 }
1022 
1024 {
1025  switch (IDP_ui_data_type(prop)) {
1026  case IDP_UI_DATA_TYPE_STRING: {
1027  IDPropertyUIDataString *ui_data_string = (IDPropertyUIDataString *)prop->ui_data;
1028  MEM_SAFE_FREE(ui_data_string->default_value);
1029  break;
1030  }
1031  case IDP_UI_DATA_TYPE_ID: {
1032  break;
1033  }
1034  case IDP_UI_DATA_TYPE_INT: {
1035  IDPropertyUIDataInt *ui_data_int = (IDPropertyUIDataInt *)prop->ui_data;
1036  MEM_SAFE_FREE(ui_data_int->default_array);
1037  break;
1038  }
1039  case IDP_UI_DATA_TYPE_FLOAT: {
1040  IDPropertyUIDataFloat *ui_data_float = (IDPropertyUIDataFloat *)prop->ui_data;
1041  MEM_SAFE_FREE(ui_data_float->default_array);
1042  break;
1043  }
1045  break;
1046  }
1047  }
1048 
1050 
1051  MEM_freeN(prop->ui_data);
1052  prop->ui_data = NULL;
1053 }
1054 
1055 void IDP_FreePropertyContent_ex(IDProperty *prop, const bool do_id_user)
1056 {
1057  switch (prop->type) {
1058  case IDP_ARRAY:
1059  IDP_FreeArray(prop);
1060  break;
1061  case IDP_STRING:
1062  IDP_FreeString(prop);
1063  break;
1064  case IDP_GROUP:
1065  IDP_FreeGroup(prop, do_id_user);
1066  break;
1067  case IDP_IDPARRAY:
1068  IDP_FreeIDPArray(prop, do_id_user);
1069  break;
1070  case IDP_ID:
1071  if (do_id_user) {
1072  id_us_min(IDP_Id(prop));
1073  }
1074  break;
1075  }
1076 
1077  if (prop->ui_data != NULL) {
1078  IDP_ui_data_free(prop);
1079  }
1080 }
1081 
1083 {
1084  IDP_FreePropertyContent_ex(prop, true);
1085 }
1086 
1087 void IDP_FreeProperty_ex(IDProperty *prop, const bool do_id_user)
1088 {
1089  IDP_FreePropertyContent_ex(prop, do_id_user);
1090  MEM_freeN(prop);
1091 }
1092 
1094 {
1096  MEM_freeN(prop);
1097 }
1098 
1100 {
1102  prop->data.pointer = NULL;
1103  prop->len = prop->totallen = 0;
1104 }
1105 
1106 void IDP_Reset(IDProperty *prop, const IDProperty *reference)
1107 {
1108  if (prop == NULL) {
1109  return;
1110  }
1111  IDP_ClearProperty(prop);
1112  if (reference != NULL) {
1113  IDP_MergeGroup(prop, reference, true);
1114  }
1115 }
1116 
1117 void IDP_foreach_property(IDProperty *id_property_root,
1118  const int type_filter,
1120  void *user_data)
1121 {
1122  if (!id_property_root) {
1123  return;
1124  }
1125 
1126  if (type_filter == 0 || (1 << id_property_root->type) & type_filter) {
1127  callback(id_property_root, user_data);
1128  }
1129 
1130  /* Recursive call into container types of ID properties. */
1131  switch (id_property_root->type) {
1132  case IDP_GROUP: {
1133  LISTBASE_FOREACH (IDProperty *, loop, &id_property_root->data.group) {
1134  IDP_foreach_property(loop, type_filter, callback, user_data);
1135  }
1136  break;
1137  }
1138  case IDP_IDPARRAY: {
1139  IDProperty *loop = IDP_Array(id_property_root);
1140  for (int i = 0; i < id_property_root->len; i++) {
1141  IDP_foreach_property(&loop[i], type_filter, callback, user_data);
1142  }
1143  break;
1144  }
1145  default:
1146  break; /* Nothing to do here with other types of IDProperties... */
1147  }
1148 }
1149 
1150 void IDP_WriteProperty_OnlyData(const IDProperty *prop, BlendWriter *writer);
1151 
1152 static void write_ui_data(const IDProperty *prop, BlendWriter *writer)
1153 {
1154  IDPropertyUIData *ui_data = prop->ui_data;
1155 
1156  BLO_write_string(writer, ui_data->description);
1157 
1158  switch (IDP_ui_data_type(prop)) {
1159  case IDP_UI_DATA_TYPE_STRING: {
1160  IDPropertyUIDataString *ui_data_string = (IDPropertyUIDataString *)ui_data;
1161  BLO_write_string(writer, ui_data_string->default_value);
1162  BLO_write_struct(writer, IDPropertyUIDataString, ui_data);
1163  break;
1164  }
1165  case IDP_UI_DATA_TYPE_ID: {
1166  BLO_write_struct(writer, IDPropertyUIDataID, ui_data);
1167  break;
1168  }
1169  case IDP_UI_DATA_TYPE_INT: {
1170  IDPropertyUIDataInt *ui_data_int = (IDPropertyUIDataInt *)ui_data;
1171  if (prop->type == IDP_ARRAY) {
1173  writer, (uint)ui_data_int->default_array_len, (int32_t *)ui_data_int->default_array);
1174  }
1175  BLO_write_struct(writer, IDPropertyUIDataInt, ui_data);
1176  break;
1177  }
1178  case IDP_UI_DATA_TYPE_FLOAT: {
1179  IDPropertyUIDataFloat *ui_data_float = (IDPropertyUIDataFloat *)ui_data;
1180  if (prop->type == IDP_ARRAY) {
1182  writer, (uint)ui_data_float->default_array_len, ui_data_float->default_array);
1183  }
1184  BLO_write_struct(writer, IDPropertyUIDataFloat, ui_data);
1185  break;
1186  }
1189  break;
1190  }
1191  }
1192 }
1193 
1194 static void IDP_WriteArray(const IDProperty *prop, BlendWriter *writer)
1195 {
1196  /* Remember to set #IDProperty.totallen to len in the linking code! */
1197  if (prop->data.pointer) {
1198  BLO_write_raw(writer, MEM_allocN_len(prop->data.pointer), prop->data.pointer);
1199 
1200  if (prop->subtype == IDP_GROUP) {
1201  IDProperty **array = prop->data.pointer;
1202  int a;
1203 
1204  for (a = 0; a < prop->len; a++) {
1205  IDP_BlendWrite(writer, array[a]);
1206  }
1207  }
1208  }
1209 }
1210 
1211 static void IDP_WriteIDPArray(const IDProperty *prop, BlendWriter *writer)
1212 {
1213  /* Remember to set #IDProperty.totallen to len in the linking code! */
1214  if (prop->data.pointer) {
1215  const IDProperty *array = prop->data.pointer;
1216 
1217  BLO_write_struct_array(writer, IDProperty, prop->len, array);
1218 
1219  for (int a = 0; a < prop->len; a++) {
1220  IDP_WriteProperty_OnlyData(&array[a], writer);
1221  }
1222  }
1223 }
1224 
1225 static void IDP_WriteString(const IDProperty *prop, BlendWriter *writer)
1226 {
1227  /* Remember to set #IDProperty.totallen to len in the linking code! */
1228  BLO_write_raw(writer, (size_t)prop->len, prop->data.pointer);
1229 }
1230 
1231 static void IDP_WriteGroup(const IDProperty *prop, BlendWriter *writer)
1232 {
1233  LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) {
1234  IDP_BlendWrite(writer, loop);
1235  }
1236 }
1237 
1238 /* Functions to read/write ID Properties */
1240 {
1241  switch (prop->type) {
1242  case IDP_GROUP:
1243  IDP_WriteGroup(prop, writer);
1244  break;
1245  case IDP_STRING:
1246  IDP_WriteString(prop, writer);
1247  break;
1248  case IDP_ARRAY:
1249  IDP_WriteArray(prop, writer);
1250  break;
1251  case IDP_IDPARRAY:
1252  IDP_WriteIDPArray(prop, writer);
1253  break;
1254  }
1255  if (prop->ui_data != NULL) {
1256  write_ui_data(prop, writer);
1257  }
1258 }
1259 
1260 void IDP_BlendWrite(BlendWriter *writer, const IDProperty *prop)
1261 {
1262  BLO_write_struct(writer, IDProperty, prop);
1263  IDP_WriteProperty_OnlyData(prop, writer);
1264 }
1265 
1266 static void IDP_DirectLinkProperty(IDProperty *prop, BlendDataReader *reader);
1267 
1268 static void read_ui_data(IDProperty *prop, BlendDataReader *reader)
1269 {
1270  BLO_read_data_address(reader, &prop->ui_data);
1271  if (!prop->ui_data) {
1272  /* Can happen when opening more recent files with unknown tyes of IDProperties. */
1273  return;
1274  }
1275  BLO_read_data_address(reader, &prop->ui_data->description);
1276 
1277  switch (IDP_ui_data_type(prop)) {
1278  case IDP_UI_DATA_TYPE_STRING: {
1279  IDPropertyUIDataString *ui_data_string = (IDPropertyUIDataString *)prop->ui_data;
1280  BLO_read_data_address(reader, &ui_data_string->default_value);
1281  break;
1282  }
1283  case IDP_UI_DATA_TYPE_ID: {
1284  break;
1285  }
1286  case IDP_UI_DATA_TYPE_INT: {
1287  IDPropertyUIDataInt *ui_data_int = (IDPropertyUIDataInt *)prop->ui_data;
1288  if (prop->type == IDP_ARRAY) {
1290  reader, ui_data_int->default_array_len, (int **)&ui_data_int->default_array);
1291  }
1292  break;
1293  }
1294  case IDP_UI_DATA_TYPE_FLOAT: {
1295  IDPropertyUIDataFloat *ui_data_float = (IDPropertyUIDataFloat *)prop->ui_data;
1296  if (prop->type == IDP_ARRAY) {
1298  reader, ui_data_float->default_array_len, (double **)&ui_data_float->default_array);
1299  }
1300  break;
1301  }
1304  break;
1305  }
1306  }
1307 }
1308 
1310 {
1311  /* since we didn't save the extra buffer, set totallen to len */
1312  prop->totallen = prop->len;
1313  BLO_read_data_address(reader, &prop->data.pointer);
1314 
1315  IDProperty *array = (IDProperty *)prop->data.pointer;
1316 
1317  /* NOTE:, idp-arrays didn't exist in 2.4x, so the pointer will be cleared
1318  * there's not really anything we can do to correct this, at least don't crash */
1319  if (array == NULL) {
1320  prop->len = 0;
1321  prop->totallen = 0;
1322  }
1323 
1324  for (int i = 0; i < prop->len; i++) {
1325  IDP_DirectLinkProperty(&array[i], reader);
1326  }
1327 }
1328 
1330 {
1331  /* since we didn't save the extra buffer, set totallen to len */
1332  prop->totallen = prop->len;
1333 
1334  if (prop->subtype == IDP_GROUP) {
1335  BLO_read_pointer_array(reader, &prop->data.pointer);
1336  IDProperty **array = prop->data.pointer;
1337 
1338  for (int i = 0; i < prop->len; i++) {
1339  IDP_DirectLinkProperty(array[i], reader);
1340  }
1341  }
1342  else if (prop->subtype == IDP_DOUBLE) {
1343  BLO_read_double_array(reader, prop->len, (double **)&prop->data.pointer);
1344  }
1345  else {
1346  /* also used for floats */
1347  BLO_read_int32_array(reader, prop->len, (int **)&prop->data.pointer);
1348  }
1349 }
1350 
1352 {
1353  /* Since we didn't save the extra string buffer, set totallen to len. */
1354  prop->totallen = prop->len;
1355  BLO_read_data_address(reader, &prop->data.pointer);
1356 }
1357 
1359 {
1360  ListBase *lb = &prop->data.group;
1361 
1362  BLO_read_list(reader, lb);
1363 
1364  /* Link child id properties now. */
1365  LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) {
1366  IDP_DirectLinkProperty(loop, reader);
1367  }
1368 }
1369 
1371 {
1372  switch (prop->type) {
1373  case IDP_GROUP:
1374  IDP_DirectLinkGroup(prop, reader);
1375  break;
1376  case IDP_STRING:
1377  IDP_DirectLinkString(prop, reader);
1378  break;
1379  case IDP_ARRAY:
1380  IDP_DirectLinkArray(prop, reader);
1381  break;
1382  case IDP_IDPARRAY:
1383  IDP_DirectLinkIDPArray(prop, reader);
1384  break;
1385  case IDP_DOUBLE:
1386  /* Workaround for doubles.
1387  * They are stored in the same field as `int val, val2` in the #IDPropertyData struct,
1388  * they have to deal with endianness specifically.
1389  *
1390  * In theory, val and val2 would've already been swapped
1391  * if switch_endian is true, so we have to first un-swap
1392  * them then re-swap them as a single 64-bit entity. */
1393  if (BLO_read_requires_endian_switch(reader)) {
1397  }
1398  break;
1399  case IDP_INT:
1400  case IDP_FLOAT:
1401  case IDP_ID:
1402  break; /* Nothing special to do here. */
1403  default:
1404  /* Unknown IDP type, nuke it (we cannot handle unknown types everywhere in code,
1405  * IDP are way too polymorphic to do it safely. */
1406  printf(
1407  "%s: found unknown IDProperty type %d, reset to Integer one !\n", __func__, prop->type);
1408  /* NOTE: we do not attempt to free unknown prop, we have no way to know how to do that! */
1409  prop->type = IDP_INT;
1410  prop->subtype = 0;
1411  IDP_Int(prop) = 0;
1412  }
1413 
1414  if (prop->ui_data != NULL) {
1415  read_ui_data(prop, reader);
1416  }
1417 }
1418 
1419 void IDP_BlendReadData_impl(BlendDataReader *reader, IDProperty **prop, const char *caller_func_id)
1420 {
1421  if (*prop) {
1422  if ((*prop)->type == IDP_GROUP) {
1423  IDP_DirectLinkGroup(*prop, reader);
1424  }
1425  else {
1426  /* corrupt file! */
1427  printf("%s: found non group data, freeing type %d!\n", caller_func_id, (*prop)->type);
1428  /* don't risk id, data's likely corrupt. */
1429  // IDP_FreePropertyContent(*prop);
1430  *prop = NULL;
1431  }
1432  }
1433 }
1434 
1436 {
1437  if (!prop) {
1438  return;
1439  }
1440 
1441  switch (prop->type) {
1442  case IDP_ID: /* PointerProperty */
1443  {
1444  void *newaddr = BLO_read_get_new_id_address(reader, lib, IDP_Id(prop));
1445  if (IDP_Id(prop) && !newaddr && G.debug) {
1446  printf("Error while loading \"%s\". Data not found in file!\n", prop->name);
1447  }
1448  prop->data.pointer = newaddr;
1449  break;
1450  }
1451  case IDP_IDPARRAY: /* CollectionProperty */
1452  {
1453  IDProperty *idp_array = IDP_IDPArray(prop);
1454  for (int i = 0; i < prop->len; i++) {
1455  IDP_BlendReadLib(reader, lib, &(idp_array[i]));
1456  }
1457  break;
1458  }
1459  case IDP_GROUP: /* PointerProperty */
1460  {
1461  LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) {
1462  IDP_BlendReadLib(reader, lib, loop);
1463  }
1464  break;
1465  }
1466  default:
1467  break; /* Nothing to do for other IDProps. */
1468  }
1469 }
1470 
1471 void IDP_BlendReadExpand(struct BlendExpander *expander, IDProperty *prop)
1472 {
1473  if (!prop) {
1474  return;
1475  }
1476 
1477  switch (prop->type) {
1478  case IDP_ID:
1479  BLO_expand(expander, IDP_Id(prop));
1480  break;
1481  case IDP_IDPARRAY: {
1482  IDProperty *idp_array = IDP_IDPArray(prop);
1483  for (int i = 0; i < prop->len; i++) {
1484  IDP_BlendReadExpand(expander, &idp_array[i]);
1485  }
1486  break;
1487  }
1488  case IDP_GROUP:
1489  LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) {
1490  IDP_BlendReadExpand(expander, loop);
1491  }
1492  break;
1493  }
1494 }
1495 
1497 {
1498  if (prop->type == IDP_STRING) {
1499  return IDP_UI_DATA_TYPE_STRING;
1500  }
1501  if (prop->type == IDP_ID) {
1502  return IDP_UI_DATA_TYPE_ID;
1503  }
1504  if (prop->type == IDP_INT || (prop->type == IDP_ARRAY && prop->subtype == IDP_INT)) {
1505  return IDP_UI_DATA_TYPE_INT;
1506  }
1507  if (ELEM(prop->type, IDP_FLOAT, IDP_DOUBLE) ||
1508  (prop->type == IDP_ARRAY && ELEM(prop->subtype, IDP_FLOAT, IDP_DOUBLE))) {
1509  return IDP_UI_DATA_TYPE_FLOAT;
1510  }
1512 }
1513 
1515 {
1517 }
1518 
1520 {
1521  if (prop->ui_data != NULL) {
1522  return prop->ui_data;
1523  }
1524 
1525  switch (IDP_ui_data_type(prop)) {
1526  case IDP_UI_DATA_TYPE_STRING: {
1527  prop->ui_data = MEM_callocN(sizeof(IDPropertyUIDataString), __func__);
1528  break;
1529  }
1530  case IDP_UI_DATA_TYPE_ID: {
1531  IDPropertyUIDataID *ui_data = MEM_callocN(sizeof(IDPropertyUIDataID), __func__);
1532  prop->ui_data = (IDPropertyUIData *)ui_data;
1533  break;
1534  }
1535  case IDP_UI_DATA_TYPE_INT: {
1536  IDPropertyUIDataInt *ui_data = MEM_callocN(sizeof(IDPropertyUIDataInt), __func__);
1537  ui_data->min = INT_MIN;
1538  ui_data->max = INT_MAX;
1539  ui_data->soft_min = INT_MIN;
1540  ui_data->soft_max = INT_MAX;
1541  ui_data->step = 1;
1542  prop->ui_data = (IDPropertyUIData *)ui_data;
1543  break;
1544  }
1545  case IDP_UI_DATA_TYPE_FLOAT: {
1546  IDPropertyUIDataFloat *ui_data = MEM_callocN(sizeof(IDPropertyUIDataFloat), __func__);
1547  ui_data->min = -FLT_MAX;
1548  ui_data->max = FLT_MAX;
1549  ui_data->soft_min = -FLT_MAX;
1550  ui_data->soft_max = FLT_MAX;
1551  ui_data->step = 1.0f;
1552  ui_data->precision = 3;
1553  prop->ui_data = (IDPropertyUIData *)ui_data;
1554  break;
1555  }
1557  /* UI data not supported for remaining types, this shouldn't be called in those cases. */
1559  break;
1560  }
1561  }
1562 
1563  return prop->ui_data;
1564 }
1565 
#define IDP_Float(prop)
Definition: BKE_idprop.h:269
#define IDP_IDPArray(prop)
Definition: BKE_idprop.h:272
#define IDP_Int(prop)
Definition: BKE_idprop.h:244
#define IDP_Id(prop)
Definition: BKE_idprop.h:273
void(* IDPForeachPropertyCallback)(struct IDProperty *id_property, void *user_data)
Definition: BKE_idprop.h:295
void IDP_print(const struct IDProperty *prop)
eIDPropertyUIDataType
Definition: BKE_idprop.h:325
@ IDP_UI_DATA_TYPE_ID
Definition: BKE_idprop.h:335
@ IDP_UI_DATA_TYPE_UNSUPPORTED
Definition: BKE_idprop.h:327
@ IDP_UI_DATA_TYPE_INT
Definition: BKE_idprop.h:329
@ IDP_UI_DATA_TYPE_FLOAT
Definition: BKE_idprop.h:331
@ IDP_UI_DATA_TYPE_STRING
Definition: BKE_idprop.h:333
#define IDP_String(prop)
Definition: BKE_idprop.h:271
#define IDP_Double(prop)
Definition: BKE_idprop.h:270
#define IDP_Array(prop)
Definition: BKE_idprop.h:245
@ LIB_ID_CREATE_NO_USER_REFCOUNT
Definition: BKE_lib_id.h:126
void id_us_min(struct ID *id)
Definition: lib_id.c:313
void id_us_plus(struct ID *id)
Definition: lib_id.c:305
#define BLI_assert_unreachable()
Definition: BLI_assert.h:93
#define BLI_assert(a)
Definition: BLI_assert.h:46
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:336
void BLI_insertlinkreplace(ListBase *listbase, void *vreplacelink, void *vnewlink) ATTR_NONNULL(1
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
Definition: BLI_listbase.h:354
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition: listbase.c:301
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:466
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:100
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void * BLI_findstring(const struct ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
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, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
unsigned int uint
Definition: BLI_sys_types.h:67
#define SWAP(type, a, b)
#define STREQLEN(a, b, n)
#define UNUSED(x)
#define ELEM(...)
#define STREQ(a, b)
void BLO_write_double_array(BlendWriter *writer, uint num, const double *data_ptr)
Definition: writefile.c:1586
#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:5138
void BLO_write_int32_array(BlendWriter *writer, uint num, const int32_t *data_ptr)
Definition: writefile.c:1571
void BLO_read_double_array(BlendDataReader *reader, int array_size, double **ptr_p)
Definition: readfile.c:5206
void BLO_read_int32_array(BlendDataReader *reader, int array_size, int32_t **ptr_p)
Definition: readfile.c:5177
#define BLO_write_struct(writer, struct_name, data_ptr)
void BLO_read_list(BlendDataReader *reader, struct ListBase *list)
Definition: readfile.c:5172
void BLO_write_string(BlendWriter *writer, const char *data_ptr)
Definition: writefile.c:1601
#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:5143
void BLO_write_raw(BlendWriter *writer, size_t size_in_bytes, const void *data_ptr)
Definition: writefile.c:1489
void BLO_read_pointer_array(BlendDataReader *reader, void **ptr_p)
Definition: readfile.c:5245
typedef double(DMatrix)[4][4]
#define CLOG_ERROR(clg_ref,...)
Definition: CLG_log.h:190
@ IDP_STRING_SUB_UTF8
Definition: DNA_ID.h:164
@ IDP_STRING_SUB_BYTE
Definition: DNA_ID.h:165
@ IDP_DOUBLE
Definition: DNA_ID.h:143
@ IDP_FLOAT
Definition: DNA_ID.h:138
@ IDP_STRING
Definition: DNA_ID.h:136
@ IDP_IDPARRAY
Definition: DNA_ID.h:144
@ IDP_INT
Definition: DNA_ID.h:137
@ IDP_GROUP
Definition: DNA_ID.h:141
@ IDP_ARRAY
Definition: DNA_ID.h:140
@ IDP_ID
Definition: DNA_ID.h:142
#define DEFAULT_ALLOC_FOR_NULL_STRINGS
Definition: DNA_ID.h:132
#define MAX_IDPROP_NAME
Definition: DNA_ID.h:131
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)
#define MEM_SAFE_FREE(v)
void * user_data
DEGForeachIDComponentCallback callback
SyclQueue void void * src
SyclQueue void * dest
int len
Definition: draw_manager.c:108
DRWShaderLibrary * lib
#define IDP_ARRAY_REALLOC_LIMIT
Definition: idprop.c:38
void IDP_SyncGroupTypes(IDProperty *dest, const IDProperty *src, const bool do_arraylen)
Definition: idprop.c:517
void IDP_Reset(IDProperty *prop, const IDProperty *reference)
Definition: idprop.c:1106
void IDP_ui_data_free(IDProperty *prop)
Definition: idprop.c:1023
bool IDP_InsertToGroup(IDProperty *group, IDProperty *previous, IDProperty *pnew)
Definition: idprop.c:644
bool IDP_AddToGroup(IDProperty *group, IDProperty *prop)
Definition: idprop.c:631
static void IDP_WriteGroup(const IDProperty *prop, BlendWriter *writer)
Definition: idprop.c:1231
IDProperty * IDP_GetProperties(ID *id, const bool create_if_needed)
Definition: idprop.c:778
void IDP_ConcatStringC(IDProperty *prop, const char *st)
Definition: idprop.c:402
float IDP_coerce_to_float_or_zero(const IDProperty *prop)
Definition: idprop.c:732
void IDP_ConcatString(IDProperty *str1, IDProperty *append)
Definition: idprop.c:413
void IDP_BlendReadExpand(struct BlendExpander *expander, IDProperty *prop)
Definition: idprop.c:1471
bool IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const bool is_strict)
Definition: idprop.c:795
eIDPropertyUIDataType IDP_ui_data_type(const IDProperty *prop)
Definition: idprop.c:1496
bool IDP_ui_data_supported(const IDProperty *prop)
Definition: idprop.c:1514
static void idp_resize_group_array(IDProperty *prop, int newlen, void *newarr)
Definition: idprop.c:185
IDProperty * IDP_NewString(const char *st, const char *name, int maxlen)
Definition: idprop.c:339
void IDP_SyncGroupValues(IDProperty *dest, const IDProperty *src)
Definition: idprop.c:490
IDProperty * IDP_CopyProperty(const IDProperty *prop)
Definition: idprop.c:764
void IDP_ReplaceGroupInGroup(IDProperty *dest, const IDProperty *src)
Definition: idprop.c:539
#define GETPROP(prop, i)
Definition: idprop.c:59
void IDP_MergeGroup_ex(IDProperty *dest, const IDProperty *src, const bool do_overwrite, const int flag)
Definition: idprop.c:585
static IDProperty * IDP_CopyArray(const IDProperty *prop, const int flag)
Definition: idprop.c:310
void IDP_foreach_property(IDProperty *id_property_root, const int type_filter, IDPForeachPropertyCallback callback, void *user_data)
Definition: idprop.c:1117
static IDProperty * IDP_CopyID(const IDProperty *prop, const int flag)
Definition: idprop.c:439
static void IDP_FreeIDPArray(IDProperty *prop, const bool do_id_user)
Definition: idprop.c:97
void IDP_FreeString(IDProperty *prop)
Definition: idprop.c:424
static IDProperty * IDP_CopyGroup(const IDProperty *prop, const int flag)
Definition: idprop.c:476
static void IDP_DirectLinkIDPArray(IDProperty *prop, BlendDataReader *reader)
Definition: idprop.c:1309
void IDP_WriteProperty_OnlyData(const IDProperty *prop, BlendWriter *writer)
Definition: idprop.c:1239
void IDP_CopyPropertyContent(IDProperty *dst, IDProperty *src)
Definition: idprop.c:769
void IDP_RemoveFromGroup(IDProperty *group, IDProperty *prop)
Definition: idprop.c:657
IDProperty * IDP_NewIDPArray(const char *name)
Definition: idprop.c:63
void IDP_FreeProperty(IDProperty *prop)
Definition: idprop.c:1093
static size_t idp_size_table[]
Definition: idprop.c:43
void IDP_AssignID(IDProperty *prop, ID *id, const int flag)
Definition: idprop.c:452
int IDP_coerce_to_int_or_zero(const IDProperty *prop)
Definition: idprop.c:704
IDProperty * IDP_CopyProperty_ex(const IDProperty *prop, const int flag)
Definition: idprop.c:746
void IDP_FreeProperty_ex(IDProperty *prop, const bool do_id_user)
Definition: idprop.c:1087
void IDP_AssignString(IDProperty *prop, const char *st, int maxlen)
Definition: idprop.c:383
static IDProperty * IDP_CopyString(const IDProperty *prop, const int flag)
Definition: idprop.c:368
void IDP_FreePropertyContent(IDProperty *prop)
Definition: idprop.c:1082
void IDP_ReplaceInGroup_ex(IDProperty *group, IDProperty *prop, IDProperty *prop_exist)
Definition: idprop.c:563
void IDP_BlendReadLib(BlendLibReader *reader, Library *lib, IDProperty *prop)
Definition: idprop.c:1435
void IDP_FreePropertyContent_ex(IDProperty *prop, const bool do_id_user)
Definition: idprop.c:1055
static void IDP_DirectLinkGroup(IDProperty *prop, BlendDataReader *reader)
Definition: idprop.c:1358
void IDP_FreeFromGroup(IDProperty *group, IDProperty *prop)
Definition: idprop.c:666
static void IDP_DirectLinkString(IDProperty *prop, BlendDataReader *reader)
Definition: idprop.c:1351
void IDP_ClearProperty(IDProperty *prop)
Definition: idprop.c:1099
static IDProperty * idp_generic_copy(const IDProperty *prop, const int UNUSED(flag))
Definition: idprop.c:293
IDPropertyUIData * IDP_ui_data_ensure(IDProperty *prop)
Definition: idprop.c:1519
IDProperty * IDP_GetPropertyFromGroup(const IDProperty *prop, const char *name)
Definition: idprop.c:672
double IDP_coerce_to_double_or_zero(const IDProperty *prop)
Definition: idprop.c:718
void IDP_ResizeIDPArray(IDProperty *prop, int newlen)
Definition: idprop.c:141
static void IDP_DirectLinkProperty(IDProperty *prop, BlendDataReader *reader)
Definition: idprop.c:1370
IDPropertyUIData * IDP_ui_data_copy(const IDProperty *prop)
Definition: idprop.c:256
static void IDP_FreeGroup(IDProperty *prop, const bool do_id_user)
Definition: idprop.c:688
void IDP_MergeGroup(IDProperty *dest, const IDProperty *src, const bool do_overwrite)
Definition: idprop.c:626
static void IDP_DirectLinkArray(IDProperty *prop, BlendDataReader *reader)
Definition: idprop.c:1329
IDProperty * IDP_GetIndexArray(IDProperty *prop, int index)
Definition: idprop.c:126
void IDP_AppendArray(IDProperty *prop, IDProperty *item)
Definition: idprop.c:133
static void IDP_WriteString(const IDProperty *prop, BlendWriter *writer)
Definition: idprop.c:1225
IDProperty * IDP_GetPropertyTypeFromGroup(const IDProperty *prop, const char *name, const char type)
Definition: idprop.c:678
static CLG_LogRef LOG
Definition: idprop.c:40
void IDP_SetIndexArray(IDProperty *prop, int index, IDProperty *item)
Definition: idprop.c:110
void IDP_ResizeArray(IDProperty *prop, int newlen)
Definition: idprop.c:211
void IDP_ui_data_free_unique_contents(IDPropertyUIData *ui_data, const eIDPropertyUIDataType type, const IDPropertyUIData *other)
Definition: idprop.c:981
void IDP_ReplaceInGroup(IDProperty *group, IDProperty *prop)
Definition: idprop.c:578
static void IDP_WriteArray(const IDProperty *prop, BlendWriter *writer)
Definition: idprop.c:1194
void IDP_BlendWrite(BlendWriter *writer, const IDProperty *prop)
Definition: idprop.c:1260
static void write_ui_data(const IDProperty *prop, BlendWriter *writer)
Definition: idprop.c:1152
static void read_ui_data(IDProperty *prop, BlendDataReader *reader)
Definition: idprop.c:1268
IDProperty * IDP_CopyIDPArray(const IDProperty *array, const int flag)
Definition: idprop.c:73
void IDP_FreeArray(IDProperty *prop)
Definition: idprop.c:248
static void IDP_WriteIDPArray(const IDProperty *prop, BlendWriter *writer)
Definition: idprop.c:1211
void IDP_BlendReadData_impl(BlendDataReader *reader, IDProperty **prop, const char *caller_func_id)
Definition: idprop.c:1419
bool IDP_EqualsProperties(IDProperty *prop1, IDProperty *prop2)
Definition: idprop.c:882
IDProperty * IDP_New(const char type, const IDPropertyTemplate *val, const char *name)
Definition: idprop.c:887
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:28
size_t(* MEM_allocN_len)(const void *vmemh)
Definition: mallocn.c:26
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
#define G(x, y, z)
#define fabsf(x)
Definition: metal/compat.h:219
static unsigned a[3]
Definition: RandGen.cpp:78
static const pxr::TfToken st("st", pxr::TfToken::Immortal)
static void copy(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node)
__int64 int64_t
Definition: stdint.h:89
signed int int32_t
Definition: stdint.h:77
ListBase group
Definition: DNA_ID.h:101
void * pointer
Definition: DNA_ID.h:100
double * default_array
Definition: DNA_ID.h:74
int default_array_len
Definition: DNA_ID.h:60
int * default_array
Definition: DNA_ID.h:59
char * default_value
Definition: DNA_ID.h:91
char * description
Definition: DNA_ID.h:49
short flag
Definition: DNA_ID.h:109
int len
Definition: DNA_ID.h:121
struct IDProperty * next
Definition: DNA_ID.h:107
IDPropertyUIData * ui_data
Definition: DNA_ID.h:128
char name[64]
Definition: DNA_ID.h:111
IDPropertyData data
Definition: DNA_ID.h:117
struct IDProperty * prev
Definition: DNA_ID.h:107
char subtype
Definition: DNA_ID.h:108
int totallen
Definition: DNA_ID.h:126
char type
Definition: DNA_ID.h:108
Definition: DNA_ID.h:368
IDProperty * properties
Definition: DNA_ID.h:409
struct IDPropertyTemplate::@27 array
const char * str
Definition: BKE_idprop.h:29
struct ID * id
Definition: BKE_idprop.h:33
struct IDPropertyTemplate::@26 string