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::*;
#[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),
}
#[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),
}
#[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),
}
#[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,
#[num_enum(catch_all)]
Unknown(u16),
}
#[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<StdEncoding> {
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,
}
}
}
#[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<u16> {
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<u16> { self.start_glyph()..=self.end_glyph() }
pub fn coverage(&self) -> RangeInclusive<u16> {
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<u16> {
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<u16> {
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<u16> {
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<Self, Self::Error> {
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)),
}
}
}
#[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<u16> {
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<Self, ReadError> {
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<LanguageSystem<'a>, 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<Option<LanguageSystem<'a>>, ReadError> {
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<Item = Result<LanguageSystem<'a>, 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<Self, Self::Error> {
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<LanguageSystem<'a>, 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<Self, ReadError> {
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<ScriptTable<'a>, 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<Option<ScriptTable<'a>>, ReadError> {
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<Item = Result<ScriptTable<'a>, 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<Self, Self::Error> {
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 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<u16> {
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<Self, ReadError> {
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); }
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<Feature<'a>, 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<Option<Feature<'a>>, ReadError> {
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<Item = Result<Feature<'a>, 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<Self, Self::Error> {
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(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<Primitive = u16> {
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<LookupFlag> { 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<S, S::Error> {
let offset = self.uint16(6 + index as usize) as usize;
self.data[offset..].try_into()
}
pub fn subtables(&self) -> impl ExactSizeIterator<Item = Result<S, S::Error>> + '_ {
(0..self.subtable_count()).map(|x| self.subtable(x))
}
}
impl<'a, T, S> LookupTable<'a, T, S> {
pub fn mark_filtering_set(&self) -> Option<u16> {
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<Primitive = u16>, 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<Self, Self::Error> {
Ok(Self { data: value, phantom: PhantomData })
}
}