use crate::core::error::{ConfigError, Result};
const RESERVED_DEVICE_NAMES: [&str; 22] = [
"CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8",
"COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
];
fn is_reserved_device_name(value: &str) -> bool {
let stem = value.split('.').next().unwrap_or(value);
RESERVED_DEVICE_NAMES
.iter()
.any(|reserved| stem.eq_ignore_ascii_case(reserved))
}
pub fn is_plain_file_name(value: &str) -> bool {
is_safe_path_component(value)
}
pub fn is_safe_path_component(value: &str) -> bool {
!value.is_empty()
&& value != "."
&& value != ".."
&& !value.contains('/')
&& !value.contains('\\')
&& !value.contains(':')
&& !value.chars().any(char::is_control)
&& !is_reserved_device_name(value)
}
pub fn validate_plain_file_name(value: &str) -> Result<&str> {
if is_plain_file_name(value) {
Ok(value)
} else {
Err(ConfigError::InvalidPathComponent(value.to_string()))
}
}
pub fn validate_path_component(value: &str) -> Result<&str> {
if is_safe_path_component(value) {
Ok(value)
} else {
Err(ConfigError::InvalidPathComponent(value.to_string()))
}
}
#[cfg(test)]
mod tests;