use super::{hex_value, is_digit, is_hex_digit, is_space, to_utf8, unescape};
pub(crate) fn fixup_string_bytes(source: &[u8]) -> Option<Vec<u8>> {
if source.is_empty() || !source.contains(&b'\\') {
return Some(source.to_vec());
}
let mut data = source.to_vec();
let size = data.len();
let mut write = 0usize;
let mut i = 0usize;
while i < size {
if data[i] != b'\\' {
data[write] = data[i];
write += 1;
i += 1;
continue;
}
if i + 1 == size {
return None;
}
let escape = data[i + 1];
i += 2;
match escape {
b'\n' => {
data[write] = b'\n';
write += 1;
}
b'\r' => {
data[write] = b'\n';
write += 1;
if i < size && data[i] == b'\n' {
i += 1;
}
}
b'x' => {
if i + 2 > size {
return None;
}
let mut code = 0u8;
for _ in 0..2 {
let ch = data[i];
if !is_hex_digit(ch) {
return None;
}
code = code.wrapping_mul(16).wrapping_add(hex_value(ch)?);
i += 1;
}
data[write] = code;
write += 1;
}
b'z' => {
while i < size && is_space(data[i]) {
i += 1;
}
}
b'u' => {
if i + 3 > size || data[i] != b'{' {
return None;
}
i += 1;
if i == size || data[i] == b'}' {
return None;
}
let mut code = 0u32;
for _ in 0..16 {
if i == size {
return None;
}
let ch = data[i];
if ch == b'}' {
break;
}
if !is_hex_digit(ch) {
return None;
}
code = code
.checked_mul(16)?
.checked_add(u32::from(hex_value(ch)?))?;
i += 1;
}
if i == size || data[i] != b'}' {
return None;
}
i += 1;
write += to_utf8(&mut data[write..], code)?;
}
byte if is_digit(byte) => {
let mut code = u32::from(byte - b'0');
for _ in 0..2 {
if i == size || !is_digit(data[i]) {
break;
}
code = code
.checked_mul(10)?
.checked_add(u32::from(data[i] - b'0'))?;
i += 1;
}
let code = u8::try_from(code).ok()?;
data[write] = code;
write += 1;
}
other => {
data[write] = unescape(other);
write += 1;
}
}
}
data.truncate(write);
Some(data)
}
pub(crate) fn multiline_string_bytes(value: &[u8]) -> Vec<u8> {
if value.is_empty() {
return Vec::new();
}
let source = if value.starts_with(b"\r\n") {
&value[2..]
} else if value.starts_with(b"\n") {
&value[1..]
} else {
value
};
let mut result = Vec::with_capacity(source.len());
let mut index = 0usize;
while index < source.len() {
if source[index] == b'\r' && source.get(index + 1) == Some(&b'\n') {
result.push(b'\n');
index += 2;
} else {
result.push(source[index]);
index += 1;
}
}
result
}