Blender V4.3
idprop.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <cfloat>
10#include <climits>
11#include <cstddef>
12#include <cstdio>
13#include <cstdlib>
14#include <cstring>
15
16#include <fmt/format.h>
17
18#include "BLI_endian_switch.h"
19#include "BLI_listbase.h"
20#include "BLI_math_base.h"
21#include "BLI_set.hh"
22#include "BLI_string.h"
23#include "BLI_utildefines.h"
24
25#include "BKE_global.hh"
26#include "BKE_idprop.hh"
27#include "BKE_lib_id.hh"
28
29#include "CLG_log.h"
30
31#include "MEM_guardedalloc.h"
32
33#include "BLO_read_write.hh"
34
35#include "BLI_strict_flags.h" /* Keep last. */
36
37/* IDPropertyTemplate is a union in DNA_ID.h */
38
43#define IDP_ARRAY_REALLOC_LIMIT 200
44
45static CLG_LogRef LOG = {"bke.idprop"};
46
48static size_t idp_size_table[] = {
49 1, /* #IDP_STRING */
50 sizeof(int), /* #IDP_INT */
51 sizeof(float), /* #IDP_FLOAT */
52 sizeof(float[3]), /* DEPRECATED (was vector). */
53 sizeof(float[16]), /* DEPRECATED (was matrix). */
54 0, /* #IDP_ARRAY (no fixed size). */
55 sizeof(ListBase), /* #IDP_GROUP */
56 sizeof(void *), /* #IDP_ID */
57 sizeof(double), /* #IDP_DOUBLE */
58 0, /* #IDP_IDPARRAY (no fixed size). */
59 sizeof(int8_t), /* #IDP_BOOLEAN */
60 sizeof(int), /* #IDP_ENUM */
61};
62
63/* -------------------------------------------------------------------- */
67#define GETPROP(prop, i) &(IDP_IDPArray(prop)[i])
68
69IDProperty *IDP_NewIDPArray(const char *name)
70{
71 IDProperty *prop = static_cast<IDProperty *>(
72 MEM_callocN(sizeof(IDProperty), "IDProperty prop array"));
73 prop->type = IDP_IDPARRAY;
74 prop->len = 0;
75 STRNCPY(prop->name, name);
76
77 return prop;
78}
79
81{
82 /* don't use MEM_dupallocN because this may be part of an array */
84
85 IDProperty *narray = static_cast<IDProperty *>(MEM_mallocN(sizeof(IDProperty), __func__));
86 *narray = *array;
87
88 narray->data.pointer = MEM_dupallocN(array->data.pointer);
89 for (int i = 0; i < narray->len; i++) {
90 /* OK, the copy functions always allocate a new structure,
91 * which doesn't work here. instead, simply copy the
92 * contents of the new structure into the array cell,
93 * then free it. this makes for more maintainable
94 * code than simply re-implementing the copy functions
95 * in this loop. */
96 IDProperty *tmp = IDP_CopyProperty_ex(GETPROP(narray, i), flag);
97 memcpy(GETPROP(narray, i), tmp, sizeof(IDProperty));
98 MEM_freeN(tmp);
99 }
100
101 return narray;
102}
103
104static void IDP_FreeIDPArray(IDProperty *prop, const bool do_id_user)
105{
106 BLI_assert(prop->type == IDP_IDPARRAY);
107
108 for (int i = 0; i < prop->len; i++) {
109 IDP_FreePropertyContent_ex(GETPROP(prop, i), do_id_user);
110 }
111
112 if (prop->data.pointer) {
113 MEM_freeN(prop->data.pointer);
114 }
115}
116
117void IDP_SetIndexArray(IDProperty *prop, int index, IDProperty *item)
118{
119 BLI_assert(prop->type == IDP_IDPARRAY);
120
121 if (index >= prop->len || index < 0) {
122 return;
123 }
124
125 IDProperty *old = GETPROP(prop, index);
126 if (item != old) {
128
129 memcpy(old, item, sizeof(IDProperty));
130 }
131}
132
134{
135 BLI_assert(prop->type == IDP_IDPARRAY);
136
137 return GETPROP(prop, index);
138}
139
141{
142 BLI_assert(prop->type == IDP_IDPARRAY);
143
144 IDP_ResizeIDPArray(prop, prop->len + 1);
145 IDP_SetIndexArray(prop, prop->len - 1, item);
146}
147
148void IDP_ResizeIDPArray(IDProperty *prop, int newlen)
149{
150 BLI_assert(prop->type == IDP_IDPARRAY);
151
152 /* first check if the array buffer size has room */
153 if (newlen <= prop->totallen) {
154 if (newlen < prop->len && prop->totallen - newlen < IDP_ARRAY_REALLOC_LIMIT) {
155 for (int i = newlen; i < prop->len; i++) {
157 }
158
159 prop->len = newlen;
160 return;
161 }
162 if (newlen >= prop->len) {
163 prop->len = newlen;
164 return;
165 }
166 }
167
168 /* free trailing items */
169 if (newlen < prop->len) {
170 /* newlen is smaller */
171 for (int i = newlen; i < prop->len; i++) {
173 }
174 }
175
176 /* NOTE: This code comes from python, here's the corresponding comment. */
177 /* This over-allocates proportional to the list size, making room
178 * for additional growth. The over-allocation is mild, but is
179 * enough to give linear-time amortized behavior over a long
180 * sequence of appends() in the presence of a poorly-performing
181 * system realloc().
182 * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
183 */
184 int newsize = newlen;
185 newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize;
186 prop->data.pointer = MEM_recallocN(prop->data.pointer, sizeof(IDProperty) * size_t(newsize));
187 prop->len = newlen;
188 prop->totallen = newsize;
189}
190
191/* ----------- Numerical Array Type ----------- */
192static void idp_resize_group_array(IDProperty *prop, int newlen, void *newarr)
193{
194 if (prop->subtype != IDP_GROUP) {
195 return;
196 }
197
198 if (newlen >= prop->len) {
199 /* bigger */
200 IDProperty **array = static_cast<IDProperty **>(newarr);
201 for (int a = prop->len; a < newlen; a++) {
202 array[a] = blender::bke::idprop::create_group("IDP_ResizeArray group").release();
203 }
204 }
205 else {
206 /* smaller */
207 IDProperty **array = static_cast<IDProperty **>(prop->data.pointer);
208
209 for (int a = newlen; a < prop->len; a++) {
211 }
212 }
213}
214
215void IDP_ResizeArray(IDProperty *prop, int newlen)
216{
217 const bool is_grow = newlen >= prop->len;
218
219 /* first check if the array buffer size has room */
220 if (newlen <= prop->totallen && prop->totallen - newlen < IDP_ARRAY_REALLOC_LIMIT) {
221 idp_resize_group_array(prop, newlen, prop->data.pointer);
222 prop->len = newlen;
223 return;
224 }
225
226 /* NOTE: This code comes from python, here's the corresponding comment. */
227 /* This over-allocates proportional to the list size, making room
228 * for additional growth. The over-allocation is mild, but is
229 * enough to give linear-time amortized behavior over a long
230 * sequence of appends() in the presence of a poorly-performing
231 * system realloc().
232 * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
233 */
234 int newsize = newlen;
235 newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize;
236
237 if (is_grow == false) {
238 idp_resize_group_array(prop, newlen, prop->data.pointer);
239 }
240
241 prop->data.pointer = MEM_recallocN(prop->data.pointer,
242 idp_size_table[int(prop->subtype)] * size_t(newsize));
243
244 if (is_grow == true) {
245 idp_resize_group_array(prop, newlen, prop->data.pointer);
246 }
247
248 prop->len = newlen;
249 prop->totallen = newsize;
250}
251
253{
254 if (prop->data.pointer) {
255 idp_resize_group_array(prop, 0, nullptr);
256 MEM_freeN(prop->data.pointer);
257 }
258}
259
261{
262 IDPropertyUIData *dst_ui_data = static_cast<IDPropertyUIData *>(MEM_dupallocN(prop->ui_data));
263
264 /* Copy extra type specific data. */
265 switch (IDP_ui_data_type(prop)) {
267 const IDPropertyUIDataString *src = (const IDPropertyUIDataString *)prop->ui_data;
269 dst->default_value = static_cast<char *>(MEM_dupallocN(src->default_value));
270 break;
271 }
272 case IDP_UI_DATA_TYPE_ID: {
273 break;
274 }
276 const IDPropertyUIDataInt *src = (const IDPropertyUIDataInt *)prop->ui_data;
277 IDPropertyUIDataInt *dst = (IDPropertyUIDataInt *)dst_ui_data;
278 dst->default_array = static_cast<int *>(MEM_dupallocN(src->default_array));
279 dst->enum_items = static_cast<IDPropertyUIDataEnumItem *>(MEM_dupallocN(src->enum_items));
280 for (const int64_t i : blender::IndexRange(src->enum_items_num)) {
281 const IDPropertyUIDataEnumItem &src_item = src->enum_items[i];
282 IDPropertyUIDataEnumItem &dst_item = dst->enum_items[i];
283 dst_item.identifier = BLI_strdup(src_item.identifier);
284 dst_item.name = BLI_strdup_null(src_item.name);
285 dst_item.description = BLI_strdup_null(src_item.description);
286 }
287 break;
288 }
290 const IDPropertyUIDataBool *src = (const IDPropertyUIDataBool *)prop->ui_data;
291 IDPropertyUIDataBool *dst = (IDPropertyUIDataBool *)dst_ui_data;
292 dst->default_array = static_cast<int8_t *>(MEM_dupallocN(src->default_array));
293 break;
294 }
296 const IDPropertyUIDataFloat *src = (const IDPropertyUIDataFloat *)prop->ui_data;
297 IDPropertyUIDataFloat *dst = (IDPropertyUIDataFloat *)dst_ui_data;
298 dst->default_array = static_cast<double *>(MEM_dupallocN(src->default_array));
299 break;
300 }
302 break;
303 }
304 }
305
306 dst_ui_data->description = static_cast<char *>(MEM_dupallocN(prop->ui_data->description));
307
308 return dst_ui_data;
309}
310
311static IDProperty *idp_generic_copy(const IDProperty *prop, const int /*flag*/)
312{
313 IDProperty *newp = static_cast<IDProperty *>(MEM_callocN(sizeof(IDProperty), __func__));
314
315 STRNCPY(newp->name, prop->name);
316 newp->type = prop->type;
317 newp->flag = prop->flag;
318 newp->data.val = prop->data.val;
319 newp->data.val2 = prop->data.val2;
320
321 if (prop->ui_data != nullptr) {
322 newp->ui_data = IDP_ui_data_copy(prop);
323 }
324
325 return newp;
326}
327
328static IDProperty *IDP_CopyArray(const IDProperty *prop, const int flag)
329{
330 IDProperty *newp = idp_generic_copy(prop, flag);
331
332 if (prop->data.pointer) {
333 newp->data.pointer = MEM_dupallocN(prop->data.pointer);
334
335 if (prop->type == IDP_GROUP) {
336 IDProperty **array = static_cast<IDProperty **>(newp->data.pointer);
337 int a;
338
339 for (a = 0; a < prop->len; a++) {
341 }
342 }
343 }
344 newp->len = prop->len;
345 newp->subtype = prop->subtype;
346 newp->totallen = prop->totallen;
347
348 return newp;
349}
350
353/* -------------------------------------------------------------------- */
358 const size_t st_maxncpy,
359 const char *name,
360 const eIDPropertyFlag flags)
361{
362 IDProperty *prop = static_cast<IDProperty *>(
363 MEM_callocN(sizeof(IDProperty), "IDProperty string"));
364
365 if (st == nullptr) {
366 prop->data.pointer = MEM_mallocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1");
367 *IDP_String(prop) = '\0';
369 prop->len = 1; /* nullptr string, has len of 1 to account for null byte. */
370 }
371 else {
372 /* include null terminator '\0' */
373 const int stlen = int((st_maxncpy > 0) ? BLI_strnlen(st, st_maxncpy - 1) : strlen(st)) + 1;
374
375 prop->data.pointer = MEM_mallocN(size_t(stlen), "id property string 2");
376 prop->len = prop->totallen = stlen;
377
378 /* Ensured above, must always be true otherwise null terminator assignment will be invalid. */
379 BLI_assert(stlen > 0);
380 if (stlen > 1) {
381 memcpy(prop->data.pointer, st, size_t(stlen));
382 }
383 IDP_String(prop)[stlen - 1] = '\0';
384 }
385
386 prop->type = IDP_STRING;
387 STRNCPY(prop->name, name);
388 prop->flag = short(flags);
389
390 return prop;
391}
392
393IDProperty *IDP_NewString(const char *st, const char *name, const eIDPropertyFlag flags)
394{
395 return IDP_NewStringMaxSize(st, 0, name, flags);
396}
397
398static IDProperty *IDP_CopyString(const IDProperty *prop, const int flag)
399{
400 BLI_assert(prop->type == IDP_STRING);
401 IDProperty *newp = idp_generic_copy(prop, flag);
402
403 if (prop->data.pointer) {
404 newp->data.pointer = MEM_dupallocN(prop->data.pointer);
405 }
406 newp->len = prop->len;
407 newp->subtype = prop->subtype;
408 newp->totallen = prop->totallen;
409
410 return newp;
411}
412
413void IDP_AssignStringMaxSize(IDProperty *prop, const char *st, const size_t st_maxncpy)
414{
415 /* FIXME: This function is broken for bytes (in case there are null chars in it),
416 * needs a dedicated function which takes directly the size of the byte buffer. */
417
418 BLI_assert(prop->type == IDP_STRING);
419 const bool is_byte = prop->subtype == IDP_STRING_SUB_BYTE;
420 const int stlen = int((st_maxncpy > 0) ? BLI_strnlen(st, st_maxncpy - 1) : strlen(st)) +
421 (is_byte ? 0 : 1);
422 IDP_ResizeArray(prop, stlen);
423 if (stlen > 0) {
424 memcpy(prop->data.pointer, st, size_t(stlen));
425 if (is_byte == false) {
426 IDP_String(prop)[stlen - 1] = '\0';
427 }
428 }
429}
430
431void IDP_AssignString(IDProperty *prop, const char *st)
432{
433 /* FIXME: Should never be called for `byte` subtype, needs an assert. */
434
435 IDP_AssignStringMaxSize(prop, st, 0);
436}
437
439{
440 BLI_assert(prop->type == IDP_STRING);
441
442 if (prop->data.pointer) {
443 MEM_freeN(prop->data.pointer);
444 }
445}
448/* -------------------------------------------------------------------- */
453{
454 for (const int64_t i : blender::IndexRange(ui_data->enum_items_num)) {
455 IDPropertyUIDataEnumItem &item = ui_data->enum_items[i];
457 MEM_SAFE_FREE(item.name);
459 }
460 MEM_SAFE_FREE(ui_data->enum_items);
461}
462
464{
465 BLI_assert(prop->type == IDP_INT);
466 const IDPropertyUIDataInt *ui_data = reinterpret_cast<const IDPropertyUIDataInt *>(
467 prop->ui_data);
468
469 const int value = IDP_Int(prop);
470 for (const IDPropertyUIDataEnumItem &item :
471 blender::Span(ui_data->enum_items, ui_data->enum_items_num))
472 {
473 if (item.value == value) {
474 return &item;
475 }
476 }
477 return nullptr;
478}
479
481 const int items_num,
482 void (*error_fn)(const char *))
483{
484 blender::Set<int> used_values;
485 blender::Set<const char *> used_identifiers;
486 used_values.reserve(items_num);
487 used_identifiers.reserve(items_num);
488
489 bool is_valid = true;
490 for (const int64_t i : blender::IndexRange(items_num)) {
491 const IDPropertyUIDataEnumItem &item = items[i];
492 if (item.identifier == nullptr || item.identifier[0] == '\0') {
493 if (error_fn) {
494 const std::string msg = "Item identifier is empty";
495 error_fn(msg.c_str());
496 }
497 is_valid = false;
498 }
499 if (!used_identifiers.add(item.identifier)) {
500 if (error_fn) {
501 const std::string msg = fmt::format("Item identifier '{}' is already used",
502 item.identifier);
503 error_fn(msg.c_str());
504 }
505 is_valid = false;
506 }
507 if (!used_values.add(item.value)) {
508 if (error_fn) {
509 const std::string msg = fmt::format(
510 "Item value {} for item '{}' is already used", item.value, item.identifier);
511 error_fn(msg.c_str());
512 }
513 is_valid = false;
514 }
515 }
516 return is_valid;
517}
518
521/* -------------------------------------------------------------------- */
525static IDProperty *IDP_CopyID(const IDProperty *prop, const int flag)
526{
527 BLI_assert(prop->type == IDP_ID);
528 IDProperty *newp = idp_generic_copy(prop, flag);
529
530 newp->data.pointer = prop->data.pointer;
532 id_us_plus(IDP_Id(newp));
533 }
534
535 return newp;
536}
537
538void IDP_AssignID(IDProperty *prop, ID *id, const int flag)
539{
540 BLI_assert(prop->type == IDP_ID);
541 /* Do not assign embedded IDs to IDProperties. */
542 BLI_assert(!id || (id->flag & ID_FLAG_EMBEDDED_DATA) == 0);
543
544 if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0 && IDP_Id(prop) != nullptr) {
545 id_us_min(IDP_Id(prop));
546 }
547
548 prop->data.pointer = id;
549
551 id_us_plus(IDP_Id(prop));
552 }
553}
554
557/* -------------------------------------------------------------------- */
564static IDProperty *IDP_CopyGroup(const IDProperty *prop, const int flag)
565{
566 BLI_assert(prop->type == IDP_GROUP);
567 IDProperty *newp = idp_generic_copy(prop, flag);
568 newp->len = prop->len;
569 newp->subtype = prop->subtype;
570
571 LISTBASE_FOREACH (IDProperty *, link, &prop->data.group) {
573 }
574
575 return newp;
576}
577
579{
580 BLI_assert(dest->type == IDP_GROUP);
581 BLI_assert(src->type == IDP_GROUP);
582
583 LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) {
584 IDProperty *other = static_cast<IDProperty *>(
585 BLI_findstring(&dest->data.group, prop->name, offsetof(IDProperty, name)));
586 if (other && prop->type == other->type) {
587 switch (prop->type) {
588 case IDP_INT:
589 case IDP_FLOAT:
590 case IDP_DOUBLE:
591 case IDP_BOOLEAN:
592 other->data = prop->data;
593 break;
594 case IDP_GROUP:
595 IDP_SyncGroupValues(other, prop);
596 break;
597 default: {
598 BLI_insertlinkreplace(&dest->data.group, other, IDP_CopyProperty(prop));
599 IDP_FreeProperty(other);
600 break;
601 }
602 }
603 }
604 }
605}
606
607void IDP_SyncGroupTypes(IDProperty *dest, const IDProperty *src, const bool do_arraylen)
608{
609 LISTBASE_FOREACH_MUTABLE (IDProperty *, prop_dst, &dest->data.group) {
610 const IDProperty *prop_src = IDP_GetPropertyFromGroup((IDProperty *)src, prop_dst->name);
611 if (prop_src != nullptr) {
612 /* check of we should replace? */
613 if ((prop_dst->type != prop_src->type || prop_dst->subtype != prop_src->subtype) ||
614 (do_arraylen && ELEM(prop_dst->type, IDP_ARRAY, IDP_IDPARRAY) &&
615 (prop_src->len != prop_dst->len)))
616 {
617 BLI_insertlinkreplace(&dest->data.group, prop_dst, IDP_CopyProperty(prop_src));
618 IDP_FreeProperty(prop_dst);
619 }
620 else if (prop_dst->type == IDP_GROUP) {
621 IDP_SyncGroupTypes(prop_dst, prop_src, do_arraylen);
622 }
623 }
624 else {
625 IDP_FreeFromGroup(dest, prop_dst);
626 }
627 }
628}
629
631{
632 BLI_assert(dest->type == IDP_GROUP);
633 BLI_assert(src->type == IDP_GROUP);
634
635 LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) {
636 IDProperty *loop;
637 for (loop = static_cast<IDProperty *>(dest->data.group.first); loop; loop = loop->next) {
638 if (STREQ(loop->name, prop->name)) {
640 IDP_FreeProperty(loop);
641 break;
642 }
643 }
644
645 /* only add at end if not added yet */
646 if (loop == nullptr) {
648 dest->len++;
649 BLI_addtail(&dest->data.group, copy);
650 }
651 }
652}
653
655{
656 BLI_assert(group->type == IDP_GROUP);
657 BLI_assert(prop_exist == IDP_GetPropertyFromGroup(group, prop->name));
658
659 if (prop_exist != nullptr) {
660 BLI_insertlinkreplace(&group->data.group, prop_exist, prop);
661 IDP_FreeProperty(prop_exist);
662 }
663 else {
664 group->len++;
665 BLI_addtail(&group->data.group, prop);
666 }
667}
668
670{
671 IDProperty *prop_exist = IDP_GetPropertyFromGroup(group, prop->name);
672
673 IDP_ReplaceInGroup_ex(group, prop, prop_exist);
674}
675
677 const IDProperty *src,
678 const bool do_overwrite,
679 const int flag)
680{
681 BLI_assert(dest->type == IDP_GROUP);
682 BLI_assert(src->type == IDP_GROUP);
683
684 if (do_overwrite) {
685 LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) {
686 if (prop->type == IDP_GROUP) {
687 IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name);
688
689 if (prop_exist != nullptr) {
690 IDP_MergeGroup_ex(prop_exist, prop, do_overwrite, flag);
691 continue;
692 }
693 }
694
697 }
698 }
699 else {
700 LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) {
701 IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name);
702 if (prop_exist != nullptr) {
703 if (prop->type == IDP_GROUP) {
704 IDP_MergeGroup_ex(prop_exist, prop, do_overwrite, flag);
705 continue;
706 }
707 }
708 else {
710 dest->len++;
711 BLI_addtail(&dest->data.group, copy);
712 }
713 }
714 }
715}
716
717void IDP_MergeGroup(IDProperty *dest, const IDProperty *src, const bool do_overwrite)
718{
719 IDP_MergeGroup_ex(dest, src, do_overwrite, 0);
720}
721
723{
724 BLI_assert(group->type == IDP_GROUP);
725
726 if (IDP_GetPropertyFromGroup(group, prop->name) == nullptr) {
727 group->len++;
728 BLI_addtail(&group->data.group, prop);
729 return true;
730 }
731
732 return false;
733}
734
735bool IDP_InsertToGroup(IDProperty *group, IDProperty *previous, IDProperty *pnew)
736{
737 BLI_assert(group->type == IDP_GROUP);
738
739 if (IDP_GetPropertyFromGroup(group, pnew->name) == nullptr) {
740 group->len++;
741 BLI_insertlinkafter(&group->data.group, previous, pnew);
742 return true;
743 }
744
745 return false;
746}
747
749{
750 BLI_assert(group->type == IDP_GROUP);
751 BLI_assert(BLI_findindex(&group->data.group, prop) != -1);
752
753 group->len--;
754 BLI_remlink(&group->data.group, prop);
755}
756
758{
759 IDP_RemoveFromGroup(group, prop);
760 IDP_FreeProperty(prop);
761}
762
763IDProperty *IDP_GetPropertyFromGroup(const IDProperty *prop, const char *name)
764{
765 BLI_assert(prop->type == IDP_GROUP);
766
767 return (IDProperty *)BLI_findstring(&prop->data.group, name, offsetof(IDProperty, name));
768}
769IDProperty *IDP_GetPropertyTypeFromGroup(const IDProperty *prop, const char *name, const char type)
770{
771 IDProperty *idprop = IDP_GetPropertyFromGroup(prop, name);
772 return (idprop && idprop->type == type) ? idprop : nullptr;
773}
774
775/* Ok, the way things work, Groups free the ID Property structs of their children.
776 * This is because all ID Property freeing functions free only direct data (not the ID Property
777 * struct itself), but for Groups the child properties *are* considered
778 * direct data. */
779static void IDP_FreeGroup(IDProperty *prop, const bool do_id_user)
780{
781 BLI_assert(prop->type == IDP_GROUP);
782
783 LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) {
784 IDP_FreePropertyContent_ex(loop, do_id_user);
785 }
786 BLI_freelistN(&prop->data.group);
787}
788
791/* -------------------------------------------------------------------- */
796{
797 switch (prop->type) {
798 case IDP_INT:
799 return IDP_Int(prop);
800 case IDP_DOUBLE:
801 return int(IDP_Double(prop));
802 case IDP_FLOAT:
803 return int(IDP_Float(prop));
804 case IDP_BOOLEAN:
805 return int(IDP_Bool(prop));
806 default:
807 return 0;
808 }
809}
810
812{
813 switch (prop->type) {
814 case IDP_DOUBLE:
815 return IDP_Double(prop);
816 case IDP_FLOAT:
817 return double(IDP_Float(prop));
818 case IDP_INT:
819 return double(IDP_Int(prop));
820 case IDP_BOOLEAN:
821 return double(IDP_Bool(prop));
822 default:
823 return 0.0;
824 }
825}
826
828{
829 switch (prop->type) {
830 case IDP_FLOAT:
831 return IDP_Float(prop);
832 case IDP_DOUBLE:
833 return float(IDP_Double(prop));
834 case IDP_INT:
835 return float(IDP_Int(prop));
836 case IDP_BOOLEAN:
837 return float(IDP_Bool(prop));
838 default:
839 return 0.0f;
840 }
841}
842
844{
845 switch (prop->type) {
846 case IDP_GROUP:
847 return IDP_CopyGroup(prop, flag);
848 case IDP_STRING:
849 return IDP_CopyString(prop, flag);
850 case IDP_ID:
851 return IDP_CopyID(prop, flag);
852 case IDP_ARRAY:
853 return IDP_CopyArray(prop, flag);
854 case IDP_IDPARRAY:
855 return IDP_CopyIDPArray(prop, flag);
856 default:
857 return idp_generic_copy(prop, flag);
858 }
859}
860
862{
863 return IDP_CopyProperty_ex(prop, 0);
864}
865
867{
868 IDProperty *idprop_tmp = IDP_CopyProperty(src);
869 idprop_tmp->prev = dst->prev;
870 idprop_tmp->next = dst->next;
871 std::swap(*dst, *idprop_tmp);
872 IDP_FreeProperty(idprop_tmp);
873}
874
876{
877 return id->properties;
878}
879
881{
882 if (id->properties == nullptr) {
883 id->properties = static_cast<IDProperty *>(MEM_callocN(sizeof(IDProperty), "IDProperty"));
884 id->properties->type = IDP_GROUP;
885 /* NOTE(@ideasman42): Don't overwrite the data's name and type
886 * some functions might need this if they
887 * don't have a real ID, should be named elsewhere. */
888 // STRNCPY(id->name, "top_level_group");
889 }
890 return id->properties;
891}
892
894 const IDProperty *prop2,
895 const bool is_strict)
896{
897 if (prop1 == nullptr && prop2 == nullptr) {
898 return true;
899 }
900 if (prop1 == nullptr || prop2 == nullptr) {
901 return is_strict ? false : true;
902 }
903 if (prop1->type != prop2->type) {
904 return false;
905 }
906
907 switch (prop1->type) {
908 case IDP_INT:
909 return (IDP_Int(prop1) == IDP_Int(prop2));
910 case IDP_FLOAT:
911#if !defined(NDEBUG) && defined(WITH_PYTHON)
912 {
913 float p1 = IDP_Float(prop1);
914 float p2 = IDP_Float(prop2);
915 if ((p1 != p2) && ((fabsf(p1 - p2) / max_ff(p1, p2)) < 0.001f)) {
916 printf(
917 "WARNING: Comparing two float properties that have nearly the same value (%f vs. "
918 "%f)\n",
919 p1,
920 p2);
921 printf(" p1: ");
922 IDP_print(prop1);
923 printf(" p2: ");
924 IDP_print(prop2);
925 }
926 }
927#endif
928 return (IDP_Float(prop1) == IDP_Float(prop2));
929 case IDP_DOUBLE:
930 return (IDP_Double(prop1) == IDP_Double(prop2));
931 case IDP_BOOLEAN:
932 return (IDP_Bool(prop1) == IDP_Bool(prop2));
933 case IDP_STRING: {
934 return ((prop1->len == prop2->len) &&
935 STREQLEN(IDP_String(prop1), IDP_String(prop2), size_t(prop1->len)));
936 }
937 case IDP_ARRAY:
938 if (prop1->len == prop2->len && prop1->subtype == prop2->subtype) {
939 return (memcmp(IDP_Array(prop1),
940 IDP_Array(prop2),
941 idp_size_table[int(prop1->subtype)] * size_t(prop1->len)) == 0);
942 }
943 return false;
944 case IDP_GROUP: {
945 if (is_strict && prop1->len != prop2->len) {
946 return false;
947 }
948
949 LISTBASE_FOREACH (const IDProperty *, link1, &prop1->data.group) {
950 const IDProperty *link2 = IDP_GetPropertyFromGroup(prop2, link1->name);
951
952 if (!IDP_EqualsProperties_ex(link1, link2, is_strict)) {
953 return false;
954 }
955 }
956
957 return true;
958 }
959 case IDP_IDPARRAY: {
960 const IDProperty *array1 = IDP_IDPArray(prop1);
961 const IDProperty *array2 = IDP_IDPArray(prop2);
962
963 if (prop1->len != prop2->len) {
964 return false;
965 }
966
967 for (int i = 0; i < prop1->len; i++) {
968 if (!IDP_EqualsProperties_ex(&array1[i], &array2[i], is_strict)) {
969 return false;
970 }
971 }
972 return true;
973 }
974 case IDP_ID:
975 return (IDP_Id(prop1) == IDP_Id(prop2));
976 default:
978 break;
979 }
980
981 return true;
982}
983
984bool IDP_EqualsProperties(const IDProperty *prop1, const IDProperty *prop2)
985{
986 return IDP_EqualsProperties_ex(prop1, prop2, true);
987}
988
989IDProperty *IDP_New(const char type,
990 const IDPropertyTemplate *val,
991 const char *name,
992 const eIDPropertyFlag flags)
993{
994 IDProperty *prop = nullptr;
995
996 switch (type) {
997 case IDP_INT:
998 prop = static_cast<IDProperty *>(MEM_callocN(sizeof(IDProperty), "IDProperty int"));
999 prop->data.val = val->i;
1000 break;
1001 case IDP_FLOAT:
1002 prop = static_cast<IDProperty *>(MEM_callocN(sizeof(IDProperty), "IDProperty float"));
1003 *(float *)&prop->data.val = val->f;
1004 break;
1005 case IDP_DOUBLE:
1006 prop = static_cast<IDProperty *>(MEM_callocN(sizeof(IDProperty), "IDProperty double"));
1007 *(double *)&prop->data.val = val->d;
1008 break;
1009 case IDP_BOOLEAN:
1010 prop = static_cast<IDProperty *>(MEM_callocN(sizeof(IDProperty), "IDProperty boolean"));
1011 prop->data.val = bool(val->i);
1012 break;
1013 case IDP_ARRAY: {
1014 /* FIXME: This seems to be the only place in code allowing `IDP_GROUP` as subtype of an
1015 * `IDP_ARRAY`. This is most likely a mistake. `IDP_GROUP` array should be of type
1016 * `IDP_IDPARRAY`, as done e.g. in #idp_from_PySequence_Buffer in bpy API. */
1018 prop = static_cast<IDProperty *>(MEM_callocN(sizeof(IDProperty), "IDProperty array"));
1019 prop->subtype = val->array.type;
1020 if (val->array.len) {
1021 prop->data.pointer = MEM_callocN(
1022 idp_size_table[val->array.type] * size_t(val->array.len), "id property array");
1023 }
1024 prop->len = prop->totallen = val->array.len;
1025 break;
1026 }
1027 CLOG_ERROR(&LOG, "bad array type.");
1028 return nullptr;
1029 }
1030 case IDP_STRING: {
1031 const char *st = val->string.str;
1032
1033 prop = static_cast<IDProperty *>(MEM_callocN(sizeof(IDProperty), "IDProperty string"));
1034 if (val->string.subtype == IDP_STRING_SUB_BYTE) {
1035 /* NOTE: Intentionally not null terminated. */
1036 if (st == nullptr) {
1037 prop->data.pointer = MEM_mallocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1");
1038 *IDP_String(prop) = '\0';
1040 prop->len = 0;
1041 }
1042 else {
1043 prop->data.pointer = MEM_mallocN(size_t(val->string.len), "id property string 2");
1044 prop->len = prop->totallen = val->string.len;
1045 memcpy(prop->data.pointer, st, size_t(val->string.len));
1046 }
1048 }
1049 else {
1050 if (st == nullptr || val->string.len <= 1) {
1051 prop->data.pointer = MEM_mallocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1");
1052 *IDP_String(prop) = '\0';
1054 /* nullptr string, has len of 1 to account for null byte. */
1055 prop->len = 1;
1056 }
1057 else {
1058 BLI_assert(int(val->string.len) <= int(strlen(st)) + 1);
1059 prop->data.pointer = MEM_mallocN(size_t(val->string.len), "id property string 3");
1060 memcpy(prop->data.pointer, st, size_t(val->string.len) - 1);
1061 IDP_String(prop)[val->string.len - 1] = '\0';
1062 prop->len = prop->totallen = val->string.len;
1063 }
1065 }
1066 break;
1067 }
1068 case IDP_GROUP: {
1069 /* Values are set properly by calloc. */
1070 prop = static_cast<IDProperty *>(MEM_callocN(sizeof(IDProperty), "IDProperty group"));
1071 break;
1072 }
1073 case IDP_ID: {
1074 prop = static_cast<IDProperty *>(MEM_callocN(sizeof(IDProperty), "IDProperty datablock"));
1075 prop->data.pointer = (void *)val->id;
1076 prop->type = IDP_ID;
1077 id_us_plus(IDP_Id(prop));
1078 break;
1079 }
1080 default: {
1081 prop = static_cast<IDProperty *>(MEM_callocN(sizeof(IDProperty), "IDProperty array"));
1082 break;
1083 }
1084 }
1085
1086 prop->type = type;
1087 STRNCPY(prop->name, name);
1088 prop->flag = short(flags);
1089
1090 return prop;
1091}
1092
1094 const eIDPropertyUIDataType type,
1095 const IDPropertyUIData *other)
1096{
1097 if (ui_data->description != other->description) {
1098 MEM_SAFE_FREE(ui_data->description);
1099 }
1100
1101 switch (type) {
1103 const IDPropertyUIDataString *other_string = (const IDPropertyUIDataString *)other;
1104 IDPropertyUIDataString *ui_data_string = (IDPropertyUIDataString *)ui_data;
1105 if (ui_data_string->default_value != other_string->default_value) {
1106 MEM_SAFE_FREE(ui_data_string->default_value);
1107 }
1108 break;
1109 }
1110 case IDP_UI_DATA_TYPE_ID: {
1111 break;
1112 }
1113 case IDP_UI_DATA_TYPE_INT: {
1114 const IDPropertyUIDataInt *other_int = (const IDPropertyUIDataInt *)other;
1115 IDPropertyUIDataInt *ui_data_int = (IDPropertyUIDataInt *)ui_data;
1116 if (ui_data_int->default_array != other_int->default_array) {
1117 MEM_SAFE_FREE(ui_data_int->default_array);
1118 }
1119 if (ui_data_int->enum_items != other_int->enum_items) {
1121 }
1122 break;
1123 }
1125 const IDPropertyUIDataBool *other_bool = (const IDPropertyUIDataBool *)other;
1126 IDPropertyUIDataBool *ui_data_bool = (IDPropertyUIDataBool *)ui_data;
1127 if (ui_data_bool->default_array != other_bool->default_array) {
1128 MEM_SAFE_FREE(ui_data_bool->default_array);
1129 }
1130 break;
1131 }
1133 const IDPropertyUIDataFloat *other_float = (const IDPropertyUIDataFloat *)other;
1134 IDPropertyUIDataFloat *ui_data_float = (IDPropertyUIDataFloat *)ui_data;
1135 if (ui_data_float->default_array != other_float->default_array) {
1136 MEM_SAFE_FREE(ui_data_float->default_array);
1137 }
1138 break;
1139 }
1141 break;
1142 }
1143 }
1144}
1145
1146static void ui_data_free(IDPropertyUIData *ui_data, const eIDPropertyUIDataType type)
1147{
1148 switch (type) {
1150 IDPropertyUIDataString *ui_data_string = (IDPropertyUIDataString *)ui_data;
1151 MEM_SAFE_FREE(ui_data_string->default_value);
1152 break;
1153 }
1154 case IDP_UI_DATA_TYPE_ID: {
1155 break;
1156 }
1157 case IDP_UI_DATA_TYPE_INT: {
1158 IDPropertyUIDataInt *ui_data_int = (IDPropertyUIDataInt *)ui_data;
1159 MEM_SAFE_FREE(ui_data_int->default_array);
1161 break;
1162 }
1164 IDPropertyUIDataBool *ui_data_bool = (IDPropertyUIDataBool *)ui_data;
1165 MEM_SAFE_FREE(ui_data_bool->default_array);
1166 break;
1167 }
1169 IDPropertyUIDataFloat *ui_data_float = (IDPropertyUIDataFloat *)ui_data;
1170 MEM_SAFE_FREE(ui_data_float->default_array);
1171 break;
1172 }
1174 break;
1175 }
1176 }
1177
1178 MEM_SAFE_FREE(ui_data->description);
1179
1180 MEM_freeN(ui_data);
1181}
1182
1184{
1186 prop->ui_data = nullptr;
1187}
1188
1189void IDP_FreePropertyContent_ex(IDProperty *prop, const bool do_id_user)
1190{
1191 switch (prop->type) {
1192 case IDP_ARRAY:
1193 IDP_FreeArray(prop);
1194 break;
1195 case IDP_STRING:
1196 IDP_FreeString(prop);
1197 break;
1198 case IDP_GROUP:
1199 IDP_FreeGroup(prop, do_id_user);
1200 break;
1201 case IDP_IDPARRAY:
1202 IDP_FreeIDPArray(prop, do_id_user);
1203 break;
1204 case IDP_ID:
1205 if (do_id_user) {
1206 id_us_min(IDP_Id(prop));
1207 }
1208 break;
1209 }
1210
1211 if (prop->ui_data != nullptr) {
1212 IDP_ui_data_free(prop);
1213 }
1214}
1215
1217{
1218 IDP_FreePropertyContent_ex(prop, true);
1219}
1220
1221void IDP_FreeProperty_ex(IDProperty *prop, const bool do_id_user)
1222{
1223 IDP_FreePropertyContent_ex(prop, do_id_user);
1224 MEM_freeN(prop);
1225}
1226
1228{
1230 MEM_freeN(prop);
1231}
1232
1234{
1236 prop->data.pointer = nullptr;
1237 prop->len = prop->totallen = 0;
1238}
1239
1240void IDP_Reset(IDProperty *prop, const IDProperty *reference)
1241{
1242 if (prop == nullptr) {
1243 return;
1244 }
1245 IDP_ClearProperty(prop);
1246 if (reference != nullptr) {
1247 IDP_MergeGroup(prop, reference, true);
1248 }
1249}
1250
1251void IDP_foreach_property(IDProperty *id_property_root,
1252 const int type_filter,
1253 const blender::FunctionRef<void(IDProperty *id_property)> callback)
1254{
1255 if (!id_property_root) {
1256 return;
1257 }
1258
1259 if (type_filter == 0 || (1 << id_property_root->type) & type_filter) {
1260 callback(id_property_root);
1261 }
1262
1263 /* Recursive call into container types of ID properties. */
1264 switch (id_property_root->type) {
1265 case IDP_GROUP: {
1266 LISTBASE_FOREACH (IDProperty *, loop, &id_property_root->data.group) {
1267 IDP_foreach_property(loop, type_filter, callback);
1268 }
1269 break;
1270 }
1271 case IDP_IDPARRAY: {
1272 IDProperty *loop = static_cast<IDProperty *>(IDP_Array(id_property_root));
1273 for (int i = 0; i < id_property_root->len; i++) {
1274 IDP_foreach_property(&loop[i], type_filter, callback);
1275 }
1276 break;
1277 }
1278 default:
1279 break; /* Nothing to do here with other types of IDProperties... */
1280 }
1281}
1282
1283void IDP_WriteProperty_OnlyData(const IDProperty *prop, BlendWriter *writer);
1284
1285static void write_ui_data(const IDProperty *prop, BlendWriter *writer)
1286{
1287 IDPropertyUIData *ui_data = prop->ui_data;
1288
1289 BLO_write_string(writer, ui_data->description);
1290
1291 switch (IDP_ui_data_type(prop)) {
1293 IDPropertyUIDataString *ui_data_string = (IDPropertyUIDataString *)ui_data;
1294 BLO_write_string(writer, ui_data_string->default_value);
1295 BLO_write_struct(writer, IDPropertyUIDataString, ui_data);
1296 break;
1297 }
1298 case IDP_UI_DATA_TYPE_ID: {
1299 BLO_write_struct(writer, IDPropertyUIDataID, ui_data);
1300 break;
1301 }
1302 case IDP_UI_DATA_TYPE_INT: {
1303 IDPropertyUIDataInt *ui_data_int = (IDPropertyUIDataInt *)ui_data;
1304 if (prop->type == IDP_ARRAY) {
1306 writer, uint(ui_data_int->default_array_len), (int32_t *)ui_data_int->default_array);
1307 }
1309 writer, IDPropertyUIDataEnumItem, ui_data_int->enum_items_num, ui_data_int->enum_items);
1310 for (const int64_t i : blender::IndexRange(ui_data_int->enum_items_num)) {
1311 IDPropertyUIDataEnumItem &item = ui_data_int->enum_items[i];
1312 BLO_write_string(writer, item.identifier);
1313 BLO_write_string(writer, item.name);
1314 BLO_write_string(writer, item.description);
1315 }
1316 BLO_write_struct(writer, IDPropertyUIDataInt, ui_data);
1317 break;
1318 }
1320 IDPropertyUIDataBool *ui_data_bool = (IDPropertyUIDataBool *)ui_data;
1321 if (prop->type == IDP_ARRAY) {
1322 BLO_write_int8_array(writer,
1323 uint(ui_data_bool->default_array_len),
1324 (const int8_t *)ui_data_bool->default_array);
1325 }
1326 BLO_write_struct(writer, IDPropertyUIDataBool, ui_data);
1327 break;
1328 }
1330 IDPropertyUIDataFloat *ui_data_float = (IDPropertyUIDataFloat *)ui_data;
1331 if (prop->type == IDP_ARRAY) {
1333 writer, uint(ui_data_float->default_array_len), ui_data_float->default_array);
1334 }
1335 BLO_write_struct(writer, IDPropertyUIDataFloat, ui_data);
1336 break;
1337 }
1340 break;
1341 }
1342 }
1343}
1344
1345static void IDP_WriteArray(const IDProperty *prop, BlendWriter *writer)
1346{
1347 /* Remember to set #IDProperty.totallen to len in the linking code! */
1348 if (prop->data.pointer) {
1349 /* Only write the actual data (`prop->len`), not the whole allocated buffer (`prop->totallen`).
1350 */
1351 switch (eIDPropertyType(prop->subtype)) {
1352 case IDP_GROUP: {
1353 BLO_write_pointer_array(writer, uint32_t(prop->len), prop->data.pointer);
1354
1355 IDProperty **array = static_cast<IDProperty **>(prop->data.pointer);
1356 for (int i = 0; i < prop->len; i++) {
1357 IDP_BlendWrite(writer, array[i]);
1358 }
1359 break;
1360 }
1361 case IDP_DOUBLE:
1363 writer, uint32_t(prop->len), static_cast<double *>(prop->data.pointer));
1364 break;
1365 case IDP_INT:
1366 BLO_write_int32_array(writer, uint32_t(prop->len), static_cast<int *>(prop->data.pointer));
1367 break;
1368 case IDP_FLOAT:
1370 writer, uint32_t(prop->len), static_cast<float *>(prop->data.pointer));
1371 break;
1372 case IDP_BOOLEAN:
1374 writer, uint32_t(prop->len), static_cast<int8_t *>(prop->data.pointer));
1375 break;
1376 case IDP_STRING:
1377 case IDP_ARRAY:
1378 case IDP_ID:
1379 case IDP_IDPARRAY:
1381 break;
1382 }
1383 }
1384}
1385
1386static void IDP_WriteIDPArray(const IDProperty *prop, BlendWriter *writer)
1387{
1388 /* Remember to set #IDProperty.totallen to len in the linking code! */
1389 if (prop->data.pointer) {
1390 const IDProperty *array = static_cast<const IDProperty *>(prop->data.pointer);
1391
1392 BLO_write_struct_array(writer, IDProperty, prop->len, array);
1393
1394 for (int a = 0; a < prop->len; a++) {
1395 IDP_WriteProperty_OnlyData(&array[a], writer);
1396 }
1397 }
1398}
1399
1400static void IDP_WriteString(const IDProperty *prop, BlendWriter *writer)
1401{
1402 /* Remember to set #IDProperty.totallen to len in the linking code! */
1403 /* Do not use #BLO_write_string here, since 'bytes' sub-type of IDProperties may not be
1404 * null-terminated. */
1405 BLO_write_char_array(writer, uint(prop->len), static_cast<char *>(prop->data.pointer));
1406}
1407
1408static void IDP_WriteGroup(const IDProperty *prop, BlendWriter *writer)
1409{
1410 LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) {
1411 IDP_BlendWrite(writer, loop);
1412 }
1413}
1414
1415/* Functions to read/write ID Properties */
1417{
1418 switch (prop->type) {
1419 case IDP_GROUP:
1420 IDP_WriteGroup(prop, writer);
1421 break;
1422 case IDP_STRING:
1423 IDP_WriteString(prop, writer);
1424 break;
1425 case IDP_ARRAY:
1426 IDP_WriteArray(prop, writer);
1427 break;
1428 case IDP_IDPARRAY:
1429 IDP_WriteIDPArray(prop, writer);
1430 break;
1431 }
1432 if (prop->ui_data != nullptr) {
1433 write_ui_data(prop, writer);
1434 }
1435}
1436
1437void IDP_BlendWrite(BlendWriter *writer, const IDProperty *prop)
1438{
1439 BLO_write_struct(writer, IDProperty, prop);
1440 IDP_WriteProperty_OnlyData(prop, writer);
1441}
1442
1443static void IDP_DirectLinkProperty(IDProperty *prop, BlendDataReader *reader);
1444
1445static void read_ui_data(IDProperty *prop, BlendDataReader *reader)
1446{
1447 /* NOTE: null UI data can happen when opening more recent files with unknown types of
1448 * IDProperties. */
1449
1450 switch (IDP_ui_data_type(prop)) {
1453 if (prop->ui_data) {
1454 IDPropertyUIDataString *ui_data_string = (IDPropertyUIDataString *)prop->ui_data;
1455 BLO_read_string(reader, &ui_data_string->default_value);
1456 }
1457 break;
1458 }
1459 case IDP_UI_DATA_TYPE_ID: {
1461 break;
1462 }
1463 case IDP_UI_DATA_TYPE_INT: {
1465 IDPropertyUIDataInt *ui_data_int = (IDPropertyUIDataInt *)prop->ui_data;
1466 if (prop->type == IDP_ARRAY) {
1468 reader, ui_data_int->default_array_len, (int **)&ui_data_int->default_array);
1469 }
1470 else {
1471 ui_data_int->default_array = nullptr;
1472 ui_data_int->default_array_len = 0;
1473 }
1474 BLO_read_struct_array(reader,
1476 size_t(ui_data_int->enum_items_num),
1477 &ui_data_int->enum_items);
1478 for (const int64_t i : blender::IndexRange(ui_data_int->enum_items_num)) {
1479 IDPropertyUIDataEnumItem &item = ui_data_int->enum_items[i];
1480 BLO_read_string(reader, &item.identifier);
1481 BLO_read_string(reader, &item.name);
1482 BLO_read_string(reader, &item.description);
1483 }
1484 break;
1485 }
1488 IDPropertyUIDataBool *ui_data_bool = (IDPropertyUIDataBool *)prop->ui_data;
1489 if (prop->type == IDP_ARRAY) {
1491 reader, ui_data_bool->default_array_len, (int8_t **)&ui_data_bool->default_array);
1492 }
1493 else {
1494 ui_data_bool->default_array = nullptr;
1495 ui_data_bool->default_array_len = 0;
1496 }
1497 break;
1498 }
1501 IDPropertyUIDataFloat *ui_data_float = (IDPropertyUIDataFloat *)prop->ui_data;
1502 if (prop->type == IDP_ARRAY) {
1504 reader, ui_data_float->default_array_len, (double **)&ui_data_float->default_array);
1505 }
1506 else {
1507 ui_data_float->default_array = nullptr;
1508 ui_data_float->default_array_len = 0;
1509 }
1510 break;
1511 }
1514 /* Do not attempt to read unknown data. */
1515 prop->ui_data = nullptr;
1516 break;
1517 }
1518 }
1519
1520 if (prop->ui_data) {
1521 BLO_read_string(reader, &prop->ui_data->description);
1522 }
1523}
1524
1526{
1527 /* since we didn't save the extra buffer, set totallen to len */
1528 prop->totallen = prop->len;
1529 BLO_read_struct_array(reader, IDProperty, size_t(prop->len), &prop->data.pointer);
1530
1532
1533 /* NOTE:, idp-arrays didn't exist in 2.4x, so the pointer will be cleared
1534 * there's not really anything we can do to correct this, at least don't crash */
1535 if (array == nullptr) {
1536 prop->len = 0;
1537 prop->totallen = 0;
1538 }
1539
1540 for (int i = 0; i < prop->len; i++) {
1541 IDP_DirectLinkProperty(&array[i], reader);
1542 }
1543}
1544
1546{
1547 /* since we didn't save the extra buffer, set totallen to len */
1548 prop->totallen = prop->len;
1549
1550 switch (eIDPropertyType(prop->subtype)) {
1551 case IDP_GROUP: {
1552 BLO_read_pointer_array(reader, prop->len, &prop->data.pointer);
1553 IDProperty **array = static_cast<IDProperty **>(prop->data.pointer);
1554 for (int i = 0; i < prop->len; i++) {
1555 IDP_DirectLinkProperty(array[i], reader);
1556 }
1557 break;
1558 }
1559 case IDP_DOUBLE:
1560 BLO_read_double_array(reader, prop->len, (double **)&prop->data.pointer);
1561 break;
1562 case IDP_INT:
1563 BLO_read_int32_array(reader, prop->len, (int **)&prop->data.pointer);
1564 break;
1565 case IDP_FLOAT:
1566 BLO_read_float_array(reader, prop->len, (float **)&prop->data.pointer);
1567 break;
1568 case IDP_BOOLEAN:
1569 BLO_read_int8_array(reader, prop->len, (int8_t **)&prop->data.pointer);
1570 break;
1571 case IDP_STRING:
1572 case IDP_ARRAY:
1573 case IDP_ID:
1574 case IDP_IDPARRAY:
1576 break;
1577 }
1578}
1579
1581{
1582 /* Since we didn't save the extra string buffer, set totallen to len. */
1583 prop->totallen = prop->len;
1584 BLO_read_char_array(reader, prop->len, reinterpret_cast<char **>(&prop->data.pointer));
1585}
1586
1588{
1589 ListBase *lb = &prop->data.group;
1590
1591 BLO_read_struct_list(reader, IDProperty, lb);
1592
1593 /* Link child id properties now. */
1594 LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) {
1595 IDP_DirectLinkProperty(loop, reader);
1596 }
1597}
1598
1600{
1601 switch (prop->type) {
1602 case IDP_GROUP:
1603 IDP_DirectLinkGroup(prop, reader);
1604 break;
1605 case IDP_STRING:
1606 IDP_DirectLinkString(prop, reader);
1607 break;
1608 case IDP_ARRAY:
1609 IDP_DirectLinkArray(prop, reader);
1610 break;
1611 case IDP_IDPARRAY:
1612 IDP_DirectLinkIDPArray(prop, reader);
1613 break;
1614 case IDP_DOUBLE:
1615 /* Workaround for doubles.
1616 * They are stored in the same field as `int val, val2` in the #IDPropertyData struct,
1617 * they have to deal with endianness specifically.
1618 *
1619 * In theory, val and val2 would've already been swapped
1620 * if switch_endian is true, so we have to first un-swap
1621 * them then re-swap them as a single 64-bit entity. */
1622 if (BLO_read_requires_endian_switch(reader)) {
1626 }
1627 break;
1628 case IDP_INT:
1629 case IDP_FLOAT:
1630 case IDP_BOOLEAN:
1631 case IDP_ID:
1632 break; /* Nothing special to do here. */
1633 default:
1634 /* Unknown IDP type, nuke it (we cannot handle unknown types everywhere in code,
1635 * IDP are way too polymorphic to do it safely. */
1636 printf(
1637 "%s: found unknown IDProperty type %d, reset to Integer one !\n", __func__, prop->type);
1638 /* NOTE: we do not attempt to free unknown prop, we have no way to know how to do that! */
1639 prop->type = IDP_INT;
1640 prop->subtype = 0;
1641 IDP_Int(prop) = 0;
1642 }
1643
1644 if (prop->ui_data != nullptr) {
1645 read_ui_data(prop, reader);
1646 }
1647}
1648
1649void IDP_BlendReadData_impl(BlendDataReader *reader, IDProperty **prop, const char *caller_func_id)
1650{
1651 if (*prop) {
1652 if ((*prop)->type == IDP_GROUP) {
1653 IDP_DirectLinkGroup(*prop, reader);
1654 }
1655 else {
1656 /* corrupt file! */
1657 printf("%s: found non group data, freeing type %d!\n", caller_func_id, (*prop)->type);
1658 /* don't risk id, data's likely corrupt. */
1659 // IDP_FreePropertyContent(*prop);
1660 *prop = nullptr;
1661 }
1662 }
1663}
1664
1666{
1667 if (prop->type == IDP_STRING) {
1669 }
1670 if (prop->type == IDP_ID) {
1671 return IDP_UI_DATA_TYPE_ID;
1672 }
1673 if (prop->type == IDP_INT || (prop->type == IDP_ARRAY && prop->subtype == IDP_INT)) {
1674 return IDP_UI_DATA_TYPE_INT;
1675 }
1676 if (ELEM(prop->type, IDP_FLOAT, IDP_DOUBLE) ||
1677 (prop->type == IDP_ARRAY && ELEM(prop->subtype, IDP_FLOAT, IDP_DOUBLE)))
1678 {
1680 }
1681 if (prop->type == IDP_BOOLEAN || (prop->type == IDP_ARRAY && prop->subtype == IDP_BOOLEAN)) {
1683 }
1685}
1686
1688{
1690}
1691
1693{
1694 switch (type) {
1696 return static_cast<IDPropertyUIData *>(
1697 MEM_callocN(sizeof(IDPropertyUIDataString), __func__));
1698 }
1699 case IDP_UI_DATA_TYPE_ID: {
1700 IDPropertyUIDataID *ui_data = static_cast<IDPropertyUIDataID *>(
1701 MEM_callocN(sizeof(IDPropertyUIDataID), __func__));
1702 return &ui_data->base;
1703 }
1704 case IDP_UI_DATA_TYPE_INT: {
1705 IDPropertyUIDataInt *ui_data = static_cast<IDPropertyUIDataInt *>(
1706 MEM_callocN(sizeof(IDPropertyUIDataInt), __func__));
1707 ui_data->min = INT_MIN;
1708 ui_data->max = INT_MAX;
1709 ui_data->soft_min = INT_MIN;
1710 ui_data->soft_max = INT_MAX;
1711 ui_data->step = 1;
1712 return &ui_data->base;
1713 }
1715 IDPropertyUIDataBool *ui_data = static_cast<IDPropertyUIDataBool *>(
1716 MEM_callocN(sizeof(IDPropertyUIDataBool), __func__));
1717 return &ui_data->base;
1718 }
1720 IDPropertyUIDataFloat *ui_data = static_cast<IDPropertyUIDataFloat *>(
1721 MEM_callocN(sizeof(IDPropertyUIDataFloat), __func__));
1722 ui_data->min = -FLT_MAX;
1723 ui_data->max = FLT_MAX;
1724 ui_data->soft_min = -FLT_MAX;
1725 ui_data->soft_max = FLT_MAX;
1726 ui_data->step = 1.0f;
1727 ui_data->precision = 3;
1728 return &ui_data->base;
1729 }
1731 /* UI data not supported for remaining types, this shouldn't be called in those cases. */
1733 break;
1734 }
1735 }
1736 return nullptr;
1737}
1738
1740{
1741 if (prop->ui_data != nullptr) {
1742 return prop->ui_data;
1743 }
1744 prop->ui_data = ui_data_alloc(IDP_ui_data_type(prop));
1745 return prop->ui_data;
1746}
1747
1749 const eIDPropertyUIDataType dst_type)
1750{
1751 IDPropertyUIData *dst = ui_data_alloc(dst_type);
1752 *dst = *src;
1753 src->description = nullptr;
1754 return dst;
1755}
1756
1758 const eIDPropertyUIDataType src_type,
1759 const eIDPropertyUIDataType dst_type)
1760{
1761 switch (src_type) {
1763 switch (dst_type) {
1765 return src;
1769 case IDP_UI_DATA_TYPE_ID: {
1770 IDPropertyUIData *dst = convert_base_ui_data(src, dst_type);
1771 ui_data_free(src, src_type);
1772 return dst;
1773 }
1775 break;
1776 }
1777 break;
1778 }
1779 case IDP_UI_DATA_TYPE_ID: {
1780 switch (dst_type) {
1782 return src;
1787 IDPropertyUIData *dst = convert_base_ui_data(src, dst_type);
1788 ui_data_free(src, src_type);
1789 return dst;
1790 }
1792 break;
1793 }
1794 break;
1795 }
1796 case IDP_UI_DATA_TYPE_INT: {
1797 IDPropertyUIDataInt *src_int = reinterpret_cast<IDPropertyUIDataInt *>(src);
1798 switch (dst_type) {
1800 return src;
1803 IDPropertyUIData *dst = convert_base_ui_data(src, dst_type);
1804 ui_data_free(src, src_type);
1805 return dst;
1806 }
1808 IDPropertyUIDataBool *dst = reinterpret_cast<IDPropertyUIDataBool *>(
1809 convert_base_ui_data(src, dst_type));
1810 dst->default_value = src_int->default_value != 0;
1811 if (src_int->default_array) {
1812 dst->default_array = static_cast<int8_t *>(MEM_malloc_arrayN(
1813 size_t(src_int->default_array_len), sizeof(*dst->default_array), __func__));
1814 for (int i = 0; i < src_int->default_array_len; i++) {
1815 dst->default_array[i] = src_int->default_array[i] != 0;
1816 }
1817 }
1818 ui_data_free(src, src_type);
1819 return &dst->base;
1820 }
1822 IDPropertyUIDataFloat *dst = reinterpret_cast<IDPropertyUIDataFloat *>(
1823 convert_base_ui_data(src, dst_type));
1824 dst->min = double(src_int->min);
1825 dst->max = double(src_int->max);
1826 dst->soft_min = double(src_int->soft_min);
1827 dst->soft_max = double(src_int->soft_max);
1828 dst->step = float(src_int->step);
1829 dst->default_value = double(src_int->default_value);
1830 if (src_int->default_array) {
1831 dst->default_array = static_cast<double *>(MEM_malloc_arrayN(
1832 size_t(src_int->default_array_len), sizeof(*dst->default_array), __func__));
1833 for (int i = 0; i < src_int->default_array_len; i++) {
1834 dst->default_array[i] = double(src_int->default_array[i]);
1835 }
1836 }
1837 ui_data_free(src, src_type);
1838 return &dst->base;
1839 }
1841 break;
1842 }
1843 break;
1844 }
1846 IDPropertyUIDataBool *src_bool = reinterpret_cast<IDPropertyUIDataBool *>(src);
1847 switch (dst_type) {
1849 return src;
1852 IDPropertyUIData *dst = convert_base_ui_data(src, dst_type);
1853 ui_data_free(src, src_type);
1854 return dst;
1855 }
1856 case IDP_UI_DATA_TYPE_INT: {
1857 IDPropertyUIDataInt *dst = reinterpret_cast<IDPropertyUIDataInt *>(
1858 convert_base_ui_data(src, dst_type));
1859 dst->min = 0;
1860 dst->max = 1;
1861 dst->soft_min = 0;
1862 dst->soft_max = 1;
1863 dst->step = 1;
1864 dst->default_value = int(src_bool->default_value);
1865 if (src_bool->default_array) {
1866 dst->default_array = static_cast<int *>(MEM_malloc_arrayN(
1867 size_t(src_bool->default_array_len), sizeof(*dst->default_array), __func__));
1868 for (int i = 0; i < src_bool->default_array_len; i++) {
1869 dst->default_array[i] = int(src_bool->default_array[i]);
1870 }
1871 }
1872 ui_data_free(src, src_type);
1873 return &dst->base;
1874 }
1876 IDPropertyUIDataFloat *dst = reinterpret_cast<IDPropertyUIDataFloat *>(
1877 convert_base_ui_data(src, dst_type));
1878 dst->min = 0.0;
1879 dst->max = 1.0;
1880 dst->soft_min = 0.0;
1881 dst->soft_max = 1.0;
1882 dst->step = 1.0;
1883 if (src_bool->default_array) {
1884 dst->default_array = static_cast<double *>(MEM_malloc_arrayN(
1885 size_t(src_bool->default_array_len), sizeof(*dst->default_array), __func__));
1886 for (int i = 0; i < src_bool->default_array_len; i++) {
1887 dst->default_array[i] = src_bool->default_array[i] == 0 ? 0.0 : 1.0;
1888 }
1889 }
1890 ui_data_free(src, src_type);
1891 return &dst->base;
1892 }
1894 break;
1895 }
1896 break;
1897 }
1899 IDPropertyUIDataFloat *src_float = reinterpret_cast<IDPropertyUIDataFloat *>(src);
1900 switch (dst_type) {
1902 return src;
1905 return convert_base_ui_data(src, dst_type);
1906 case IDP_UI_DATA_TYPE_INT: {
1907 auto clamp_double_to_int = [](const double value) {
1908 return int(std::clamp<double>(value, INT_MIN, INT_MAX));
1909 };
1910 IDPropertyUIDataInt *dst = reinterpret_cast<IDPropertyUIDataInt *>(
1911 convert_base_ui_data(src, dst_type));
1912 dst->min = clamp_double_to_int(src_float->min);
1913 dst->max = clamp_double_to_int(src_float->max);
1914 dst->soft_min = clamp_double_to_int(src_float->soft_min);
1915 dst->soft_max = clamp_double_to_int(src_float->soft_max);
1916 dst->step = clamp_double_to_int(src_float->step);
1917 dst->default_value = clamp_double_to_int(src_float->default_value);
1918 if (src_float->default_array) {
1919 dst->default_array = static_cast<int *>(MEM_malloc_arrayN(
1920 size_t(src_float->default_array_len), sizeof(*dst->default_array), __func__));
1921 for (int i = 0; i < src_float->default_array_len; i++) {
1922 dst->default_array[i] = clamp_double_to_int(src_float->default_array[i]);
1923 }
1924 }
1925 ui_data_free(src, src_type);
1926 return &dst->base;
1927 }
1929 IDPropertyUIDataBool *dst = reinterpret_cast<IDPropertyUIDataBool *>(
1930 convert_base_ui_data(src, dst_type));
1931 dst->default_value = src_float->default_value > 0.0f;
1932 if (src_float->default_array) {
1933 dst->default_array = static_cast<int8_t *>(MEM_malloc_arrayN(
1934 size_t(src_float->default_array_len), sizeof(*dst->default_array), __func__));
1935 for (int i = 0; i < src_float->default_array_len; i++) {
1936 dst->default_array[i] = src_float->default_array[i] > 0.0f;
1937 }
1938 }
1939 ui_data_free(src, src_type);
1940 return &dst->base;
1941 }
1943 break;
1944 }
1945 break;
1946 }
1948 break;
1949 }
1950 ui_data_free(src, src_type);
1951 return nullptr;
1952}
1953
#define IDP_Float(prop)
#define IDP_IDPArray(prop)
#define IDP_Int(prop)
#define IDP_Id(prop)
#define IDP_Bool(prop)
eIDPropertyUIDataType
@ IDP_UI_DATA_TYPE_ID
@ IDP_UI_DATA_TYPE_BOOLEAN
@ IDP_UI_DATA_TYPE_UNSUPPORTED
@ IDP_UI_DATA_TYPE_INT
@ IDP_UI_DATA_TYPE_FLOAT
@ IDP_UI_DATA_TYPE_STRING
#define IDP_String(prop)
#define IDP_Double(prop)
void IDP_print(const IDProperty *prop)
#define IDP_Array(prop)
@ LIB_ID_CREATE_NO_USER_REFCOUNT
void id_us_plus(ID *id)
Definition lib_id.cc:351
void id_us_min(ID *id)
Definition lib_id.cc:359
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
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)
void * BLI_findstring(const struct ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define LISTBASE_FOREACH(type, var, list)
void BLI_insertlinkreplace(ListBase *listbase, void *vreplacelink, void *vnewlink) ATTR_NONNULL(1
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition listbase.cc:331
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:496
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE float max_ff(float a, float b)
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.c:40
#define STRNCPY(dst, src)
Definition BLI_string.h:593
int char char int int int int size_t BLI_strnlen(const char *str, size_t maxlen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition string.c:909
char * BLI_strdup_null(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_MALLOC
Definition string.c:45
unsigned int uint
#define STREQLEN(a, b, n)
#define ELEM(...)
#define STREQ(a, b)
void BLO_write_double_array(BlendWriter *writer, uint num, const double *data_ptr)
void BLO_write_int32_array(BlendWriter *writer, uint num, const int32_t *data_ptr)
void BLO_read_double_array(BlendDataReader *reader, int array_size, double **ptr_p)
Definition readfile.cc:4982
void BLO_read_float_array(BlendDataReader *reader, int array_size, float **ptr_p)
Definition readfile.cc:4967
void BLO_read_int32_array(BlendDataReader *reader, int array_size, int32_t **ptr_p)
Definition readfile.cc:4947
#define BLO_write_struct(writer, struct_name, data_ptr)
void BLO_read_string(BlendDataReader *reader, char **ptr_p)
Definition readfile.cc:4992
void BLO_write_float_array(BlendWriter *writer, uint num, const float *data_ptr)
void BLO_write_string(BlendWriter *writer, const char *data_ptr)
#define BLO_write_struct_array(writer, struct_name, array_size, data_ptr)
void BLO_write_int8_array(BlendWriter *writer, uint num, const int8_t *data_ptr)
void BLO_read_char_array(BlendDataReader *reader, int array_size, char **ptr_p)
Definition readfile.cc:4929
bool BLO_read_requires_endian_switch(BlendDataReader *reader)
Definition readfile.cc:4903
void BLO_write_char_array(BlendWriter *writer, uint num, const char *data_ptr)
#define BLO_read_struct_list(reader, struct_name, list)
#define BLO_read_struct_array(reader, struct_name, array_size, ptr_p)
void BLO_read_pointer_array(BlendDataReader *reader, int array_size, void **ptr_p)
Definition readfile.cc:5052
#define BLO_read_struct(reader, struct_name, ptr_p)
void BLO_read_int8_array(BlendDataReader *reader, int array_size, int8_t **ptr_p)
Definition readfile.cc:4941
void BLO_write_pointer_array(BlendWriter *writer, uint num, const void *data_ptr)
typedef double(DMatrix)[4][4]
#define CLOG_ERROR(clg_ref,...)
Definition CLG_log.h:182
#define DEFAULT_ALLOC_FOR_NULL_STRINGS
Definition DNA_ID.h:186
@ ID_FLAG_EMBEDDED_DATA
Definition DNA_ID.h:725
@ IDP_STRING_SUB_UTF8
@ IDP_STRING_SUB_BYTE
eIDPropertyType
@ IDP_DOUBLE
@ IDP_FLOAT
@ IDP_STRING
@ IDP_BOOLEAN
@ IDP_IDPARRAY
@ IDP_INT
@ IDP_GROUP
@ IDP_ARRAY
@ IDP_ID
eIDPropertyFlag
struct ListBase ListBase
Read Guarded memory(de)allocation.
#define MEM_recallocN(vmemh, len)
#define MEM_SAFE_FREE(v)
void reserve(const int64_t n)
Definition BLI_set.hh:614
bool add(const Key &key)
Definition BLI_set.hh:248
#define printf
DEGForeachIDComponentCallback callback
#define offsetof(t, d)
#define fabsf(x)
int len
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
#define IDP_ARRAY_REALLOC_LIMIT
Definition idprop.cc:43
static IDProperty * IDP_CopyArray(const IDProperty *prop, const int flag)
Definition idprop.cc:328
void IDP_SyncGroupTypes(IDProperty *dest, const IDProperty *src, const bool do_arraylen)
Definition idprop.cc:607
bool IDP_EqualsProperties(const IDProperty *prop1, const IDProperty *prop2)
Definition idprop.cc:984
void IDP_Reset(IDProperty *prop, const IDProperty *reference)
Definition idprop.cc:1240
IDProperty * IDP_NewString(const char *st, const char *name, const eIDPropertyFlag flags)
Definition idprop.cc:393
void IDP_ui_data_free(IDProperty *prop)
Definition idprop.cc:1183
IDProperty * IDP_CopyProperty_ex(const IDProperty *prop, const int flag)
Definition idprop.cc:843
bool IDP_InsertToGroup(IDProperty *group, IDProperty *previous, IDProperty *pnew)
Definition idprop.cc:735
bool IDP_AddToGroup(IDProperty *group, IDProperty *prop)
Definition idprop.cc:722
static void IDP_WriteGroup(const IDProperty *prop, BlendWriter *writer)
Definition idprop.cc:1408
static IDProperty * IDP_CopyGroup(const IDProperty *prop, const int flag)
Definition idprop.cc:564
float IDP_coerce_to_float_or_zero(const IDProperty *prop)
Definition idprop.cc:827
static IDProperty * idp_generic_copy(const IDProperty *prop, const int)
Definition idprop.cc:311
IDPropertyUIData * IDP_TryConvertUIData(IDPropertyUIData *src, const eIDPropertyUIDataType src_type, const eIDPropertyUIDataType dst_type)
Definition idprop.cc:1757
static IDProperty * IDP_CopyID(const IDProperty *prop, const int flag)
Definition idprop.cc:525
IDProperty * IDP_CopyProperty(const IDProperty *prop)
Definition idprop.cc:861
eIDPropertyUIDataType IDP_ui_data_type(const IDProperty *prop)
Definition idprop.cc:1665
bool IDP_ui_data_supported(const IDProperty *prop)
Definition idprop.cc:1687
static void idp_resize_group_array(IDProperty *prop, int newlen, void *newarr)
Definition idprop.cc:192
IDProperty * IDP_GetPropertyFromGroup(const IDProperty *prop, const char *name)
Definition idprop.cc:763
void IDP_SyncGroupValues(IDProperty *dest, const IDProperty *src)
Definition idprop.cc:578
IDPropertyUIData * IDP_ui_data_copy(const IDProperty *prop)
Definition idprop.cc:260
IDProperty * IDP_New(const char type, const IDPropertyTemplate *val, const char *name, const eIDPropertyFlag flags)
Definition idprop.cc:989
void IDP_ReplaceGroupInGroup(IDProperty *dest, const IDProperty *src)
Definition idprop.cc:630
#define GETPROP(prop, i)
Definition idprop.cc:67
IDProperty * IDP_GetProperties(ID *id)
Definition idprop.cc:875
void IDP_MergeGroup_ex(IDProperty *dest, const IDProperty *src, const bool do_overwrite, const int flag)
Definition idprop.cc:676
static void IDP_FreeIDPArray(IDProperty *prop, const bool do_id_user)
Definition idprop.cc:104
void IDP_FreeString(IDProperty *prop)
Definition idprop.cc:438
bool IDP_EnumItemsValidate(const IDPropertyUIDataEnumItem *items, const int items_num, void(*error_fn)(const char *))
Definition idprop.cc:480
static void IDP_DirectLinkIDPArray(IDProperty *prop, BlendDataReader *reader)
Definition idprop.cc:1525
void IDP_WriteProperty_OnlyData(const IDProperty *prop, BlendWriter *writer)
Definition idprop.cc:1416
void IDP_RemoveFromGroup(IDProperty *group, IDProperty *prop)
Definition idprop.cc:748
void IDP_FreeProperty(IDProperty *prop)
Definition idprop.cc:1227
static size_t idp_size_table[]
Definition idprop.cc:48
void IDP_AssignID(IDProperty *prop, ID *id, const int flag)
Definition idprop.cc:538
int IDP_coerce_to_int_or_zero(const IDProperty *prop)
Definition idprop.cc:795
void IDP_CopyPropertyContent(IDProperty *dst, const IDProperty *src)
Definition idprop.cc:866
void IDP_FreeProperty_ex(IDProperty *prop, const bool do_id_user)
Definition idprop.cc:1221
static IDPropertyUIData * ui_data_alloc(const eIDPropertyUIDataType type)
Definition idprop.cc:1692
void IDP_FreePropertyContent(IDProperty *prop)
Definition idprop.cc:1216
void IDP_AssignStringMaxSize(IDProperty *prop, const char *st, const size_t st_maxncpy)
Definition idprop.cc:413
void IDP_ReplaceInGroup_ex(IDProperty *group, IDProperty *prop, IDProperty *prop_exist)
Definition idprop.cc:654
void IDP_foreach_property(IDProperty *id_property_root, const int type_filter, const blender::FunctionRef< void(IDProperty *id_property)> callback)
Definition idprop.cc:1251
IDProperty * IDP_GetPropertyTypeFromGroup(const IDProperty *prop, const char *name, const char type)
Definition idprop.cc:769
void IDP_FreePropertyContent_ex(IDProperty *prop, const bool do_id_user)
Definition idprop.cc:1189
static void IDP_DirectLinkGroup(IDProperty *prop, BlendDataReader *reader)
Definition idprop.cc:1587
void IDP_FreeFromGroup(IDProperty *group, IDProperty *prop)
Definition idprop.cc:757
static void IDP_DirectLinkString(IDProperty *prop, BlendDataReader *reader)
Definition idprop.cc:1580
void IDP_ClearProperty(IDProperty *prop)
Definition idprop.cc:1233
static void ui_data_free(IDPropertyUIData *ui_data, const eIDPropertyUIDataType type)
Definition idprop.cc:1146
IDProperty * IDP_GetIndexArray(IDProperty *prop, int index)
Definition idprop.cc:133
double IDP_coerce_to_double_or_zero(const IDProperty *prop)
Definition idprop.cc:811
IDProperty * IDP_NewStringMaxSize(const char *st, const size_t st_maxncpy, const char *name, const eIDPropertyFlag flags)
Definition idprop.cc:357
void IDP_ResizeIDPArray(IDProperty *prop, int newlen)
Definition idprop.cc:148
static void IDP_DirectLinkProperty(IDProperty *prop, BlendDataReader *reader)
Definition idprop.cc:1599
static IDPropertyUIData * convert_base_ui_data(IDPropertyUIData *src, const eIDPropertyUIDataType dst_type)
Definition idprop.cc:1748
static void IDP_FreeGroup(IDProperty *prop, const bool do_id_user)
Definition idprop.cc:779
void IDP_MergeGroup(IDProperty *dest, const IDProperty *src, const bool do_overwrite)
Definition idprop.cc:717
bool IDP_EqualsProperties_ex(const IDProperty *prop1, const IDProperty *prop2, const bool is_strict)
Definition idprop.cc:893
static void IDP_int_ui_data_free_enum_items(IDPropertyUIDataInt *ui_data)
Definition idprop.cc:452
static void IDP_DirectLinkArray(IDProperty *prop, BlendDataReader *reader)
Definition idprop.cc:1545
void IDP_AppendArray(IDProperty *prop, IDProperty *item)
Definition idprop.cc:140
static void IDP_WriteString(const IDProperty *prop, BlendWriter *writer)
Definition idprop.cc:1400
static CLG_LogRef LOG
Definition idprop.cc:45
void IDP_SetIndexArray(IDProperty *prop, int index, IDProperty *item)
Definition idprop.cc:117
void IDP_ResizeArray(IDProperty *prop, int newlen)
Definition idprop.cc:215
void IDP_ui_data_free_unique_contents(IDPropertyUIData *ui_data, const eIDPropertyUIDataType type, const IDPropertyUIData *other)
Definition idprop.cc:1093
static IDProperty * IDP_CopyString(const IDProperty *prop, const int flag)
Definition idprop.cc:398
void IDP_ReplaceInGroup(IDProperty *group, IDProperty *prop)
Definition idprop.cc:669
static void IDP_WriteArray(const IDProperty *prop, BlendWriter *writer)
Definition idprop.cc:1345
void IDP_BlendWrite(BlendWriter *writer, const IDProperty *prop)
Definition idprop.cc:1437
static void write_ui_data(const IDProperty *prop, BlendWriter *writer)
Definition idprop.cc:1285
static void read_ui_data(IDProperty *prop, BlendDataReader *reader)
Definition idprop.cc:1445
IDPropertyUIData * IDP_ui_data_ensure(IDProperty *prop)
Definition idprop.cc:1739
void IDP_FreeArray(IDProperty *prop)
Definition idprop.cc:252
IDProperty * IDP_EnsureProperties(ID *id)
Definition idprop.cc:880
static void IDP_WriteIDPArray(const IDProperty *prop, BlendWriter *writer)
Definition idprop.cc:1386
void IDP_BlendReadData_impl(BlendDataReader *reader, IDProperty **prop, const char *caller_func_id)
Definition idprop.cc:1649
const IDPropertyUIDataEnumItem * IDP_EnumItemFind(const IDProperty *prop)
Definition idprop.cc:463
IDProperty * IDP_NewIDPArray(const char *name)
Definition idprop.cc:69
IDProperty * IDP_CopyIDPArray(const IDProperty *array, const int flag)
Definition idprop.cc:80
void IDP_AssignString(IDProperty *prop, const char *st)
Definition idprop.cc:431
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:45
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
void *(* MEM_dupallocN)(const void *vmemh)
Definition mallocn.cc:39
std::unique_ptr< IDProperty, IDPropertyDeleter > create_group(StringRefNull prop_name, eIDPropertyFlag flags={})
Allocate a new IDProperty of type IDP_GROUP.
static void copy(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node)
#define FLT_MAX
Definition stdcycles.h:14
unsigned int uint32_t
Definition stdint.h:80
__int64 int64_t
Definition stdint.h:89
signed int int32_t
Definition stdint.h:77
signed char int8_t
Definition stdint.h:75
ListBase group
Definition DNA_ID.h:146
void * pointer
Definition DNA_ID.h:145
int8_t * default_array
Definition DNA_ID.h:100
IDPropertyUIData base
Definition DNA_ID.h:99
double * default_array
Definition DNA_ID.h:110
IDPropertyUIData base
Definition DNA_ID.h:109
IDPropertyUIData base
Definition DNA_ID.h:132
IDPropertyUIData base
Definition DNA_ID.h:82
IDPropertyUIDataEnumItem * enum_items
Definition DNA_ID.h:94
int * default_array
Definition DNA_ID.h:83
char * description
Definition DNA_ID.h:59
short flag
Definition DNA_ID.h:161
int len
Definition DNA_ID.h:174
struct IDProperty * next
Definition DNA_ID.h:152
IDPropertyUIData * ui_data
Definition DNA_ID.h:182
char name[64]
Definition DNA_ID.h:163
IDPropertyData data
Definition DNA_ID.h:168
struct IDProperty * prev
Definition DNA_ID.h:152
char subtype
Definition DNA_ID.h:159
int totallen
Definition DNA_ID.h:180
char type
Definition DNA_ID.h:154
Definition DNA_ID.h:413
void * first
const char * str
Definition BKE_idprop.hh:37
struct IDPropertyTemplate::@30 array
struct IDPropertyTemplate::@29 string
uint8_t flag
Definition wm_window.cc:138