use chardetng::EncodingDetector;
use crate::error::CribaError;
pub fn ensure_utf8(input: &[u8]) -> Result<String, CribaError> {
match String::from_utf8(input.to_vec()) {
Ok(s) => Ok(s),
Err(_) => {
let mut detector = EncodingDetector::new();
detector.feed(input, true);
let encoding = detector.guess(None, false);
if encoding.name() == "UTF-8" {
return Ok(String::from_utf8_lossy(input).into_owned());
}
let (decoded, _enc, had_errors) = encoding.decode(input);
if had_errors {
tracing::warn!("errores durante transcodificación de {}", encoding.name());
}
Ok(decoded.into_owned())
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_utf8_passthrough() {
let input = b"BEGIN:VCARD\nFN:Juan P\xc3\xa9rez\nEND:VCARD\n";
let result = ensure_utf8(input).unwrap();
assert!(result.contains("Juan Pérez"));
}
#[test]
fn test_iso_8859_1_to_utf8() {
let input = b"BEGIN:VCARD\nFN:Juan P\xe9rez\nEND:VCARD\n";
let result = ensure_utf8(input).unwrap();
assert!(result.contains("Juan Pérez"));
}
#[test]
fn test_invalid_utf8_replacement() {
let input: &[u8] = b"Hello \xff World";
let result = ensure_utf8(input).unwrap();
assert!(result.contains('\u{FFFD}') || result.contains('ÿ'));
}
#[test]
fn test_iso_spanish_chars() {
let input = b"FN:Pe\xf1a\n";
let result = ensure_utf8(input).unwrap();
assert!(result.contains("Peña"));
}
}