use std::path::{Component, Path};
pub(crate) fn normalized_path(path: &Path) -> Vec<u8> {
return normalize_bytes(path.as_os_str().as_encoded_bytes(), cfg!(windows));
}
pub(crate) fn normalize_bytes(native: &[u8], windows: bool) -> Vec<u8> {
let mut bytes: Vec<u8> = native.to_vec();
if windows {
for byte in &mut bytes {
if *byte == b'\\' { *byte = b'/'; }
}
if bytes.len() > 2 && bytes[0].is_ascii_alphabetic() && bytes[1] == b':' && bytes[2] != b'/' {
bytes.insert(2, b'/');
}
}
return bytes;
}
pub(crate) fn prefix_parts(path: &Path) -> usize {
if !cfg!(windows) { return 0; }
let Some(Component::Prefix(prefix)) = path.components().next() else { return 0; };
return count_prefix_parts(prefix.as_os_str().as_encoded_bytes());
}
pub(crate) fn count_prefix_parts(prefix: &[u8]) -> usize {
let mut count: usize = 0;
let mut in_component: bool = false;
for byte in prefix {
if *byte == b'/' || *byte == b'\\' {
in_component = false;
} else if !in_component {
count += 1;
in_component = true;
}
}
return count;
}
pub(crate) fn is_slash(byte: &u8) -> bool {
return *byte == b'/';
}
pub(crate) fn safe_component(component: &[u8]) -> String {
let mut safe: String = String::new();
for chunk in component.utf8_chunks() {
for character in chunk.valid().chars() {
if character == ':' {
safe.push_str("\\x3a");
} else if character == '\\' {
safe.push_str("\\\\");
} else if character.is_control() {
safe.push_str(format!("\\u{{{:x}}}", character as u32).as_str());
} else {
safe.push(character);
}
}
for byte in chunk.invalid() {
safe.push_str(format!("\\x{byte:02x}").as_str());
}
}
return safe;
}
#[cfg(test)]
#[path = "path_name_bytes_tests.rs"]
mod tests;