Skip to content

Commit b187e1d

Browse files
committed
serializer: Fix handling of backslashes and Unicode escape sequences in CSS content
1 parent fa6f5eb commit b187e1d

File tree

1 file changed

+35
-1
lines changed

1 file changed

+35
-1
lines changed

src/serializer.rs

+35-1
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,11 @@ where
311311
}
312312
}
313313

314+
fn is_valid_unicode_escape(s: &str) -> bool {
315+
// Check if it is a valid Unicode escape sequence
316+
s.len() == 4 && s.chars().all(|c| c.is_digit(16))
317+
}
318+
314319
impl<W> fmt::Write for CssStringWriter<'_, W>
315320
where
316321
W: fmt::Write,
@@ -320,7 +325,36 @@ where
320325
for (i, b) in s.bytes().enumerate() {
321326
let escaped = match_byte! { b,
322327
b'"' => Some("\\\""),
323-
b'\\' => Some("\\\\"),
328+
b'\\' => {
329+
// Handle backslash
330+
if i + 1 < s.len() {
331+
match s.as_bytes()[i + 1] {
332+
b'0'..=b'9' | b'a'..=b'f' | b'A'..=b'F' => {
333+
// If the character following the backslash is part of a Unicode escape sequence, preserve the entire sequence
334+
if i + 4 <= s.len() {
335+
let next_4_chars = &s[i + 1..i + 5];
336+
if is_valid_unicode_escape(next_4_chars) {
337+
// Preserve the entire Unicode escape sequence
338+
Some("\\")
339+
} else {
340+
// If it is not a valid Unicode escape sequence, escape the backslash itself
341+
Some("\\\\")
342+
}
343+
} else {
344+
// If there are fewer than 4 characters following, escape the backslash itself
345+
Some("\\\\")
346+
}
347+
}
348+
_ => {
349+
// If the character following the backslash is any other character, escape the backslash itself
350+
Some("\\\\")
351+
}
352+
}
353+
} else {
354+
// If the backslash is the last character, escape the backslash itself
355+
Some("\\\\")
356+
}
357+
},
324358
b'\0' => Some("\u{FFFD}"),
325359
b'\x01'..=b'\x1F' | b'\x7F' => None,
326360
_ => continue,

0 commit comments

Comments
 (0)