use std::convert::TryFrom; use std::io; use crate::error::IntoIOError; use crate::util::read_big_endian; macro_rules! guard { ($cond:expr) => { if !$cond { return None; } } } pub fn from_latin_1(bytes: &[u8]) -> Option { guard!(bytes.len() >= 1); Some(bytes.iter().map(|&b| char::from(b)).collect()) } pub fn from_ucs_2_bom(bytes: &[u8]) -> Option { let len = bytes.len(); guard!(len % 2 == 0); guard!(len >= 2); let bom = read_big_endian(&bytes[0..2], 8); guard!(bom == 0xfeff || bom == 0xfffe); let mut res = String::with_capacity(len/2 - 1); for i in 1 .. len/2 { let val = if bom == 0xfeff { 256 * bytes[2*i] as u16 + bytes[2*i+1] as u16 } else { 256 * bytes[2*i+1] as u16 + bytes[2*i] as u16 }; match char::try_from(val as u32) { Ok(c) => res.push(c), Err(_) => return None, }; } Some(res) } pub fn from_utf8_mistaken_as_latin1(latin1: &str) -> io::Result { latin1 .chars() .map(|c| u8::try_from(u32::from(c))) .collect::, _>>() .map_err(|e| e.ioerr()) .and_then(|v| std::str::from_utf8(&v) .map(|s| s.to_string()) .map_err(|e| e.ioerr())) }