pub mod language;
mod encoding;
mod name;
mod platform;
pub use encoding::EncodingID;
pub use language::LanguageID;
pub use name::NameID;
pub use platform::PlatformID;
use crate::Result;
#[derive(Clone, Debug)]
pub enum Names {
Format0(Names0),
Format1(Names1),
}
table! {
@position
@write
#[doc = "A naming table in format 0."]
pub Names0 {
format (u16), count (u16), offset (u16), records (Vec<Record>) |this, tape, _| { tape.take_given(this.count as usize)
},
data (Vec<u8>) |this, tape, position| {
tape.jump(position + this.offset as u64)?;
tape.take_bytes(measure(&this.records))
},
}
}
table! {
@position
@write
#[doc = "A naming table in format 1."]
pub Names1 {
format (u16), count (u16), offset (u16), records (Vec<Record>) |this, tape, _| { tape.take_given(this.count as usize)
},
language_tag_count (u16), language_tags (Vec<LanguageTag>) |this, tape, _| { tape.take_given(this.language_tag_count as usize)
},
data (Vec<u8>) |this, tape, position| {
tape.jump(position + this.offset as u64)?;
tape.take_bytes(measure(&this.records))
},
}
}
table! {
@write
#[doc = "A record of a naming table."]
#[derive(Copy)]
pub Record { platform_id (PlatformID), encoding_id (EncodingID), language_id (LanguageID) |this, tape| { tape.take_given(this.platform_id)
},
name_id (NameID), size (u16 ), offset (u16 ), }
}
table! {
@write
#[doc = "A language tag."]
#[derive(Copy)]
pub LanguageTag { size (u16), offset (u16), }
}
pub type Context = encoding::macintosh::Context;
impl Names {
pub fn iter(
&self,
) -> impl Iterator<Item = ((PlatformID, EncodingID, LanguageID, NameID), Option<String>)>
+ DoubleEndedIterator
+ '_ {
let (records, data) = match self {
Self::Format0(ref table) => (&table.records, &table.data),
Self::Format1(ref table) => (&table.records, &table.data),
};
records.iter().map(move |record| {
let offset = record.offset as usize;
let size = record.size as usize;
(
(
record.platform_id,
record.encoding_id,
record.language_id,
record.name_id,
),
decode(
record.platform_id,
record.encoding_id,
record.language_id,
&data[offset..(offset + size)],
),
)
})
}
pub fn from_iter<T, U, V, W>(
records: T,
language_tags: U,
context: &mut Context,
) -> Result<Self>
where
T: IntoIterator<Item = ((PlatformID, EncodingID, LanguageID, NameID), V)>,
U: IntoIterator<Item = W>,
V: AsRef<str>,
W: AsRef<str>,
{
let mut data = vec![];
let records = records
.into_iter()
.map(
|((platform_id, encoding_id, language_id, name_id), value)| {
let offset = data.len();
encode(
platform_id,
encoding_id,
language_id,
value.as_ref(),
&mut data,
context,
)?;
Ok(Record {
platform_id,
encoding_id,
language_id,
name_id,
size: (data.len() - offset) as _,
offset: offset as _,
})
},
)
.collect::<Result<Vec<_>>>()?;
let language_tags = language_tags
.into_iter()
.map(|value| {
let offset = data.len();
encoding::unicode::encode_utf16(value.as_ref(), &mut data);
LanguageTag {
size: (data.len() - offset) as _,
offset: offset as _,
}
})
.collect::<Vec<_>>();
let table = if language_tags.is_empty() {
Self::Format0(Names0 {
format: 0,
count: records.len() as _,
offset: (2 * (3 + records.len() * 6)) as _,
records,
data,
})
} else {
Self::Format1(Names1 {
format: 1,
count: records.len() as _,
offset: (2 * (3 + records.len() * 6 + 1 + language_tags.len() * 2)) as _,
records,
language_tag_count: language_tags.len() as _,
language_tags,
data,
})
};
Ok(table)
}
pub fn language_tags(&self) -> impl Iterator<Item = Option<String>> + DoubleEndedIterator + '_ {
let (records, data) = match self {
Self::Format0(ref table) => (&[][..], &table.data),
Self::Format1(ref table) => (&table.language_tags[..], &table.data),
};
records.iter().map(|record| {
let offset = record.offset as usize;
let size = record.size as usize;
encoding::unicode::decode_utf16(&data[offset..(offset + size)])
})
}
}
impl crate::value::Read for Names {
fn read<T: crate::tape::Read>(tape: &mut T) -> Result<Self> {
Ok(match tape.peek::<u16>()? {
0 => Self::Format0(tape.take()?),
1 => Self::Format1(tape.take()?),
_ => raise!("found an unknown format of the naming table"),
})
}
}
impl crate::value::Write for Names {
fn write<T: crate::tape::Write>(&self, tape: &mut T) -> Result<()> {
match self {
Self::Format0(value) => tape.give(value),
Self::Format1(value) => tape.give(value),
}
}
}
fn decode(
platform_id: PlatformID,
encoding_id: EncodingID,
language_id: LanguageID,
data: &[u8],
) -> Option<String> {
match platform_id {
PlatformID::Unicode => encoding::unicode::decode(data, encoding_id),
PlatformID::Macintosh => encoding::macintosh::decode(data, encoding_id, language_id),
PlatformID::Windows => encoding::windows::decode(data, encoding_id),
}
}
fn encode(
platform_id: PlatformID,
encoding_id: EncodingID,
language_id: LanguageID,
value: &str,
data: &mut Vec<u8>,
context: &mut encoding::macintosh::Context,
) -> Result<()> {
match platform_id {
PlatformID::Unicode => encoding::unicode::encode(value, encoding_id, data),
PlatformID::Macintosh => {
encoding::macintosh::encode(value, encoding_id, language_id, data, context)
}
PlatformID::Windows => encoding::windows::encode(value, encoding_id, data),
}
}
fn measure(records: &[Record]) -> usize {
let mut size = 0;
for record in records {
let end = record.offset + record.size;
if end > size {
size = end;
}
}
size as usize
}