BLI_string_ref: add copy_bytes_truncated method

Needed to copy non UTF8 bytes into a null terminated string.

Ref !144052
This commit is contained in:
Campbell Barton
2025-08-07 06:25:29 +10:00
parent 558d1c4774
commit accacc65fc
3 changed files with 84 additions and 0 deletions

View File

@@ -77,6 +77,17 @@ class StringRefBase {
void copy_utf8_truncated(char *dst, int64_t dst_size) const;
template<size_t N> void copy_utf8_truncated(char (&dst)[N]) const;
/**
* Copy the string into a char array. The copied string will be null-terminated. If it does not
* fit, it will be truncated.
*
* \note #copy_utf8_truncated should be used UTF8 strings,
* this should be used for strings which are allowed to contain arbitrary
* byte sequences without a known encoding such as file-paths.
*/
void copy_bytes_truncated(char *dst, int64_t dst_size) const;
template<size_t N> void copy_bytes_truncated(char (&dst)[N]) const;
/**
* Copy the string into a buffer. The buffer has to be one byte larger than the size of the
* string, because the copied string will be null-terminated. Only use this when you are
@@ -231,6 +242,11 @@ template<size_t N> inline void StringRefBase::copy_utf8_truncated(char (&dst)[N]
this->copy_utf8_truncated(dst, N);
}
template<size_t N> inline void StringRefBase::copy_bytes_truncated(char (&dst)[N]) const
{
this->copy_bytes_truncated(dst, N);
}
/**
* Return true when the string starts with the given prefix.
*/

View File

@@ -44,4 +44,20 @@ void StringRefBase::copy_utf8_truncated(char *dst, const int64_t dst_size) const
dst[new_len] = '\0';
}
void StringRefBase::copy_bytes_truncated(char *dst, const int64_t dst_size) const
{
/* Destination must at least hold the null terminator. */
BLI_assert(dst_size >= 1);
/* Common case when the string can just be copied over entirely. */
if (size_ < dst_size) {
this->copy_unsafe(dst);
return;
}
const int64_t new_len = std::min(size_, dst_size - 1);
memcpy(dst, data_, new_len);
dst[new_len] = '\0';
}
} // namespace blender

View File

@@ -464,6 +464,58 @@ TEST(string_ref, CopyUtf8Truncated)
}
}
TEST(string_ref, CopyBytesTruncated)
{
{
StringRef ref("hello");
char dst[10];
memset(dst, 0xFF, 10);
ref.copy_bytes_truncated(dst);
EXPECT_EQ(dst[5], '\0');
EXPECT_EQ(dst[6], 0xFF);
EXPECT_EQ(ref, dst);
}
{
StringRef ref("0123456789");
char dst[4];
memset(dst, 0xFF, 4);
ref.copy_bytes_truncated(dst);
EXPECT_EQ(dst[0], '0');
EXPECT_EQ(dst[1], '1');
EXPECT_EQ(dst[2], '2');
EXPECT_EQ(dst[3], '\0');
}
{
/* Simple 4 byte string. */
StringRef ref("01234");
{
char dst[1];
ref.copy_bytes_truncated(dst);
EXPECT_EQ(dst[0], '\0');
}
{
char dst[2];
ref.copy_bytes_truncated(dst);
EXPECT_EQ(dst[0], '0');
}
{
char dst[3];
ref.copy_bytes_truncated(dst);
EXPECT_EQ(StringRef(dst), "01");
}
{
char dst[4];
ref.copy_bytes_truncated(dst);
EXPECT_EQ(StringRef(dst), "012");
}
{
char dst[5];
ref.copy_bytes_truncated(dst);
EXPECT_EQ(StringRef(dst), "0123");
}
}
}
TEST(string_ref, FromStringView)
{
std::string_view view = "hello";