BLI_string: add BLI_str_unescape utility function

Performs the reverse of BLI_str_escape.
This allows logic to be removed from RNA path handling.
This commit is contained in:
Campbell Barton 2020-12-10 13:42:59 +11:00
parent 7fc1d76037
commit 15d801625c
3 changed files with 42 additions and 1 deletions

View File

@ -87,6 +87,8 @@ char *BLI_sprintfN(const char *__restrict format, ...) ATTR_WARN_UNUSED_RESULT
size_t BLI_str_escape(char *__restrict dst, const char *__restrict src, const size_t dst_maxncpy)
ATTR_NONNULL();
size_t BLI_str_unescape(char *__restrict dst, const char *__restrict src, const size_t src_maxncpy)
ATTR_NONNULL();
size_t BLI_str_format_int_grouped(char dst[16], int num) ATTR_NONNULL();
size_t BLI_str_format_uint64_grouped(char dst[16], uint64_t num) ATTR_NONNULL();

View File

@ -356,6 +356,41 @@ size_t BLI_str_escape(char *__restrict dst, const char *__restrict src, const si
return len;
}
/**
* This roughly matches C and Python's string escaping with double quotes - `"`.
*
* The destination will never be larger than the source, it will either be the same
* or up to half when all characters are escaped.
*
* \param dst: The destination string, at least the size of `strlen(src) + 1`.
* \param src: The escaped source string.
* \param dst_maxncpy: The maximum number of bytes allowable to copy.
*
* \note This is used for for parsing animation paths in blend files.
*/
size_t BLI_str_unescape(char *__restrict dst, const char *__restrict src, const size_t src_maxncpy)
{
size_t len = 0;
for (size_t i = 0; i < src_maxncpy && (*src != '\0'); i++, src++) {
char c = *src;
if (c == '\\') {
char c_next = *(src + 1);
if (((c_next == '"') && ((void)(c = '"'), true)) || /* Quote. */
((c_next == '\\') && ((void)(c = '\\'), true)) || /* Backslash. */
((c_next == 't') && ((void)(c = '\t'), true)) || /* Tab. */
((c_next == 'n') && ((void)(c = '\n'), true))) /* Newline. */
{
i++;
src++;
}
}
dst[len++] = c;
}
dst[len] = 0;
return len;
}
/**
* Makes a copy of the text within the "" that appear after some text 'blahblah'
* i.e. for string 'pose["apples"]' with prefix 'pose[', it should grab "apples"

View File

@ -803,7 +803,7 @@ TEST_F(StringCasecmpNatural, TextAndNumbers)
testReturnsMoreThanZeroForAll(positive);
}
/* BLI_str_escape */
/* BLI_str_escape, BLI_str_unescape */
class StringEscape : public testing::Test {
protected:
@ -822,6 +822,10 @@ class StringEscape : public testing::Test {
dst_test_len = BLI_str_escape(dst_test, item[0], SIZE_MAX);
EXPECT_STREQ(dst_test, item[1]);
EXPECT_EQ(dst_test_len, strlen(dst_test));
/* Escape back. */
dst_test_len = BLI_str_unescape(dst_test, item[1], strlen(item[1]));
EXPECT_STREQ(dst_test, item[0]);
EXPECT_EQ(dst_test_len, strlen(dst_test));
}
}
};