diff options
Diffstat (limited to 'source/blender/makesrna/intern/rna_access.c')
-rw-r--r-- | source/blender/makesrna/intern/rna_access.c | 1336 |
1 files changed, 3 insertions, 1333 deletions
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index cf4182243b9..04707c01d6b 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -46,6 +46,7 @@ #include "RNA_access.h" #include "RNA_define.h" #include "RNA_enum_types.h" +#include "RNA_path.h" #include "WM_api.h" #include "WM_message.h" @@ -738,7 +739,7 @@ PropertyRNA *RNA_struct_find_property(PointerRNA *ptr, const char *identifier) } /* Find the property which uses the given nested struct */ -static PropertyRNA *RNA_struct_find_nested(PointerRNA *ptr, StructRNA *srna) +PropertyRNA *rna_struct_find_nested(PointerRNA *ptr, StructRNA *srna) { PropertyRNA *prop = NULL; @@ -1422,7 +1423,7 @@ StructRNA *RNA_property_pointer_type(PointerRNA *ptr, PropertyRNA *prop) return cprop->item_type; } } - /* ignore other types, RNA_struct_find_nested calls with unchecked props */ + /* ignore other types, rna_struct_find_nested calls with unchecked props */ return &RNA_UnknownType; } @@ -4821,1337 +4822,6 @@ PointerRNA rna_array_lookup_int( return rna_pointer_inherit_refine(ptr, type, ((char *)data) + index * itemsize); } -/* RNA Path - Experiment */ - -/** - * Extract the first token from `path`. - * - * \param path: Extract the token from path, step the pointer to the beginning of the next token - * \return The nil terminated token. - */ -static char *rna_path_token(const char **path, char *fixedbuf, int fixedlen) -{ - int len = 0; - - /* Get data until `.` or `[`. */ - const char *p = *path; - while (*p && !ELEM(*p, '.', '[')) { - len++; - p++; - } - - /* Empty, return. */ - if (UNLIKELY(len == 0)) { - return NULL; - } - - /* Try to use fixed buffer if possible. */ - char *buf = (len + 1 < fixedlen) ? fixedbuf : MEM_mallocN(sizeof(char) * (len + 1), __func__); - memcpy(buf, *path, sizeof(char) * len); - buf[len] = '\0'; - - if (*p == '.') { - p++; - } - *path = p; - - return buf; -} - -/** - * Extract the first token in brackets from `path` (with quoted text support). - * - * - `[0]` -> `0` - * - `["Some\"Quote"]` -> `Some"Quote` - * - * \param path: Extract the token from path, step the pointer to the beginning of the next token - * (past quoted text and brackets). - * \return The nil terminated token. - */ -static char *rna_path_token_in_brackets(const char **path, - char *fixedbuf, - int fixedlen, - bool *r_quoted) -{ - int len = 0; - bool quoted = false; - - BLI_assert(r_quoted != NULL); - - /* Get data between `[]`, check escaping quotes and back-slashes with #BLI_str_unescape. */ - if (UNLIKELY(**path != '[')) { - return NULL; - } - - (*path)++; - const char *p = *path; - - /* 2 kinds of look-ups now, quoted or unquoted. */ - if (*p == '"') { - /* Find the matching quote. */ - (*path)++; - p = *path; - const char *p_end = BLI_str_escape_find_quote(p); - if (p_end == NULL) { - /* No Matching quote. */ - return NULL; - } - /* Exclude the last quote from the length. */ - len += (p_end - p); - - /* Skip the last quoted char to get the `]`. */ - p_end += 1; - p = p_end; - quoted = true; - } - else { - /* Find the matching bracket. */ - while (*p && (*p != ']')) { - len++; - p++; - } - } - - if (UNLIKELY(*p != ']')) { - return NULL; - } - - /* Empty, return. */ - if (UNLIKELY(len == 0)) { - return NULL; - } - - /* Try to use fixed buffer if possible. */ - char *buf = (len + 1 < fixedlen) ? fixedbuf : MEM_mallocN(sizeof(char) * (len + 1), __func__); - - /* Copy string, taking into account escaped ']' */ - if (quoted) { - BLI_str_unescape(buf, *path, len); - /* +1 to step over the last quote. */ - BLI_assert((*path)[len] == '"'); - p = (*path) + len + 1; - } - else { - memcpy(buf, *path, sizeof(char) * len); - buf[len] = '\0'; - } - /* Set path to start of next token. */ - if (*p == ']') { - p++; - } - if (*p == '.') { - p++; - } - *path = p; - - *r_quoted = quoted; - - return buf; -} - -/** - * \return true when the key in the path is correctly parsed and found in the collection - * or when the path is empty. - */ -static bool rna_path_parse_collection_key(const char **path, - PointerRNA *ptr, - PropertyRNA *prop, - PointerRNA *r_nextptr) -{ - char fixedbuf[256]; - int intkey; - - *r_nextptr = *ptr; - - /* end of path, ok */ - if (!(**path)) { - return true; - } - - bool found = false; - if (**path == '[') { - bool quoted; - char *token; - - /* resolve the lookup with [] brackets */ - token = rna_path_token_in_brackets(path, fixedbuf, sizeof(fixedbuf), "ed); - - if (!token) { - return false; - } - - /* check for "" to see if it is a string */ - if (quoted) { - if (RNA_property_collection_lookup_string(ptr, prop, token, r_nextptr)) { - found = true; - } - else { - r_nextptr->data = NULL; - } - } - else { - /* otherwise do int lookup */ - intkey = atoi(token); - if (intkey == 0 && (token[0] != '0' || token[1] != '\0')) { - return false; /* we can be sure the fixedbuf was used in this case */ - } - if (RNA_property_collection_lookup_int(ptr, prop, intkey, r_nextptr)) { - found = true; - } - else { - r_nextptr->data = NULL; - } - } - - if (token != fixedbuf) { - MEM_freeN(token); - } - } - else { - if (RNA_property_collection_type_get(ptr, prop, r_nextptr)) { - found = true; - } - else { - /* ensure we quit on invalid values */ - r_nextptr->data = NULL; - } - } - - return found; -} - -static bool rna_path_parse_array_index(const char **path, - PointerRNA *ptr, - PropertyRNA *prop, - int *r_index) -{ - char fixedbuf[256]; - int index_arr[RNA_MAX_ARRAY_DIMENSION] = {0}; - int len[RNA_MAX_ARRAY_DIMENSION]; - const int dim = RNA_property_array_dimension(ptr, prop, len); - int i; - - *r_index = -1; - - /* end of path, ok */ - if (!(**path)) { - return true; - } - - for (i = 0; i < dim; i++) { - int temp_index = -1; - char *token; - - /* multi index resolve */ - if (**path == '[') { - bool quoted; - token = rna_path_token_in_brackets(path, fixedbuf, sizeof(fixedbuf), "ed); - - if (token == NULL) { - /* invalid syntax blah[] */ - return false; - } - /* check for "" to see if it is a string */ - if (quoted) { - temp_index = RNA_property_array_item_index(prop, *token); - } - else { - /* otherwise do int lookup */ - temp_index = atoi(token); - - if (temp_index == 0 && (token[0] != '0' || token[1] != '\0')) { - if (token != fixedbuf) { - MEM_freeN(token); - } - - return false; - } - } - } - else if (dim == 1) { - /* location.x || scale.X, single dimension arrays only */ - token = rna_path_token(path, fixedbuf, sizeof(fixedbuf)); - if (token == NULL) { - /* invalid syntax blah. */ - return false; - } - temp_index = RNA_property_array_item_index(prop, *token); - } - else { - /* just to avoid uninitialized pointer use */ - token = fixedbuf; - } - - if (token != fixedbuf) { - MEM_freeN(token); - } - - /* out of range */ - if (temp_index < 0 || temp_index >= len[i]) { - return false; - } - - index_arr[i] = temp_index; - /* end multi index resolve */ - } - - /* arrays always contain numbers so further values are not valid */ - if (**path) { - return false; - } - - /* flatten index over all dimensions */ - { - int totdim = 1; - int flat_index = 0; - - for (i = dim - 1; i >= 0; i--) { - flat_index += index_arr[i] * totdim; - totdim *= len[i]; - } - - *r_index = flat_index; - } - return true; -} - -/** - * Generic rna path parser. - * - * \note All parameters besides \a ptr and \a path are optional. - * - * \param ptr: The root of given RNA path. - * \param path: The RNA path. - * \param r_ptr: The final RNA data holding the last property in \a path. - * \param r_prop: The final property of \a r_ptr, from \a path. - * \param r_index: The final index in the \a r_prop, if defined by \a path. - * \param r_item_ptr: Only valid for Pointer and Collection, return the actual value of the - * pointer, or of the collection item. - * Mutually exclusive with \a eval_pointer option. - * \param r_elements: A list of \a PropertyElemRNA items(pairs of \a PointerRNA, \a PropertyRNA - * that represent the whole given \a path). - * \param eval_pointer: If \a true, and \a path leads to a Pointer property, or an item in a - * Collection property, \a r_ptr will be set to the value of that property, - * and \a r_prop will be NULL. - * Mutually exclusive with \a r_item_ptr. - * - * \return \a true on success, \a false if the path is somehow invalid. - */ -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) -{ - BLI_assert(r_item_ptr == NULL || !eval_pointer); - PropertyRNA *prop; - PointerRNA curptr, nextptr; - PropertyElemRNA *prop_elem = NULL; - int index = -1; - char fixedbuf[256]; - int type; - const bool do_item_ptr = r_item_ptr != NULL && !eval_pointer; - - if (do_item_ptr) { - RNA_POINTER_INVALIDATE(&nextptr); - } - - prop = NULL; - curptr = *ptr; - - if (path == NULL || *path == '\0') { - return false; - } - - while (*path) { - if (do_item_ptr) { - RNA_POINTER_INVALIDATE(&nextptr); - } - - const bool use_id_prop = (*path == '['); - /* custom property lookup ? - * C.object["someprop"] - */ - - if (!curptr.data) { - return false; - } - - /* look up property name in current struct */ - bool quoted = false; - char *token = use_id_prop ? - rna_path_token_in_brackets(&path, fixedbuf, sizeof(fixedbuf), "ed) : - rna_path_token(&path, fixedbuf, sizeof(fixedbuf)); - if (!token) { - return false; - } - - prop = NULL; - if (use_id_prop) { /* look up property name in current struct */ - IDProperty *group = RNA_struct_idprops(&curptr, 0); - if (group && quoted) { - prop = (PropertyRNA *)IDP_GetPropertyFromGroup(group, token); - } - } - else { - prop = RNA_struct_find_property(&curptr, token); - } - - if (token != fixedbuf) { - MEM_freeN(token); - } - - if (!prop) { - return false; - } - - if (r_elements) { - prop_elem = MEM_mallocN(sizeof(PropertyElemRNA), __func__); - prop_elem->ptr = curptr; - prop_elem->prop = prop; - prop_elem->index = -1; /* index will be added later, if needed. */ - BLI_addtail(r_elements, prop_elem); - } - - type = RNA_property_type(prop); - - /* now look up the value of this property if it is a pointer or - * collection, otherwise return the property rna so that the - * caller can read the value of the property itself */ - switch (type) { - case PROP_POINTER: { - /* resolve pointer if further path elements follow - * or explicitly requested - */ - if (do_item_ptr || eval_pointer || *path != '\0') { - nextptr = RNA_property_pointer_get(&curptr, prop); - } - - if (eval_pointer || *path != '\0') { - curptr = nextptr; - prop = NULL; /* now we have a PointerRNA, the prop is our parent so forget it */ - index = -1; - } - break; - } - case PROP_COLLECTION: { - /* Resolve pointer if further path elements follow. - * Note that if path is empty, rna_path_parse_collection_key will do nothing anyway, - * so do_item_ptr is of no use in that case. - */ - if (*path) { - if (!rna_path_parse_collection_key(&path, &curptr, prop, &nextptr)) { - return false; - } - - if (eval_pointer || *path != '\0') { - curptr = nextptr; - prop = NULL; /* now we have a PointerRNA, the prop is our parent so forget it */ - index = -1; - } - } - break; - } - default: - if (r_index || prop_elem) { - if (!rna_path_parse_array_index(&path, &curptr, prop, &index)) { - return false; - } - - if (prop_elem) { - prop_elem->index = index; - } - } - break; - } - } - - if (r_ptr) { - *r_ptr = curptr; - } - if (r_prop) { - *r_prop = prop; - } - if (r_index) { - *r_index = index; - } - if (r_item_ptr && do_item_ptr) { - *r_item_ptr = nextptr; - } - - if (prop_elem && (prop_elem->ptr.data != curptr.data || prop_elem->prop != prop || - prop_elem->index != index)) { - prop_elem = MEM_mallocN(sizeof(PropertyElemRNA), __func__); - prop_elem->ptr = curptr; - prop_elem->prop = prop; - prop_elem->index = index; - BLI_addtail(r_elements, prop_elem); - } - - return true; -} - -bool RNA_path_resolve(const PointerRNA *ptr, - const char *path, - PointerRNA *r_ptr, - PropertyRNA **r_prop) -{ - if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, NULL, NULL, true)) { - return false; - } - - return r_ptr->data != NULL; -} - -bool RNA_path_resolve_full( - const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index) -{ - if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, NULL, NULL, true)) { - return false; - } - - return r_ptr->data != NULL; -} - -bool RNA_path_resolve_full_maybe_null( - const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index) -{ - return rna_path_parse(ptr, path, r_ptr, r_prop, r_index, NULL, NULL, true); -} - -bool RNA_path_resolve_property(const PointerRNA *ptr, - const char *path, - PointerRNA *r_ptr, - PropertyRNA **r_prop) -{ - if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, NULL, NULL, false)) { - return false; - } - - return r_ptr->data != NULL && *r_prop != NULL; -} - -bool RNA_path_resolve_property_full( - const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index) -{ - if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, NULL, NULL, false)) { - return false; - } - - return r_ptr->data != NULL && *r_prop != NULL; -} - -bool RNA_path_resolve_property_and_item_pointer(const PointerRNA *ptr, - const char *path, - PointerRNA *r_ptr, - PropertyRNA **r_prop, - PointerRNA *r_item_ptr) -{ - if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, r_item_ptr, NULL, false)) { - return false; - } - - return r_ptr->data != NULL && *r_prop != NULL; -} - -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) -{ - if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, r_item_ptr, NULL, false)) { - return false; - } - - return r_ptr->data != NULL && *r_prop != NULL; -} -bool RNA_path_resolve_elements(PointerRNA *ptr, const char *path, ListBase *r_elements) -{ - return rna_path_parse(ptr, path, NULL, NULL, NULL, NULL, r_elements, false); -} - -char *RNA_path_append(const char *path, - const PointerRNA *UNUSED(ptr), - PropertyRNA *prop, - int intkey, - const char *strkey) -{ - DynStr *dynstr; - char *result; - - dynstr = BLI_dynstr_new(); - - /* add .identifier */ - if (path) { - BLI_dynstr_append(dynstr, path); - if (*path) { - BLI_dynstr_append(dynstr, "."); - } - } - - BLI_dynstr_append(dynstr, RNA_property_identifier(prop)); - - if (RNA_property_type(prop) == PROP_COLLECTION) { - /* add ["strkey"] or [intkey] */ - BLI_dynstr_append(dynstr, "["); - - if (strkey) { - const int strkey_esc_max_size = (strlen(strkey) * 2) + 1; - char *strkey_esc = BLI_array_alloca(strkey_esc, strkey_esc_max_size); - BLI_str_escape(strkey_esc, strkey, strkey_esc_max_size); - BLI_dynstr_append(dynstr, "\""); - BLI_dynstr_append(dynstr, strkey_esc); - BLI_dynstr_append(dynstr, "\""); - } - else { - char appendstr[128]; - BLI_snprintf(appendstr, sizeof(appendstr), "%d", intkey); - BLI_dynstr_append(dynstr, appendstr); - } - - BLI_dynstr_append(dynstr, "]"); - } - - result = BLI_dynstr_get_cstring(dynstr); - BLI_dynstr_free(dynstr); - - return result; -} - -/* Having both path append & back seems like it could be useful, - * this function isn't used at the moment. */ -static UNUSED_FUNCTION_WITH_RETURN_TYPE(char *, RNA_path_back)(const char *path) -{ - char fixedbuf[256]; - const char *previous, *current; - char *result; - int i; - - if (!path) { - return NULL; - } - - previous = NULL; - current = path; - - /* parse token by token until the end, then we back up to the previous - * position and strip of the next token to get the path one step back */ - while (*current) { - char *token; - - token = rna_path_token(¤t, fixedbuf, sizeof(fixedbuf)); - - if (!token) { - return NULL; - } - if (token != fixedbuf) { - MEM_freeN(token); - } - - /* in case of collection we also need to strip off [] */ - bool quoted; - token = rna_path_token_in_brackets(¤t, fixedbuf, sizeof(fixedbuf), "ed); - if (token && token != fixedbuf) { - MEM_freeN(token); - } - - if (!*current) { - break; - } - - previous = current; - } - - if (!previous) { - return NULL; - } - - /* copy and strip off last token */ - i = previous - path; - result = BLI_strdup(path); - - if (i > 0 && result[i - 1] == '.') { - i--; - } - result[i] = 0; - - return result; -} - -const char *RNA_path_array_index_token_find(const char *rna_path, const PropertyRNA *array_prop) -{ - if (array_prop != NULL) { - if (!ELEM(array_prop->type, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) { - BLI_assert(array_prop->arraydimension == 0); - return NULL; - } - if (array_prop->arraydimension == 0) { - return NULL; - } - } - - /* Valid 'array part' of a rna path can only have '[', ']' and digit characters. - * It may have more than one of those (e.g. `[12][1]`) in case of multi-dimensional arrays. */ - off_t rna_path_len = (off_t)strlen(rna_path); - if (rna_path[rna_path_len] != ']') { - return NULL; - } - const char *last_valid_index_token_start = NULL; - for (rna_path_len--; rna_path_len >= 0; rna_path_len--) { - switch (rna_path[rna_path_len]) { - case '[': - if (rna_path_len <= 0 || rna_path[rna_path_len - 1] != ']') { - return &rna_path[rna_path_len]; - } - last_valid_index_token_start = &rna_path[rna_path_len]; - rna_path_len--; - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - break; - default: - return last_valid_index_token_start; - } - } - return last_valid_index_token_start; -} - -/* generic path search func - * if its needed this could also reference the IDProperty direct */ -typedef struct IDP_Chain { - struct IDP_Chain *up; /* parent member, reverse and set to child for path conversion. */ - - const char *name; - int index; - -} IDP_Chain; - -static char *rna_idp_path_create(IDP_Chain *child_link) -{ - DynStr *dynstr = BLI_dynstr_new(); - char *path; - bool is_first = true; - - int tot = 0; - IDP_Chain *link = child_link; - - /* reverse the list */ - IDP_Chain *link_prev; - link_prev = NULL; - while (link) { - IDP_Chain *link_next = link->up; - link->up = link_prev; - link_prev = link; - link = link_next; - tot++; - } - - for (link = link_prev; link; link = link->up) { - /* pass */ - if (link->index >= 0) { - BLI_dynstr_appendf(dynstr, is_first ? "%s[%d]" : ".%s[%d]", link->name, link->index); - } - else { - BLI_dynstr_appendf(dynstr, is_first ? "%s" : ".%s", link->name); - } - - is_first = false; - } - - path = BLI_dynstr_get_cstring(dynstr); - BLI_dynstr_free(dynstr); - - if (*path == '\0') { - MEM_freeN(path); - path = NULL; - } - - return path; -} - -static char *rna_idp_path(PointerRNA *ptr, - IDProperty *haystack, - IDProperty *needle, - IDP_Chain *parent_link) -{ - char *path = NULL; - IDP_Chain link; - - IDProperty *iter; - int i; - - BLI_assert(haystack->type == IDP_GROUP); - - link.up = parent_link; - /* Always set both name and index, else a stale value might get used. */ - link.name = NULL; - link.index = -1; - - for (i = 0, iter = haystack->data.group.first; iter; iter = iter->next, i++) { - if (needle == iter) { /* found! */ - link.name = iter->name; - link.index = -1; - path = rna_idp_path_create(&link); - break; - } - - /* Early out in case the IDProperty type cannot contain RNA properties. */ - if (!ELEM(iter->type, IDP_GROUP, IDP_IDPARRAY)) { - continue; - } - - /* Ensure this is RNA. */ - /* NOTE: `iter` might be a fully user-defined IDProperty (a.k.a. custom data), which name - * collides with an actual fully static RNA property of the same struct (which would then not - * be flagged with `PROP_IDPROPERTY`). - * - * That case must be ignored here, we only want to deal with runtime RNA properties stored in - * IDProps. - * - * See T84091. */ - PropertyRNA *prop = RNA_struct_find_property(ptr, iter->name); - if (prop == NULL || (prop->flag & PROP_IDPROPERTY) == 0) { - continue; - } - - if (iter->type == IDP_GROUP) { - if (prop->type == PROP_POINTER) { - PointerRNA child_ptr = RNA_property_pointer_get(ptr, prop); - if (RNA_pointer_is_null(&child_ptr)) { - /* Pointer ID prop might be a 'leaf' in the IDProp group hierarchy, in which case a NULL - * value is perfectly valid. Just means it won't match the searched needle. */ - continue; - } - - link.name = iter->name; - link.index = -1; - if ((path = rna_idp_path(&child_ptr, iter, needle, &link))) { - break; - } - } - } - else if (iter->type == IDP_IDPARRAY) { - if (prop->type == PROP_COLLECTION) { - IDProperty *array = IDP_IDPArray(iter); - if (needle >= array && needle < (iter->len + array)) { /* found! */ - link.name = iter->name; - link.index = (int)(needle - array); - path = rna_idp_path_create(&link); - break; - } - int j; - link.name = iter->name; - for (j = 0; j < iter->len; j++, array++) { - PointerRNA child_ptr; - if (RNA_property_collection_lookup_int(ptr, prop, j, &child_ptr)) { - if (RNA_pointer_is_null(&child_ptr)) { - /* Array item ID prop might be a 'leaf' in the IDProp group hierarchy, in which case - * a NULL value is perfectly valid. Just means it won't match the searched needle. */ - continue; - } - link.index = j; - if ((path = rna_idp_path(&child_ptr, array, needle, &link))) { - break; - } - } - } - if (path) { - break; - } - } - } - } - - return path; -} - -char *RNA_path_from_struct_to_idproperty(PointerRNA *ptr, IDProperty *needle) -{ - IDProperty *haystack = RNA_struct_idprops(ptr, false); - - if (haystack) { /* can fail when called on bones */ - return rna_idp_path(ptr, haystack, needle, NULL); - } - return NULL; -} - -static char *rna_path_from_ID_to_idpgroup(const PointerRNA *ptr) -{ - PointerRNA id_ptr; - - BLI_assert(ptr->owner_id != NULL); - - /* TODO: Support Bones/PoseBones. no pointers stored to the bones from here, only the ID. - * See example in T25746. - * Unless this is added only way to find this is to also search - * all bones and pose bones of an armature or object. - */ - RNA_id_pointer_create(ptr->owner_id, &id_ptr); - - return RNA_path_from_struct_to_idproperty(&id_ptr, ptr->data); -} - -ID *RNA_find_real_ID_and_path(Main *bmain, ID *id, const char **r_path) -{ - if (r_path) { - *r_path = ""; - } - - if ((id == NULL) || (id->flag & LIB_EMBEDDED_DATA) == 0) { - return id; - } - - const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id); - if (r_path) { - switch (GS(id->name)) { - case ID_NT: - *r_path = "node_tree"; - break; - case ID_GR: - *r_path = "collection"; - break; - default: - BLI_assert_msg(0, "Missing handling of embedded id type."); - } - } - - if (id_type->owner_get == NULL) { - BLI_assert_msg(0, "Missing handling of embedded id type."); - return id; - } - return id_type->owner_get(bmain, id); -} - -static char *rna_prepend_real_ID_path(Main *bmain, ID *id, char *path, ID **r_real_id) -{ - if (r_real_id != NULL) { - *r_real_id = NULL; - } - - const char *prefix; - ID *real_id = RNA_find_real_ID_and_path(bmain, id, &prefix); - - if (r_real_id != NULL) { - *r_real_id = real_id; - } - - if (path != NULL) { - char *new_path = NULL; - - if (real_id) { - if (prefix[0]) { - new_path = BLI_sprintfN("%s%s%s", prefix, path[0] == '[' ? "" : ".", path); - } - else { - return path; - } - } - - MEM_freeN(path); - return new_path; - } - return prefix[0] != '\0' ? BLI_strdup(prefix) : NULL; -} - -char *RNA_path_from_ID_to_struct(const PointerRNA *ptr) -{ - char *ptrpath = NULL; - - if (!ptr->owner_id || !ptr->data) { - return NULL; - } - - if (!RNA_struct_is_ID(ptr->type)) { - if (ptr->type->path) { - /* if type has a path to some ID, use it */ - ptrpath = ptr->type->path((PointerRNA *)ptr); - } - else if (ptr->type->nested && RNA_struct_is_ID(ptr->type->nested)) { - PointerRNA parentptr; - PropertyRNA *userprop; - - /* find the property in the struct we're nested in that references this struct, and - * use its identifier as the first part of the path used... - */ - RNA_id_pointer_create(ptr->owner_id, &parentptr); - userprop = RNA_struct_find_nested(&parentptr, ptr->type); - - if (userprop) { - ptrpath = BLI_strdup(RNA_property_identifier(userprop)); - } - else { - return NULL; /* can't do anything about this case yet... */ - } - } - else if (RNA_struct_is_a(ptr->type, &RNA_PropertyGroup)) { - /* special case, easier to deal with here than in ptr->type->path() */ - return rna_path_from_ID_to_idpgroup(ptr); - } - else { - return NULL; - } - } - - return ptrpath; -} - -char *RNA_path_from_real_ID_to_struct(Main *bmain, const PointerRNA *ptr, struct ID **r_real) -{ - char *path = RNA_path_from_ID_to_struct(ptr); - - /* NULL path is valid in that case, when given struct is an ID one... */ - return rna_prepend_real_ID_path(bmain, ptr->owner_id, path, r_real); -} - -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]) -{ - int dimsize_step[RNA_MAX_ARRAY_LENGTH + 1]; - int i = totdims - 1; - dimsize_step[i + 1] = 1; - dimsize_step[i] = dimsize[i]; - while (--i != -1) { - dimsize_step[i] = dimsize[i] * dimsize_step[i + 1]; - } - while (++i != index_dim) { - int index_round = index / dimsize_step[i + 1]; - r_index_multi[i] = index_round; - index -= (index_round * dimsize_step[i + 1]); - } - BLI_assert(index == 0); -} - -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) -{ - int dimsize[RNA_MAX_ARRAY_LENGTH]; - int totdims = RNA_property_array_dimension(ptr, prop, dimsize); - int index_multi[RNA_MAX_ARRAY_LENGTH]; - - rna_path_array_multi_from_flat_index(dimsize, totdims, index_dim, index, index_multi); - - for (int i = 0, offset = 0; (i < index_dim) && (offset < index_str_len); i++) { - offset += BLI_snprintf_rlen( - &index_str[offset], index_str_len - offset, "[%d]", index_multi[i]); - } -} - -char *RNA_path_from_ID_to_property_index(const PointerRNA *ptr, - PropertyRNA *prop, - int index_dim, - int index) -{ - const bool is_rna = (prop->magic == RNA_MAGIC); - const char *propname; - char *ptrpath, *path; - - if (!ptr->owner_id || !ptr->data) { - return NULL; - } - - /* path from ID to the struct holding this property */ - ptrpath = RNA_path_from_ID_to_struct(ptr); - - propname = RNA_property_identifier(prop); - - /* support indexing w/ multi-dimensional arrays */ - char index_str[RNA_MAX_ARRAY_LENGTH * 12 + 1]; - if (index_dim == 0) { - index_str[0] = '\0'; - } - else { - rna_path_array_multi_string_from_flat_index( - ptr, prop, index_dim, index, index_str, sizeof(index_str)); - } - - if (ptrpath) { - if (is_rna) { - path = BLI_sprintfN("%s.%s%s", ptrpath, propname, index_str); - } - else { - char propname_esc[MAX_IDPROP_NAME * 2]; - BLI_str_escape(propname_esc, propname, sizeof(propname_esc)); - path = BLI_sprintfN("%s[\"%s\"]%s", ptrpath, propname_esc, index_str); - } - MEM_freeN(ptrpath); - } - else if (RNA_struct_is_ID(ptr->type)) { - if (is_rna) { - path = BLI_sprintfN("%s%s", propname, index_str); - } - else { - char propname_esc[MAX_IDPROP_NAME * 2]; - BLI_str_escape(propname_esc, propname, sizeof(propname_esc)); - path = BLI_sprintfN("[\"%s\"]%s", propname_esc, index_str); - } - } - else { - path = NULL; - } - - return path; -} - -char *RNA_path_from_ID_to_property(const PointerRNA *ptr, PropertyRNA *prop) -{ - return RNA_path_from_ID_to_property_index(ptr, prop, 0, -1); -} - -char *RNA_path_from_real_ID_to_property_index(Main *bmain, - const PointerRNA *ptr, - PropertyRNA *prop, - int index_dim, - int index, - ID **r_real_id) -{ - char *path = RNA_path_from_ID_to_property_index(ptr, prop, index_dim, index); - - /* NULL path is always an error here, in that case do not return the 'fake ID from real ID' part - * of the path either. */ - return path != NULL ? rna_prepend_real_ID_path(bmain, ptr->owner_id, path, r_real_id) : NULL; -} - -char *RNA_path_resolve_from_type_to_property(const PointerRNA *ptr, - PropertyRNA *prop, - const StructRNA *type) -{ - /* Try to recursively find an "type"'d ancestor, - * to handle situations where path from ID is not enough. */ - PointerRNA idptr; - ListBase path_elems = {NULL}; - char *path = NULL; - char *full_path = RNA_path_from_ID_to_property(ptr, prop); - - if (full_path == NULL) { - return NULL; - } - - RNA_id_pointer_create(ptr->owner_id, &idptr); - - if (RNA_path_resolve_elements(&idptr, full_path, &path_elems)) { - PropertyElemRNA *prop_elem; - - for (prop_elem = path_elems.last; prop_elem; prop_elem = prop_elem->prev) { - if (RNA_struct_is_a(prop_elem->ptr.type, type)) { - char *ref_path = RNA_path_from_ID_to_struct(&prop_elem->ptr); - if (ref_path) { - path = BLI_strdup(full_path + strlen(ref_path) + 1); /* +1 for the linking '.' */ - MEM_freeN(ref_path); - } - break; - } - } - - BLI_freelistN(&path_elems); - } - - MEM_freeN(full_path); - return path; -} - -char *RNA_path_full_ID_py(Main *bmain, ID *id) -{ - const char *path; - ID *id_real = RNA_find_real_ID_and_path(bmain, id, &path); - - if (id_real) { - id = id_real; - } - else { - path = ""; - } - - char lib_filepath_esc[(sizeof(id->lib->filepath) * 2) + 4]; - if (ID_IS_LINKED(id)) { - int ofs = 0; - memcpy(lib_filepath_esc, ", \"", 3); - ofs += 3; - ofs += BLI_str_escape(lib_filepath_esc + ofs, id->lib->filepath, sizeof(lib_filepath_esc)); - memcpy(lib_filepath_esc + ofs, "\"", 2); - } - else { - lib_filepath_esc[0] = '\0'; - } - - char id_esc[(sizeof(id->name) - 2) * 2]; - BLI_str_escape(id_esc, id->name + 2, sizeof(id_esc)); - - return BLI_sprintfN("bpy.data.%s[\"%s\"%s]%s%s", - BKE_idtype_idcode_to_name_plural(GS(id->name)), - id_esc, - lib_filepath_esc, - path[0] ? "." : "", - path); -} - -char *RNA_path_full_struct_py(Main *bmain, const PointerRNA *ptr) -{ - char *id_path; - char *data_path; - - char *ret; - - if (!ptr->owner_id) { - return NULL; - } - - /* never fails */ - id_path = RNA_path_full_ID_py(bmain, ptr->owner_id); - - data_path = RNA_path_from_ID_to_struct(ptr); - - /* XXX data_path may be NULL (see T36788), - * do we want to get the 'bpy.data.foo["bar"].(null)' stuff? */ - ret = BLI_sprintfN("%s.%s", id_path, data_path); - - if (data_path) { - MEM_freeN(data_path); - } - MEM_freeN(id_path); - - return ret; -} - -char *RNA_path_full_property_py_ex( - Main *bmain, const PointerRNA *ptr, PropertyRNA *prop, int index, bool use_fallback) -{ - char *id_path; - const char *data_delim; - const char *data_path; - bool data_path_free; - - char *ret; - - if (!ptr->owner_id) { - return NULL; - } - - /* never fails */ - id_path = RNA_path_full_ID_py(bmain, ptr->owner_id); - - data_path = RNA_path_from_ID_to_property(ptr, prop); - if (data_path) { - data_delim = (data_path[0] == '[') ? "" : "."; - data_path_free = true; - } - else { - if (use_fallback) { - /* Fuzzy fallback. Be explicit in our ignorance. */ - data_path = RNA_property_identifier(prop); - data_delim = " ... "; - } - else { - data_delim = "."; - } - data_path_free = false; - } - - if ((index == -1) || (RNA_property_array_check(prop) == false)) { - ret = BLI_sprintfN("%s%s%s", id_path, data_delim, data_path); - } - else { - ret = BLI_sprintfN("%s%s%s[%d]", id_path, data_delim, data_path, index); - } - MEM_freeN(id_path); - if (data_path_free) { - MEM_freeN((void *)data_path); - } - - return ret; -} - -char *RNA_path_full_property_py(Main *bmain, const PointerRNA *ptr, PropertyRNA *prop, int index) -{ - return RNA_path_full_property_py_ex(bmain, ptr, prop, index, false); -} - -char *RNA_path_struct_property_py(PointerRNA *ptr, PropertyRNA *prop, int index) -{ - char *data_path; - - char *ret; - - if (!ptr->owner_id) { - return NULL; - } - - data_path = RNA_path_from_ID_to_property(ptr, prop); - - if (data_path == NULL) { - /* This may not be an ID at all, check for simple when pointer owns property. - * TODO: more complex nested case. */ - if (!RNA_struct_is_ID(ptr->type)) { - const char *prop_identifier = RNA_property_identifier(prop); - if (RNA_struct_find_property(ptr, prop_identifier) == prop) { - data_path = BLI_strdup(prop_identifier); - } - } - } - - if ((index == -1) || (RNA_property_array_check(prop) == false)) { - ret = BLI_strdup(data_path); - } - else { - ret = BLI_sprintfN("%s[%d]", data_path, index); - } - - if (data_path) { - MEM_freeN(data_path); - } - - return ret; -} - -char *RNA_path_property_py(const PointerRNA *UNUSED(ptr), PropertyRNA *prop, int index) -{ - const bool is_rna = (prop->magic == RNA_MAGIC); - const char *propname = RNA_property_identifier(prop); - char *ret; - - if ((index == -1) || (RNA_property_array_check(prop) == false)) { - if (is_rna) { - ret = BLI_strdup(propname); - } - else { - char propname_esc[MAX_IDPROP_NAME * 2]; - BLI_str_escape(propname_esc, propname, sizeof(propname_esc)); - ret = BLI_sprintfN("[\"%s\"]", propname_esc); - } - } - else { - if (is_rna) { - ret = BLI_sprintfN("%s[%d]", propname, index); - } - else { - char propname_esc[MAX_IDPROP_NAME * 2]; - BLI_str_escape(propname_esc, propname, sizeof(propname_esc)); - ret = BLI_sprintfN("[\"%s\"][%d]", propname_esc, index); - } - } - - return ret; -} - /* Quick name based property access */ bool RNA_boolean_get(PointerRNA *ptr, const char *name) |