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