diff --git a/examples/fontinfotest.rs b/examples/fontinfotest.rs deleted file mode 100644 index b0854576..00000000 --- a/examples/fontinfotest.rs +++ /dev/null @@ -1,1304 +0,0 @@ -#[macro_use] -extern crate serde_derive; -#[macro_use] -extern crate serde_repr; - -use std::convert::TryFrom; -use std::env; -use std::ffi::OsStr; -use std::path::Path; -use std::path::PathBuf; - -use plist; -use serde::de::Deserializer; -use serde::ser::{SerializeSeq, Serializer}; -use serde::{Deserialize, Serialize}; - -use norad::{Error, FormatVersion, Guideline, MetaInfo}; - -fn main() -> Result<(), Error> { - let mut args = env::args().skip(1); - - let path = match args.next().map(PathBuf::from) { - Some(ref p) if p.exists() && p.extension() == Some(OsStr::new("ufo")) => p.to_owned(), - _ => { - eprintln!("Please supply a path to a UFO to read from"); - std::process::exit(1); - } - }; - - let meta: MetaInfo = plist::from_file(path.join("metainfo.plist"))?; - let mut fontinfo: FontInfo = - match FontInfo::from_file(path.join("fontinfo.plist"), meta.format_version) { - Ok(v) => v, - Err(e) => { - eprintln!("Loading the fontinfo failed: {}", e); - std::process::exit(1); - } - }; - - let lib_path = path.join("lib.plist"); - let lib = if lib_path.exists() { - Some(plist::Value::from_file(lib_path)?.into_dictionary().unwrap()) - } else { - None - }; - - if meta.format_version == FormatVersion::V1 { - if let Some(v) = lib { - if let Some(data) = v.get("org.robofab.postScriptHintData") { - if let plist::Value::Dictionary(d) = data { - if let Some(value) = d.get("blueFuzz") { - fontinfo.postscript_blue_fuzz = Some(IntegerOrFloat::try_from(value)?) - } - // if let Some(value) = d.get("blueScale") { - // fontinfo.postscript_blue_scale = - // Some(IntegerOrFloat::try_from(value).unwrap()) - // } - // use serde to do all this? - } else { - // error - } - } - } - } - - // v1 features - - plist::to_file_xml("/tmp/fontinfo.plist", &fontinfo).unwrap(); - - Ok(()) -} - -use types::{ - Bitlist, Float, Integer, IntegerOrFloat, NonNegativeInteger, NonNegativeIntegerOrFloat, -}; - -#[derive(Debug, Clone, Default, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -#[serde(rename_all = "camelCase")] -pub struct FontInfo { - pub ascender: Option, - pub cap_height: Option, - pub copyright: Option, - pub descender: Option, - pub family_name: Option, - pub guidelines: Option>, - pub italic_angle: Option, - #[serde(rename = "macintoshFONDFamilyID")] - pub macintosh_fond_family_id: Option, - #[serde(rename = "macintoshFONDName")] - pub macintosh_fond_name: Option, - pub note: Option, - pub open_type_gasp_range_records: Option>, - pub open_type_head_created: Option, - pub open_type_head_flags: Option, - #[serde(rename = "openTypeHeadLowestRecPPEM")] - pub open_type_head_lowest_rec_ppem: Option, - pub open_type_hhea_ascender: Option, - pub open_type_hhea_caret_offset: Option, - pub open_type_hhea_caret_slope_rise: Option, - pub open_type_hhea_caret_slope_run: Option, - pub open_type_hhea_descender: Option, - pub open_type_hhea_line_gap: Option, - pub open_type_name_compatible_full_name: Option, - pub open_type_name_description: Option, - #[serde(rename = "openTypeNameDesignerURL")] - pub open_type_name_designer_url: Option, - pub open_type_name_designer: Option, - #[serde(rename = "openTypeNameLicenseURL")] - pub open_type_name_license_url: Option, - pub open_type_name_license: Option, - #[serde(rename = "openTypeNameManufacturerURL")] - pub open_type_name_manufacturer_url: Option, - pub open_type_name_manufacturer: Option, - pub open_type_name_preferred_family_name: Option, - pub open_type_name_preferred_subfamily_name: Option, - pub open_type_name_records: Option>, - pub open_type_name_sample_text: Option, - #[serde(rename = "openTypeNameUniqueID")] - pub open_type_name_unique_id: Option, - pub open_type_name_version: Option, - #[serde(rename = "openTypeNameWWSFamilyName")] - pub open_type_name_wws_family_name: Option, - #[serde(rename = "openTypeNameWWSSubfamilyName")] - pub open_type_name_wws_subfamily_name: Option, - #[serde(rename = "openTypeOS2CodePageRanges")] - pub open_type_os2_code_page_ranges: Option, - #[serde(rename = "openTypeOS2FamilyClass")] - pub open_type_os2_family_class: Option, - #[serde(rename = "openTypeOS2Panose")] - pub open_type_os2_panose: Option, - #[serde(rename = "openTypeOS2Selection")] - pub open_type_os2_selection: Option, - #[serde(rename = "openTypeOS2StrikeoutPosition")] - pub open_type_os2_strikeout_position: Option, - #[serde(rename = "openTypeOS2StrikeoutSize")] - pub open_type_os2_strikeout_size: Option, - #[serde(rename = "openTypeOS2SubscriptXOffset")] - pub open_type_os2_subscript_x_offset: Option, - #[serde(rename = "openTypeOS2SubscriptXSize")] - pub open_type_os2_subscript_x_size: Option, - #[serde(rename = "openTypeOS2SubscriptYOffset")] - pub open_type_os2_subscript_y_offset: Option, - #[serde(rename = "openTypeOS2SubscriptYSize")] - pub open_type_os2_subscript_y_size: Option, - #[serde(rename = "openTypeOS2SuperscriptXOffset")] - pub open_type_os2_superscript_x_offset: Option, - #[serde(rename = "openTypeOS2SuperscriptXSize")] - pub open_type_os2_superscript_x_size: Option, - #[serde(rename = "openTypeOS2SuperscriptYOffset")] - pub open_type_os2_superscript_y_offset: Option, - #[serde(rename = "openTypeOS2SuperscriptYSize")] - pub open_type_os2_superscript_y_size: Option, - #[serde(rename = "openTypeOS2Type")] - pub open_type_os2_type: Option, - #[serde(rename = "openTypeOS2TypoAscender")] - pub open_type_os2_typo_ascender: Option, - #[serde(rename = "openTypeOS2TypoDescender")] - pub open_type_os2_typo_descender: Option, - #[serde(rename = "openTypeOS2TypoLineGap")] - pub open_type_os2_typo_line_gap: Option, - #[serde(rename = "openTypeOS2UnicodeRanges")] - pub open_type_os2_unicode_ranges: Option, - #[serde(rename = "openTypeOS2VendorID")] - pub open_type_os2_vendor_id: Option, - #[serde(rename = "openTypeOS2WeightClass")] - pub open_type_os2_weight_class: Option, - #[serde(rename = "openTypeOS2WidthClass")] - pub open_type_os2_width_class: Option, - #[serde(rename = "openTypeOS2WinAscent")] - pub open_type_os2_win_ascent: Option, - #[serde(rename = "openTypeOS2WinDescent")] - pub open_type_os2_win_descent: Option, - pub open_type_vhea_caret_offset: Option, - pub open_type_vhea_caret_slope_rise: Option, - pub open_type_vhea_caret_slope_run: Option, - pub open_type_vhea_vert_typo_ascender: Option, - pub open_type_vhea_vert_typo_descender: Option, - pub open_type_vhea_vert_typo_line_gap: Option, - pub postscript_blue_fuzz: Option, - pub postscript_blue_scale: Option, - pub postscript_blue_shift: Option, - pub postscript_blue_values: Option>, - pub postscript_default_character: Option, - pub postscript_default_width_x: Option, - pub postscript_family_blues: Option>, - pub postscript_family_other_blues: Option>, - pub postscript_font_name: Option, - pub postscript_force_bold: Option, - pub postscript_full_name: Option, - pub postscript_is_fixed_pitch: Option, - pub postscript_nominal_width_x: Option, - pub postscript_other_blues: Option>, - pub postscript_slant_angle: Option, - pub postscript_stem_snap_h: Option>, - pub postscript_stem_snap_v: Option>, - pub postscript_underline_position: Option, - pub postscript_underline_thickness: Option, - #[serde(rename = "postscriptUniqueID")] - pub postscript_unique_id: Option, - pub postscript_weight_name: Option, - pub postscript_windows_character_set: Option, - pub style_map_family_name: Option, - pub style_map_style_name: Option, - pub style_name: Option, - pub trademark: Option, - pub units_per_em: Option, - pub version_major: Option, - pub version_minor: Option, - pub woff_major_version: Option, - pub woff_metadata_copyright: Option, - pub woff_metadata_credits: Option, - pub woff_metadata_description: Option, - pub woff_metadata_extensions: Option>, - pub woff_metadata_license: Option, - pub woff_metadata_licensee: Option, - pub woff_metadata_trademark: Option, - #[serde(rename = "woffMetadataUniqueID")] - pub woff_metadata_unique_id: Option, - pub woff_metadata_vendor: Option, - pub woff_minor_version: Option, - pub x_height: Option, - pub year: Option, -} - -#[derive(Deserialize)] -#[serde(deny_unknown_fields)] -#[allow(non_snake_case)] -struct FontInfoV2 { - ascender: Option, - capHeight: Option, - copyright: Option, - descender: Option, - familyName: Option, - italicAngle: Option, - macintoshFONDFamilyID: Option, - macintoshFONDName: Option, - note: Option, - openTypeHeadCreated: Option, - openTypeHeadFlags: Option, - openTypeHeadLowestRecPPEM: Option, - openTypeHheaAscender: Option, - openTypeHheaCaretOffset: Option, - openTypeHheaCaretSlopeRise: Option, - openTypeHheaCaretSlopeRun: Option, - openTypeHheaDescender: Option, - openTypeHheaLineGap: Option, - openTypeNameCompatibleFullName: Option, - openTypeNameDescription: Option, - openTypeNameDesigner: Option, - openTypeNameDesignerURL: Option, - openTypeNameLicense: Option, - openTypeNameLicenseURL: Option, - openTypeNameManufacturer: Option, - openTypeNameManufacturerURL: Option, - openTypeNamePreferredFamilyName: Option, - openTypeNamePreferredSubfamilyName: Option, - openTypeNameSampleText: Option, - openTypeNameUniqueID: Option, - openTypeNameVersion: Option, - openTypeNameWWSFamilyName: Option, - openTypeNameWWSSubfamilyName: Option, - openTypeOS2CodePageRanges: Option, - openTypeOS2FamilyClass: Option, - openTypeOS2Panose: Option, - openTypeOS2Selection: Option, - openTypeOS2StrikeoutPosition: Option, - openTypeOS2StrikeoutSize: Option, - openTypeOS2SubscriptXOffset: Option, - openTypeOS2SubscriptXSize: Option, - openTypeOS2SubscriptYOffset: Option, - openTypeOS2SubscriptYSize: Option, - openTypeOS2SuperscriptXOffset: Option, - openTypeOS2SuperscriptXSize: Option, - openTypeOS2SuperscriptYOffset: Option, - openTypeOS2SuperscriptYSize: Option, - openTypeOS2Type: Option, - openTypeOS2TypoAscender: Option, - openTypeOS2TypoDescender: Option, - openTypeOS2TypoLineGap: Option, - openTypeOS2UnicodeRanges: Option, - openTypeOS2VendorID: Option, - openTypeOS2WeightClass: Option, - openTypeOS2WidthClass: Option, - openTypeOS2WinAscent: Option, - openTypeOS2WinDescent: Option, - openTypeVheaCaretOffset: Option, - openTypeVheaCaretSlopeRise: Option, - openTypeVheaCaretSlopeRun: Option, - openTypeVheaVertTypoAscender: Option, - openTypeVheaVertTypoDescender: Option, - openTypeVheaVertTypoLineGap: Option, - postscriptBlueFuzz: Option, - postscriptBlueScale: Option, - postscriptBlueShift: Option, - postscriptBlueValues: Option>, - postscriptDefaultCharacter: Option, - postscriptDefaultWidthX: Option, - postscriptFamilyBlues: Option>, - postscriptFamilyOtherBlues: Option>, - postscriptFontName: Option, - postscriptForceBold: Option, - postscriptFullName: Option, - postscriptIsFixedPitch: Option, - postscriptNominalWidthX: Option, - postscriptOtherBlues: Option>, - postscriptSlantAngle: Option, - postscriptStemSnapH: Option>, - postscriptStemSnapV: Option>, - postscriptUnderlinePosition: Option, - postscriptUnderlineThickness: Option, - postscriptUniqueID: Option, - postscriptWeightName: Option, - postscriptWindowsCharacterSet: Option, - styleMapFamilyName: Option, - styleMapStyleName: Option, - styleName: Option, - trademark: Option, - unitsPerEm: Option, - versionMajor: Option, - versionMinor: Option, - xHeight: Option, - year: Option, -} - -#[derive(Deserialize)] -#[serde(deny_unknown_fields)] -#[allow(non_snake_case)] -struct FontInfoV1 { - ascender: Option, - capHeight: Option, - copyright: Option, - createdBy: Option, - defaultWidth: Option, - descender: Option, - designer: Option, - designerURL: Option, - familyName: Option, - fondID: Option, - fondName: Option, - fontName: Option, - fontStyle: Option, - fullName: Option, - italicAngle: Option, - license: Option, - licenseURL: Option, - menuName: Option, - msCharSet: Option, - note: Option, - notice: Option, - otFamilyName: Option, - otMacName: Option, - otStyleName: Option, - slantAngle: Option, - styleName: Option, - trademark: Option, - ttUniqueID: Option, - ttVendor: Option, - ttVersion: Option, - uniqueID: Option, - unitsPerEm: Option, - vendorURL: Option, - versionMajor: Option, - versionMinor: Option, - weightName: Option, - weightValue: Option, - widthName: Option, - xHeight: Option, // Does not appear in spec but ufoLib. - year: Option, // Does not appear in spec but ufoLib. -} - -impl FontInfo { - pub fn from_file>( - path: P, - format_version: FormatVersion, - ) -> Result { - match format_version { - FormatVersion::V3 => { - let fontinfo: FontInfo = plist::from_file(path)?; - // fontinfo.validate()?; - Ok(fontinfo) - } - FormatVersion::V2 => { - let fontinfo_v2: FontInfoV2 = plist::from_file(path)?; - let fontinfo = FontInfo { - ascender: fontinfo_v2.ascender, - cap_height: fontinfo_v2.capHeight, - copyright: fontinfo_v2.copyright, - descender: fontinfo_v2.descender, - family_name: fontinfo_v2.familyName, - italic_angle: fontinfo_v2.italicAngle, - macintosh_fond_family_id: fontinfo_v2.macintoshFONDFamilyID, - macintosh_fond_name: fontinfo_v2.macintoshFONDName, - note: fontinfo_v2.note, - open_type_head_created: fontinfo_v2.openTypeHeadCreated, - open_type_head_flags: fontinfo_v2.openTypeHeadFlags, - open_type_head_lowest_rec_ppem: fontinfo_v2 - .openTypeHeadLowestRecPPEM - .map(|v| v.round().abs() as NonNegativeInteger), - open_type_hhea_ascender: fontinfo_v2 - .openTypeHheaAscender - .map(|v| v.round() as Integer), - open_type_hhea_caret_offset: fontinfo_v2 - .openTypeHheaCaretOffset - .map(|v| v.round() as Integer), - open_type_hhea_caret_slope_rise: fontinfo_v2.openTypeHheaCaretSlopeRise, - open_type_hhea_caret_slope_run: fontinfo_v2.openTypeHheaCaretSlopeRun, - open_type_hhea_descender: fontinfo_v2 - .openTypeHheaDescender - .map(|v| v.round() as Integer), - open_type_hhea_line_gap: fontinfo_v2 - .openTypeHheaLineGap - .map(|v| v.round() as Integer), - open_type_name_compatible_full_name: fontinfo_v2.openTypeNameCompatibleFullName, - open_type_name_description: fontinfo_v2.openTypeNameDescription, - open_type_name_designer: fontinfo_v2.openTypeNameDesigner, - open_type_name_designer_url: fontinfo_v2.openTypeNameDesignerURL, - open_type_name_license: fontinfo_v2.openTypeNameLicense, - open_type_name_license_url: fontinfo_v2.openTypeNameLicenseURL, - open_type_name_manufacturer: fontinfo_v2.openTypeNameManufacturer, - open_type_name_manufacturer_url: fontinfo_v2.openTypeNameManufacturerURL, - open_type_name_preferred_family_name: fontinfo_v2 - .openTypeNamePreferredFamilyName, - open_type_name_preferred_subfamily_name: fontinfo_v2 - .openTypeNamePreferredSubfamilyName, - open_type_name_sample_text: fontinfo_v2.openTypeNameSampleText, - open_type_name_unique_id: fontinfo_v2.openTypeNameUniqueID, - open_type_name_version: fontinfo_v2.openTypeNameVersion, - open_type_name_wws_family_name: fontinfo_v2.openTypeNameWWSFamilyName, - open_type_name_wws_subfamily_name: fontinfo_v2.openTypeNameWWSSubfamilyName, - open_type_os2_code_page_ranges: fontinfo_v2.openTypeOS2CodePageRanges, - open_type_os2_family_class: fontinfo_v2.openTypeOS2FamilyClass, - open_type_os2_panose: fontinfo_v2.openTypeOS2Panose.map(OS2Panose::from), - open_type_os2_selection: fontinfo_v2.openTypeOS2Selection, - open_type_os2_strikeout_position: fontinfo_v2 - .openTypeOS2StrikeoutPosition - .map(|v| v.round() as Integer), - open_type_os2_strikeout_size: fontinfo_v2 - .openTypeOS2StrikeoutSize - .map(|v| v.round() as Integer), - open_type_os2_subscript_x_offset: fontinfo_v2 - .openTypeOS2SubscriptXOffset - .map(|v| v.round() as Integer), - open_type_os2_subscript_x_size: fontinfo_v2 - .openTypeOS2SubscriptXSize - .map(|v| v.round() as Integer), - open_type_os2_subscript_y_offset: fontinfo_v2 - .openTypeOS2SubscriptYOffset - .map(|v| v.round() as Integer), - open_type_os2_subscript_y_size: fontinfo_v2 - .openTypeOS2SubscriptYSize - .map(|v| v.round() as Integer), - open_type_os2_superscript_x_offset: fontinfo_v2 - .openTypeOS2SuperscriptXOffset - .map(|v| v.round() as Integer), - open_type_os2_superscript_x_size: fontinfo_v2 - .openTypeOS2SuperscriptXSize - .map(|v| v.round() as Integer), - open_type_os2_superscript_y_offset: fontinfo_v2 - .openTypeOS2SuperscriptYOffset - .map(|v| v.round() as Integer), - open_type_os2_superscript_y_size: fontinfo_v2 - .openTypeOS2SuperscriptYSize - .map(|v| v.round() as Integer), - open_type_os2_type: fontinfo_v2.openTypeOS2Type, - open_type_os2_typo_ascender: fontinfo_v2 - .openTypeOS2TypoAscender - .map(|v| v.round() as Integer), - open_type_os2_typo_descender: fontinfo_v2 - .openTypeOS2TypoDescender - .map(|v| v.round() as Integer), - open_type_os2_typo_line_gap: fontinfo_v2 - .openTypeOS2TypoLineGap - .map(|v| v.round() as Integer), - open_type_os2_unicode_ranges: fontinfo_v2.openTypeOS2UnicodeRanges, - open_type_os2_vendor_id: fontinfo_v2.openTypeOS2VendorID, - open_type_os2_weight_class: fontinfo_v2.openTypeOS2WeightClass, - open_type_os2_width_class: fontinfo_v2.openTypeOS2WidthClass, - open_type_os2_win_ascent: fontinfo_v2 - .openTypeOS2WinAscent - .map(|v| v.round().abs() as NonNegativeInteger), - open_type_os2_win_descent: fontinfo_v2 - .openTypeOS2WinDescent - .map(|v| v.round().abs() as NonNegativeInteger), - open_type_vhea_caret_offset: fontinfo_v2 - .openTypeVheaCaretOffset - .map(|v| v.round() as Integer), - open_type_vhea_caret_slope_rise: fontinfo_v2.openTypeVheaCaretSlopeRise, - open_type_vhea_caret_slope_run: fontinfo_v2.openTypeVheaCaretSlopeRun, - open_type_vhea_vert_typo_ascender: fontinfo_v2 - .openTypeVheaVertTypoAscender - .map(|v| v.round() as Integer), - open_type_vhea_vert_typo_descender: fontinfo_v2 - .openTypeVheaVertTypoDescender - .map(|v| v.round() as Integer), - open_type_vhea_vert_typo_line_gap: fontinfo_v2 - .openTypeVheaVertTypoLineGap - .map(|v| v.round() as Integer), - postscript_blue_fuzz: fontinfo_v2.postscriptBlueFuzz, - postscript_blue_scale: fontinfo_v2.postscriptBlueScale, - postscript_blue_shift: fontinfo_v2.postscriptBlueShift, - postscript_blue_values: fontinfo_v2.postscriptBlueValues, - postscript_default_character: fontinfo_v2.postscriptDefaultCharacter, - postscript_default_width_x: fontinfo_v2.postscriptDefaultWidthX, - postscript_family_blues: fontinfo_v2.postscriptFamilyBlues, - postscript_family_other_blues: fontinfo_v2.postscriptFamilyOtherBlues, - postscript_font_name: fontinfo_v2.postscriptFontName, - postscript_force_bold: fontinfo_v2.postscriptForceBold, - postscript_full_name: fontinfo_v2.postscriptFullName, - postscript_is_fixed_pitch: fontinfo_v2.postscriptIsFixedPitch, - postscript_nominal_width_x: fontinfo_v2.postscriptNominalWidthX, - postscript_other_blues: fontinfo_v2.postscriptOtherBlues, - postscript_slant_angle: fontinfo_v2.postscriptSlantAngle, - postscript_stem_snap_h: fontinfo_v2.postscriptStemSnapH, - postscript_stem_snap_v: fontinfo_v2.postscriptStemSnapV, - postscript_underline_position: fontinfo_v2.postscriptUnderlinePosition, - postscript_underline_thickness: fontinfo_v2.postscriptUnderlineThickness, - postscript_unique_id: fontinfo_v2.postscriptUniqueID, - postscript_weight_name: fontinfo_v2.postscriptWeightName, - postscript_windows_character_set: fontinfo_v2.postscriptWindowsCharacterSet, - style_map_family_name: fontinfo_v2.styleMapFamilyName, - style_map_style_name: fontinfo_v2.styleMapStyleName, - style_name: fontinfo_v2.styleName, - trademark: fontinfo_v2.trademark, - units_per_em: fontinfo_v2 - .unitsPerEm - .map(|v| NonNegativeIntegerOrFloat::new(v.abs()).unwrap()), - version_major: fontinfo_v2.versionMajor, - version_minor: fontinfo_v2.versionMinor.map(|v| v.abs() as NonNegativeInteger), - x_height: fontinfo_v2.xHeight, - year: fontinfo_v2.year, - ..FontInfo::default() - }; - // fontinfo.validate(); - Ok(fontinfo) - } - FormatVersion::V1 => { - let fontinfo_v1: FontInfoV1 = plist::from_file(path)?; - let fontinfo = FontInfo { - ascender: fontinfo_v1.ascender, - cap_height: fontinfo_v1.capHeight, - copyright: fontinfo_v1.copyright, - descender: fontinfo_v1.descender, - family_name: fontinfo_v1.familyName, - italic_angle: fontinfo_v1.italicAngle, - macintosh_fond_family_id: fontinfo_v1.fondID, - macintosh_fond_name: fontinfo_v1.fondName, - note: fontinfo_v1.note, - open_type_name_compatible_full_name: fontinfo_v1.otMacName, - open_type_name_description: fontinfo_v1.notice, - open_type_name_designer_url: fontinfo_v1.designerURL, - open_type_name_designer: fontinfo_v1.designer, - open_type_name_license_url: fontinfo_v1.licenseURL, - open_type_name_license: fontinfo_v1.license, - open_type_name_manufacturer_url: fontinfo_v1.vendorURL, - open_type_name_manufacturer: fontinfo_v1.createdBy, - open_type_name_preferred_family_name: fontinfo_v1.otFamilyName, - open_type_name_preferred_subfamily_name: fontinfo_v1.otStyleName, - open_type_name_unique_id: fontinfo_v1.ttUniqueID, - open_type_name_version: fontinfo_v1.ttVersion, - open_type_os2_vendor_id: fontinfo_v1.ttVendor, - open_type_os2_weight_class: match fontinfo_v1.weightValue { - Some(v) => match v { - -1 => None, - _ => Some(v.abs() as NonNegativeInteger), - }, - None => None, - }, - open_type_os2_width_class: match fontinfo_v1.widthName { - Some(v) => match v.as_ref() { - "Ultra-condensed" => Some(OS2WidthClass::UltraCondensed), - "Extra-condensed" => Some(OS2WidthClass::ExtraCondensed), - "Condensed" => Some(OS2WidthClass::Condensed), - "Semi-condensed" => Some(OS2WidthClass::SemiCondensed), - "Medium (normal)" => Some(OS2WidthClass::Normal), - "Normal" => Some(OS2WidthClass::Normal), - "All" => Some(OS2WidthClass::Normal), - "medium" => Some(OS2WidthClass::Normal), - "Medium" => Some(OS2WidthClass::Normal), - "Semi-expanded" => Some(OS2WidthClass::SemiExpanded), - "Expanded" => Some(OS2WidthClass::Expanded), - "Extra-expanded" => Some(OS2WidthClass::ExtraExpanded), - "Ultra-expanded" => Some(OS2WidthClass::UltraExpanded), - _ => Err(Error::FontInfoError)?, - }, - None => None, - }, - postscript_default_width_x: fontinfo_v1.defaultWidth, - postscript_font_name: fontinfo_v1.fontName, - postscript_full_name: fontinfo_v1.fullName, - postscript_slant_angle: fontinfo_v1.slantAngle, - postscript_unique_id: fontinfo_v1.uniqueID, - postscript_weight_name: fontinfo_v1.weightName, - postscript_windows_character_set: match fontinfo_v1.msCharSet { - Some(v) => match v { - 0 => Some(PostscriptWindowsCharacterSet::ANSI), - 1 => Some(PostscriptWindowsCharacterSet::Default), - 2 => Some(PostscriptWindowsCharacterSet::Symbol), - 77 => Some(PostscriptWindowsCharacterSet::Macintosh), - 128 => Some(PostscriptWindowsCharacterSet::ShiftJIS), - 129 => Some(PostscriptWindowsCharacterSet::Hangul), - 130 => Some(PostscriptWindowsCharacterSet::HangulJohab), - 134 => Some(PostscriptWindowsCharacterSet::GB2312), - 136 => Some(PostscriptWindowsCharacterSet::ChineseBIG5), - 161 => Some(PostscriptWindowsCharacterSet::Greek), - 162 => Some(PostscriptWindowsCharacterSet::Turkish), - 163 => Some(PostscriptWindowsCharacterSet::Vietnamese), - 177 => Some(PostscriptWindowsCharacterSet::Hebrew), - 178 => Some(PostscriptWindowsCharacterSet::Arabic), - 186 => Some(PostscriptWindowsCharacterSet::Baltic), - 200 => Some(PostscriptWindowsCharacterSet::Bitstream), - 204 => Some(PostscriptWindowsCharacterSet::Cyrillic), - 222 => Some(PostscriptWindowsCharacterSet::Thai), - 238 => Some(PostscriptWindowsCharacterSet::EasternEuropean), - 255 => Some(PostscriptWindowsCharacterSet::OEM), - _ => Err(Error::FontInfoError)?, - }, - None => None, - }, - style_map_family_name: fontinfo_v1.menuName, - style_map_style_name: match fontinfo_v1.fontStyle { - Some(v) => match v { - 0 | 64 => Some(StyleMapStyle::Regular), - 1 => Some(StyleMapStyle::Italic), - 32 => Some(StyleMapStyle::Bold), - 33 => Some(StyleMapStyle::BoldItalic), - _ => Err(Error::FontInfoError)?, - }, - None => None, - }, - style_name: fontinfo_v1.styleName, - trademark: fontinfo_v1.trademark, - units_per_em: fontinfo_v1 - .unitsPerEm - .map(|v| NonNegativeIntegerOrFloat::new(v.abs()).unwrap()), - version_major: fontinfo_v1.versionMajor, - version_minor: fontinfo_v1.versionMinor.map(|v| v.abs() as NonNegativeInteger), - x_height: fontinfo_v1.xHeight, - year: fontinfo_v1.year, - ..FontInfo::default() - }; - // fontinfo.validate(); - Ok(fontinfo) - } - } - } -} - -/// Corresponds to [gasp Range Record Format](http://unifiedfontobject.org/versions/ufo3/fontinfo.plist/#gasp-range-record-format). -#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -#[serde(rename_all = "camelCase")] -pub struct GaspRangeRecord { - #[serde(rename = "rangeMaxPPEM")] - range_max_ppem: NonNegativeInteger, - range_gasp_behavior: Vec, -} - -/// Corresponds to [rangeGaspBehavior Bits](http://unifiedfontobject.org/versions/ufo3/fontinfo.plist/#rangegaspbehavior-bits). -#[derive(Debug, Clone, Copy, Serialize_repr, Deserialize_repr, PartialEq)] -#[repr(u8)] -pub enum GaspBehavior { - Gridfit = 0, - DoGray = 1, - SymmetricGridfit = 2, - SymmetricSmoothing = 3, -} - -/// Corresponds to [Name Record Format](http://unifiedfontobject.org/versions/ufo3/fontinfo.plist/#name-record-format). -#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct NameRecord { - #[serde(rename = "nameID")] - name_id: NonNegativeInteger, - #[serde(rename = "platformID")] - platform_id: NonNegativeInteger, - #[serde(rename = "encodingID")] - encoding_id: NonNegativeInteger, - #[serde(rename = "languageID")] - language_id: NonNegativeInteger, - string: String, -} - -/// Corresponds to the allowed values for [openTypeOS2WidthClass](http://unifiedfontobject.org/versions/ufo3/fontinfo.plist/#opentype-os2-table-fields). -#[derive(Debug, Clone, Copy, Serialize_repr, Deserialize_repr, PartialEq)] -#[repr(u8)] -pub enum OS2WidthClass { - UltraCondensed = 1, - ExtraCondensed = 2, - Condensed = 3, - SemiCondensed = 4, - Normal = 5, - SemiExpanded = 6, - Expanded = 7, - ExtraExpanded = 8, - UltraExpanded = 9, -} - -/// Corresponds to [openTypeOS2FamilyClass](http://unifiedfontobject.org/versions/ufo3/fontinfo.plist/#opentype-os2-table-fields). -#[derive(Debug, Clone, Default, PartialEq)] -pub struct OS2FamilyClass { - class_id: u8, - subclass_id: u8, -} - -impl OS2FamilyClass { - /// The first number, representing the class ID, must be in the range 0-14. - /// The second number, representing the subclass, must be in the range 0-15. - fn is_valid(&self) -> bool { - (0..=14).contains(&self.class_id) && (0..=15).contains(&self.subclass_id) - } -} - -impl Serialize for OS2FamilyClass { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut seq = serializer.serialize_seq(Some(2))?; - seq.serialize_element(&self.class_id)?; - seq.serialize_element(&self.subclass_id)?; - seq.end() - } -} - -impl<'de> Deserialize<'de> for OS2FamilyClass { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let values: Vec = Deserialize::deserialize(deserializer)?; - if values.len() != 2 { - return Err(serde::de::Error::custom( - "openTypeOS2FamilyClass must have exactly two elements.", - )); - } - - Ok(OS2FamilyClass { class_id: values[0], subclass_id: values[1] }) - } -} - -/// Corresponds to [openTypeOS2Panose](http://unifiedfontobject.org/versions/ufo3/fontinfo.plist/#opentype-os2-table-fields). -#[derive(Debug, Clone, Default, PartialEq)] -pub struct OS2Panose { - family_type: NonNegativeInteger, - serif_style: NonNegativeInteger, - weight: NonNegativeInteger, - proportion: NonNegativeInteger, - contrast: NonNegativeInteger, - stroke_variation: NonNegativeInteger, - arm_style: NonNegativeInteger, - letterform: NonNegativeInteger, - midline: NonNegativeInteger, - x_height: NonNegativeInteger, -} - -impl Serialize for OS2Panose { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut seq = serializer.serialize_seq(Some(10))?; - seq.serialize_element(&self.family_type)?; - seq.serialize_element(&self.serif_style)?; - seq.serialize_element(&self.weight)?; - seq.serialize_element(&self.proportion)?; - seq.serialize_element(&self.contrast)?; - seq.serialize_element(&self.stroke_variation)?; - seq.serialize_element(&self.arm_style)?; - seq.serialize_element(&self.letterform)?; - seq.serialize_element(&self.midline)?; - seq.serialize_element(&self.x_height)?; - seq.end() - } -} - -impl<'de> Deserialize<'de> for OS2Panose { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let values: Vec = Deserialize::deserialize(deserializer)?; - if values.len() != 10 { - return Err(serde::de::Error::custom( - "openTypeOS2Panose must have exactly ten elements.", - )); - } - - Ok(OS2Panose { - family_type: values[0], - serif_style: values[1], - weight: values[2], - proportion: values[3], - contrast: values[4], - stroke_variation: values[5], - arm_style: values[6], - letterform: values[7], - midline: values[8], - x_height: values[9], - }) - } -} - -impl From for OS2Panose { - fn from(value: OS2PanoseV2) -> Self { - OS2Panose { - family_type: value.family_type.abs() as NonNegativeInteger, - serif_style: value.serif_style.abs() as NonNegativeInteger, - weight: value.weight.abs() as NonNegativeInteger, - proportion: value.proportion.abs() as NonNegativeInteger, - contrast: value.contrast.abs() as NonNegativeInteger, - stroke_variation: value.stroke_variation.abs() as NonNegativeInteger, - arm_style: value.arm_style.abs() as NonNegativeInteger, - letterform: value.letterform.abs() as NonNegativeInteger, - midline: value.midline.abs() as NonNegativeInteger, - x_height: value.x_height.abs() as NonNegativeInteger, - } - } -} - -/// OS2PanoseV2 is from UFO v2 and allows negative integers, while the OpenType specification -/// specifies unsigned integers. -#[derive(Debug, Clone, Default, PartialEq)] -struct OS2PanoseV2 { - family_type: Integer, - serif_style: Integer, - weight: Integer, - proportion: Integer, - contrast: Integer, - stroke_variation: Integer, - arm_style: Integer, - letterform: Integer, - midline: Integer, - x_height: Integer, -} - -impl Serialize for OS2PanoseV2 { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut seq = serializer.serialize_seq(Some(10))?; - seq.serialize_element(&self.family_type)?; - seq.serialize_element(&self.serif_style)?; - seq.serialize_element(&self.weight)?; - seq.serialize_element(&self.proportion)?; - seq.serialize_element(&self.contrast)?; - seq.serialize_element(&self.stroke_variation)?; - seq.serialize_element(&self.arm_style)?; - seq.serialize_element(&self.letterform)?; - seq.serialize_element(&self.midline)?; - seq.serialize_element(&self.x_height)?; - seq.end() - } -} - -impl<'de> Deserialize<'de> for OS2PanoseV2 { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let values: Vec = Deserialize::deserialize(deserializer)?; - if values.len() != 10 { - return Err(serde::de::Error::custom( - "openTypeOS2Panose must have exactly ten elements.", - )); - } - - Ok(OS2PanoseV2 { - family_type: values[0], - serif_style: values[1], - weight: values[2], - proportion: values[3], - contrast: values[4], - stroke_variation: values[5], - arm_style: values[6], - letterform: values[7], - midline: values[8], - x_height: values[9], - }) - } -} - -/// Corresponds to postscriptWindowsCharacterSet in [PostScript Specific Data](http://unifiedfontobject.org/versions/ufo3/fontinfo.plist/#postscript-specific-data). -#[derive(Debug, Clone, Copy, Serialize_repr, Deserialize_repr, PartialEq)] -#[repr(u8)] -pub enum PostscriptWindowsCharacterSet { - ANSI = 1, - Default = 2, - Symbol = 3, - Macintosh = 4, - ShiftJIS = 5, - Hangul = 6, - HangulJohab = 7, - GB2312 = 8, - ChineseBIG5 = 9, - Greek = 10, - Turkish = 11, - Vietnamese = 12, - Hebrew = 13, - Arabic = 14, - Baltic = 15, - Bitstream = 16, - Cyrillic = 17, - Thai = 18, - EasternEuropean = 19, - OEM = 20, -} - -/// Corresponds to woffMetadataCopyright in [WOFF Data](http://unifiedfontobject.org/versions/ufo3/fontinfo.plist/#woff-data). -#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)] -pub struct WoffMetadataCopyright { - text: Vec, -} - -/// Corresponds to woffMetadataCredits in [WOFF Data](http://unifiedfontobject.org/versions/ufo3/fontinfo.plist/#woff-data). -#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)] -pub struct WoffMetadataCredits { - credits: Vec, -} - -#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)] -pub struct WoffMetadataCredit { - name: String, - url: Option, - role: Option, - dir: Option, - class: Option, -} - -/// Corresponds to woffMetadataDescription in [WOFF Data](http://unifiedfontobject.org/versions/ufo3/fontinfo.plist/#woff-data). -#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)] -pub struct WoffMetadataDescription { - url: Option, - text: Vec, -} - -#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)] -pub struct WoffMetadataTextRecord { - text: String, - language: Option, - dir: Option, - class: Option, -} - -#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)] -pub struct WoffMetadataExtensionRecord { - id: Option, - names: Vec, - items: Vec, -} - -#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)] -pub struct WoffMetadataExtensionNameRecord { - text: String, - language: Option, - dir: Option, - class: Option, -} - -#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)] -pub struct WoffMetadataExtensionItemRecord { - id: Option, // XXX: Spec does not specify if required, assume optional. - names: Vec, - values: Vec, -} - -#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)] -pub struct WoffMetadataExtensionValueRecord { - text: String, - language: Option, - dir: Option, - class: Option, -} - -/// Corresponds to woffMetadataLicense in [WOFF Data](http://unifiedfontobject.org/versions/ufo3/fontinfo.plist/#woff-data). -#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)] -pub struct WoffMetadataLicense { - url: Option, - id: Option, - text: Vec, -} - -/// Corresponds to woffMetadataLicensee in [WOFF Data](http://unifiedfontobject.org/versions/ufo3/fontinfo.plist/#woff-data). -#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)] -pub struct WoffMetadataLicensee { - name: String, - dir: Option, - class: Option, -} - -/// Corresponds to woffMetadataTrademark in [WOFF Data](http://unifiedfontobject.org/versions/ufo3/fontinfo.plist/#woff-data). -#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)] -pub struct WoffMetadataTrademark { - text: Vec, -} - -/// Corresponds to woffMetadataUniqueID in [WOFF Data](http://unifiedfontobject.org/versions/ufo3/fontinfo.plist/#woff-data). -#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)] -pub struct WoffMetadataUniqueID { - id: String, -} - -/// Corresponds to woffMetadataVendor in [WOFF Data](http://unifiedfontobject.org/versions/ufo3/fontinfo.plist/#woff-data). -#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)] -pub struct WoffMetadataVendor { - name: String, - url: String, - dir: Option, - class: Option, -} - -/// Corresponds to the writing direction attribute used in [WOFF Data](http://unifiedfontobject.org/versions/ufo3/fontinfo.plist/#woff-data). -/// If present, is either "ltr" or "rtl". -#[derive(Debug, Eq, PartialEq, Clone)] -pub enum WoffAttributeDirection { - LeftToRight, - RightToLeft, -} - -impl Serialize for WoffAttributeDirection { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - match self { - WoffAttributeDirection::LeftToRight => serializer.serialize_str(&"ltr"), - WoffAttributeDirection::RightToLeft => serializer.serialize_str(&"rtl"), - } - } -} - -impl<'de> Deserialize<'de> for WoffAttributeDirection { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let string = String::deserialize(deserializer)?; - match string.as_ref() { - "ltr" => Ok(WoffAttributeDirection::LeftToRight), - "rtl" => Ok(WoffAttributeDirection::RightToLeft), - _ => Err(serde::de::Error::custom("unknown value for the WOFF direction attribute.")), - } - } -} - -/// Corresponds to the styleMapStyleName in [Generic Identification Information](http://unifiedfontobject.org/versions/ufo3/fontinfo.plist/#generic-identification-information). -/// If present, is either "regular", "italic", "bold" or "bold italic". -#[derive(Debug, Eq, PartialEq, Clone)] -pub enum StyleMapStyle { - Regular, - Italic, - Bold, - BoldItalic, -} - -impl Serialize for StyleMapStyle { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - match self { - StyleMapStyle::Regular => serializer.serialize_str(&"regular"), - StyleMapStyle::Italic => serializer.serialize_str(&"italic"), - StyleMapStyle::Bold => serializer.serialize_str(&"bold"), - StyleMapStyle::BoldItalic => serializer.serialize_str(&"bold italic"), - } - } -} - -impl<'de> Deserialize<'de> for StyleMapStyle { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let string = String::deserialize(deserializer)?; - match string.as_ref() { - "regular" => Ok(StyleMapStyle::Regular), - "italic" => Ok(StyleMapStyle::Italic), - "bold" => Ok(StyleMapStyle::Bold), - "bold italic" => Ok(StyleMapStyle::BoldItalic), - _ => Err(serde::de::Error::custom("unknown value for styleMapStyleName.")), - } - } -} - -mod types { - use std::convert::TryFrom; - use std::f64; - use std::ops::Deref; - - use plist; - use serde::de::Deserializer; - use serde::ser::Serializer; - use serde::{Deserialize, Serialize}; - - use super::Error; - - pub type Integer = i32; - pub type NonNegativeInteger = u32; - pub type Float = f64; - pub type Bitlist = Vec; - - // impl TryFrom<&plist::Value> for Float { - // type Error = Error; - - // fn try_from(value: &plist::Value) -> Result { - // // XXX: Errors should be ConversionError or smth - // let v: f64 = match value { - // plist::Value::Integer(i) => match i.as_signed() { - // Some(i) => i as f64, - // None => Err(Error::ExpectedPositiveValue)?, - // }, - // plist::Value::Real(r) => *r, - // _ => Err(Error::ExpectedPositiveValue)?, - // }; - - // Ok(v) - // } - // } - - /// IntegerOrFloat represents a number that can be an integer or float. It should - /// serialize to an integer if it effectively represents one. - #[derive(Debug, Clone, Copy, PartialEq)] - pub struct IntegerOrFloat(f64); - - impl IntegerOrFloat { - pub fn new(value: f64) -> Self { - IntegerOrFloat(value) - } - - pub fn get(&self) -> f64 { - self.0 - } - - pub fn set(&mut self, value: f64) { - self.0 = value - } - - pub fn is_integer(&self) -> bool { - (self.0 - self.round()).abs() < std::f64::EPSILON - } - } - - impl Deref for IntegerOrFloat { - type Target = f64; - - fn deref(&self) -> &f64 { - &self.0 - } - } - - impl From for IntegerOrFloat { - fn from(value: i32) -> Self { - IntegerOrFloat(value as f64) - } - } - - impl From for IntegerOrFloat { - fn from(value: f64) -> Self { - IntegerOrFloat(value) - } - } - - impl TryFrom<&plist::Value> for IntegerOrFloat { - type Error = Error; - - fn try_from(value: &plist::Value) -> Result { - // XXX: Errors should be ConversionError or smth - let v: f64 = match value { - plist::Value::Integer(i) => match i.as_signed() { - Some(i) => i as f64, - None => Err(Error::ExpectedPositiveValue)?, - }, - plist::Value::Real(r) => *r, - _ => Err(Error::ExpectedPositiveValue)?, - }; - - Ok(IntegerOrFloat::new(v)) - } - } - - impl Serialize for IntegerOrFloat { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - if self.is_integer() { - serializer.serialize_i32(self.0 as i32) - } else { - serializer.serialize_f64(self.0) - } - } - } - - impl<'de> Deserialize<'de> for IntegerOrFloat { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let value: f64 = Deserialize::deserialize(deserializer)?; - Ok(IntegerOrFloat(value)) - } - } - - /// NonNegativeIntegerOrFloat represents a number that can be a NonNegative integer or float. - /// It should serialize to an integer if it effectively represents one. - #[derive(Debug, Clone, Copy, PartialEq)] - pub struct NonNegativeIntegerOrFloat(f64); - - impl NonNegativeIntegerOrFloat { - pub fn new(value: f64) -> Option { - if value.is_sign_positive() { - Some(NonNegativeIntegerOrFloat(value)) - } else { - None - } - } - - pub fn get(&self) -> f64 { - self.0 - } - - pub fn try_set(&mut self, value: f64) -> Result<(), Error> { - if value.is_sign_positive() { - self.0 = value; - Ok(()) - } else { - Err(Error::ExpectedPositiveValue) - } - } - - pub fn is_integer(&self) -> bool { - (self.0 - self.round()).abs() < std::f64::EPSILON - } - } - - impl Deref for NonNegativeIntegerOrFloat { - type Target = f64; - - fn deref(&self) -> &f64 { - &self.0 - } - } - - impl TryFrom for NonNegativeIntegerOrFloat { - type Error = Error; - - fn try_from(value: i32) -> Result { - match NonNegativeIntegerOrFloat::new(value as f64) { - Some(v) => Ok(v), - _ => Err(Error::ExpectedPositiveValue), - } - } - } - - impl TryFrom for NonNegativeIntegerOrFloat { - type Error = Error; - - fn try_from(value: f64) -> Result { - match NonNegativeIntegerOrFloat::new(value) { - Some(v) => Ok(v), - _ => Err(Error::ExpectedPositiveValue), - } - } - } - - impl TryFrom for NonNegativeIntegerOrFloat { - type Error = Error; - - fn try_from(value: IntegerOrFloat) -> Result { - match NonNegativeIntegerOrFloat::new(*value) { - Some(v) => Ok(v), - _ => Err(Error::ExpectedPositiveValue), - } - } - } - - impl Serialize for NonNegativeIntegerOrFloat { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - if self.is_integer() { - serializer.serialize_i32(self.0 as i32) - } else { - serializer.serialize_f64(self.0) - } - } - } - - impl<'de> Deserialize<'de> for NonNegativeIntegerOrFloat { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let value: f64 = Deserialize::deserialize(deserializer)?; - match NonNegativeIntegerOrFloat::try_from(value) { - Ok(v) => Ok(v), - Err(e) => Err(serde::de::Error::custom(e)), - } - } - } -} diff --git a/examples/plisttest.rs b/examples/plisttest.rs deleted file mode 100644 index 9f6e4383..00000000 --- a/examples/plisttest.rs +++ /dev/null @@ -1,120 +0,0 @@ -use std::collections::HashMap; -use std::ffi::OsStr; -use std::path::Path; -use std::path::PathBuf; - -use plist; -use plist::Dictionary; -use plist::Value; -#[macro_use] -extern crate serde_derive; - -use norad::IntegerOrFloat; - -fn main() -> Result<(), Error> { - let file_path = "testdata/fontinfotest_v1.ufo/lib.plist"; - let book: plist::Dictionary = plist::Value::from_file(file_path) - .expect("failed to read book.xml") - .into_dictionary() - .ok_or(Error::ExpectedPlistDictionaryError { file: file_path.into() })?; - - let ps_hinting_data_key = "org.robofab.postScriptHintData"; - let ps_hinting_data = book - .get(ps_hinting_data_key) - .expect("must have ps hinting data") - .as_dictionary() - .ok_or(Error::ExpectedPlistKeyToDictionaryError { key: ps_hinting_data_key.into() })?; - - println!( - "{:?}", - ps_hinting_data.get("blueFuzz").and_then(|v| v - .as_real() - .or_else(|| v.as_signed_integer().and_then(|v| Some(v as f64)))) - ); - println!("{:?}", ps_hinting_data.get("blueScale").and_then(|v| v.as_real())); - - // --- - - #[derive(Debug, Deserialize)] - struct LibData { - #[serde(rename = "org.robofab.postScriptHintData")] - ps_hinting_data: Option, - - #[serde(rename = "org.robofab.opentype.classes")] - feature_classes: Option, - #[serde(rename = "org.robofab.opentype.featureorder")] - feature_order: Option>, - #[serde(rename = "org.robofab.opentype.features")] - features: Option>, - } - - #[derive(Debug, Deserialize)] - #[serde(rename_all = "camelCase")] - struct PsHintingData { - blue_fuzz: Option, - blue_scale: Option, - blue_shift: Option, - blue_values: Option>>, - family_blues: Option>>, - family_other_blues: Option>>, - force_bold: Option, - other_blues: Option>>, - stem_snap_h: Option>, - stem_snap_v: Option>, - } - - let lib_data: LibData = - plist::from_file(file_path).map_err(|e| Error::Custom(format!("{}", e)))?; - - println!("{:?}", lib_data); - let ttt: Vec = - lib_data.ps_hinting_data.unwrap().blue_values.unwrap().into_iter().flatten().collect(); - println!("{:?}", ttt); - - // convert features - let mut feature_text = String::new(); - - if let Some(feature_classes) = lib_data.feature_classes { - feature_text.push_str(&feature_classes); - } - - if let Some(features) = lib_data.features { - let order: Vec = if let Some(feature_order) = lib_data.feature_order { - feature_order - } else { - features.keys().cloned().collect::>() - }; - - for key in order { - // Ignore non-existant keys because defcon does it, too. - if let Some(txt) = features.get(&key) { - feature_text.push_str(&txt); - } - } - } - - println!("{}", feature_text); - - Ok(()) -} - -#[derive(Debug)] -enum Error { - ExpectedPlistDictionaryError { file: String }, - ExpectedPlistKeyToDictionaryError { key: String }, - Custom(String), -} - -impl std::fmt::Display for Error { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match self { - Error::ExpectedPlistDictionaryError { file } => { - write!(f, "Expected file {} to contain a dictionary.", file) - } - Error::ExpectedPlistKeyToDictionaryError { key } => { - write!(f, "Expected the key {} to contain a dictionary.", key) - } - Error::Custom(s) => write!(f, "{}", s), - } - } -}