Blender V4.5
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_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_idprop.hh"
26#include "BKE_lib_id.hh"
27
28#include "CLG_log.h"
29
30#include "MEM_guardedalloc.h"
31
32#include "BLO_read_write.hh"
33
34#include "BLI_strict_flags.h" /* IWYU pragma: keep. Keep last. */
35
36/* IDPropertyTemplate is a union in DNA_ID.h */
37
42#define IDP_ARRAY_REALLOC_LIMIT 200
43
44static CLG_LogRef LOG = {"bke.idprop"};
45
47static size_t idp_size_table[] = {
48 1, /* #IDP_STRING */
49 sizeof(int), /* #IDP_INT */
50 sizeof(float), /* #IDP_FLOAT */
51 sizeof(float[3]), /* DEPRECATED (was vector). */
52 sizeof(float[16]), /* DEPRECATED (was matrix). */
53 0, /* #IDP_ARRAY (no fixed size). */
54 sizeof(ListBase), /* #IDP_GROUP */
55 sizeof(void *), /* #IDP_ID */
56 sizeof(double), /* #IDP_DOUBLE */
57 0, /* #IDP_IDPARRAY (no fixed size). */
58 sizeof(int8_t), /* #IDP_BOOLEAN */
59 sizeof(int), /* #IDP_ENUM */
60};
61
62/* -------------------------------------------------------------------- */
65
66#define GETPROP(prop, i) &(IDP_IDPArray(prop)[i])
67
69{
70 IDProperty *prop = MEM_callocN<IDProperty>("IDProperty prop array");
71 prop->type = IDP_IDPARRAY;
72 prop->len = 0;
73 name.copy_utf8_truncated(prop->name);
74
75 return prop;
76}
77
79{
80 /* don't use MEM_dupallocN because this may be part of an array */
82
83 IDProperty *narray = MEM_mallocN<IDProperty>(__func__);
84 *narray = *array;
85
86 narray->data.pointer = MEM_dupallocN(array->data.pointer);
87 for (int i = 0; i < narray->len; i++) {
88 /* OK, the copy functions always allocate a new structure,
89 * which doesn't work here. instead, simply copy the
90 * contents of the new structure into the array cell,
91 * then free it. this makes for more maintainable
92 * code than simply re-implementing the copy functions
93 * in this loop. */
95 memcpy(GETPROP(narray, i), tmp, sizeof(IDProperty));
96 MEM_freeN(tmp);
97 }
98
99 return narray;
100}
101
102static void IDP_FreeIDPArray(IDProperty *prop, const bool do_id_user)
103{
104 BLI_assert(prop->type == IDP_IDPARRAY);
105
106 for (int i = 0; i < prop->len; i++) {
107 IDP_FreePropertyContent_ex(GETPROP(prop, i), do_id_user);
108 }
109
110 if (prop->data.pointer) {
111 MEM_freeN(prop->data.pointer);
112 }
113}
114
115void IDP_SetIndexArray(IDProperty *prop, int index, IDProperty *item)
116{
117 BLI_assert(prop->type == IDP_IDPARRAY);
118
119 if (index >= prop->len || index < 0) {
120 return;
121 }
122
123 IDProperty *old = GETPROP(prop, index);
124 if (item != old) {
126
127 memcpy(old, item, sizeof(IDProperty));
128 }
129}
130
132{
133 BLI_assert(prop->type == IDP_IDPARRAY);
134
135 return GETPROP(prop, index);
136}
137
139{
140 BLI_assert(prop->type == IDP_IDPARRAY);
141
142 IDP_ResizeIDPArray(prop, prop->len + 1);
143 IDP_SetIndexArray(prop, prop->len - 1, item);
144}
145
146void IDP_ResizeIDPArray(IDProperty *prop, int newlen)
147{
148 BLI_assert(prop->type == IDP_IDPARRAY);
149
150 /* first check if the array buffer size has room */
151 if (newlen <= prop->totallen) {
152 if (newlen < prop->len && prop->totallen - newlen < IDP_ARRAY_REALLOC_LIMIT) {
153 for (int i = newlen; i < prop->len; i++) {
155 }
156
157 prop->len = newlen;
158 return;
159 }
160 if (newlen >= prop->len) {
161 prop->len = newlen;
162 return;
163 }
164 }
165
166 /* free trailing items */
167 if (newlen < prop->len) {
168 /* newlen is smaller */
169 for (int i = newlen; i < prop->len; i++) {
171 }
172 }
173
174 /* NOTE: This code comes from python, here's the corresponding comment. */
175 /* This over-allocates proportional to the list size, making room
176 * for additional growth. The over-allocation is mild, but is
177 * enough to give linear-time amortized behavior over a long
178 * sequence of appends() in the presence of a poorly-performing
179 * system realloc().
180 * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
181 */
182 int newsize = newlen;
183 newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize;
184 prop->data.pointer = MEM_recallocN(prop->data.pointer, sizeof(IDProperty) * size_t(newsize));
185 prop->len = newlen;
186 prop->totallen = newsize;
187}
188
189/* ----------- Numerical Array Type ----------- */
190static void idp_resize_group_array(IDProperty *prop, int newlen, void *newarr)
191{
192 if (prop->subtype != IDP_GROUP) {
193 return;
194 }
195
196 if (newlen >= prop->len) {
197 /* bigger */
198 IDProperty **array = static_cast<IDProperty **>(newarr);
199 for (int a = prop->len; a < newlen; a++) {
200 array[a] = blender::bke::idprop::create_group("IDP_ResizeArray group").release();
201 }
202 }
203 else {
204 /* smaller */
205 IDProperty **array = static_cast<IDProperty **>(prop->data.pointer);
206
207 for (int a = newlen; a < prop->len; a++) {
209 }
210 }
211}
212
213void IDP_ResizeArray(IDProperty *prop, int newlen)
214{
215 const bool is_grow = newlen >= prop->len;
216
217 /* first check if the array buffer size has room */
218 if (newlen <= prop->totallen && prop->totallen - newlen < IDP_ARRAY_REALLOC_LIMIT) {
219 idp_resize_group_array(prop, newlen, prop->data.pointer);
220 prop->len = newlen;
221 return;
222 }
223
224 /* NOTE: This code comes from python, here's the corresponding comment. */
225 /* This over-allocates proportional to the list size, making room
226 * for additional growth. The over-allocation is mild, but is
227 * enough to give linear-time amortized behavior over a long
228 * sequence of appends() in the presence of a poorly-performing
229 * system realloc().
230 * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
231 */
232 int newsize = newlen;
233 newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize;
234
235 if (is_grow == false) {
236 idp_resize_group_array(prop, newlen, prop->data.pointer);
237 }
238
239 prop->data.pointer = MEM_recallocN(prop->data.pointer,
240 idp_size_table[int(prop->subtype)] * size_t(newsize));
241
242 if (is_grow == true) {
243 idp_resize_group_array(prop, newlen, prop->data.pointer);
244 }
245
246 prop->len = newlen;
247 prop->totallen = newsize;
248}
249
251{
252 if (prop->data.pointer) {
253 idp_resize_group_array(prop, 0, nullptr);
254 MEM_freeN(prop->data.pointer);
255 }
256}
257
259{
260 IDPropertyUIData *dst_ui_data = static_cast<IDPropertyUIData *>(MEM_dupallocN(prop->ui_data));
261
262 /* Copy extra type specific data. */
263 switch (IDP_ui_data_type(prop)) {
265 const IDPropertyUIDataString *src = (const IDPropertyUIDataString *)prop->ui_data;
267 dst->default_value = static_cast<char *>(MEM_dupallocN(src->default_value));
268 break;
269 }
270 case IDP_UI_DATA_TYPE_ID: {
271 break;
272 }
274 const IDPropertyUIDataInt *src = (const IDPropertyUIDataInt *)prop->ui_data;
275 IDPropertyUIDataInt *dst = (IDPropertyUIDataInt *)dst_ui_data;
276 dst->default_array = static_cast<int *>(MEM_dupallocN(src->default_array));
277 dst->enum_items = static_cast<IDPropertyUIDataEnumItem *>(MEM_dupallocN(src->enum_items));
278 for (const int64_t i : blender::IndexRange(src->enum_items_num)) {
279 const IDPropertyUIDataEnumItem &src_item = src->enum_items[i];
280 IDPropertyUIDataEnumItem &dst_item = dst->enum_items[i];
281 dst_item.identifier = BLI_strdup(src_item.identifier);
282 dst_item.name = BLI_strdup_null(src_item.name);
283 dst_item.description = BLI_strdup_null(src_item.description);
284 }
285 break;
286 }
288 const IDPropertyUIDataBool *src = (const IDPropertyUIDataBool *)prop->ui_data;
289 IDPropertyUIDataBool *dst = (IDPropertyUIDataBool *)dst_ui_data;
290 dst->default_array = static_cast<int8_t *>(MEM_dupallocN(src->default_array));
291 break;
292 }
294 const IDPropertyUIDataFloat *src = (const IDPropertyUIDataFloat *)prop->ui_data;
295 IDPropertyUIDataFloat *dst = (IDPropertyUIDataFloat *)dst_ui_data;
296 dst->default_array = static_cast<double *>(MEM_dupallocN(src->default_array));
297 break;
298 }
300 break;
301 }
302 }
303
304 dst_ui_data->description = static_cast<char *>(MEM_dupallocN(prop->ui_data->description));
305
306 return dst_ui_data;
307}
308
309static IDProperty *idp_generic_copy(const IDProperty *prop, const int /*flag*/)
310{
311 IDProperty *newp = MEM_callocN<IDProperty>(__func__);
312
313 STRNCPY(newp->name, prop->name);
314 newp->type = prop->type;
315 newp->flag = prop->flag;
316 newp->data.val = prop->data.val;
317 newp->data.val2 = prop->data.val2;
318
319 if (prop->ui_data != nullptr) {
320 newp->ui_data = IDP_ui_data_copy(prop);
321 }
322
323 return newp;
324}
325
326static IDProperty *IDP_CopyArray(const IDProperty *prop, const int flag)
327{
328 IDProperty *newp = idp_generic_copy(prop, flag);
329
330 if (prop->data.pointer) {
331 newp->data.pointer = MEM_dupallocN(prop->data.pointer);
332
333 if (prop->type == IDP_GROUP) {
334 IDProperty **array = static_cast<IDProperty **>(newp->data.pointer);
335 int a;
336
337 for (a = 0; a < prop->len; a++) {
339 }
340 }
341 }
342 newp->len = prop->len;
343 newp->subtype = prop->subtype;
344 newp->totallen = prop->totallen;
345
346 return newp;
347}
348
350
351/* -------------------------------------------------------------------- */
354
356 const size_t st_maxncpy,
357 const blender::StringRef name,
358 const eIDPropertyFlag flags)
359{
360 IDProperty *prop = MEM_callocN<IDProperty>("IDProperty string");
361
362 if (st == nullptr) {
364 "id property string 1");
365 *IDP_String(prop) = '\0';
367 prop->len = 1; /* nullptr string, has len of 1 to account for null byte. */
368 }
369 else {
370 /* include null terminator '\0' */
371 const int stlen = int((st_maxncpy > 0) ? BLI_strnlen(st, st_maxncpy - 1) : strlen(st)) + 1;
372
373 prop->data.pointer = MEM_malloc_arrayN<char>(size_t(stlen), "id property string 2");
374 prop->len = prop->totallen = stlen;
375
376 /* Ensured above, must always be true otherwise null terminator assignment will be invalid. */
377 BLI_assert(stlen > 0);
378 if (stlen > 1) {
379 memcpy(prop->data.pointer, st, size_t(stlen));
380 }
381 IDP_String(prop)[stlen - 1] = '\0';
382 }
383
384 prop->type = IDP_STRING;
385 name.copy_utf8_truncated(prop->name);
386 prop->flag = short(flags);
387
388 return prop;
389}
390
391IDProperty *IDP_NewString(const char *st,
392 const blender::StringRef name,
393 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}
446
447
448/* -------------------------------------------------------------------- */
451
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
520
521/* -------------------------------------------------------------------- */
524
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
556
557/* -------------------------------------------------------------------- */
560
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 IDProperty *prop,
656 IDProperty *prop_exist,
657 const int flag)
658{
659 BLI_assert(group->type == IDP_GROUP);
660 BLI_assert(prop_exist == IDP_GetPropertyFromGroup(group, prop->name));
661
662 if (prop_exist != nullptr) {
663 BLI_insertlinkreplace(&group->data.group, prop_exist, prop);
665 }
666 else {
667 group->len++;
668 BLI_addtail(&group->data.group, prop);
669 }
670}
671
673{
674 IDProperty *prop_exist = IDP_GetPropertyFromGroup(group, prop->name);
675
676 IDP_ReplaceInGroup_ex(group, prop, prop_exist, 0);
677}
678
680 const IDProperty *src,
681 const bool do_overwrite,
682 const int flag)
683{
684 BLI_assert(dest->type == IDP_GROUP);
685 BLI_assert(src->type == IDP_GROUP);
686
687 if (do_overwrite) {
688 LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) {
689 if (prop->type == IDP_GROUP) {
690 IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name);
691
692 if (prop_exist != nullptr) {
693 IDP_MergeGroup_ex(prop_exist, prop, do_overwrite, flag);
694 continue;
695 }
696 }
697
700 }
701 }
702 else {
703 LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) {
704 IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name);
705 if (prop_exist != nullptr) {
706 if (prop->type == IDP_GROUP) {
707 IDP_MergeGroup_ex(prop_exist, prop, do_overwrite, flag);
708 continue;
709 }
710 }
711 else {
713 dest->len++;
714 BLI_addtail(&dest->data.group, copy);
715 }
716 }
717 }
718}
719
720void IDP_MergeGroup(IDProperty *dest, const IDProperty *src, const bool do_overwrite)
721{
722 IDP_MergeGroup_ex(dest, src, do_overwrite, 0);
723}
724
726{
727 BLI_assert(group->type == IDP_GROUP);
728
729 if (IDP_GetPropertyFromGroup(group, prop->name) == nullptr) {
730 group->len++;
731 BLI_addtail(&group->data.group, prop);
732 return true;
733 }
734
735 return false;
736}
737
738bool IDP_InsertToGroup(IDProperty *group, IDProperty *previous, IDProperty *pnew)
739{
740 BLI_assert(group->type == IDP_GROUP);
741
742 if (IDP_GetPropertyFromGroup(group, pnew->name) == nullptr) {
743 group->len++;
744 BLI_insertlinkafter(&group->data.group, previous, pnew);
745 return true;
746 }
747
748 return false;
749}
750
752{
753 BLI_assert(group->type == IDP_GROUP);
754 BLI_assert(BLI_findindex(&group->data.group, prop) != -1);
755
756 group->len--;
757 BLI_remlink(&group->data.group, prop);
758}
759
761{
762 IDP_RemoveFromGroup(group, prop);
763 IDP_FreeProperty(prop);
764}
765
767{
768 BLI_assert(prop->type == IDP_GROUP);
770 [&](const IDProperty &elem) { return elem.name == name; });
771}
772
773IDProperty *IDP_GetPropertyFromGroup(const IDProperty *prop, const char *name)
774{
775 BLI_assert(prop->type == IDP_GROUP);
776 return (IDProperty *)BLI_findstring(&prop->data.group, name, offsetof(IDProperty, name));
777}
778
780 const blender::StringRef name,
781 const char type)
782{
783 IDProperty *idprop = IDP_GetPropertyFromGroup(prop, name);
784 return (idprop && idprop->type == type) ? idprop : nullptr;
785}
786
787/* Ok, the way things work, Groups free the ID Property structs of their children.
788 * This is because all ID Property freeing functions free only direct data (not the ID Property
789 * struct itself), but for Groups the child properties *are* considered
790 * direct data. */
791static void IDP_FreeGroup(IDProperty *prop, const bool do_id_user)
792{
793 BLI_assert(prop->type == IDP_GROUP);
794
795 LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) {
796 IDP_FreePropertyContent_ex(loop, do_id_user);
797 }
798 BLI_freelistN(&prop->data.group);
799}
800
802
803/* -------------------------------------------------------------------- */
806
808{
809 switch (prop->type) {
810 case IDP_INT:
811 return IDP_Int(prop);
812 case IDP_DOUBLE:
813 return int(IDP_Double(prop));
814 case IDP_FLOAT:
815 return int(IDP_Float(prop));
816 case IDP_BOOLEAN:
817 return int(IDP_Bool(prop));
818 default:
819 return 0;
820 }
821}
822
824{
825 switch (prop->type) {
826 case IDP_DOUBLE:
827 return IDP_Double(prop);
828 case IDP_FLOAT:
829 return double(IDP_Float(prop));
830 case IDP_INT:
831 return double(IDP_Int(prop));
832 case IDP_BOOLEAN:
833 return double(IDP_Bool(prop));
834 default:
835 return 0.0;
836 }
837}
838
840{
841 switch (prop->type) {
842 case IDP_FLOAT:
843 return IDP_Float(prop);
844 case IDP_DOUBLE:
845 return float(IDP_Double(prop));
846 case IDP_INT:
847 return float(IDP_Int(prop));
848 case IDP_BOOLEAN:
849 return float(IDP_Bool(prop));
850 default:
851 return 0.0f;
852 }
853}
854
856{
857 switch (prop->type) {
858 case IDP_GROUP:
859 return IDP_CopyGroup(prop, flag);
860 case IDP_STRING:
861 return IDP_CopyString(prop, flag);
862 case IDP_ID:
863 return IDP_CopyID(prop, flag);
864 case IDP_ARRAY:
865 return IDP_CopyArray(prop, flag);
866 case IDP_IDPARRAY:
867 return IDP_CopyIDPArray(prop, flag);
868 default:
869 return idp_generic_copy(prop, flag);
870 }
871}
872
874{
875 return IDP_CopyProperty_ex(prop, 0);
876}
877
879{
880 IDProperty *idprop_tmp = IDP_CopyProperty(src);
881 idprop_tmp->prev = dst->prev;
882 idprop_tmp->next = dst->next;
883 std::swap(*dst, *idprop_tmp);
884 IDP_FreeProperty(idprop_tmp);
885}
886
888{
889 return id->properties;
890}
891
893{
894 if (id->properties == nullptr) {
895 id->properties = MEM_callocN<IDProperty>("IDProperty");
896 id->properties->type = IDP_GROUP;
897 /* NOTE(@ideasman42): Don't overwrite the data's name and type
898 * some functions might need this if they
899 * don't have a real ID, should be named elsewhere. */
900 // STRNCPY(id->name, "top_level_group");
901 }
902 return id->properties;
903}
904
906 const IDProperty *prop2,
907 const bool is_strict)
908{
909 if (prop1 == nullptr && prop2 == nullptr) {
910 return true;
911 }
912 if (prop1 == nullptr || prop2 == nullptr) {
913 return is_strict ? false : true;
914 }
915 if (prop1->type != prop2->type) {
916 return false;
917 }
918
919 switch (prop1->type) {
920 case IDP_INT:
921 return (IDP_Int(prop1) == IDP_Int(prop2));
922 case IDP_FLOAT:
923#if !defined(NDEBUG) && defined(WITH_PYTHON)
924 {
925 float p1 = IDP_Float(prop1);
926 float p2 = IDP_Float(prop2);
927 if ((p1 != p2) && ((fabsf(p1 - p2) / max_ff(fabsf(p1), fabsf(p2))) < 0.001f)) {
928 printf(
929 "WARNING: Comparing two float properties that have nearly the same value (%f vs. "
930 "%f)\n",
931 p1,
932 p2);
933 printf(" p1: ");
934 IDP_print(prop1);
935 printf(" p2: ");
936 IDP_print(prop2);
937 }
938 }
939#endif
940 return (IDP_Float(prop1) == IDP_Float(prop2));
941 case IDP_DOUBLE:
942 return (IDP_Double(prop1) == IDP_Double(prop2));
943 case IDP_BOOLEAN:
944 return (IDP_Bool(prop1) == IDP_Bool(prop2));
945 case IDP_STRING: {
946 return ((prop1->len == prop2->len) &&
947 STREQLEN(IDP_String(prop1), IDP_String(prop2), size_t(prop1->len)));
948 }
949 case IDP_ARRAY:
950 if (prop1->len == prop2->len && prop1->subtype == prop2->subtype) {
951 return (memcmp(IDP_Array(prop1),
952 IDP_Array(prop2),
953 idp_size_table[int(prop1->subtype)] * size_t(prop1->len)) == 0);
954 }
955 return false;
956 case IDP_GROUP: {
957 if (is_strict && prop1->len != prop2->len) {
958 return false;
959 }
960
961 LISTBASE_FOREACH (const IDProperty *, link1, &prop1->data.group) {
962 const IDProperty *link2 = IDP_GetPropertyFromGroup(prop2, link1->name);
963
964 if (!IDP_EqualsProperties_ex(link1, link2, is_strict)) {
965 return false;
966 }
967 }
968
969 return true;
970 }
971 case IDP_IDPARRAY: {
972 const IDProperty *array1 = IDP_IDPArray(prop1);
973 const IDProperty *array2 = IDP_IDPArray(prop2);
974
975 if (prop1->len != prop2->len) {
976 return false;
977 }
978
979 for (int i = 0; i < prop1->len; i++) {
980 if (!IDP_EqualsProperties_ex(&array1[i], &array2[i], is_strict)) {
981 return false;
982 }
983 }
984 return true;
985 }
986 case IDP_ID:
987 return (IDP_Id(prop1) == IDP_Id(prop2));
988 default:
990 break;
991 }
992
993 return true;
994}
995
996bool IDP_EqualsProperties(const IDProperty *prop1, const IDProperty *prop2)
997{
998 return IDP_EqualsProperties_ex(prop1, prop2, true);
999}
1000
1001IDProperty *IDP_New(const char type,
1002 const IDPropertyTemplate *val,
1003 const blender::StringRef name,
1004 const eIDPropertyFlag flags)
1005{
1006 IDProperty *prop = nullptr;
1007
1008 switch (type) {
1009 case IDP_INT:
1010 prop = MEM_callocN<IDProperty>("IDProperty int");
1011 prop->data.val = val->i;
1012 break;
1013 case IDP_FLOAT:
1014 prop = MEM_callocN<IDProperty>("IDProperty float");
1015 *(float *)&prop->data.val = val->f;
1016 break;
1017 case IDP_DOUBLE:
1018 prop = MEM_callocN<IDProperty>("IDProperty double");
1019 *(double *)&prop->data.val = val->d;
1020 break;
1021 case IDP_BOOLEAN:
1022 prop = MEM_callocN<IDProperty>("IDProperty boolean");
1023 prop->data.val = bool(val->i);
1024 break;
1025 case IDP_ARRAY: {
1026 /* FIXME: This seems to be the only place in code allowing `IDP_GROUP` as subtype of an
1027 * `IDP_ARRAY`. This is most likely a mistake. `IDP_GROUP` array should be of type
1028 * `IDP_IDPARRAY`, as done e.g. in #idp_from_PySequence_Buffer in bpy API. */
1030 prop = MEM_callocN<IDProperty>("IDProperty array");
1031 prop->subtype = val->array.type;
1032 if (val->array.len) {
1034 size_t(val->array.len), idp_size_table[val->array.type], "id property array");
1035 }
1036 prop->len = prop->totallen = val->array.len;
1037 break;
1038 }
1039 CLOG_ERROR(&LOG, "bad array type.");
1040 return nullptr;
1041 }
1042 case IDP_STRING: {
1043 const char *st = val->string.str;
1044
1045 prop = MEM_callocN<IDProperty>("IDProperty string");
1046 if (val->string.subtype == IDP_STRING_SUB_BYTE) {
1047 /* NOTE: Intentionally not null terminated. */
1048 if (st == nullptr) {
1050 "id property string 1");
1051 *IDP_String(prop) = '\0';
1053 prop->len = 0;
1054 }
1055 else {
1056 prop->data.pointer = MEM_malloc_arrayN<char>(size_t(val->string.len),
1057 "id property string 2");
1058 prop->len = prop->totallen = val->string.len;
1059 memcpy(prop->data.pointer, st, size_t(val->string.len));
1060 }
1062 }
1063 else {
1064 if (st == nullptr || val->string.len <= 1) {
1066 "id property string 1");
1067 *IDP_String(prop) = '\0';
1069 /* nullptr string, has len of 1 to account for null byte. */
1070 prop->len = 1;
1071 }
1072 else {
1073 BLI_assert(int(val->string.len) <= int(strlen(st)) + 1);
1074 prop->data.pointer = MEM_malloc_arrayN<char>(size_t(val->string.len),
1075 "id property string 3");
1076 memcpy(prop->data.pointer, st, size_t(val->string.len) - 1);
1077 IDP_String(prop)[val->string.len - 1] = '\0';
1078 prop->len = prop->totallen = val->string.len;
1079 }
1081 }
1082 break;
1083 }
1084 case IDP_GROUP: {
1085 /* Values are set properly by calloc. */
1086 prop = MEM_callocN<IDProperty>("IDProperty group");
1087 break;
1088 }
1089 case IDP_ID: {
1090 prop = MEM_callocN<IDProperty>("IDProperty datablock");
1091 prop->data.pointer = (void *)val->id;
1092 prop->type = IDP_ID;
1093 id_us_plus(IDP_Id(prop));
1094 break;
1095 }
1096 default: {
1097 prop = MEM_callocN<IDProperty>("IDProperty array");
1098 break;
1099 }
1100 }
1101
1102 prop->type = type;
1103 name.copy_utf8_truncated(prop->name);
1104 prop->flag = short(flags);
1105
1106 return prop;
1107}
1108
1110 const eIDPropertyUIDataType type,
1111 const IDPropertyUIData *other)
1112{
1113 if (ui_data->description != other->description) {
1114 MEM_SAFE_FREE(ui_data->description);
1115 }
1116
1117 switch (type) {
1119 const IDPropertyUIDataString *other_string = (const IDPropertyUIDataString *)other;
1120 IDPropertyUIDataString *ui_data_string = (IDPropertyUIDataString *)ui_data;
1121 if (ui_data_string->default_value != other_string->default_value) {
1122 MEM_SAFE_FREE(ui_data_string->default_value);
1123 }
1124 break;
1125 }
1126 case IDP_UI_DATA_TYPE_ID: {
1127 break;
1128 }
1129 case IDP_UI_DATA_TYPE_INT: {
1130 const IDPropertyUIDataInt *other_int = (const IDPropertyUIDataInt *)other;
1131 IDPropertyUIDataInt *ui_data_int = (IDPropertyUIDataInt *)ui_data;
1132 if (ui_data_int->default_array != other_int->default_array) {
1133 MEM_SAFE_FREE(ui_data_int->default_array);
1134 }
1135 if (ui_data_int->enum_items != other_int->enum_items) {
1137 }
1138 break;
1139 }
1141 const IDPropertyUIDataBool *other_bool = (const IDPropertyUIDataBool *)other;
1142 IDPropertyUIDataBool *ui_data_bool = (IDPropertyUIDataBool *)ui_data;
1143 if (ui_data_bool->default_array != other_bool->default_array) {
1144 MEM_SAFE_FREE(ui_data_bool->default_array);
1145 }
1146 break;
1147 }
1149 const IDPropertyUIDataFloat *other_float = (const IDPropertyUIDataFloat *)other;
1150 IDPropertyUIDataFloat *ui_data_float = (IDPropertyUIDataFloat *)ui_data;
1151 if (ui_data_float->default_array != other_float->default_array) {
1152 MEM_SAFE_FREE(ui_data_float->default_array);
1153 }
1154 break;
1155 }
1157 break;
1158 }
1159 }
1160}
1161
1162static void ui_data_free(IDPropertyUIData *ui_data, const eIDPropertyUIDataType type)
1163{
1164 switch (type) {
1166 IDPropertyUIDataString *ui_data_string = (IDPropertyUIDataString *)ui_data;
1167 MEM_SAFE_FREE(ui_data_string->default_value);
1168 break;
1169 }
1170 case IDP_UI_DATA_TYPE_ID: {
1171 break;
1172 }
1173 case IDP_UI_DATA_TYPE_INT: {
1174 IDPropertyUIDataInt *ui_data_int = (IDPropertyUIDataInt *)ui_data;
1175 MEM_SAFE_FREE(ui_data_int->default_array);
1177 break;
1178 }
1180 IDPropertyUIDataBool *ui_data_bool = (IDPropertyUIDataBool *)ui_data;
1181 MEM_SAFE_FREE(ui_data_bool->default_array);
1182 break;
1183 }
1185 IDPropertyUIDataFloat *ui_data_float = (IDPropertyUIDataFloat *)ui_data;
1186 MEM_SAFE_FREE(ui_data_float->default_array);
1187 break;
1188 }
1190 break;
1191 }
1192 }
1193
1194 MEM_SAFE_FREE(ui_data->description);
1195
1196 MEM_freeN(ui_data);
1197}
1198
1200{
1202 prop->ui_data = nullptr;
1203}
1204
1205void IDP_FreePropertyContent_ex(IDProperty *prop, const bool do_id_user)
1206{
1207 switch (prop->type) {
1208 case IDP_ARRAY:
1209 IDP_FreeArray(prop);
1210 break;
1211 case IDP_STRING:
1212 IDP_FreeString(prop);
1213 break;
1214 case IDP_GROUP:
1215 IDP_FreeGroup(prop, do_id_user);
1216 break;
1217 case IDP_IDPARRAY:
1218 IDP_FreeIDPArray(prop, do_id_user);
1219 break;
1220 case IDP_ID:
1221 if (do_id_user) {
1222 id_us_min(IDP_Id(prop));
1223 }
1224 break;
1225 }
1226
1227 if (prop->ui_data != nullptr) {
1228 IDP_ui_data_free(prop);
1229 }
1230}
1231
1233{
1234 IDP_FreePropertyContent_ex(prop, true);
1235}
1236
1237void IDP_FreeProperty_ex(IDProperty *prop, const bool do_id_user)
1238{
1239 IDP_FreePropertyContent_ex(prop, do_id_user);
1240 MEM_freeN(prop);
1241}
1242
1244{
1246 MEM_freeN(prop);
1247}
1248
1250{
1252 prop->data.pointer = nullptr;
1253 prop->len = prop->totallen = 0;
1254}
1255
1256void IDP_Reset(IDProperty *prop, const IDProperty *reference)
1257{
1258 if (prop == nullptr) {
1259 return;
1260 }
1261 IDP_ClearProperty(prop);
1262 if (reference != nullptr) {
1263 IDP_MergeGroup(prop, reference, true);
1264 }
1265}
1266
1267void IDP_foreach_property(IDProperty *id_property_root,
1268 const int type_filter,
1269 const blender::FunctionRef<void(IDProperty *id_property)> callback)
1270{
1271 if (!id_property_root) {
1272 return;
1273 }
1274
1275 if (type_filter == 0 || (1 << id_property_root->type) & type_filter) {
1276 callback(id_property_root);
1277 }
1278
1279 /* Recursive call into container types of ID properties. */
1280 switch (id_property_root->type) {
1281 case IDP_GROUP: {
1282 LISTBASE_FOREACH (IDProperty *, loop, &id_property_root->data.group) {
1283 IDP_foreach_property(loop, type_filter, callback);
1284 }
1285 break;
1286 }
1287 case IDP_IDPARRAY: {
1288 IDProperty *loop = static_cast<IDProperty *>(IDP_Array(id_property_root));
1289 for (int i = 0; i < id_property_root->len; i++) {
1290 IDP_foreach_property(&loop[i], type_filter, callback);
1291 }
1292 break;
1293 }
1294 default:
1295 break; /* Nothing to do here with other types of IDProperties... */
1296 }
1297}
1298
1299void IDP_WriteProperty_OnlyData(const IDProperty *prop, BlendWriter *writer);
1300
1301static void write_ui_data(const IDProperty *prop, BlendWriter *writer)
1302{
1303 IDPropertyUIData *ui_data = prop->ui_data;
1304
1305 BLO_write_string(writer, ui_data->description);
1306
1307 switch (IDP_ui_data_type(prop)) {
1309 IDPropertyUIDataString *ui_data_string = (IDPropertyUIDataString *)ui_data;
1310 BLO_write_string(writer, ui_data_string->default_value);
1311 BLO_write_struct(writer, IDPropertyUIDataString, ui_data);
1312 break;
1313 }
1314 case IDP_UI_DATA_TYPE_ID: {
1315 BLO_write_struct(writer, IDPropertyUIDataID, ui_data);
1316 break;
1317 }
1318 case IDP_UI_DATA_TYPE_INT: {
1319 IDPropertyUIDataInt *ui_data_int = (IDPropertyUIDataInt *)ui_data;
1320 if (prop->type == IDP_ARRAY) {
1322 writer, uint(ui_data_int->default_array_len), (int32_t *)ui_data_int->default_array);
1323 }
1325 writer, IDPropertyUIDataEnumItem, ui_data_int->enum_items_num, ui_data_int->enum_items);
1326 for (const int64_t i : blender::IndexRange(ui_data_int->enum_items_num)) {
1327 IDPropertyUIDataEnumItem &item = ui_data_int->enum_items[i];
1328 BLO_write_string(writer, item.identifier);
1329 BLO_write_string(writer, item.name);
1330 BLO_write_string(writer, item.description);
1331 }
1332 BLO_write_struct(writer, IDPropertyUIDataInt, ui_data);
1333 break;
1334 }
1336 IDPropertyUIDataBool *ui_data_bool = (IDPropertyUIDataBool *)ui_data;
1337 if (prop->type == IDP_ARRAY) {
1338 BLO_write_int8_array(writer,
1339 uint(ui_data_bool->default_array_len),
1340 (const int8_t *)ui_data_bool->default_array);
1341 }
1342 BLO_write_struct(writer, IDPropertyUIDataBool, ui_data);
1343 break;
1344 }
1346 IDPropertyUIDataFloat *ui_data_float = (IDPropertyUIDataFloat *)ui_data;
1347 if (prop->type == IDP_ARRAY) {
1349 writer, uint(ui_data_float->default_array_len), ui_data_float->default_array);
1350 }
1351 BLO_write_struct(writer, IDPropertyUIDataFloat, ui_data);
1352 break;
1353 }
1356 break;
1357 }
1358 }
1359}
1360
1361static void IDP_WriteArray(const IDProperty *prop, BlendWriter *writer)
1362{
1363 /* Remember to set #IDProperty.totallen to len in the linking code! */
1364 if (prop->data.pointer) {
1365 /* Only write the actual data (`prop->len`), not the whole allocated buffer (`prop->totallen`).
1366 */
1367 switch (eIDPropertyType(prop->subtype)) {
1368 case IDP_GROUP: {
1369 BLO_write_pointer_array(writer, uint32_t(prop->len), prop->data.pointer);
1370
1371 IDProperty **array = static_cast<IDProperty **>(prop->data.pointer);
1372 for (int i = 0; i < prop->len; i++) {
1373 IDP_BlendWrite(writer, array[i]);
1374 }
1375 break;
1376 }
1377 case IDP_DOUBLE:
1379 writer, uint32_t(prop->len), static_cast<double *>(prop->data.pointer));
1380 break;
1381 case IDP_INT:
1382 BLO_write_int32_array(writer, uint32_t(prop->len), static_cast<int *>(prop->data.pointer));
1383 break;
1384 case IDP_FLOAT:
1386 writer, uint32_t(prop->len), static_cast<float *>(prop->data.pointer));
1387 break;
1388 case IDP_BOOLEAN:
1390 writer, uint32_t(prop->len), static_cast<int8_t *>(prop->data.pointer));
1391 break;
1392 case IDP_STRING:
1393 case IDP_ARRAY:
1394 case IDP_ID:
1395 case IDP_IDPARRAY:
1397 break;
1398 }
1399 }
1400}
1401
1402static void IDP_WriteIDPArray(const IDProperty *prop, BlendWriter *writer)
1403{
1404 /* Remember to set #IDProperty.totallen to len in the linking code! */
1405 if (prop->data.pointer) {
1406 const IDProperty *array = static_cast<const IDProperty *>(prop->data.pointer);
1407
1408 BLO_write_struct_array(writer, IDProperty, prop->len, array);
1409
1410 for (int a = 0; a < prop->len; a++) {
1411 IDP_WriteProperty_OnlyData(&array[a], writer);
1412 }
1413 }
1414}
1415
1416static void IDP_WriteString(const IDProperty *prop, BlendWriter *writer)
1417{
1418 /* Remember to set #IDProperty.totallen to len in the linking code! */
1419 /* Do not use #BLO_write_string here, since 'bytes' sub-type of IDProperties may not be
1420 * null-terminated. */
1421 BLO_write_char_array(writer, uint(prop->len), static_cast<char *>(prop->data.pointer));
1422}
1423
1424static void IDP_WriteGroup(const IDProperty *prop, BlendWriter *writer)
1425{
1426 LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) {
1427 IDP_BlendWrite(writer, loop);
1428 }
1429}
1430
1431/* Functions to read/write ID Properties */
1433{
1434 switch (prop->type) {
1435 case IDP_GROUP:
1436 IDP_WriteGroup(prop, writer);
1437 break;
1438 case IDP_STRING:
1439 IDP_WriteString(prop, writer);
1440 break;
1441 case IDP_ARRAY:
1442 IDP_WriteArray(prop, writer);
1443 break;
1444 case IDP_IDPARRAY:
1445 IDP_WriteIDPArray(prop, writer);
1446 break;
1447 }
1448 if (prop->ui_data != nullptr) {
1449 write_ui_data(prop, writer);
1450 }
1451}
1452
1453void IDP_BlendWrite(BlendWriter *writer, const IDProperty *prop)
1454{
1455 BLO_write_struct(writer, IDProperty, prop);
1456 IDP_WriteProperty_OnlyData(prop, writer);
1457}
1458
1459static void IDP_DirectLinkProperty(IDProperty *prop, BlendDataReader *reader);
1460
1461static void read_ui_data(IDProperty *prop, BlendDataReader *reader)
1462{
1463 /* NOTE: null UI data can happen when opening more recent files with unknown types of
1464 * IDProperties. */
1465
1466 switch (IDP_ui_data_type(prop)) {
1469 if (prop->ui_data) {
1470 IDPropertyUIDataString *ui_data_string = (IDPropertyUIDataString *)prop->ui_data;
1471 BLO_read_string(reader, &ui_data_string->default_value);
1472 }
1473 break;
1474 }
1475 case IDP_UI_DATA_TYPE_ID: {
1477 break;
1478 }
1479 case IDP_UI_DATA_TYPE_INT: {
1481 IDPropertyUIDataInt *ui_data_int = (IDPropertyUIDataInt *)prop->ui_data;
1482 if (prop->type == IDP_ARRAY) {
1484 reader, ui_data_int->default_array_len, (&ui_data_int->default_array));
1485 }
1486 else {
1487 ui_data_int->default_array = nullptr;
1488 ui_data_int->default_array_len = 0;
1489 }
1490 BLO_read_struct_array(reader,
1492 size_t(ui_data_int->enum_items_num),
1493 &ui_data_int->enum_items);
1494 for (const int64_t i : blender::IndexRange(ui_data_int->enum_items_num)) {
1495 IDPropertyUIDataEnumItem &item = ui_data_int->enum_items[i];
1496 BLO_read_string(reader, &item.identifier);
1497 BLO_read_string(reader, &item.name);
1498 BLO_read_string(reader, &item.description);
1499 }
1500 break;
1501 }
1504 IDPropertyUIDataBool *ui_data_bool = (IDPropertyUIDataBool *)prop->ui_data;
1505 if (prop->type == IDP_ARRAY) {
1507 reader, ui_data_bool->default_array_len, (&ui_data_bool->default_array));
1508 }
1509 else {
1510 ui_data_bool->default_array = nullptr;
1511 ui_data_bool->default_array_len = 0;
1512 }
1513 break;
1514 }
1517 IDPropertyUIDataFloat *ui_data_float = (IDPropertyUIDataFloat *)prop->ui_data;
1518 if (prop->type == IDP_ARRAY) {
1520 reader, ui_data_float->default_array_len, (&ui_data_float->default_array));
1521 }
1522 else {
1523 ui_data_float->default_array = nullptr;
1524 ui_data_float->default_array_len = 0;
1525 }
1526 break;
1527 }
1530 /* Do not attempt to read unknown data. */
1531 prop->ui_data = nullptr;
1532 break;
1533 }
1534 }
1535
1536 if (prop->ui_data) {
1537 BLO_read_string(reader, &prop->ui_data->description);
1538 }
1539}
1540
1542{
1543 /* since we didn't save the extra buffer, set totallen to len */
1544 prop->totallen = prop->len;
1545 BLO_read_struct_array(reader, IDProperty, size_t(prop->len), &prop->data.pointer);
1546
1548
1549 /* NOTE:, idp-arrays didn't exist in 2.4x, so the pointer will be cleared
1550 * there's not really anything we can do to correct this, at least don't crash */
1551 if (array == nullptr) {
1552 prop->len = 0;
1553 prop->totallen = 0;
1554 }
1555
1556 for (int i = 0; i < prop->len; i++) {
1557 IDP_DirectLinkProperty(&array[i], reader);
1558 }
1559}
1560
1562{
1563 /* since we didn't save the extra buffer, set totallen to len */
1564 prop->totallen = prop->len;
1565
1566 switch (eIDPropertyType(prop->subtype)) {
1567 case IDP_GROUP: {
1568 BLO_read_pointer_array(reader, prop->len, &prop->data.pointer);
1569 IDProperty **array = static_cast<IDProperty **>(prop->data.pointer);
1570 for (int i = 0; i < prop->len; i++) {
1571 IDP_DirectLinkProperty(array[i], reader);
1572 }
1573 break;
1574 }
1575 case IDP_DOUBLE:
1576 BLO_read_double_array(reader, prop->len, (double **)&prop->data.pointer);
1577 break;
1578 case IDP_INT:
1579 BLO_read_int32_array(reader, prop->len, (int **)&prop->data.pointer);
1580 break;
1581 case IDP_FLOAT:
1582 BLO_read_float_array(reader, prop->len, (float **)&prop->data.pointer);
1583 break;
1584 case IDP_BOOLEAN:
1585 BLO_read_int8_array(reader, prop->len, (int8_t **)&prop->data.pointer);
1586 break;
1587 case IDP_STRING:
1588 case IDP_ARRAY:
1589 case IDP_ID:
1590 case IDP_IDPARRAY:
1592 break;
1593 }
1594}
1595
1597{
1598 /* Since we didn't save the extra string buffer, set totallen to len. */
1599 prop->totallen = prop->len;
1600 BLO_read_char_array(reader, prop->len, reinterpret_cast<char **>(&prop->data.pointer));
1601}
1602
1604{
1605 ListBase *lb = &prop->data.group;
1606
1607 BLO_read_struct_list(reader, IDProperty, lb);
1608
1609 /* Link child id properties now. */
1610 LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) {
1611 IDP_DirectLinkProperty(loop, reader);
1612 }
1613}
1614
1616{
1617 switch (prop->type) {
1618 case IDP_GROUP:
1619 IDP_DirectLinkGroup(prop, reader);
1620 break;
1621 case IDP_STRING:
1622 IDP_DirectLinkString(prop, reader);
1623 break;
1624 case IDP_ARRAY:
1625 IDP_DirectLinkArray(prop, reader);
1626 break;
1627 case IDP_IDPARRAY:
1628 IDP_DirectLinkIDPArray(prop, reader);
1629 break;
1630 case IDP_DOUBLE:
1631 /* Workaround for doubles.
1632 * They are stored in the same field as `int val, val2` in the #IDPropertyData struct,
1633 * they have to deal with endianness specifically.
1634 *
1635 * In theory, val and val2 would've already been swapped
1636 * if switch_endian is true, so we have to first un-swap
1637 * them then re-swap them as a single 64-bit entity. */
1638 if (BLO_read_requires_endian_switch(reader)) {
1642 }
1643 break;
1644 case IDP_INT:
1645 case IDP_FLOAT:
1646 case IDP_BOOLEAN:
1647 case IDP_ID:
1648 break; /* Nothing special to do here. */
1649 default:
1650 /* Unknown IDP type, nuke it (we cannot handle unknown types everywhere in code,
1651 * IDP are way too polymorphic to do it safely. */
1652 printf(
1653 "%s: found unknown IDProperty type %d, reset to Integer one !\n", __func__, prop->type);
1654 /* NOTE: we do not attempt to free unknown prop, we have no way to know how to do that! */
1655 prop->type = IDP_INT;
1656 prop->subtype = 0;
1657 IDP_Int(prop) = 0;
1658 }
1659
1660 if (prop->ui_data != nullptr) {
1661 read_ui_data(prop, reader);
1662 }
1663}
1664
1665void IDP_BlendReadData_impl(BlendDataReader *reader, IDProperty **prop, const char *caller_func_id)
1666{
1667 if (*prop) {
1668 if ((*prop)->type == IDP_GROUP) {
1669 IDP_DirectLinkGroup(*prop, reader);
1670 }
1671 else {
1672 /* corrupt file! */
1673 printf("%s: found non group data, freeing type %d!\n", caller_func_id, (*prop)->type);
1674 /* don't risk id, data's likely corrupt. */
1675 // IDP_FreePropertyContent(*prop);
1676 *prop = nullptr;
1677 }
1678 }
1679}
1680
1682{
1683 if (prop->type == IDP_STRING) {
1685 }
1686 if (prop->type == IDP_ID) {
1687 return IDP_UI_DATA_TYPE_ID;
1688 }
1689 if (prop->type == IDP_INT || (prop->type == IDP_ARRAY && prop->subtype == IDP_INT)) {
1690 return IDP_UI_DATA_TYPE_INT;
1691 }
1692 if (ELEM(prop->type, IDP_FLOAT, IDP_DOUBLE) ||
1693 (prop->type == IDP_ARRAY && ELEM(prop->subtype, IDP_FLOAT, IDP_DOUBLE)))
1694 {
1696 }
1697 if (prop->type == IDP_BOOLEAN || (prop->type == IDP_ARRAY && prop->subtype == IDP_BOOLEAN)) {
1699 }
1701}
1702
1704{
1706}
1707
1709{
1710 switch (type) {
1713 return &ui_data->base;
1714 }
1715 case IDP_UI_DATA_TYPE_ID: {
1717 return &ui_data->base;
1718 }
1719 case IDP_UI_DATA_TYPE_INT: {
1721 ui_data->min = INT_MIN;
1722 ui_data->max = INT_MAX;
1723 ui_data->soft_min = INT_MIN;
1724 ui_data->soft_max = INT_MAX;
1725 ui_data->step = 1;
1726 return &ui_data->base;
1727 }
1730 return &ui_data->base;
1731 }
1734 ui_data->min = -FLT_MAX;
1735 ui_data->max = FLT_MAX;
1736 ui_data->soft_min = -FLT_MAX;
1737 ui_data->soft_max = FLT_MAX;
1738 ui_data->step = 1.0f;
1739 ui_data->precision = 3;
1740 return &ui_data->base;
1741 }
1743 /* UI data not supported for remaining types, this shouldn't be called in those cases. */
1745 break;
1746 }
1747 }
1748 return nullptr;
1749}
1750
1752{
1753 if (prop->ui_data != nullptr) {
1754 return prop->ui_data;
1755 }
1756 prop->ui_data = ui_data_alloc(IDP_ui_data_type(prop));
1757 return prop->ui_data;
1758}
1759
1761 const eIDPropertyUIDataType dst_type)
1762{
1763 IDPropertyUIData *dst = ui_data_alloc(dst_type);
1764 *dst = *src;
1765 src->description = nullptr;
1766 return dst;
1767}
1768
1770 const eIDPropertyUIDataType src_type,
1771 const eIDPropertyUIDataType dst_type)
1772{
1773 switch (src_type) {
1775 switch (dst_type) {
1777 return src;
1781 case IDP_UI_DATA_TYPE_ID: {
1782 IDPropertyUIData *dst = convert_base_ui_data(src, dst_type);
1783 ui_data_free(src, src_type);
1784 return dst;
1785 }
1787 break;
1788 }
1789 break;
1790 }
1791 case IDP_UI_DATA_TYPE_ID: {
1792 switch (dst_type) {
1794 return src;
1799 IDPropertyUIData *dst = convert_base_ui_data(src, dst_type);
1800 ui_data_free(src, src_type);
1801 return dst;
1802 }
1804 break;
1805 }
1806 break;
1807 }
1808 case IDP_UI_DATA_TYPE_INT: {
1809 IDPropertyUIDataInt *src_int = reinterpret_cast<IDPropertyUIDataInt *>(src);
1810 switch (dst_type) {
1812 return src;
1815 IDPropertyUIData *dst = convert_base_ui_data(src, dst_type);
1816 ui_data_free(src, src_type);
1817 return dst;
1818 }
1820 IDPropertyUIDataBool *dst = reinterpret_cast<IDPropertyUIDataBool *>(
1821 convert_base_ui_data(src, dst_type));
1822 dst->default_value = src_int->default_value != 0;
1823 if (src_int->default_array) {
1825 __func__);
1826 for (int i = 0; i < src_int->default_array_len; i++) {
1827 dst->default_array[i] = src_int->default_array[i] != 0;
1828 }
1829 }
1830 ui_data_free(src, src_type);
1831 return &dst->base;
1832 }
1834 IDPropertyUIDataFloat *dst = reinterpret_cast<IDPropertyUIDataFloat *>(
1835 convert_base_ui_data(src, dst_type));
1836 dst->min = double(src_int->min);
1837 dst->max = double(src_int->max);
1838 dst->soft_min = double(src_int->soft_min);
1839 dst->soft_max = double(src_int->soft_max);
1840 dst->step = float(src_int->step);
1841 dst->default_value = double(src_int->default_value);
1842 if (src_int->default_array) {
1844 __func__);
1845 for (int i = 0; i < src_int->default_array_len; i++) {
1846 dst->default_array[i] = double(src_int->default_array[i]);
1847 }
1848 }
1849 ui_data_free(src, src_type);
1850 return &dst->base;
1851 }
1853 break;
1854 }
1855 break;
1856 }
1858 IDPropertyUIDataBool *src_bool = reinterpret_cast<IDPropertyUIDataBool *>(src);
1859 switch (dst_type) {
1861 return src;
1864 IDPropertyUIData *dst = convert_base_ui_data(src, dst_type);
1865 ui_data_free(src, src_type);
1866 return dst;
1867 }
1868 case IDP_UI_DATA_TYPE_INT: {
1869 IDPropertyUIDataInt *dst = reinterpret_cast<IDPropertyUIDataInt *>(
1870 convert_base_ui_data(src, dst_type));
1871 dst->min = 0;
1872 dst->max = 1;
1873 dst->soft_min = 0;
1874 dst->soft_max = 1;
1875 dst->step = 1;
1876 dst->default_value = int(src_bool->default_value);
1877 if (src_bool->default_array) {
1879 __func__);
1880 for (int i = 0; i < src_bool->default_array_len; i++) {
1881 dst->default_array[i] = int(src_bool->default_array[i]);
1882 }
1883 }
1884 ui_data_free(src, src_type);
1885 return &dst->base;
1886 }
1888 IDPropertyUIDataFloat *dst = reinterpret_cast<IDPropertyUIDataFloat *>(
1889 convert_base_ui_data(src, dst_type));
1890 dst->min = 0.0;
1891 dst->max = 1.0;
1892 dst->soft_min = 0.0;
1893 dst->soft_max = 1.0;
1894 dst->step = 1.0;
1895 if (src_bool->default_array) {
1897 __func__);
1898 for (int i = 0; i < src_bool->default_array_len; i++) {
1899 dst->default_array[i] = src_bool->default_array[i] == 0 ? 0.0 : 1.0;
1900 }
1901 }
1902 ui_data_free(src, src_type);
1903 return &dst->base;
1904 }
1906 break;
1907 }
1908 break;
1909 }
1911 IDPropertyUIDataFloat *src_float = reinterpret_cast<IDPropertyUIDataFloat *>(src);
1912 switch (dst_type) {
1914 return src;
1917 return convert_base_ui_data(src, dst_type);
1918 case IDP_UI_DATA_TYPE_INT: {
1919 auto clamp_double_to_int = [](const double value) {
1920 return int(std::clamp<double>(value, INT_MIN, INT_MAX));
1921 };
1922 IDPropertyUIDataInt *dst = reinterpret_cast<IDPropertyUIDataInt *>(
1923 convert_base_ui_data(src, dst_type));
1924 dst->min = clamp_double_to_int(src_float->min);
1925 dst->max = clamp_double_to_int(src_float->max);
1926 dst->soft_min = clamp_double_to_int(src_float->soft_min);
1927 dst->soft_max = clamp_double_to_int(src_float->soft_max);
1928 dst->step = clamp_double_to_int(src_float->step);
1929 dst->default_value = clamp_double_to_int(src_float->default_value);
1930 if (src_float->default_array) {
1931 dst->default_array = MEM_malloc_arrayN<int>(size_t(src_float->default_array_len),
1932 __func__);
1933 for (int i = 0; i < src_float->default_array_len; i++) {
1934 dst->default_array[i] = clamp_double_to_int(src_float->default_array[i]);
1935 }
1936 }
1937 ui_data_free(src, src_type);
1938 return &dst->base;
1939 }
1941 IDPropertyUIDataBool *dst = reinterpret_cast<IDPropertyUIDataBool *>(
1942 convert_base_ui_data(src, dst_type));
1943 dst->default_value = src_float->default_value > 0.0f;
1944 if (src_float->default_array) {
1946 __func__);
1947 for (int i = 0; i < src_float->default_array_len; i++) {
1948 dst->default_array[i] = src_float->default_array[i] > 0.0f;
1949 }
1950 }
1951 ui_data_free(src, src_type);
1952 return &dst->base;
1953 }
1955 break;
1956 }
1957 break;
1958 }
1960 break;
1961 }
1962 ui_data_free(src, src_type);
1963 return nullptr;
1964}
1965
#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(const IDProperty *prop)
Definition idprop.cc:1681
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)
IDProperty * IDP_CopyProperty_ex(const IDProperty *prop, int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition idprop.cc:855
IDProperty * IDP_CopyProperty(const IDProperty *prop) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition idprop.cc:873
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:353
void id_us_min(ID *id)
Definition lib_id.cc:361
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
BLI_INLINE void BLI_endian_switch_int64(int64_t *val) ATTR_NONNULL(1)
BLI_INLINE void BLI_endian_switch_int32(int *val) ATTR_NONNULL(1)
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)
void * BLI_findstring(const ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:608
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_insertlinkafter(ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition listbase.cc:332
T * BLI_listbase_find(const ListBase &listbase, Fn &&predicate)
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:923
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:688
unsigned int uint
#define STREQLEN(a, b, n)
#define ELEM(...)
#define STREQ(a, b)
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:5326
void BLO_read_int32_array(BlendDataReader *reader, int64_t array_size, int32_t **ptr_p)
Definition readfile.cc:5306
#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:5341
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:5351
void BLO_write_string(BlendWriter *writer, const char *data_ptr)
#define BLO_write_struct_array(writer, struct_name, array_size, data_ptr)
bool BLO_read_requires_endian_switch(BlendDataReader *reader)
Definition readfile.cc:5244
void BLO_read_int8_array(BlendDataReader *reader, int64_t array_size, int8_t **ptr_p)
Definition readfile.cc:5290
#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:5278
#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:5402
void BLO_write_char_array(BlendWriter *writer, int64_t num, const char *data_ptr)
#define CLOG_ERROR(clg_ref,...)
Definition CLG_log.h:182
@ ID_FLAG_EMBEDDED_DATA
Definition DNA_ID.h:687
@ 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.
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
void copy_utf8_truncated(char *dst, int64_t dst_size) const
Definition string_ref.cc:28
#define offsetof(t, d)
#define fabsf(x)
#define printf(...)
#define MEM_recallocN(vmemh, len)
#define MEM_SAFE_FREE(v)
#define DEFAULT_ALLOC_FOR_NULL_STRINGS
#define IDP_ARRAY_REALLOC_LIMIT
Definition idprop.cc:42
static IDProperty * IDP_CopyArray(const IDProperty *prop, const int flag)
Definition idprop.cc:326
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:996
IDProperty * IDP_NewStringMaxSize(const char *st, const size_t st_maxncpy, const blender::StringRef name, const eIDPropertyFlag flags)
Definition idprop.cc:355
void IDP_Reset(IDProperty *prop, const IDProperty *reference)
Definition idprop.cc:1256
void IDP_ui_data_free(IDProperty *prop)
Definition idprop.cc:1199
IDProperty * IDP_CopyProperty_ex(const IDProperty *prop, const int flag)
Definition idprop.cc:855
bool IDP_InsertToGroup(IDProperty *group, IDProperty *previous, IDProperty *pnew)
Definition idprop.cc:738
bool IDP_AddToGroup(IDProperty *group, IDProperty *prop)
Definition idprop.cc:725
static void IDP_WriteGroup(const IDProperty *prop, BlendWriter *writer)
Definition idprop.cc:1424
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:839
static IDProperty * idp_generic_copy(const IDProperty *prop, const int)
Definition idprop.cc:309
IDPropertyUIData * IDP_TryConvertUIData(IDPropertyUIData *src, const eIDPropertyUIDataType src_type, const eIDPropertyUIDataType dst_type)
Definition idprop.cc:1769
static IDProperty * IDP_CopyID(const IDProperty *prop, const int flag)
Definition idprop.cc:525
IDProperty * IDP_CopyProperty(const IDProperty *prop)
Definition idprop.cc:873
eIDPropertyUIDataType IDP_ui_data_type(const IDProperty *prop)
Definition idprop.cc:1681
bool IDP_ui_data_supported(const IDProperty *prop)
Definition idprop.cc:1703
static void idp_resize_group_array(IDProperty *prop, int newlen, void *newarr)
Definition idprop.cc:190
IDProperty * IDP_GetPropertyTypeFromGroup(const IDProperty *prop, const blender::StringRef name, const char type)
Definition idprop.cc:779
void IDP_SyncGroupValues(IDProperty *dest, const IDProperty *src)
Definition idprop.cc:578
IDPropertyUIData * IDP_ui_data_copy(const IDProperty *prop)
Definition idprop.cc:258
void IDP_ReplaceGroupInGroup(IDProperty *dest, const IDProperty *src)
Definition idprop.cc:630
#define GETPROP(prop, i)
Definition idprop.cc:66
IDProperty * IDP_GetProperties(ID *id)
Definition idprop.cc:887
void IDP_MergeGroup_ex(IDProperty *dest, const IDProperty *src, const bool do_overwrite, const int flag)
Definition idprop.cc:679
static void IDP_FreeIDPArray(IDProperty *prop, const bool do_id_user)
Definition idprop.cc:102
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:1541
void IDP_WriteProperty_OnlyData(const IDProperty *prop, BlendWriter *writer)
Definition idprop.cc:1432
IDProperty * IDP_NewString(const char *st, const blender::StringRef name, const eIDPropertyFlag flags)
Definition idprop.cc:391
void IDP_RemoveFromGroup(IDProperty *group, IDProperty *prop)
Definition idprop.cc:751
void IDP_FreeProperty(IDProperty *prop)
Definition idprop.cc:1243
static size_t idp_size_table[]
Definition idprop.cc:47
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:807
IDProperty * IDP_NewIDPArray(const blender::StringRef name)
Definition idprop.cc:68
void IDP_CopyPropertyContent(IDProperty *dst, const IDProperty *src)
Definition idprop.cc:878
void IDP_FreeProperty_ex(IDProperty *prop, const bool do_id_user)
Definition idprop.cc:1237
static IDPropertyUIData * ui_data_alloc(const eIDPropertyUIDataType type)
Definition idprop.cc:1708
void IDP_FreePropertyContent(IDProperty *prop)
Definition idprop.cc:1232
void IDP_AssignStringMaxSize(IDProperty *prop, const char *st, const size_t st_maxncpy)
Definition idprop.cc:413
void IDP_foreach_property(IDProperty *id_property_root, const int type_filter, const blender::FunctionRef< void(IDProperty *id_property)> callback)
Definition idprop.cc:1267
void IDP_FreePropertyContent_ex(IDProperty *prop, const bool do_id_user)
Definition idprop.cc:1205
static void IDP_DirectLinkGroup(IDProperty *prop, BlendDataReader *reader)
Definition idprop.cc:1603
void IDP_FreeFromGroup(IDProperty *group, IDProperty *prop)
Definition idprop.cc:760
static void IDP_DirectLinkString(IDProperty *prop, BlendDataReader *reader)
Definition idprop.cc:1596
void IDP_ClearProperty(IDProperty *prop)
Definition idprop.cc:1249
static void ui_data_free(IDPropertyUIData *ui_data, const eIDPropertyUIDataType type)
Definition idprop.cc:1162
IDProperty * IDP_New(const char type, const IDPropertyTemplate *val, const blender::StringRef name, const eIDPropertyFlag flags)
Definition idprop.cc:1001
IDProperty * IDP_GetIndexArray(IDProperty *prop, int index)
Definition idprop.cc:131
IDProperty * IDP_GetPropertyFromGroup(const IDProperty *prop, const blender::StringRef name)
Definition idprop.cc:766
double IDP_coerce_to_double_or_zero(const IDProperty *prop)
Definition idprop.cc:823
void IDP_ResizeIDPArray(IDProperty *prop, int newlen)
Definition idprop.cc:146
static void IDP_DirectLinkProperty(IDProperty *prop, BlendDataReader *reader)
Definition idprop.cc:1615
static IDPropertyUIData * convert_base_ui_data(IDPropertyUIData *src, const eIDPropertyUIDataType dst_type)
Definition idprop.cc:1760
static void IDP_FreeGroup(IDProperty *prop, const bool do_id_user)
Definition idprop.cc:791
void IDP_MergeGroup(IDProperty *dest, const IDProperty *src, const bool do_overwrite)
Definition idprop.cc:720
void IDP_ReplaceInGroup_ex(IDProperty *group, IDProperty *prop, IDProperty *prop_exist, const int flag)
Definition idprop.cc:654
bool IDP_EqualsProperties_ex(const IDProperty *prop1, const IDProperty *prop2, const bool is_strict)
Definition idprop.cc:905
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:1561
void IDP_AppendArray(IDProperty *prop, IDProperty *item)
Definition idprop.cc:138
static void IDP_WriteString(const IDProperty *prop, BlendWriter *writer)
Definition idprop.cc:1416
void IDP_SetIndexArray(IDProperty *prop, int index, IDProperty *item)
Definition idprop.cc:115
void IDP_ResizeArray(IDProperty *prop, int newlen)
Definition idprop.cc:213
void IDP_ui_data_free_unique_contents(IDPropertyUIData *ui_data, const eIDPropertyUIDataType type, const IDPropertyUIData *other)
Definition idprop.cc:1109
static IDProperty * IDP_CopyString(const IDProperty *prop, const int flag)
Definition idprop.cc:398
void IDP_ReplaceInGroup(IDProperty *group, IDProperty *prop)
Definition idprop.cc:672
static void IDP_WriteArray(const IDProperty *prop, BlendWriter *writer)
Definition idprop.cc:1361
void IDP_BlendWrite(BlendWriter *writer, const IDProperty *prop)
Definition idprop.cc:1453
static void write_ui_data(const IDProperty *prop, BlendWriter *writer)
Definition idprop.cc:1301
static void read_ui_data(IDProperty *prop, BlendDataReader *reader)
Definition idprop.cc:1461
IDPropertyUIData * IDP_ui_data_ensure(IDProperty *prop)
Definition idprop.cc:1751
void IDP_FreeArray(IDProperty *prop)
Definition idprop.cc:250
IDProperty * IDP_EnsureProperties(ID *id)
Definition idprop.cc:892
static void IDP_WriteIDPArray(const IDProperty *prop, BlendWriter *writer)
Definition idprop.cc:1402
void IDP_BlendReadData_impl(BlendDataReader *reader, IDProperty **prop, const char *caller_func_id)
Definition idprop.cc:1665
const IDPropertyUIDataEnumItem * IDP_EnumItemFind(const IDProperty *prop)
Definition idprop.cc:463
IDProperty * IDP_CopyIDPArray(const IDProperty *array, const int flag)
Definition idprop.cc:78
void IDP_AssignString(IDProperty *prop, const char *st)
Definition idprop.cc:431
#define LOG(severity)
Definition log.h:32
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)
#define FLT_MAX
Definition stdcycles.h:14
ListBase group
Definition DNA_ID.h:138
void * pointer
Definition DNA_ID.h:137
int8_t default_value
Definition DNA_ID.h:96
int8_t * default_array
Definition DNA_ID.h:92
IDPropertyUIData base
Definition DNA_ID.h:91
double * default_array
Definition DNA_ID.h:102
IDPropertyUIData base
Definition DNA_ID.h:101
IDPropertyUIData base
Definition DNA_ID.h:124
IDPropertyUIData base
Definition DNA_ID.h:74
IDPropertyUIDataEnumItem * enum_items
Definition DNA_ID.h:86
int * default_array
Definition DNA_ID.h:75
IDPropertyUIData base
Definition DNA_ID.h:118
char * description
Definition DNA_ID.h:51
short flag
Definition DNA_ID.h:153
int len
Definition DNA_ID.h:165
struct IDProperty * next
Definition DNA_ID.h:144
IDPropertyUIData * ui_data
Definition DNA_ID.h:173
char name[64]
Definition DNA_ID.h:154
IDPropertyData data
Definition DNA_ID.h:159
struct IDProperty * prev
Definition DNA_ID.h:144
char subtype
Definition DNA_ID.h:151
int totallen
Definition DNA_ID.h:171
char type
Definition DNA_ID.h:146
Definition DNA_ID.h:404
IDProperty * properties
Definition DNA_ID.h:446
short flag
Definition DNA_ID.h:420
void * first
i
Definition text_draw.cc:230
struct IDPropertyTemplate::@347174163205254236177334334344125337263066142041 string
struct IDPropertyTemplate::@057340115353163137130262213324257034202360355133 array
const char * str
Definition BKE_idprop.hh:37
uint len
uint8_t flag
Definition wm_window.cc:139