Blender V4.3
rna_path.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <cstdlib>
10#include <cstring>
11
12#include <fmt/format.h>
13
14#include "BLI_alloca.h"
15#include "BLI_dynstr.h"
16#include "BLI_listbase.h"
17#include "BLI_string.h"
18#include "BLI_string_ref.hh"
19#include "BLI_utildefines.h"
20
21#include "BKE_idprop.hh"
22#include "BKE_idtype.hh"
23#include "BKE_lib_id.hh"
24
25#include "DNA_ID.h" /* For ID properties. */
26
27#include "MEM_guardedalloc.h"
28
29#include "RNA_access.hh"
30#include "RNA_define.hh"
31#include "RNA_path.hh"
32#include "RNA_prototypes.hh"
33
35#include "rna_internal.hh"
36
37bool operator==(const RNAPath &left, const RNAPath &right)
38{
39 if (left.path != right.path) {
40 return false;
41 }
42
43 if (left.key.has_value() || right.key.has_value()) {
44 return left.key == right.key;
45 }
46
47 return left.index == right.index;
48}
49
56static char *rna_path_token(const char **path, char *fixedbuf, int fixedlen)
57{
58 int len = 0;
59
60 /* Get data until `.` or `[`. */
61 const char *p = *path;
62 while (*p && !ELEM(*p, '.', '[')) {
63 len++;
64 p++;
65 }
66
67 /* Empty, return. */
68 if (UNLIKELY(len == 0)) {
69 return nullptr;
70 }
71
72 /* Try to use fixed buffer if possible. */
73 char *buf = (len + 1 < fixedlen) ? fixedbuf :
74 (char *)MEM_mallocN(sizeof(char) * (len + 1), __func__);
75 memcpy(buf, *path, sizeof(char) * len);
76 buf[len] = '\0';
77
78 if (*p == '.') {
79 p++;
80 }
81 *path = p;
82
83 return buf;
84}
85
96static char *rna_path_token_in_brackets(const char **path,
97 char *fixedbuf,
98 int fixedlen,
99 bool *r_quoted)
100{
101 int len = 0;
102 bool quoted = false;
103
104 BLI_assert(r_quoted != nullptr);
105
106 /* Get data between `[]`, check escaping quotes and back-slashes with #BLI_str_unescape. */
107 if (UNLIKELY(**path != '[')) {
108 return nullptr;
109 }
110
111 (*path)++;
112 const char *p = *path;
113
114 /* 2 kinds of look-ups now, quoted or unquoted. */
115 if (*p == '"') {
116 /* Find the matching quote. */
117 (*path)++;
118 p = *path;
119 const char *p_end = BLI_str_escape_find_quote(p);
120 if (p_end == nullptr) {
121 /* No Matching quote. */
122 return nullptr;
123 }
124 /* Exclude the last quote from the length. */
125 len += (p_end - p);
126
127 /* Skip the last quoted char to get the `]`. */
128 p_end += 1;
129 p = p_end;
130 quoted = true;
131 }
132 else {
133 /* Find the matching bracket. */
134 while (*p && (*p != ']')) {
135 len++;
136 p++;
137 }
138 }
139
140 if (UNLIKELY(*p != ']')) {
141 return nullptr;
142 }
143
144 /* Support empty strings in quotes, as this is a valid key for an ID-property. */
145 if (!quoted) {
146 /* Empty, return. */
147 if (UNLIKELY(len == 0)) {
148 return nullptr;
149 }
150 }
151
152 /* Try to use fixed buffer if possible. */
153 char *buf = (len + 1 < fixedlen) ? fixedbuf :
154 (char *)MEM_mallocN(sizeof(char) * (len + 1), __func__);
155
156 /* Copy string, taking into account escaped ']' */
157 if (quoted) {
158 BLI_str_unescape(buf, *path, len);
159 /* +1 to step over the last quote. */
160 BLI_assert((*path)[len] == '"');
161 p = (*path) + len + 1;
162 }
163 else {
164 memcpy(buf, *path, sizeof(char) * len);
165 buf[len] = '\0';
166 }
167 /* Set path to start of next token. */
168 if (*p == ']') {
169 p++;
170 }
171 if (*p == '.') {
172 p++;
173 }
174 *path = p;
175
176 *r_quoted = quoted;
177
178 return buf;
179}
180
185static bool rna_path_parse_collection_key(const char **path,
187 PropertyRNA *prop,
188 PointerRNA *r_nextptr)
189{
190 char fixedbuf[256];
191 int intkey;
192
193 *r_nextptr = *ptr;
194
195 /* end of path, ok */
196 if (!(**path)) {
197 return true;
198 }
199
200 bool found = false;
201 if (**path == '[') {
202 bool quoted;
203 char *token;
204
205 /* resolve the lookup with [] brackets */
206 token = rna_path_token_in_brackets(path, fixedbuf, sizeof(fixedbuf), &quoted);
207
208 if (!token) {
209 return false;
210 }
211
212 /* check for "" to see if it is a string */
213 if (quoted) {
214 if (RNA_property_collection_lookup_string(ptr, prop, token, r_nextptr)) {
215 found = true;
216 }
217 else {
218 r_nextptr->data = nullptr;
219 }
220 }
221 else {
222 /* otherwise do int lookup */
223 intkey = atoi(token);
224 if (intkey == 0 && (token[0] != '0' || token[1] != '\0')) {
225 return false; /* we can be sure the fixedbuf was used in this case */
226 }
227 if (RNA_property_collection_lookup_int(ptr, prop, intkey, r_nextptr)) {
228 found = true;
229 }
230 else {
231 r_nextptr->data = nullptr;
232 }
233 }
234
235 if (token != fixedbuf) {
236 MEM_freeN(token);
237 }
238 }
239 else {
240 if (RNA_property_collection_type_get(ptr, prop, r_nextptr)) {
241 found = true;
242 }
243 else {
244 /* ensure we quit on invalid values */
245 r_nextptr->data = nullptr;
246 }
247 }
248
249 return found;
250}
251
252static bool rna_path_parse_array_index(const char **path,
254 PropertyRNA *prop,
255 int *r_index)
256{
257 char fixedbuf[256];
258 int index_arr[RNA_MAX_ARRAY_DIMENSION] = {0};
260 const int dim = RNA_property_array_dimension(ptr, prop, len);
261 int i;
262
263 *r_index = -1;
264
265 /* end of path, ok */
266 if (!(**path)) {
267 return true;
268 }
269
270 for (i = 0; i < dim; i++) {
271 int temp_index = -1;
272 char *token;
273
274 /* multi index resolve */
275 if (**path == '[') {
276 bool quoted;
277 token = rna_path_token_in_brackets(path, fixedbuf, sizeof(fixedbuf), &quoted);
278
279 if (token == nullptr) {
280 /* invalid syntax blah[] */
281 return false;
282 }
283 /* check for "" to see if it is a string */
284 if (quoted) {
285 temp_index = RNA_property_array_item_index(prop, *token);
286 }
287 else {
288 /* otherwise do int lookup */
289 temp_index = atoi(token);
290
291 if (temp_index == 0 && (token[0] != '0' || token[1] != '\0')) {
292 if (token != fixedbuf) {
293 MEM_freeN(token);
294 }
295
296 return false;
297 }
298 }
299 }
300 else if (dim == 1) {
301 /* location.x || scale.X, single dimension arrays only */
302 token = rna_path_token(path, fixedbuf, sizeof(fixedbuf));
303 if (token == nullptr) {
304 /* invalid syntax blah. */
305 return false;
306 }
307 temp_index = RNA_property_array_item_index(prop, *token);
308 }
309 else {
310 /* just to avoid uninitialized pointer use */
311 token = fixedbuf;
312 }
313
314 if (token != fixedbuf) {
315 MEM_freeN(token);
316 }
317
318 /* out of range */
319 if (temp_index < 0 || temp_index >= len[i]) {
320 return false;
321 }
322
323 index_arr[i] = temp_index;
324 /* end multi index resolve */
325 }
326
327 /* arrays always contain numbers so further values are not valid */
328 if (**path) {
329 return false;
330 }
331
332 /* flatten index over all dimensions */
333 {
334 int totdim = 1;
335 int flat_index = 0;
336
337 for (i = dim - 1; i >= 0; i--) {
338 flat_index += index_arr[i] * totdim;
339 totdim *= len[i];
340 }
341
342 *r_index = flat_index;
343 }
344 return true;
345}
346
369static bool rna_path_parse(const PointerRNA *ptr,
370 const char *path,
371 PointerRNA *r_ptr,
372 PropertyRNA **r_prop,
373 int *r_index,
374 PointerRNA *r_item_ptr,
375 ListBase *r_elements,
376 const bool eval_pointer)
377{
378 BLI_assert(r_item_ptr == nullptr || !eval_pointer);
379 PropertyRNA *prop;
380 PointerRNA curptr, nextptr;
381 PropertyElemRNA *prop_elem = nullptr;
382 int index = -1;
383 char fixedbuf[256];
384 int type;
385 const bool do_item_ptr = r_item_ptr != nullptr && !eval_pointer;
386
387 if (do_item_ptr) {
388 RNA_POINTER_INVALIDATE(&nextptr);
389 }
390
391 prop = nullptr;
392 curptr = *ptr;
393
394 if (path == nullptr || *path == '\0') {
395 return false;
396 }
397
398 while (*path) {
399 if (do_item_ptr) {
400 RNA_POINTER_INVALIDATE(&nextptr);
401 }
402
403 const bool use_id_prop = (*path == '[');
404 /* Custom property lookup: e.g. `C.object["someprop"]`. */
405
406 if (!curptr.data) {
407 return false;
408 }
409
410 /* look up property name in current struct */
411 bool quoted = false;
412 char *token = use_id_prop ?
413 rna_path_token_in_brackets(&path, fixedbuf, sizeof(fixedbuf), &quoted) :
414 rna_path_token(&path, fixedbuf, sizeof(fixedbuf));
415 if (!token) {
416 return false;
417 }
418
419 prop = nullptr;
420 if (use_id_prop) { /* look up property name in current struct */
421 IDProperty *group = RNA_struct_idprops(&curptr, false);
422 if (group && quoted) {
423 prop = (PropertyRNA *)IDP_GetPropertyFromGroup(group, token);
424 }
425 }
426 else {
427 prop = RNA_struct_find_property(&curptr, token);
428 }
429
430 if (token != fixedbuf) {
431 MEM_freeN(token);
432 }
433
434 if (!prop) {
435 return false;
436 }
437
438 if (r_elements) {
439 prop_elem = MEM_new<PropertyElemRNA>(__func__);
440 prop_elem->ptr = curptr;
441 prop_elem->prop = prop;
442 prop_elem->index = -1; /* index will be added later, if needed. */
443 BLI_addtail(r_elements, prop_elem);
444 }
445
446 type = RNA_property_type(prop);
447
448 /* now look up the value of this property if it is a pointer or
449 * collection, otherwise return the property rna so that the
450 * caller can read the value of the property itself */
451 switch (type) {
452 case PROP_POINTER: {
453 /* resolve pointer if further path elements follow
454 * or explicitly requested
455 */
456 if (do_item_ptr || eval_pointer || *path != '\0') {
457 nextptr = RNA_property_pointer_get(&curptr, prop);
458 }
459
460 if (eval_pointer || *path != '\0') {
461 curptr = nextptr;
462 prop = nullptr; /* now we have a PointerRNA, the prop is our parent so forget it */
463 index = -1;
464 }
465 break;
466 }
467 case PROP_COLLECTION: {
468 /* Resolve pointer if further path elements follow.
469 * Note that if path is empty, rna_path_parse_collection_key will do nothing anyway,
470 * so do_item_ptr is of no use in that case.
471 */
472 if (*path) {
473 if (!rna_path_parse_collection_key(&path, &curptr, prop, &nextptr)) {
474 return false;
475 }
476
477 if (eval_pointer || *path != '\0') {
478 curptr = nextptr;
479 prop = nullptr; /* now we have a PointerRNA, the prop is our parent so forget it */
480 index = -1;
481 }
482 }
483 break;
484 }
485 default:
486 if (r_index || prop_elem) {
487 if (!rna_path_parse_array_index(&path, &curptr, prop, &index)) {
488 return false;
489 }
490
491 if (prop_elem) {
492 prop_elem->index = index;
493 }
494 }
495 break;
496 }
497 }
498
499 if (r_ptr) {
500 *r_ptr = curptr;
501 }
502 if (r_prop) {
503 *r_prop = prop;
504 }
505 if (r_index) {
506 *r_index = index;
507 }
508 if (r_item_ptr && do_item_ptr) {
509 *r_item_ptr = nextptr;
510 }
511
512 if (prop_elem &&
513 (prop_elem->ptr.data != curptr.data || prop_elem->prop != prop || prop_elem->index != index))
514 {
515 prop_elem = MEM_new<PropertyElemRNA>(__func__);
516 prop_elem->ptr = curptr;
517 prop_elem->prop = prop;
518 prop_elem->index = index;
519 BLI_addtail(r_elements, prop_elem);
520 }
521
522 return true;
523}
524
526 const char *path,
527 PointerRNA *r_ptr,
528 PropertyRNA **r_prop)
529{
530 if (!rna_path_parse(ptr, path, r_ptr, r_prop, nullptr, nullptr, nullptr, true)) {
531 return false;
532 }
533
534 return r_ptr->data != nullptr;
535}
536
538 const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
539{
540 if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, nullptr, nullptr, true)) {
541 return false;
542 }
543
544 return r_ptr->data != nullptr;
545}
546
548 const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
549{
550 return rna_path_parse(ptr, path, r_ptr, r_prop, r_index, nullptr, nullptr, true);
551}
552
554 const char *path,
555 PointerRNA *r_ptr,
556 PropertyRNA **r_prop)
557{
558 if (!rna_path_parse(ptr, path, r_ptr, r_prop, nullptr, nullptr, nullptr, false)) {
559 return false;
560 }
561
562 return r_ptr->data != nullptr && *r_prop != nullptr;
563}
564
566 const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
567{
568 if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, nullptr, nullptr, false)) {
569 return false;
570 }
571
572 return r_ptr->data != nullptr && *r_prop != nullptr;
573}
574
576 const char *path,
577 PointerRNA *r_ptr,
578 PropertyRNA **r_prop,
579 PointerRNA *r_item_ptr)
580{
581 if (!rna_path_parse(ptr, path, r_ptr, r_prop, nullptr, r_item_ptr, nullptr, false)) {
582 return false;
583 }
584
585 return r_ptr->data != nullptr && *r_prop != nullptr;
586}
587
589 const char *path,
590 PointerRNA *r_ptr,
591 PropertyRNA **r_prop,
592 int *r_index,
593 PointerRNA *r_item_ptr)
594{
595 if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, r_item_ptr, nullptr, false)) {
596 return false;
597 }
598
599 return r_ptr->data != nullptr && *r_prop != nullptr;
600}
601bool RNA_path_resolve_elements(PointerRNA *ptr, const char *path, ListBase *r_elements)
602{
603 return rna_path_parse(ptr, path, nullptr, nullptr, nullptr, nullptr, r_elements, false);
604}
605
606char *RNA_path_append(const char *path,
607 const PointerRNA * /*ptr*/,
608 PropertyRNA *prop,
609 int intkey,
610 const char *strkey)
611{
612 DynStr *dynstr;
613 char *result;
614
615 dynstr = BLI_dynstr_new();
616
617 /* add .identifier */
618 if (path) {
619 BLI_dynstr_append(dynstr, path);
620 if (*path) {
621 BLI_dynstr_append(dynstr, ".");
622 }
623 }
624
626
627 const bool has_key = (intkey > -1) || (strkey != nullptr);
628 if (has_key && (RNA_property_type(prop) == PROP_COLLECTION)) {
629 /* add ["strkey"] or [intkey] */
630 BLI_dynstr_append(dynstr, "[");
631
632 if (strkey) {
633 const int strkey_esc_max_size = (strlen(strkey) * 2) + 1;
634 char *strkey_esc = static_cast<char *>(BLI_array_alloca(strkey_esc, strkey_esc_max_size));
635 BLI_str_escape(strkey_esc, strkey, strkey_esc_max_size);
636 BLI_dynstr_append(dynstr, "\"");
637 BLI_dynstr_append(dynstr, strkey_esc);
638 BLI_dynstr_append(dynstr, "\"");
639 }
640 else {
641 char appendstr[128];
642 SNPRINTF(appendstr, "%d", intkey);
643 BLI_dynstr_append(dynstr, appendstr);
644 }
645
646 BLI_dynstr_append(dynstr, "]");
647 }
648
649 result = BLI_dynstr_get_cstring(dynstr);
650 BLI_dynstr_free(dynstr);
651
652 return result;
653}
654
655/* Having both path append & back seems like it could be useful,
656 * this function isn't used at the moment. */
657static UNUSED_FUNCTION_WITH_RETURN_TYPE(char *, RNA_path_back)(const char *path)
658{
659 char fixedbuf[256];
660 const char *previous, *current;
661 char *result;
662 int i;
663
664 if (!path) {
665 return nullptr;
666 }
667
668 previous = nullptr;
669 current = path;
670
671 /* parse token by token until the end, then we back up to the previous
672 * position and strip of the next token to get the path one step back */
673 while (*current) {
674 char *token;
675
676 token = rna_path_token(&current, fixedbuf, sizeof(fixedbuf));
677
678 if (!token) {
679 return nullptr;
680 }
681 if (token != fixedbuf) {
682 MEM_freeN(token);
683 }
684
685 /* in case of collection we also need to strip off [] */
686 bool quoted;
687 token = rna_path_token_in_brackets(&current, fixedbuf, sizeof(fixedbuf), &quoted);
688 if (token && token != fixedbuf) {
689 MEM_freeN(token);
690 }
691
692 if (!*current) {
693 break;
694 }
695
696 previous = current;
697 }
698
699 if (!previous) {
700 return nullptr;
701 }
702
703 /* copy and strip off last token */
704 i = previous - path;
705 result = BLI_strdup(path);
706
707 if (i > 0 && result[i - 1] == '.') {
708 i--;
709 }
710 result[i] = 0;
711
712 return result;
713}
714
715const char *RNA_path_array_index_token_find(const char *rna_path, const PropertyRNA *array_prop)
716{
717 if (array_prop != nullptr) {
718 if (!ELEM(array_prop->type, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) {
719 BLI_assert(array_prop->arraydimension == 0);
720 return nullptr;
721 }
722 if (array_prop->arraydimension == 0) {
723 return nullptr;
724 }
725 }
726
727 /* Valid 'array part' of a rna path can only have '[', ']' and digit characters.
728 * It may have more than one of those (e.g. `[12][1]`) in case of multi-dimensional arrays. */
729 if (UNLIKELY(rna_path[0] == '\0')) {
730 return nullptr;
731 }
732 size_t rna_path_len = size_t(strlen(rna_path)) - 1;
733 if (rna_path[rna_path_len] != ']') {
734 return nullptr;
735 }
736
737 const char *last_valid_index_token_start = nullptr;
738 while (rna_path_len--) {
739 switch (rna_path[rna_path_len]) {
740 case '[':
741 if (rna_path_len <= 0 || rna_path[rna_path_len - 1] != ']') {
742 return &rna_path[rna_path_len];
743 }
744 last_valid_index_token_start = &rna_path[rna_path_len];
745 rna_path_len--;
746 break;
747 case '0':
748 case '1':
749 case '2':
750 case '3':
751 case '4':
752 case '5':
753 case '6':
754 case '7':
755 case '8':
756 case '9':
757 break;
758 default:
759 return last_valid_index_token_start;
760 }
761 }
762 return last_valid_index_token_start;
763}
764
765/* generic path search func
766 * if its needed this could also reference the IDProperty direct */
767struct IDP_Chain {
768 IDP_Chain *up; /* parent member, reverse and set to child for path conversion. */
769
770 const char *name;
771 int index;
772};
773
774static char *rna_idp_path_create(IDP_Chain *child_link)
775{
776 DynStr *dynstr = BLI_dynstr_new();
777 char *path;
778 bool is_first = true;
779
780 IDP_Chain *link = child_link;
781
782 /* reverse the list */
783 IDP_Chain *link_prev;
784 link_prev = nullptr;
785 while (link) {
786 IDP_Chain *link_next = link->up;
787 link->up = link_prev;
788 link_prev = link;
789 link = link_next;
790 }
791
792 for (link = link_prev; link; link = link->up) {
793 /* pass */
794 if (link->index >= 0) {
795 BLI_dynstr_appendf(dynstr, is_first ? "%s[%d]" : ".%s[%d]", link->name, link->index);
796 }
797 else {
798 BLI_dynstr_appendf(dynstr, is_first ? "%s" : ".%s", link->name);
799 }
800
801 is_first = false;
802 }
803
804 path = BLI_dynstr_get_cstring(dynstr);
805 BLI_dynstr_free(dynstr);
806
807 if (*path == '\0') {
808 MEM_freeN(path);
809 path = nullptr;
810 }
811
812 return path;
813}
814
816 const IDProperty *haystack,
817 const IDProperty *needle,
818 IDP_Chain *parent_link)
819{
820 char *path = nullptr;
821 IDP_Chain link;
822
823 const IDProperty *iter;
824 int i;
825
826 BLI_assert(haystack->type == IDP_GROUP);
827
828 link.up = parent_link;
829 /* Always set both name and index, else a stale value might get used. */
830 link.name = nullptr;
831 link.index = -1;
832
833 for (i = 0, iter = static_cast<IDProperty *>(haystack->data.group.first); iter;
834 iter = iter->next, i++)
835 {
836 if (needle == iter) { /* found! */
837 link.name = iter->name;
838 link.index = -1;
839 path = rna_idp_path_create(&link);
840 break;
841 }
842
843 /* Early out in case the IDProperty type cannot contain RNA properties. */
844 if (!ELEM(iter->type, IDP_GROUP, IDP_IDPARRAY)) {
845 continue;
846 }
847
848 /* Ensure this is RNA. */
849 /* NOTE: `iter` might be a fully user-defined IDProperty (a.k.a. custom data), which name
850 * collides with an actual fully static RNA property of the same struct (which would then not
851 * be flagged with `PROP_IDPROPERTY`).
852 *
853 * That case must be ignored here, we only want to deal with runtime RNA properties stored in
854 * IDProps.
855 *
856 * See #84091. */
858 if (prop == nullptr || (prop->flag & PROP_IDPROPERTY) == 0) {
859 continue;
860 }
861
862 if (iter->type == IDP_GROUP) {
863 if (prop->type == PROP_POINTER) {
864 PointerRNA child_ptr = RNA_property_pointer_get(ptr, prop);
865 if (RNA_pointer_is_null(&child_ptr)) {
866 /* Pointer ID prop might be a 'leaf' in the IDProp group hierarchy, in which case a null
867 * value is perfectly valid. Just means it won't match the searched needle. */
868 continue;
869 }
870
871 link.name = iter->name;
872 link.index = -1;
873 if ((path = rna_idp_path(&child_ptr, iter, needle, &link))) {
874 break;
875 }
876 }
877 }
878 else if (iter->type == IDP_IDPARRAY) {
879 if (prop->type == PROP_COLLECTION) {
880 const IDProperty *array = IDP_IDPArray(iter);
881 if (needle >= array && needle < (iter->len + array)) { /* found! */
882 link.name = iter->name;
883 link.index = int(needle - array);
884 path = rna_idp_path_create(&link);
885 break;
886 }
887 int j;
888 link.name = iter->name;
889 for (j = 0; j < iter->len; j++, array++) {
890 PointerRNA child_ptr;
891 if (RNA_property_collection_lookup_int(ptr, prop, j, &child_ptr)) {
892 if (RNA_pointer_is_null(&child_ptr)) {
893 /* Array item ID prop might be a 'leaf' in the IDProp group hierarchy, in which case
894 * a null value is perfectly valid. Just means it won't match the searched needle. */
895 continue;
896 }
897 link.index = j;
898 if ((path = rna_idp_path(&child_ptr, array, needle, &link))) {
899 break;
900 }
901 }
902 }
903 if (path) {
904 break;
905 }
906 }
907 }
908 }
909
910 return path;
911}
912
914 const IDProperty *needle)
915{
916 const IDProperty *haystack = RNA_struct_idprops(ptr, false);
917
918 if (!haystack) { /* can fail when called on bones */
919 return std::nullopt;
920 }
921
922 const char *path = rna_idp_path(ptr, haystack, needle, nullptr);
923 if (!path) {
924 return std::nullopt;
925 }
926
927 std::string string_path(path);
928 MEM_freeN((void *)path);
929
930 return string_path;
931}
932
933static std::optional<std::string> rna_path_from_ID_to_idpgroup(const PointerRNA *ptr)
934{
935 BLI_assert(ptr->owner_id != nullptr);
936
937 /* TODO: Support Bones/PoseBones. no pointers stored to the bones from here, only the ID.
938 * See example in #25746.
939 * Unless this is added only way to find this is to also search
940 * all bones and pose bones of an armature or object.
941 */
943
944 return RNA_path_from_struct_to_idproperty(&id_ptr, static_cast<const IDProperty *>(ptr->data));
945}
946
947ID *RNA_find_real_ID_and_path(ID *id, const char **r_path)
948{
949 if (r_path) {
950 *r_path = "";
951 }
952
953 if ((id == nullptr) || (id->flag & ID_FLAG_EMBEDDED_DATA) == 0) {
954 return id;
955 }
956
957 if (r_path) {
958 switch (GS(id->name)) {
959 case ID_NT:
960 *r_path = "node_tree";
961 break;
962 case ID_GR:
963 *r_path = "collection";
964 break;
965 default:
966 BLI_assert_msg(0, "Missing handling of embedded id type.");
967 }
968 }
969
970 ID *owner_id = BKE_id_owner_get(id);
971 BLI_assert_msg(owner_id != nullptr, "Missing handling of embedded id type.");
972 return (owner_id != nullptr) ? owner_id : id;
973}
974
975static std::optional<std::string> rna_prepend_real_ID_path(Main * /*bmain*/,
976 ID *id,
977 const blender::StringRef path,
978 ID **r_real_id)
979{
980 if (r_real_id != nullptr) {
981 *r_real_id = nullptr;
982 }
983
984 const char *prefix;
985 ID *real_id = RNA_find_real_ID_and_path(id, &prefix);
986
987 if (r_real_id != nullptr) {
988 *r_real_id = real_id;
989 }
990
991 if (!path.is_empty()) {
992 if (real_id) {
993 if (prefix[0]) {
994 return fmt::format("{}{}{}", prefix, path[0] == '[' ? "" : ".", path);
995 }
996 return path;
997 }
998 }
999
1000 if (prefix[0] == '\0') {
1001 return std::nullopt;
1002 }
1003
1004 return prefix;
1005}
1006
1007std::optional<std::string> RNA_path_from_ID_to_struct(const PointerRNA *ptr)
1008{
1009 std::optional<std::string> ptrpath;
1010
1011 if (!ptr->owner_id || !ptr->data) {
1012 return std::nullopt;
1013 }
1014
1015 if (!RNA_struct_is_ID(ptr->type)) {
1016 if (ptr->type->path) {
1017 /* if type has a path to some ID, use it */
1018 ptrpath = ptr->type->path((PointerRNA *)ptr);
1019 }
1020 else if (ptr->type->nested && RNA_struct_is_ID(ptr->type->nested)) {
1021 PropertyRNA *userprop;
1022
1023 /* find the property in the struct we're nested in that references this struct, and
1024 * use its identifier as the first part of the path used...
1025 */
1027 userprop = rna_struct_find_nested(&parentptr, ptr->type);
1028
1029 if (userprop) {
1030 ptrpath = RNA_property_identifier(userprop);
1031 }
1032 else {
1033 /* can't do anything about this case yet... */
1034 return std::nullopt;
1035 }
1036 }
1038 /* special case, easier to deal with here than in ptr->type->path() */
1040 }
1041 else {
1042 return std::nullopt;
1043 }
1044 }
1045
1046 return ptrpath;
1047}
1048
1049std::optional<std::string> RNA_path_from_real_ID_to_struct(Main *bmain,
1050 const PointerRNA *ptr,
1051 ID **r_real)
1052{
1053 const std::optional<std::string> path = RNA_path_from_ID_to_struct(ptr);
1054
1055 /* Null path is valid in that case, when given struct is an ID one. */
1056 return rna_prepend_real_ID_path(bmain, ptr->owner_id, path.value_or(""), r_real);
1057}
1058
1060 const int totdims,
1061 const int index_dim,
1062 int index,
1063 int r_index_multi[RNA_MAX_ARRAY_LENGTH])
1064{
1065 int dimsize_step[RNA_MAX_ARRAY_LENGTH + 1];
1066 int i = totdims - 1;
1067 dimsize_step[i + 1] = 1;
1068 dimsize_step[i] = dimsize[i];
1069 while (--i != -1) {
1070 dimsize_step[i] = dimsize[i] * dimsize_step[i + 1];
1071 }
1072 while (++i != index_dim) {
1073 int index_round = index / dimsize_step[i + 1];
1074 r_index_multi[i] = index_round;
1075 index -= (index_round * dimsize_step[i + 1]);
1076 }
1077 BLI_assert(index == 0);
1078}
1079
1081 PropertyRNA *prop,
1082 int index_dim,
1083 int index,
1084 char *index_str,
1085 int index_str_len)
1086{
1087 int dimsize[RNA_MAX_ARRAY_LENGTH];
1088 int totdims = RNA_property_array_dimension(ptr, prop, dimsize);
1089 int index_multi[RNA_MAX_ARRAY_LENGTH];
1090
1091 rna_path_array_multi_from_flat_index(dimsize, totdims, index_dim, index, index_multi);
1092
1093 for (int i = 0, offset = 0; (i < index_dim) && (offset < index_str_len); i++) {
1094 offset += BLI_snprintf_rlen(
1095 &index_str[offset], index_str_len - offset, "[%d]", index_multi[i]);
1096 }
1097}
1098
1100 PropertyRNA *prop,
1101 int index_dim,
1102 int index,
1103 const blender::StringRef path_prefix)
1104{
1105 const bool is_rna = (prop->magic == RNA_MAGIC);
1106
1107 const char *propname = RNA_property_identifier(prop);
1108
1109 /* support indexing w/ multi-dimensional arrays */
1110 char index_str[RNA_MAX_ARRAY_LENGTH * 12 + 1];
1111 if (index_dim == 0) {
1112 index_str[0] = '\0';
1113 }
1114 else {
1116 ptr, prop, index_dim, index, index_str, sizeof(index_str));
1117 }
1118
1119 if (!path_prefix.is_empty()) {
1120 if (is_rna) {
1121 return fmt::format("{}.{}{}", path_prefix, propname, index_str);
1122 }
1123 char propname_esc[MAX_IDPROP_NAME * 2];
1124 BLI_str_escape(propname_esc, propname, sizeof(propname_esc));
1125 return fmt::format("{}[\"{}\"]{}", path_prefix, propname_esc, index_str);
1126 }
1127
1128 if (is_rna) {
1129 if (index_dim == 0) {
1130 /* Use direct duplication instead of #fmt::format because it's faster. */
1131 return propname;
1132 }
1133 return fmt::format("{}{}", propname, index_str);
1134 }
1135
1136 char propname_esc[MAX_IDPROP_NAME * 2];
1137 BLI_str_escape(propname_esc, propname, sizeof(propname_esc));
1138 return fmt::format("[\"{}\"]{}", propname_esc, index_str);
1139}
1140
1142 PropertyRNA *prop,
1143 int index_dim,
1144 int index)
1145{
1146 return rna_path_from_ptr_to_property_index_ex(ptr, prop, index_dim, index, "");
1147}
1148
1149std::optional<std::string> RNA_path_from_ID_to_property_index(const PointerRNA *ptr,
1150 PropertyRNA *prop,
1151 int index_dim,
1152 int index)
1153{
1154 if (!ptr->owner_id || !ptr->data) {
1155 return std::nullopt;
1156 }
1157 /* Path from ID to the struct holding this property. */
1158 std::optional<std::string> ptrpath = RNA_path_from_ID_to_struct(ptr);
1159 /* When there is no path and this is not an ID, there is no path to the ID. */
1160 if (!ptrpath && !RNA_struct_is_ID(ptr->type)) {
1161 return std::nullopt;
1162 }
1163 return rna_path_from_ptr_to_property_index_ex(ptr, prop, index_dim, index, ptrpath.value_or(""));
1164}
1165
1166std::optional<std::string> RNA_path_from_ID_to_property(const PointerRNA *ptr, PropertyRNA *prop)
1167{
1168 return RNA_path_from_ID_to_property_index(ptr, prop, 0, -1);
1169}
1170
1171std::optional<std::string> RNA_path_from_real_ID_to_property_index(Main *bmain,
1172 const PointerRNA *ptr,
1173 PropertyRNA *prop,
1174 int index_dim,
1175 int index,
1176 ID **r_real_id)
1177{
1178 const std::optional<std::string> path = RNA_path_from_ID_to_property_index(
1179 ptr, prop, index_dim, index);
1180 if (!path) {
1181 return std::nullopt;
1182 }
1183
1184 /* Null path is always an error here, in that case do not return the 'fake ID from real ID' part
1185 * of the path either. */
1186 return rna_prepend_real_ID_path(bmain, ptr->owner_id, path->c_str(), r_real_id);
1187}
1188
1190 PropertyRNA *prop,
1191 const StructRNA *type)
1192{
1193 /* Try to recursively find an "type"'d ancestor,
1194 * to handle situations where path from ID is not enough. */
1195 ListBase path_elems = {nullptr};
1196 const std::optional<std::string> full_path = RNA_path_from_ID_to_property(ptr, prop);
1197 if (!full_path) {
1198 return std::nullopt;
1199 }
1200
1202
1203 std::optional<std::string> path;
1204 if (RNA_path_resolve_elements(&idptr, full_path->c_str(), &path_elems)) {
1205 LISTBASE_FOREACH_BACKWARD (PropertyElemRNA *, prop_elem, &path_elems) {
1206 if (RNA_struct_is_a(prop_elem->ptr.type, type)) {
1207 if (const std::optional<std::string> ref_path = RNA_path_from_ID_to_struct(
1208 &prop_elem->ptr))
1209 {
1210 path = blender::StringRef(*full_path).drop_prefix(ref_path->size() + 1);
1211 }
1212 break;
1213 }
1214 }
1215
1216 LISTBASE_FOREACH_MUTABLE (PropertyElemRNA *, prop_elem, &path_elems) {
1217 MEM_delete(prop_elem);
1218 }
1219 BLI_listbase_clear(&path_elems);
1220 }
1221
1222 return path;
1223}
1224
1225std::string RNA_path_full_ID_py(ID *id)
1226{
1227 const char *path;
1228 ID *id_real = RNA_find_real_ID_and_path(id, &path);
1229
1230 if (id_real) {
1231 id = id_real;
1232 }
1233 else {
1234 path = "";
1235 }
1236
1237 char lib_filepath_esc[(sizeof(id->lib->filepath) * 2) + 4];
1238 if (ID_IS_LINKED(id)) {
1239 int ofs = 0;
1240 memcpy(lib_filepath_esc, ", \"", 3);
1241 ofs += 3;
1242 ofs += BLI_str_escape(lib_filepath_esc + ofs, id->lib->filepath, sizeof(lib_filepath_esc));
1243 memcpy(lib_filepath_esc + ofs, "\"", 2);
1244 }
1245 else {
1246 lib_filepath_esc[0] = '\0';
1247 }
1248
1249 char id_esc[(sizeof(id->name) - 2) * 2];
1250 BLI_str_escape(id_esc, id->name + 2, sizeof(id_esc));
1251
1252 return fmt::format("bpy.data.{}[\"{}\"{}]{}{}",
1254 id_esc,
1255 lib_filepath_esc,
1256 path[0] ? "." : "",
1257 path);
1258}
1259
1260std::optional<std::string> RNA_path_full_struct_py(const PointerRNA *ptr)
1261{
1262 if (!ptr->owner_id) {
1263 return std::nullopt;
1264 }
1265
1266 /* never fails */
1267 std::string id_path = RNA_path_full_ID_py(ptr->owner_id);
1268
1269 std::optional<std::string> data_path = RNA_path_from_ID_to_struct(ptr);
1270
1271 /* XXX data_path may be null (see #36788),
1272 * do we want to get the 'bpy.data.foo["bar"].(null)' stuff? */
1273 return fmt::format("{}.{}", id_path, data_path.value_or(""));
1274}
1275
1276std::optional<std::string> RNA_path_full_property_py_ex(const PointerRNA *ptr,
1277 PropertyRNA *prop,
1278 int index,
1279 bool use_fallback)
1280{
1281 const char *data_delim;
1282
1283 if (!ptr->owner_id) {
1284 return std::nullopt;
1285 }
1286
1287 /* never fails */
1288 std::string id_path = RNA_path_full_ID_py(ptr->owner_id);
1289
1290 std::optional<std::string> data_path = RNA_path_from_ID_to_property(ptr, prop);
1291 if (data_path) {
1292 data_delim = ((*data_path)[0] == '[') ? "" : ".";
1293 }
1294 else {
1295 if (use_fallback) {
1296 /* Fuzzy fallback. Be explicit in our ignorance. */
1297 data_path = RNA_property_identifier(prop);
1298 data_delim = " ... ";
1299 }
1300 else {
1301 data_delim = ".";
1302 }
1303 }
1304
1305 if ((index == -1) || (RNA_property_array_check(prop) == false)) {
1306 return fmt::format("{}{}{}", id_path, data_delim, data_path.value_or(""));
1307 }
1308 return fmt::format("{}{}{}[{}]", id_path, data_delim, data_path.value_or(""), index);
1309}
1310
1311std::optional<std::string> RNA_path_full_property_py(const PointerRNA *ptr,
1312 PropertyRNA *prop,
1313 int index)
1314{
1315 return RNA_path_full_property_py_ex(ptr, prop, index, false);
1316}
1317
1318std::optional<std::string> RNA_path_struct_property_py(PointerRNA *ptr,
1319 PropertyRNA *prop,
1320 int index)
1321{
1322 if (!ptr->owner_id) {
1323 return std::nullopt;
1324 }
1325
1326 std::optional<std::string> data_path = RNA_path_from_ID_to_property(ptr, prop);
1327
1328 if (!data_path) {
1329 /* This may not be an ID at all, check for simple when pointer owns property.
1330 * TODO: more complex nested case. */
1331 if (!RNA_struct_is_ID(ptr->type)) {
1332 const char *prop_identifier = RNA_property_identifier(prop);
1333 if (RNA_struct_find_property(ptr, prop_identifier) == prop) {
1334 data_path = prop_identifier;
1335 }
1336 }
1337 }
1338
1339 if ((index == -1) || (RNA_property_array_check(prop) == false)) {
1340 return *data_path;
1341 }
1342 return fmt::format("{}[{}]", data_path.value_or(""), index);
1343}
1344
1345std::string RNA_path_property_py(const PointerRNA *ptr, PropertyRNA *prop, int index)
1346{
1347 if (RNA_property_array_check(prop) == false) {
1348 index = -1;
1349 }
1350 const int index_dim = (index == -1) ? 0 : 1;
1351 return RNA_path_from_ptr_to_property_index(ptr, prop, index_dim, index);
1352}
#define IDP_IDPArray(prop)
IDProperty * IDP_GetPropertyFromGroup(const IDProperty *prop, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition idprop.cc:763
const char * BKE_idtype_idcode_to_name_plural(short idcode)
Definition idtype.cc:175
ID * BKE_id_owner_get(ID *id, const bool debug_relationship_assert=true)
Definition lib_id.cc:2444
#define BLI_array_alloca(arr, realsize)
Definition BLI_alloca.h:25
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
A dynamically sized string ADT.
char * BLI_dynstr_get_cstring(const DynStr *ds) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition BLI_dynstr.c:149
DynStr * BLI_dynstr_new(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition BLI_dynstr.c:37
void BLI_dynstr_free(DynStr *ds) ATTR_NONNULL()
Definition BLI_dynstr.c:174
void BLI_dynstr_appendf(DynStr *__restrict ds, const char *__restrict format,...) ATTR_PRINTF_FORMAT(2
void BLI_dynstr_append(DynStr *__restrict ds, const char *cstr) ATTR_NONNULL()
Definition BLI_dynstr.c:62
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
#define LISTBASE_FOREACH_BACKWARD(type, var, list)
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.c:40
size_t size_t size_t const char * BLI_str_escape_find_quote(const char *str) ATTR_NONNULL(1)
Definition string.c:434
size_t size_t size_t BLI_str_unescape(char *__restrict dst, const char *__restrict src, size_t src_maxncpy) ATTR_NONNULL(1
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
size_t BLI_snprintf_rlen(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
size_t BLI_str_escape(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
#define UNUSED_FUNCTION_WITH_RETURN_TYPE(rtype, x)
#define UNLIKELY(x)
#define ELEM(...)
ID and Library types, which are fundamental for SDNA.
#define ID_IS_LINKED(_id)
Definition DNA_ID.h:654
@ ID_FLAG_EMBEDDED_DATA
Definition DNA_ID.h:725
#define MAX_IDPROP_NAME
Definition DNA_ID.h:185
@ ID_NT
@ ID_GR
@ IDP_IDPARRAY
@ IDP_GROUP
Read Guarded memory(de)allocation.
#define RNA_POINTER_INVALIDATE(ptr)
#define RNA_MAX_ARRAY_LENGTH
Definition RNA_define.hh:23
#define RNA_MAX_ARRAY_DIMENSION
Definition RNA_define.hh:26
@ PROP_FLOAT
Definition RNA_types.hh:67
@ PROP_BOOLEAN
Definition RNA_types.hh:65
@ PROP_INT
Definition RNA_types.hh:66
@ PROP_POINTER
Definition RNA_types.hh:70
@ PROP_COLLECTION
Definition RNA_types.hh:71
@ PROP_IDPROPERTY
Definition RNA_types.hh:315
constexpr bool is_empty() const
constexpr StringRef drop_prefix(int64_t n) const
int len
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
#define GS(x)
Definition iris.cc:202
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
bool RNA_property_array_check(PropertyRNA *prop)
bool RNA_struct_is_a(const StructRNA *type, const StructRNA *srna)
bool RNA_struct_is_ID(const StructRNA *type)
PropertyRNA * rna_struct_find_nested(PointerRNA *ptr, StructRNA *srna)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
PropertyType RNA_property_type(PropertyRNA *prop)
PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop)
IDProperty * RNA_struct_idprops(PointerRNA *ptr, bool create)
int RNA_property_array_dimension(const PointerRNA *ptr, PropertyRNA *prop, int length[])
bool RNA_property_collection_lookup_int(PointerRNA *ptr, PropertyRNA *prop, int key, PointerRNA *r_ptr)
bool RNA_pointer_is_null(const PointerRNA *ptr)
bool RNA_property_collection_lookup_string(PointerRNA *ptr, PropertyRNA *prop, const char *key, PointerRNA *r_ptr)
bool RNA_property_collection_type_get(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *r_ptr)
int RNA_property_array_item_index(PropertyRNA *prop, char name)
const char * RNA_property_identifier(const PropertyRNA *prop)
PointerRNA RNA_id_pointer_create(ID *id)
StructRNA RNA_PropertyGroup
#define RNA_MAGIC
static bool rna_path_parse_array_index(const char **path, PointerRNA *ptr, PropertyRNA *prop, int *r_index)
Definition rna_path.cc:252
std::optional< std::string > RNA_path_from_struct_to_idproperty(PointerRNA *ptr, const IDProperty *needle)
Definition rna_path.cc:913
std::optional< std::string > RNA_path_from_ID_to_struct(const PointerRNA *ptr)
Definition rna_path.cc:1007
std::optional< std::string > RNA_path_full_property_py(const PointerRNA *ptr, PropertyRNA *prop, int index)
Definition rna_path.cc:1311
std::optional< std::string > RNA_path_from_real_ID_to_struct(Main *bmain, const PointerRNA *ptr, ID **r_real)
Definition rna_path.cc:1049
std::optional< std::string > RNA_path_from_real_ID_to_property_index(Main *bmain, const PointerRNA *ptr, PropertyRNA *prop, int index_dim, int index, ID **r_real_id)
Definition rna_path.cc:1171
static char * rna_path_token_in_brackets(const char **path, char *fixedbuf, int fixedlen, bool *r_quoted)
Definition rna_path.cc:96
std::optional< std::string > RNA_path_full_property_py_ex(const PointerRNA *ptr, PropertyRNA *prop, int index, bool use_fallback)
Definition rna_path.cc:1276
static bool rna_path_parse(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index, PointerRNA *r_item_ptr, ListBase *r_elements, const bool eval_pointer)
Definition rna_path.cc:369
bool RNA_path_resolve_elements(PointerRNA *ptr, const char *path, ListBase *r_elements)
Definition rna_path.cc:601
std::optional< std::string > RNA_path_resolve_from_type_to_property(const PointerRNA *ptr, PropertyRNA *prop, const StructRNA *type)
Definition rna_path.cc:1189
bool RNA_path_resolve_full_maybe_null(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
Definition rna_path.cc:547
ID * RNA_find_real_ID_and_path(ID *id, const char **r_path)
Definition rna_path.cc:947
std::optional< std::string > RNA_path_full_struct_py(const PointerRNA *ptr)
Definition rna_path.cc:1260
bool RNA_path_resolve_property_and_item_pointer(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, PointerRNA *r_item_ptr)
Definition rna_path.cc:575
bool operator==(const RNAPath &left, const RNAPath &right)
Definition rna_path.cc:37
static char * rna_path_token(const char **path, char *fixedbuf, int fixedlen)
Definition rna_path.cc:56
std::string RNA_path_full_ID_py(ID *id)
Definition rna_path.cc:1225
static std::string rna_path_from_ptr_to_property_index_ex(const PointerRNA *ptr, PropertyRNA *prop, int index_dim, int index, const blender::StringRef path_prefix)
Definition rna_path.cc:1099
static std::optional< std::string > rna_path_from_ID_to_idpgroup(const PointerRNA *ptr)
Definition rna_path.cc:933
static std::optional< std::string > rna_prepend_real_ID_path(Main *, ID *id, const blender::StringRef path, ID **r_real_id)
Definition rna_path.cc:975
const char * RNA_path_array_index_token_find(const char *rna_path, const PropertyRNA *array_prop)
Definition rna_path.cc:715
static char * rna_idp_path_create(IDP_Chain *child_link)
Definition rna_path.cc:774
bool RNA_path_resolve_full(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
Definition rna_path.cc:537
std::optional< std::string > RNA_path_from_ID_to_property_index(const PointerRNA *ptr, PropertyRNA *prop, int index_dim, int index)
Definition rna_path.cc:1149
static bool rna_path_parse_collection_key(const char **path, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *r_nextptr)
Definition rna_path.cc:185
std::string RNA_path_property_py(const PointerRNA *ptr, PropertyRNA *prop, int index)
Definition rna_path.cc:1345
std::optional< std::string > RNA_path_from_ID_to_property(const PointerRNA *ptr, PropertyRNA *prop)
Definition rna_path.cc:1166
bool RNA_path_resolve_property(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
Definition rna_path.cc:553
static void rna_path_array_multi_string_from_flat_index(const PointerRNA *ptr, PropertyRNA *prop, int index_dim, int index, char *index_str, int index_str_len)
Definition rna_path.cc:1080
bool RNA_path_resolve_property_full(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
Definition rna_path.cc:565
bool RNA_path_resolve_property_and_item_pointer_full(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index, PointerRNA *r_item_ptr)
Definition rna_path.cc:588
std::optional< std::string > RNA_path_struct_property_py(PointerRNA *ptr, PropertyRNA *prop, int index)
Definition rna_path.cc:1318
std::string RNA_path_from_ptr_to_property_index(const PointerRNA *ptr, PropertyRNA *prop, int index_dim, int index)
Definition rna_path.cc:1141
bool RNA_path_resolve(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
Definition rna_path.cc:525
char * RNA_path_append(const char *path, const PointerRNA *, PropertyRNA *prop, int intkey, const char *strkey)
Definition rna_path.cc:606
static void rna_path_array_multi_from_flat_index(const int dimsize[RNA_MAX_ARRAY_LENGTH], const int totdims, const int index_dim, int index, int r_index_multi[RNA_MAX_ARRAY_LENGTH])
Definition rna_path.cc:1059
static char * rna_idp_path(PointerRNA *ptr, const IDProperty *haystack, const IDProperty *needle, IDP_Chain *parent_link)
Definition rna_path.cc:815
IDP_Chain * up
Definition rna_path.cc:768
const char * name
Definition rna_path.cc:770
ListBase group
Definition DNA_ID.h:146
int len
Definition DNA_ID.h:174
struct IDProperty * next
Definition DNA_ID.h:152
char name[64]
Definition DNA_ID.h:163
IDPropertyData data
Definition DNA_ID.h:168
char type
Definition DNA_ID.h:154
Definition DNA_ID.h:413
void * first
ID * owner_id
Definition RNA_types.hh:40
StructRNA * type
Definition RNA_types.hh:41
void * data
Definition RNA_types.hh:42
PointerRNA ptr
Definition RNA_path.hh:211
PropertyRNA * prop
Definition RNA_path.hh:212
unsigned int arraydimension
PropertyType type
StructRNA * nested
StructPathFunc path
PointerRNA * ptr
Definition wm_files.cc:4126