config: preserve bytes in hex escapes

Fixes #13855

Make the config string parser preserve hexadecimal escapes as bytes.
Previously all escaped values were encoded as Unicode codepoints.
This commit is contained in:
Mitchell Hashimoto
2026-08-16 14:03:18 -07:00
parent 3790fb78fe
commit 29b82dd80c

View File

@@ -20,16 +20,23 @@ pub fn parse(out: []u8, bytes: []const u8) ![]u8 {
continue;
}
// Zig's \xNN syntax represents a single byte, while the other
// escape sequences represent Unicode codepoints.
const is_byte_escape = src_i + 1 < bytes.len and
bytes[src_i + 1] == 'x';
// Parse the escape sequence
switch (std.zig.string_literal.parseEscapeSequence(
bytes,
&src_i,
)) {
.failure => return error.InvalidString,
.success => |cp| dst_i += try std.unicode.utf8Encode(
cp,
out[dst_i..],
),
.success => |cp| if (is_byte_escape) {
out[dst_i] = @intCast(cp);
dst_i += 1;
} else {
dst_i += try std.unicode.utf8Encode(cp, out[dst_i..]);
},
}
}
@@ -100,6 +107,15 @@ test "parse: escapes" {
}
}
test "parse: hex escapes are bytes" {
var buf: [128]u8 = undefined;
const result = try parse(
&buf,
"\\xe6\\x97\\xa5\\xe6\\x9c\\xac\\xe8\\xaa\\x9e",
);
try std.testing.expectEqualStrings("日本語", result);
}
test "codepointIterator: empty" {
var it = codepointIterator("");
try std.testing.expectEqual(null, try it.next());