use std::ops::RangeInclusive; use std::fmt::{ Debug, Formatter, Result as FmtResult }; use std::marker::PhantomData; use num_enum::{ FromPrimitive, IntoPrimitive }; use enumset::{ EnumSet, EnumSetType }; use bytemuck::{ Zeroable, Pod }; use mchr::str::Std as StdEncoding; use super::ReadError; use super::core::*; // Platform #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(FromPrimitive, IntoPrimitive)] #[repr(u16)] pub enum Platform { Unicode = 0, Macintosh = 1, Windows = 3, #[num_enum(catch_all)] Unknown(u16), } // Unicode #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[derive(FromPrimitive, IntoPrimitive)] #[repr(u16)] pub enum UnicodeVersion { Version1_0 = 0, Version1_1 = 1, Iso10646 = 2, Unicode2BmpOnly = 3, Unicode2 = 4, #[num_enum(catch_all)] Unknown(u16), } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[derive(FromPrimitive, IntoPrimitive)] #[repr(u16)] pub enum UnicodeLanguage { None = 0, #[num_enum(catch_all)] Unknown(u16), } // Macintosh #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[derive(FromPrimitive, IntoPrimitive)] #[repr(u16)] pub enum ScriptManagerCode { Roman = 0, Japanese = 1, TraditionalChinese = 2, Korean = 3, Arabic = 4, Hebrew = 5, Greek = 6, Russian = 7, RSymbol = 8, Devanagari = 9, Gurmukhi = 10, Gujarati = 11, Oriya = 12, Bengali = 13, Tamil = 14, Telugu = 15, Kannada = 16, Malayalam = 17, Sinhalese = 18, Burmese = 19, Khmer = 20, Thai = 21, Laotian = 22, Georgian = 23, Armenian = 24, SimplifiedChinese = 25, Tibetan = 26, Mongolian = 27, Geez = 28, Slavic = 29, Vietnamese = 30, Sindhi = 31, #[num_enum(catch_all)] Unknown(u16), } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[derive(FromPrimitive, IntoPrimitive)] #[repr(u16)] pub enum MacintoshLanguage { English = 0, French = 1, German = 2, Italian = 3, Dutch = 4, Swedish = 5, Spanish = 6, Danish = 7, Portuguese = 8, Norwegian = 9, Hebrew = 10, Japanese = 11, Arabic = 12, Finnish = 13, Greek = 14, Icelandic = 15, Maltese = 16, Turkish = 17, Croatian = 18, TraditionalChinese = 19, Urdu = 20, Hindi = 21, Thai = 22, Korean = 23, Lithuanian = 24, Polish = 25, Hungarian = 26, Estonian = 27, Latvian = 28, Sami = 29, Faroese = 30, FarsiPersian = 31, Russian = 32, SimplifiedChinese = 33, Flemish = 34, IrishGaelic = 35, Albanian = 36, Romanian = 37, Czech = 38, Slovak = 39, Slovenian = 40, Yiddish = 41, Serbian = 42, Macedonian = 43, Bulgarian = 44, Ukrainian = 45, Byelorussian = 46, Uzbek = 47, Kazakh = 48, AzerbaijaniCyrillic = 49, AzerbaijaniArabic = 50, Armenian = 51, Georgian = 52, Moldavian = 53, Kirghiz = 54, Tajiki = 55, Turkmen = 56, Mongolian = 57, MongolianCyrillic = 58, Pashto = 59, Kurdish = 60, Kashmiri = 61, Sindhi = 62, Tibetan = 63, Nepali = 64, Sanskrit = 65, Marathi = 66, Bengali = 67, Assamese = 68, Gujarati = 69, Punjabi = 70, Oriya = 71, Malayalam = 72, Kannada = 73, Tamil = 74, Telugu = 75, Sinhalese = 76, Burmese = 77, Khmer = 78, Lao = 79, Vietnamese = 80, Indonesian = 81, Tagalog = 82, MalayRoman = 83, MalayArabic = 84, Amharic = 85, Tigrinya = 86, Galla = 87, Somalia = 88, Swahili = 89, KinyarwandaRuanda = 90, Rundi = 91, NyanjaChewa = 92, Malagasy = 93, Esperanto = 94, Welsh = 128, Basque = 129, Catalan = 130, Latin = 131, Quechua = 132, Guarani = 133, Aymara = 134, Tatar = 135, Uighur = 136, Dzongkha = 137, JavaneseRoman = 138, SundaneseRoman = 139, Galician = 140, Afrikaans = 141, Breton = 142, Inuktitut = 143, ScottishGaelic = 144, ManxGaelic = 145, IrishGaelicWithDotAbove = 146, Tongan = 147, GreekPolytonic = 148, Greenlandic = 149, AzerbaijaniRoman = 150, #[num_enum(catch_all)] Unknown(u16), } // Windows #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[derive(FromPrimitive, IntoPrimitive)] #[repr(u16)] pub enum WindowsEncoding { Symbol = 0, UnicodeBmp = 1, ShiftJis = 2, Prc = 3, Big5 = 4, Wansung = 5, Johab = 6, UnicodeFullRepertoire = 10, #[num_enum(catch_all)] Unknown(u16), } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[derive(FromPrimitive, IntoPrimitive)] #[repr(u16)] pub enum WindowsLanguage { EnUs = 0x409, // TODO #[num_enum(catch_all)] Unknown(u16), } // Generic #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum PlatformEncoding { Unicode(UnicodeVersion), Macintosh(ScriptManagerCode), Windows(WindowsEncoding), Unknown(u16, u16), } impl PlatformEncoding { pub fn platform(&self) -> Platform { match self { Self::Unicode(_) => Platform::Unicode, Self::Macintosh(_) => Platform::Macintosh, Self::Windows(_) => Platform::Windows, Self::Unknown(x, _) => Platform::Unknown(*x), } } } impl From<(Platform, u16)> for PlatformEncoding { fn from(value: (Platform, u16)) -> Self { match value.0 { Platform::Unicode => Self::Unicode(value.1.into()), Platform::Macintosh => Self::Macintosh(value.1.into()), Platform::Windows => Self::Windows(value.1.into()), Platform::Unknown(x) => Self::Unknown(x, value.1), } } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum PlatformLanguage { Unicode(UnicodeLanguage), Macintosh(MacintoshLanguage), Windows(WindowsLanguage), Unknown(u16, u16), } impl PlatformLanguage { pub fn platform(&self) -> Platform { match self { Self::Unicode(_) => Platform::Unicode, Self::Macintosh(_) => Platform::Macintosh, Self::Windows(_) => Platform::Windows, Self::Unknown(x, _) => Platform::Unknown(*x), } } } impl From<(Platform, u16)> for PlatformLanguage { fn from(value: (Platform, u16)) -> Self { match value.0 { Platform::Unicode => Self::Unicode(value.1.into()), Platform::Macintosh => Self::Macintosh(value.1.into()), Platform::Windows => Self::Windows(value.1.into()), Platform::Unknown(x) => Self::Unknown(x, value.1), } } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum PlatformEncodingAndLanguage { Unicode(UnicodeVersion, UnicodeLanguage), Macintosh(ScriptManagerCode, MacintoshLanguage), Windows(WindowsEncoding, WindowsLanguage), Unknown(u16, u16, u16), } impl PlatformEncodingAndLanguage { pub fn platform(&self) -> Platform { match self { Self::Unicode(_, _) => Platform::Unicode, Self::Macintosh(_, _) => Platform::Macintosh, Self::Windows(_, _) => Platform::Windows, Self::Unknown(x, _, _) => Platform::Unknown(*x), } } pub fn encoding(&self) -> PlatformEncoding { match self { Self::Unicode(x, _) => PlatformEncoding::Unicode(*x), Self::Macintosh(x, _) => PlatformEncoding::Macintosh(*x), Self::Windows(x, _) => PlatformEncoding::Windows(*x), Self::Unknown(x, y, _) => PlatformEncoding::Unknown(*x, *y), } } pub fn language(&self) -> PlatformLanguage { match self { Self::Unicode(_, x) => PlatformLanguage::Unicode(*x), Self::Macintosh(_, x) => PlatformLanguage::Macintosh(*x), Self::Windows(_, x) => PlatformLanguage::Windows(*x), Self::Unknown(x, _, y) => PlatformLanguage::Unknown(*x, *y), } } } impl From<(Platform, u16, u16)> for PlatformEncodingAndLanguage { fn from(value: (Platform, u16, u16)) -> Self { match value.0 { Platform::Unicode => Self::Unicode(value.1.into(), value.2.into()), Platform::Macintosh => Self::Macintosh(value.1.into(), value.2.into()), Platform::Windows => Self::Windows(value.1.into(), value.2.into()), Platform::Unknown(x) => Self::Unknown(x, value.1, value.2), } } } impl From<(u16, u16, u16)> for PlatformEncodingAndLanguage { fn from(value: (u16, u16, u16)) -> Self { (Platform::from(value.0), value.1, value.2).into() } } impl From<(PlatformEncoding, u16)> for PlatformEncodingAndLanguage { fn from(value: (PlatformEncoding, u16)) -> Self { match value.0 { PlatformEncoding::Unicode(x) => Self::Unicode(x, value.1.into()), PlatformEncoding::Macintosh(x) => Self::Macintosh(x, value.1.into()), PlatformEncoding::Windows(x) => Self::Windows(x, value.1.into()), PlatformEncoding::Unknown(x, y) => Self::Unknown(x, y, value.1), } } } impl PlatformEncodingAndLanguage { pub fn character_encoding(&self) -> Option { match self { Self::Unicode(_, _) => Some(StdEncoding::Utf16BE), Self::Macintosh(ScriptManagerCode::Roman, _) => Some(StdEncoding::MacRoman), Self::Windows(WindowsEncoding::UnicodeBmp, _) => Some(StdEncoding::Utf16BE), Self::Windows(WindowsEncoding::UnicodeFullRepertoire, _) => Some(StdEncoding::Utf16BE), _ => None, } } } // Coverage Tables #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[derive(FromPrimitive, IntoPrimitive)] #[repr(u16)] pub enum CoverageTableFormat { Flat = 1, Ranges = 2, #[num_enum(catch_all)] Unknown(u16), } #[derive(Clone, Copy)] #[repr(transparent)] pub struct FlatCoverageTable<'a>(&'a [u8]); impl<'a> RandomAccess<'a> for FlatCoverageTable<'a> { fn bytes(&self) -> &'a [u8] { self.0 } } impl<'a> FlatCoverageTable<'a> { pub fn format(&self) -> CoverageTableFormat { self.uint16(0).into() } pub fn glyphs(&self) -> U16Array<'a> { self.uint16_array(4, self.uint16(2) as usize) } pub fn contains(&self, glyph: u16) -> bool { self.map(glyph).is_some() } pub fn map(&self, glyph: u16) -> Option { for (i, g) in self.glyphs().iter().enumerate() { if g == glyph { return Some(i as u16); } } None } } impl Debug for FlatCoverageTable<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.debug_struct("FlatCoverageTable") .field("glyphs", &self.glyphs()) .finish() } } #[derive(Clone, Copy, Zeroable, Pod)] #[repr(transparent)] pub struct RangeRecord([u8; 6]); impl<'a> RandomAccess<'a> for &'a RangeRecord { fn bytes(&self) -> &'a [u8] { &self.0 } } impl RangeRecord { pub fn start_glyph(&self) -> u16 { self.uint16(0) } pub fn end_glyph(&self) -> u16 { self.uint16(2) } pub fn start_coverage(&self) -> u16 { self.uint16(4) } pub fn glyphs(&self) -> RangeInclusive { self.start_glyph()..=self.end_glyph() } pub fn coverage(&self) -> RangeInclusive { let glyphs = self.glyphs(); let start = self.start_coverage(); let stop = start + glyphs.end() - glyphs.start(); start..=stop } pub fn contains(&self, glyph: u16) -> bool { let glyphs = self.glyphs(); glyph >= *glyphs.start() && glyph <= *glyphs.end() } pub fn map(&self, glyph: u16) -> Option { let glyphs = self.glyphs(); if glyph >= *glyphs.start() && glyph <= *glyphs.end() { Some(self.start_coverage() + glyph - *glyphs.start()) } else { None } } } impl Debug for RangeRecord { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.debug_struct("RangeRecord") .field("glyphs", &self.glyphs()) .field("coverage", &self.coverage()) .finish() } } #[derive(Clone, Copy)] #[repr(transparent)] pub struct RangesCoverageTable<'a>(&'a [u8]); impl<'a> RandomAccess<'a> for RangesCoverageTable<'a> { fn bytes(&self) -> &'a [u8] { self.0 } } impl<'a> RangesCoverageTable<'a> { pub fn format(&self) -> CoverageTableFormat { self.uint16(0).into() } pub fn ranges(&self) -> &'a [RangeRecord] { self.array(4, self.uint16(2) as usize) } pub fn contains(&self, glyph: u16) -> bool { self.map(glyph).is_some() } pub fn map(&self, glyph: u16) -> Option { for range in self.ranges() { if let Some(i) = range.map(glyph) { return Some(i); } } None } } impl Debug for RangesCoverageTable<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.debug_struct("RangesCoverageTable") .field("ranges", &self.ranges()) .finish() } } #[derive(Clone, Copy)] pub enum CoverageTable<'a> { Flat(FlatCoverageTable<'a>), Ranges(RangesCoverageTable<'a>), } impl<'a> RandomAccess<'a> for CoverageTable<'a> { fn bytes(&self) -> &'a [u8] { match self { Self::Flat(x) => x.bytes(), Self::Ranges(x) => x.bytes(), } } } impl<'a> CoverageTable<'a> { pub fn format(&self) -> CoverageTableFormat { self.uint16(0).into() } pub fn contains(&self, glyph: u16) -> bool { match self { Self::Flat(x) => x.contains(glyph), Self::Ranges(x) => x.contains(glyph), } } pub fn map(&self, glyph: u16) -> Option { match self { Self::Flat(x) => x.map(glyph), Self::Ranges(x) => x.map(glyph), } } } impl<'a> Debug for CoverageTable<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { match self { Self::Flat(x) => x.fmt(f), Self::Ranges(x) => x.fmt(f), } } } impl<'a> TryFrom<&'a [u8]> for CoverageTable<'a> { type Error = ReadError; fn try_from(data: &'a [u8]) -> Result { if data.len() < 4 { return Err(ReadError::UnexpectedEof); } let format: CoverageTableFormat = data.uint16(0).into(); match format { CoverageTableFormat::Flat => { let length = 4 + data.uint16(2) as usize * 2; if data.len() < length { return Err(ReadError::UnexpectedEof); } let data = &data[0..length]; Ok(Self::Flat(FlatCoverageTable(data))) }, CoverageTableFormat::Ranges => { let length = 4 + data.uint16(2) as usize * 6; if data.len() < length { return Err(ReadError::UnexpectedEof); } let data = &data[0..length]; Ok(Self::Ranges(RangesCoverageTable(data))) }, CoverageTableFormat::Unknown(x) => Err(ReadError::UnknownCoverageTableFormat(x)), } } } // Script List #[derive(Clone, Copy)] pub struct LanguageSystem<'a>(Option<&'a Tag>, &'a [u8]); impl<'a> RandomAccess<'a> for LanguageSystem<'a> { fn bytes(&self) -> &'a [u8] { self.1 } } impl<'a> LanguageSystem<'a> { pub fn tag(&self) -> Option<&'a Tag> { self.0 } pub fn required_feature(&self) -> Option { match self.uint16(2) { x @ 0..=0xFFFE => Some(x), 0xFFFF => None, } } pub fn optional_features(&self) -> U16Array<'a> { self.uint16_array(6, self.uint16(4) as usize) } } impl Debug for LanguageSystem<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.debug_struct("LanguageSystem") .field("tag", &self.tag()) .field("required_feature", &self.required_feature()) .field("optional_features", &self.optional_features()) .finish() } } impl<'a> LanguageSystem<'a> { pub fn try_from(tag: Option<&'a Tag>, data: &'a [u8]) -> Result { if data.len() < 6 { return Err(ReadError::UnexpectedEof); } let count = data.uint16(4); let size = count as usize * 2 + 6; if data.len() < size { return Err(ReadError::UnexpectedEof); } Ok(Self(tag, &data[0..size])) } } #[derive(Clone, Copy)] #[repr(transparent)] pub struct LanguageSystemList<'a>(&'a [u8]); impl<'a> RandomAccess<'a> for LanguageSystemList<'a> { fn bytes(&self) -> &'a [u8] { self.0 } } impl<'a> LanguageSystemList<'a> { pub fn len(&self) -> u16 { self.uint16(0) } pub fn is_empty(&self) -> bool { self.len() == 0 } pub fn get(&self, index: u16) -> Result, ReadError> { let offset = index as usize * 6 + 2; let tag = self.item(offset); let offset = self.uint16(offset + 4) as usize; if offset >= self.0.len() { return Err(ReadError::UnexpectedEof); } let data = &self.0[offset..]; LanguageSystem::try_from(Some(tag), data) } pub fn find(&self, find_tag: &[u8; 4]) -> Result>, ReadError> { // TODO binary search let find_tag = Tag::new(find_tag); let count = self.uint16(0); for index in 0..count { let offset = index as usize * 6 + 2; let tag = self.item(offset); if *tag == find_tag { let offset = self.uint16(offset + 4) as usize; if offset >= self.0.len() { return Err(ReadError::UnexpectedEof); } let data = &self.0[offset..]; return Ok(Some(LanguageSystem::try_from(Some(tag), data)?)); } } Ok(None) } pub fn iter(&self) -> impl ExactSizeIterator, ReadError>> + '_ { (0..self.len()).map(|x| self.get(x)) } } impl Debug for LanguageSystemList<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.debug_list() .entries(self.iter()) .finish() } } impl<'a> TryFrom<&'a [u8]> for LanguageSystemList<'a> { type Error = ReadError; fn try_from(data: &'a [u8]) -> Result { if data.len() < 2 { return Err(ReadError::UnexpectedEof); } let count = data.uint16(0); let min_size = count as usize * 6 + 2; if data.len() < min_size { return Err(ReadError::UnexpectedEof); } Ok(Self(data)) } } #[derive(Clone, Copy)] pub struct ScriptTable<'a>(&'a Tag, &'a [u8]); impl<'a> RandomAccess<'a> for ScriptTable<'a> { fn bytes(&self) -> &'a [u8] { self.1 } } impl<'a> ScriptTable<'a> { pub fn tag(&self) -> &'a Tag { self.0 } pub fn default_system(&self) -> Result, ReadError> { let offset = self.uint16(0) as usize; if offset >= self.1.len() { return Err(ReadError::UnexpectedEof); } let data = &self.1[offset..]; LanguageSystem::try_from(None, data) } pub fn additional_systems(&self) -> LanguageSystemList<'a> { LanguageSystemList(&self.1[2..]) } } impl Debug for ScriptTable<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.debug_struct("ScriptTable") .field("tag", &self.tag()) .field("default_system", &self.default_system()) .field("additional_systems", &self.additional_systems()) .finish() } } impl<'a> ScriptTable<'a> { pub fn try_from(tag: &'a Tag, data: &'a [u8]) -> Result { if data.len() < 4 { return Err(ReadError::UnexpectedEof); } let count = data.uint16(2); let min_size = count as usize * 6 + 4; if data.len() < min_size { return Err(ReadError::UnexpectedEof); } Ok(Self(tag, data)) } } #[derive(Clone, Copy)] #[repr(transparent)] pub struct ScriptList<'a>(&'a [u8]); impl<'a> RandomAccess<'a> for ScriptList<'a> { fn bytes(&self) -> &'a [u8] { self.0 } } impl<'a> ScriptList<'a> { pub fn len(&self) -> u16 { self.uint16(0) } pub fn is_empty(&self) -> bool { self.len() == 0 } pub fn get(&self, index: u16) -> Result, ReadError> { let offset = index as usize * 6 + 2; let tag = self.item(offset); let offset = self.uint16(offset + 4) as usize; if offset >= self.0.len() { return Err(ReadError::UnexpectedEof); } let data = &self.0[offset..]; ScriptTable::try_from(tag, data) } pub fn find(&self, find_tag: &[u8; 4]) -> Result>, ReadError> { // TODO binary search let find_tag = Tag::new(find_tag); let count = self.uint16(0); for index in 0..count { let offset = index as usize * 6 + 2; let tag = self.item(offset); if *tag == find_tag { let offset = self.uint16(offset + 4) as usize; if offset >= self.0.len() { return Err(ReadError::UnexpectedEof); } let data = &self.0[offset..]; return Ok(Some(ScriptTable::try_from(tag, data)?)); } } Ok(None) } pub fn iter(&self) -> impl ExactSizeIterator, ReadError>> + '_ { (0..self.len()).map(|x| self.get(x)) } } impl Debug for ScriptList<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.debug_list() .entries(self.iter()) .finish() } } impl<'a> TryFrom<&'a [u8]> for ScriptList<'a> { type Error = ReadError; fn try_from(data: &'a [u8]) -> Result { if data.len() < 2 { return Err(ReadError::UnexpectedEof); } let count = data.uint16(0); let min_size = count as usize * 6 + 2; if data.len() < min_size { return Err(ReadError::UnexpectedEof); } Ok(Self(data)) } } // Feature List #[derive(Clone, Copy)] pub struct Feature<'a>(&'a Tag, &'a [u8]); impl<'a> RandomAccess<'a> for Feature<'a> { fn bytes(&self) -> &'a [u8] { self.1 } } impl<'a> Feature<'a> { pub fn tag(&self) -> &'a Tag { self.0 } pub fn params_offset(&self) -> Option { match self.uint16(0) { 0 => None, x @ 1..=0xFFFF => Some(x), } } pub fn lookup_tables(&self) -> U16Array<'a> { self.uint16_array(4, self.uint16(2) as usize) } } impl Debug for Feature<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.debug_struct("Feature") .field("tag", &self.tag()) .field("params_offset", &self.params_offset()) .field("lookup_tables", &self.lookup_tables()) .finish() } } impl<'a> Feature<'a> { pub fn try_from(tag: &'a Tag, data: &'a [u8]) -> Result { if data.len() < 6 { return Err(ReadError::UnexpectedEof); } let count = data.uint16(2); let min_size = count as usize * 2 + 4; if data.len() < min_size { return Err(ReadError::UnexpectedEof); } // TODO check params_offset Ok(Self(tag, data)) } } #[derive(Clone, Copy)] #[repr(transparent)] pub struct FeatureList<'a>(&'a [u8]); impl<'a> RandomAccess<'a> for FeatureList<'a> { fn bytes(&self) -> &'a [u8] { self.0 } } impl<'a> FeatureList<'a> { pub fn len(&self) -> u16 { self.uint16(0) } pub fn is_empty(&self) -> bool { self.len() == 0 } pub fn get(&self, index: u16) -> Result, ReadError> { let offset = index as usize * 6 + 2; let tag = self.item(offset); let offset = self.uint16(offset + 4) as usize; if offset >= self.0.len() { return Err(ReadError::UnexpectedEof); } let data = &self.0[offset..]; Feature::try_from(tag, data) } pub fn find(&self, find_tag: &[u8; 4]) -> Result>, ReadError> { // TODO binary search let find_tag = Tag::new(find_tag); let count = self.uint16(0); for index in 0..count { let offset = index as usize * 6 + 2; let tag = self.item(offset); if *tag == find_tag { let offset = self.uint16(offset + 4) as usize; if offset >= self.0.len() { return Err(ReadError::UnexpectedEof); } let data = &self.0[offset..]; return Ok(Some(Feature::try_from(tag, data)?)); } } Ok(None) } pub fn iter(&self) -> impl ExactSizeIterator, ReadError>> + '_ { (0..self.len()).map(|x| self.get(x)) } } impl Debug for FeatureList<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.debug_list() .entries(self.iter()) .finish() } } impl<'a> TryFrom<&'a [u8]> for FeatureList<'a> { type Error = ReadError; fn try_from(data: &'a [u8]) -> Result { if data.len() < 2 { return Err(ReadError::UnexpectedEof); } let count = data.uint16(0); let min_size = count as usize * 6 + 2; if data.len() < min_size { return Err(ReadError::UnexpectedEof); } Ok(Self(data)) } } // Lookup List #[derive(EnumSetType, Debug)] #[repr(u8)] pub enum LookupFlag { RightToLeft = 0, IgnoreBaseGlyphs = 1, IgnoreLigatures = 2, IgnoreMarks = 3, UseMarkFilteringSet = 4, } pub struct LookupTable<'a, T, S> { data: &'a [u8], phantom: PhantomData<(T, S)>, } impl<'a, T, S> Clone for LookupTable<'a, T, S> { fn clone(&self) -> Self { *self } } impl<'a, T, S> Copy for LookupTable<'a, T, S> {} impl<'a, T, S> RandomAccess<'a> for LookupTable<'a, T, S> { fn bytes(&self) -> &'a [u8] { self.data } } impl<'a, T, S> LookupTable<'a, T, S> where T: FromPrimitive { pub fn r#type(&self) -> T { T::from_primitive(self.uint16(0)) } } impl<'a, T, S> LookupTable<'a, T, S> { pub fn mark_attachment_class(&self) -> u8 { self.uint8(2) } pub fn flags(&self) -> EnumSet { EnumSet::from_u8(self.uint8(3)) } } impl<'a, T, S> LookupTable<'a, T, S> where S: TryFrom<&'a [u8]> { pub fn subtable_count(&self) -> u16 { self.uint16(4) } pub fn subtable(&self, index: u16) -> Result { let offset = self.uint16(6 + index as usize) as usize; self.data[offset..].try_into() } pub fn subtables(&self) -> impl ExactSizeIterator> + '_ { (0..self.subtable_count()).map(|x| self.subtable(x)) } } impl<'a, T, S> LookupTable<'a, T, S> { pub fn mark_filtering_set(&self) -> Option { if self.flags().contains(LookupFlag::UseMarkFilteringSet) { Some(self.uint16(6 + self.uint16(4) as usize * 2)) } else { None } } } impl<'a, T, S> Debug for LookupTable<'a, T, S> where T: Debug + FromPrimitive, S: Debug + TryFrom<&'a [u8]>, S::Error: Debug { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { struct Subtables<'a, T, S>(LookupTable<'a, T, S>); impl<'a, T, S> Debug for Subtables<'a, T, S> where S: Debug + TryFrom<&'a [u8]>, S::Error: Debug { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.debug_list() .entries(self.0.subtables()) .finish() } } f.debug_struct("LookupTable") .field("type", &self.r#type()) .field("flags", &self.flags()) .field("mark_attachment_class", &self.mark_attachment_class()) .field("mark_filtering_set", &self.mark_filtering_set()) .field("subtables", &Subtables(*self)) .finish() } } impl<'a, E, T> TryFrom<&'a [u8]> for LookupTable<'a, E, T> { type Error = ReadError; fn try_from(value: &'a [u8]) -> Result { // TODO validate length Ok(Self { data: value, phantom: PhantomData }) } } /* #[derive(Clone, Copy)] #[repr(transparent)] pub struct LookupList<'a>(&'a [u8]); impl<'a> RandomAccess<'a> for LookupList<'a> { fn bytes(&self) -> &'a [u8] { self.0 } } impl<'a> LookupList<'a> { pub fn count(&self) -> u16 { self.uint16(0) } pub fn get(&self, index: u16) -> Result, LookupListError> { let offset = self.uint16(2 + index as usize * 2) as usize; if offset + 2 > self.0.len() { return Err(LookupListError::UnexpectedEof); } LookupTable::try_from(&self.0[offset..]) } pub fn iter(&self) -> impl ExactSizeIterator, LookupListError>> + '_ { (0..self.count()).map(|x| self.get(x)) } } impl Debug for LookupList<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.debug_list() .entries(self.iter()) .finish() } } */