From eea2c6b00b2825a3ee6807067ee94e3575aa90d7 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Fri, 9 May 2025 11:08:47 +0200 Subject: [PATCH] Fix: Nodes: missing name escaping when constructing RNA paths This also adds a version of `BLI_str_escape` that returns an std::string, because it's much easier to use in C++ code. --- source/blender/blenlib/BLI_string.h | 10 ++++++++++ source/blender/blenlib/intern/string.cc | 13 +++++++++++++ source/blender/nodes/intern/inverse_eval.cc | 17 ++++++++++------- 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/source/blender/blenlib/BLI_string.h b/source/blender/blenlib/BLI_string.h index 6965f13f547..78b1d689781 100644 --- a/source/blender/blenlib/BLI_string.h +++ b/source/blender/blenlib/BLI_string.h @@ -14,6 +14,10 @@ #include "BLI_compiler_attrs.h" #include "BLI_utildefines.h" +#ifdef __cplusplus +# include +#endif + /* Buffer size of maximum `uint64` plus commas and terminator. */ #define BLI_STR_FORMAT_UINT64_GROUPED_SIZE 27 @@ -230,6 +234,12 @@ char *BLI_vsprintfN(const char *__restrict format, va_list args) ATTR_NONNULL(1, */ size_t BLI_str_escape(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1, 2); + +#ifdef __cplusplus +/** Same as above, but returns an std::string. */ +std::string BLI_str_escape(const char *str); +#endif + /** * This roughly matches C and Python's string escaping with double quotes - `"`. * diff --git a/source/blender/blenlib/intern/string.cc b/source/blender/blenlib/intern/string.cc index b65e4271c6d..47633733773 100644 --- a/source/blender/blenlib/intern/string.cc +++ b/source/blender/blenlib/intern/string.cc @@ -367,6 +367,19 @@ size_t BLI_str_escape(char *__restrict dst, const char *__restrict src, const si return len; } +std::string BLI_str_escape(const char *str) +{ + if (!str) { + return {}; + } + const size_t max_result_size = strlen(str) * 2 + 1; + std::string result; + result.resize(max_result_size); + const size_t result_size = BLI_str_escape(result.data(), str, max_result_size); + result.resize(result_size); + return result; +} + BLI_INLINE bool str_unescape_pair(char c_next, char *r_out) { #define CASE_PAIR(value_src, value_dst) \ diff --git a/source/blender/nodes/intern/inverse_eval.cc b/source/blender/nodes/intern/inverse_eval.cc index c2ae95fec38..c757fddd783 100644 --- a/source/blender/nodes/intern/inverse_eval.cc +++ b/source/blender/nodes/intern/inverse_eval.cc @@ -24,6 +24,7 @@ #include "BLI_map.hh" #include "BLI_math_euler.hh" #include "BLI_set.hh" +#include "BLI_string.h" #include "DEG_depsgraph.hh" @@ -474,7 +475,7 @@ static bool set_socket_value(bContext &C, bNodeTree &tree = socket.owner_tree(); const std::string default_value_rna_path = fmt::format( - "nodes[\"{}\"].inputs[{}].default_value", node.name, socket.index()); + "nodes[\"{}\"].inputs[{}].default_value", BLI_str_escape(node.name), socket.index()); switch (socket.type) { case SOCK_FLOAT: { @@ -505,32 +506,34 @@ static bool set_socket_value(bContext &C, static bool set_value_node_value(bContext &C, bNode &node, const SocketValueVariant &value_variant) { bNodeTree &tree = node.owner_tree(); + switch (node.type_legacy) { case SH_NODE_VALUE: { const float value = value_variant.get(); const std::string rna_path = fmt::format("nodes[\"{}\"].outputs[0].default_value", - node.name); + BLI_str_escape(node.name)); return set_rna_property(C, tree.id, rna_path, value); } case FN_NODE_INPUT_INT: { const int value = value_variant.get(); - const std::string rna_path = fmt::format("nodes[\"{}\"].integer", node.name); + const std::string rna_path = fmt::format("nodes[\"{}\"].integer", BLI_str_escape(node.name)); return set_rna_property(C, tree.id, rna_path, value); } case FN_NODE_INPUT_BOOL: { const bool value = value_variant.get(); - const std::string rna_path = fmt::format("nodes[\"{}\"].boolean", node.name); + const std::string rna_path = fmt::format("nodes[\"{}\"].boolean", BLI_str_escape(node.name)); return set_rna_property(C, tree.id, rna_path, value); } case FN_NODE_INPUT_VECTOR: { const float3 value = value_variant.get(); - const std::string rna_path = fmt::format("nodes[\"{}\"].vector", node.name); + const std::string rna_path = fmt::format("nodes[\"{}\"].vector", BLI_str_escape(node.name)); return set_rna_property_float3(C, tree.id, rna_path, value); } case FN_NODE_INPUT_ROTATION: { const math::Quaternion rotation = value_variant.get(); const float3 euler = float3(math::to_euler(rotation)); - const std::string rna_path = fmt::format("nodes[\"{}\"].rotation_euler", node.name); + const std::string rna_path = fmt::format("nodes[\"{}\"].rotation_euler", + BLI_str_escape(node.name)); return set_rna_property_float3(C, tree.id, rna_path, euler); } } @@ -546,7 +549,7 @@ static bool set_modifier_value(bContext &C, DEG_id_tag_update(&object.id, ID_RECALC_GEOMETRY); const std::string main_prop_rna_path = fmt::format( - "modifiers[\"{}\"][\"{}\"]", nmd.modifier.name, interface_socket.identifier); + "modifiers[\"{}\"][\"{}\"]", BLI_str_escape(nmd.modifier.name), interface_socket.identifier); switch (interface_socket.socket_typeinfo()->type) { case SOCK_FLOAT: {