pub(in crate::filesystem) fn decode_text_file(bytes: &[u8]) -> Option<String> {
if has_binary_magic(bytes) {
return None;
}
if let Some(text) = decode_utf16(bytes) {
return Some(text);
}
let bytes = bytes.strip_prefix(&[0xEF, 0xBB, 0xBF]).unwrap_or(bytes);
if let Ok(s) = std::str::from_utf8(bytes) {
if looks_binary_header_check(bytes) {
return None;
}
return Some(s.to_owned());
}
if looks_binary(bytes) {
return None;
}
Some(String::from_utf8_lossy(bytes).into_owned())
}
pub(in crate::filesystem) fn decode_text_file_owned(bytes: Vec<u8>) -> Option<String> {
if has_binary_magic(&bytes) {
return None;
}
if let Some(text) = decode_utf16(&bytes) {
return Some(text);
}
if bytes.starts_with(&[0xEF, 0xBB, 0xBF]) {
return decode_text_file(&bytes);
}
match String::from_utf8(bytes) {
Ok(s) => {
if looks_binary_header_check(s.as_bytes()) {
return None;
}
Some(s)
}
Err(e) => {
let bytes = e.into_bytes();
if looks_binary(&bytes) {
return None;
}
Some(String::from_utf8_lossy(&bytes).into_owned())
}
}
}
fn looks_binary_header_check(bytes: &[u8]) -> bool {
let window = &bytes[..bytes.len().min(4096)];
if window.is_empty() {
return false;
}
let mut suspicious: u32 = 0;
for &byte in window {
if byte < 0x20 && !matches!(byte, b'\n' | b'\r' | b'\t' | 0x0C) {
suspicious += 1;
if (suspicious as usize) * 20 > window.len() {
return true;
}
}
}
false
}
pub(in crate::filesystem::read) fn looks_binary(bytes: &[u8]) -> bool {
if has_binary_magic(bytes) || has_utf16_nul_pattern(bytes) {
return true;
}
if let Some(first_nul) = memchr::memchr(0, bytes) {
if first_nul < 1024 {
let is_utf16 = bytes.len() >= 4
&& ((bytes[0] == 0 && bytes[1] != 0) || (bytes[0] != 0 && bytes[1] == 0));
if !is_utf16 {
return true;
}
}
}
let total = bytes.len() as u64;
if total == 0 {
return false;
}
let mut suspicious: u64 = 0;
for (i, &byte) in bytes.iter().enumerate() {
let is_susp = byte < 0x20 && !matches!(byte, b'\n' | b'\r' | b'\t' | 0x0C);
if is_susp {
suspicious += 1;
if suspicious * 20 > total {
return true;
}
}
if i & 0xFFF == 0xFFF {
let scanned = (i as u64) + 1;
let remaining = total - scanned;
if (suspicious + remaining) * 20 <= total {
return false;
}
}
}
suspicious * 20 > total
}
fn has_binary_magic(bytes: &[u8]) -> bool {
const MAGIC_HEADERS: &[&[u8]] = &[
b"%PDF-",
b"PK\x03\x04", b"\x89PNG\r\n\x1a\n",
b"\xD0\xCF\x11\xE0", b"\x7fELF", b"\xfe\xed\xfa\xce", b"\xfe\xed\xfa\xcf", b"\xcf\xfa\xed\xfe", b"\xca\xfe\xba\xbe", b"MZ", b"\x1f\x8b", b"BZh", b"\xfd7zXZ\x00", b"7z\xbc\xaf\x27\x1c", b"Rar!\x1a\x07", b"GIF87a", b"GIF89a", b"\xff\xd8\xff", b"BM", b"\x00\x00\x01\x00", b"OggS", b"ID3", b"fLaC", b"\x00asm", b"!<arch>\n", b"\x80\x02", ];
MAGIC_HEADERS.iter().any(|header| bytes.starts_with(header))
}
fn has_utf16_nul_pattern(bytes: &[u8]) -> bool {
bytes.len() >= 4
&& (bytes[0] == 0xFF && bytes[1] == 0xFE || bytes[0] == 0xFE && bytes[1] == 0xFF)
}
pub(in crate::filesystem::read) fn decode_utf16(bytes: &[u8]) -> Option<String> {
#[allow(clippy::question_mark)]
let (little_endian, payload) = if let Some(rest) = bytes.strip_prefix(&[0xFF, 0xFE]) {
(true, rest)
} else if let Some(rest) = bytes.strip_prefix(&[0xFE, 0xFF]) {
(false, rest)
} else {
return None;
};
let chunks = payload.chunks_exact(2);
if !chunks.remainder().is_empty() {
return None;
}
let units = chunks.map(|chunk| {
if little_endian {
u16::from_le_bytes([chunk[0], chunk[1]])
} else {
u16::from_be_bytes([chunk[0], chunk[1]])
}
});
let mut out = String::with_capacity(payload.len() / 2);
for r in char::decode_utf16(units) {
out.push(r.ok()?);
}
Some(out)
}