diff --git a/Cargo.toml b/Cargo.toml index da59f583..a2a7ef72 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,6 +41,7 @@ thiserror = "2.0" indexmap = { version = "2.0.0", features = ["serde"] } base64 = "0.22" close_already = "0.3" +log = "0.4" [dev-dependencies] failure = "0.1.6" diff --git a/src/glyph/parse.rs b/src/glyph/parse.rs index c7f9779a..eb58eda8 100644 --- a/src/glyph/parse.rs +++ b/src/glyph/parse.rs @@ -308,12 +308,20 @@ impl<'names> GlifParser<'names> { } let plist_slice = &raw_xml[start..end]; - let dict = plist::Value::from_reader_xml(plist_slice) - .map_err(|_| GlifLoadError::Parse(ErrorKind::BadLib))? - .into_dictionary() - .ok_or(GlifLoadError::Parse(ErrorKind::LibMustBeDictionary))?; + match plist::Value::from_reader_xml(plist_slice) + .map_err(|_| GlifLoadError::Parse(ErrorKind::BadLib)) + .and_then(|x| { + x.into_dictionary().ok_or(GlifLoadError::Parse(ErrorKind::LibMustBeDictionary)) + }) { + Ok(dict) => { + // we used to error if this was malformed but there are a number of early UFO files + // in the wild that store arbitrary xml in the lib, which doesn't parse as a plist. + // Instead of failing to parse these files, we prefer to just skip the dicts. + self.glyph.lib = dict; + } + Err(e) => log::info!("glyph {} contains invalid lib: '{e}'", self.glyph.name), + } - self.glyph.lib = dict; Ok(()) } diff --git a/src/glyph/tests.rs b/src/glyph/tests.rs index 46e2f724..cc005f2d 100644 --- a/src/glyph/tests.rs +++ b/src/glyph/tests.rs @@ -318,8 +318,9 @@ fn bad_angle() { } #[test] -#[should_panic(expected = "LibMustBeDictionary")] -fn lib_must_be_dict() { +// in a number of older UFO files in the wild glyphs can contain dictionaries +// with arbitrary non-plsit XML: +fn skip_non_lib_dictionary() { let data = r#" @@ -328,7 +329,8 @@ fn lib_must_be_dict() { "#; - let _ = parse_glyph(data.as_bytes()).unwrap(); + let glyph = parse_glyph(data.as_bytes()).unwrap(); + assert!(glyph.lib.is_empty()); } #[test]