use super::super::CoreError;
use super::creation::{utf8_error, validation_error};
use alloc::{format, string::String};
pub fn validate_utf8_detailed(bytes: &[u8]) -> Result<(), CoreError> {
match core::str::from_utf8(bytes) {
Ok(_) => Ok(()),
Err(err) => {
let position = err.valid_up_to();
let message = err.error_len().map_or_else(
|| format!("Incomplete UTF-8 sequence at position {position}"),
|len| format!("Invalid UTF-8 sequence of {len} bytes at position {position}"),
);
Err(utf8_error(position, message))
}
}
}
pub fn validate_ass_text_content(text: &str) -> Result<(), CoreError> {
for (pos, ch) in text.char_indices() {
if !is_valid_ass_char(ch) {
return Err(validation_error(format!(
"Invalid character '{}' (U+{:04X}) at position {}",
ch.escape_default().collect::<String>(),
ch as u32,
pos
)));
}
}
Ok(())
}
pub(super) fn is_valid_ass_char(ch: char) -> bool {
match ch {
c if c.is_ascii_graphic() => true,
' ' | '\t' | '\n' | '\r' => true,
c if !c.is_ascii() && !c.is_control() => true,
_ => false,
}
}
pub fn validate_bom_handling(bytes: &[u8]) -> Result<(), CoreError> {
if bytes.len() >= 3 && bytes[0..3] == [0xEF, 0xBB, 0xBF] {
return Ok(());
}
if bytes.len() >= 2 && (bytes[0..2] == [0xFF, 0xFE] || bytes[0..2] == [0xFE, 0xFF]) {
return Err(validation_error(
"UTF-16 BOM detected - ASS files should be UTF-8",
));
}
if bytes.len() >= 4
&& (bytes[0..4] == [0xFF, 0xFE, 0x00, 0x00] || bytes[0..4] == [0x00, 0x00, 0xFE, 0xFF])
{
return Err(validation_error(
"UTF-32 BOM detected - ASS files should be UTF-8",
));
}
if bytes.len() >= 2 && bytes[0..2] == [0xEF, 0xBB] {
return Err(validation_error(
"Partial UTF-8 BOM detected - file may be corrupted or incorrectly encoded",
));
}
if !bytes.is_empty() && bytes[0] == 0xEF && (bytes.len() == 1 || bytes[1] != 0xBB) {
return Err(validation_error(
"Suspicious byte sequence that could be partial BOM - check file encoding",
));
}
Ok(())
}