diff --git a/src/main.rs b/src/main.rs index 26769a5..ad81b63 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,6 @@ extern crate core; -use std::error::Error; use std::fmt::{Display, Formatter}; use std::path::PathBuf; use std::result::Result; diff --git a/src/pcd.rs b/src/pcd.rs index 20df2be..682dc1f 100644 --- a/src/pcd.rs +++ b/src/pcd.rs @@ -343,7 +343,11 @@ impl PCD { } fn put_str(dest: &mut [u8], str: &String, max_len: usize) { - let enc: Vec = Gen4Str::try_from(str).expect("should be validated before call").vec; + let enc_res = Gen4Str::try_from(str); + let enc = enc_res.unwrap_or_else(|err| { + eprintln!("Warning: invalid character '{}' on index {}, invalid characters will be skipped", err.char, err.idx); + err.sanitized + }).vec; let len = min(enc.len(), max_len - 1) * 2; dest[..len].copy_from_slice(&enc.iter().flat_map(|c| c.to_le_bytes()).collect::>()); dest[len..max_len * 2].copy_from_slice(&vec![0xffu8; max_len * 2 - len]) diff --git a/src/pokestr.rs b/src/pokestr.rs index 6d93207..b4bacd6 100644 --- a/src/pokestr.rs +++ b/src/pokestr.rs @@ -13,9 +13,15 @@ pub struct Gen4Str { pub vec: Vec, } +#[derive(Debug, PartialEq)] +pub struct EncodeError { + pub sanitized: Gen4Str, + pub idx: usize, + pub char: Utf16Grapheme, +} impl TryFrom<&String> for Gen4Str { - type Error = (usize, Utf16Grapheme); + type Error = EncodeError; fn try_from(value: &String) -> Result { let graphemes_escaped = utf16::str_to_utf16_graphemes(value); @@ -27,6 +33,8 @@ impl TryFrom<&String> for Gen4Str { let mut last_esc = 0; let mut escaped: Vec<(usize, u16)> = vec![]; + let mut err = None; + for i in 0..graphemes_escaped.len() { let g = graphemes_escaped[i]; if g == esc_graph { @@ -36,12 +44,22 @@ impl TryFrom<&String> for Gen4Str { graphemes.push(g); last_esc = 0; } - _ => return Err((i, g)) + _ => { + if err.is_none() { + err = Some((i, g)); + } + last_esc = 0; + continue; + } } } else { if last_esc > 0 { if last_esc == 1 && g != cod_graph { // only one possibility at the moment - return Err((i, g)); + if err.is_none() { + err = Some((i, g)); + } + last_esc = 0; + continue; } if last_esc == 5 { // skipped all 5 characters (including code escape) now collect and parse them @@ -52,12 +70,34 @@ impl TryFrom<&String> for Gen4Str { let g = graphemes_escaped[i - j]; match g { Utf16Grapheme::Bmp(c) => digits[digits.len() - j - 1] = c, - _ => return Err((i - j, g)) + _ => { + if err.is_none() { + err = Some((i - j, g)); + } + last_esc = 0; + continue; + } } } - let utf16_str = String::from_utf16(&digits).map_err(|_| (i, g))?; - let gen4_code = u16::from_str_radix(&*utf16_str, 16).map_err(|_| (i, g))?; + let utf16_str = String::from_utf16(&digits); + if utf16_str.is_err() { + if err.is_none() { + err = Some((i, g)); + } + continue; + } + let utf16_str = utf16_str.unwrap(); + + let gen4_code = u16::from_str_radix(&*utf16_str, 16); + if gen4_code.is_err() { + if err.is_none() { + err = Some((i, g)); + } + last_esc = 0; + continue; + } + let gen4_code = gen4_code.unwrap(); escaped.push((graphemes.len(), gen4_code)); @@ -80,12 +120,24 @@ impl TryFrom<&String> for Gen4Str { } let invalid_grapheme = pokestr.iter().enumerate().find(|(_, g)| g.is_none()); + + let str = Gen4Str { vec: pokestr.iter().flatten().map(|c| *c).collect() }; + if let Some((i, _)) = invalid_grapheme { - Err((i, graphemes[i])) - } else { - Ok(Gen4Str { - vec: pokestr.iter().map(|i| i.unwrap()).collect() + Err(EncodeError { + sanitized: str, + idx: i, + char: graphemes[i], }) + } else { + if let Some(err) = err { + return Err(EncodeError { + sanitized: str, + idx: err.0, + char: err.1, + }); + } + Ok(str) } } }