libutil: add simple NUL escaping/unescaping functions
Change-Id: Ia4cc7b8f1058439f312066422eebfaff1c2c0c6c
This commit is contained in:
@@ -366,4 +366,27 @@ std::string showBytes(uint64_t bytes)
|
||||
return fmt("%.2f MiB", bytes / (1024.0 * 1024.0));
|
||||
}
|
||||
|
||||
std::string escapeNul(const std::string & in)
|
||||
{
|
||||
using std::operator""sv;
|
||||
return replaceStrings(replaceStrings(std::move(in), R"(\)", R"(\\)"), "\0"sv, R"(\0)");
|
||||
}
|
||||
|
||||
std::string unescapeNul(const std::string & in)
|
||||
{
|
||||
std::string result;
|
||||
result.reserve(in.size());
|
||||
bool inSequence = false;
|
||||
for (auto c : in) {
|
||||
if (inSequence) {
|
||||
result += c == '0' ? '\0' : c;
|
||||
inSequence = false;
|
||||
} else if (c == '\\') {
|
||||
inSequence = true;
|
||||
} else {
|
||||
result += c;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +141,15 @@ inline std::string rewriteStrings(std::string s, const StringMap & rewrites)
|
||||
return Rewriter(rewrites)(s);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Escape NUL bytes and `\` in a string by replacing them with `\0` and `\\` respectively.
|
||||
*/
|
||||
std::string escapeNul(const std::string & in);
|
||||
/**
|
||||
* Undo replacements done by `escapeNul`. Other escape sequences (eg `\n`) are replaced by
|
||||
* the second character in the sequence (eg `n`), `\` at the end of the string is dropped.
|
||||
*/
|
||||
std::string unescapeNul(const std::string & in);
|
||||
|
||||
/**
|
||||
* Parse a string into an integer.
|
||||
|
||||
@@ -817,4 +817,21 @@ namespace nix {
|
||||
ASSERT_TRUE(e.is<std::invalid_argument>());
|
||||
ASSERT_NE(e.as<std::invalid_argument>(), nullptr);
|
||||
}
|
||||
|
||||
TEST(NulEscaping, function)
|
||||
{
|
||||
for (int c1 = CHAR_MIN; c1 < CHAR_MAX; c1++) {
|
||||
for (int c2 = CHAR_MIN; c2 < CHAR_MAX; c2++) {
|
||||
auto sequence = std::format("{}{}", char(c1), char(c2));
|
||||
for (auto str : {sequence, "a" + sequence + "b"}) {
|
||||
ASSERT_EQ(unescapeNul(escapeNul(str)), str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unknown escapes are character identity for simplicity of use
|
||||
ASSERT_EQ(unescapeNul("\\a"), "a");
|
||||
// escape of end-of-string is dropped silently
|
||||
ASSERT_EQ(unescapeNul("a\\"), "a");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user