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