#![deny(missing_copy_implementations, missing_debug_implementations, missing_docs)]
#![no_std]
#[macro_use]
extern crate tarrasque;
use tarrasque::{Extract, ExtractError, ExtractResult, Stream, View, ViewIter, be_u32};
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Fixed2_14(pub u16);
impl<'a> Extract<'a, ()> for Fixed2_14 {
#[inline]
fn extract(stream: &mut Stream<'a>, _: ()) -> ExtractResult<'a, Self> {
stream.extract(()).map(Fixed2_14)
}
}
impl Into<f32> for Fixed2_14 {
#[inline]
fn into(self) -> f32 {
f32::from(self.0) / 16384.0
}
}
impl Into<f64> for Fixed2_14 {
#[inline]
fn into(self) -> f64 {
f64::from(self.0) / 16384.0
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Fixed16_16(pub u32);
impl<'a> Extract<'a, ()> for Fixed16_16 {
#[inline]
fn extract(stream: &mut Stream<'a>, _: ()) -> ExtractResult<'a, Self> {
stream.extract(()).map(Fixed16_16)
}
}
impl Into<f32> for Fixed16_16 {
#[inline]
fn into(self) -> f32 {
Into::<f64>::into(self) as f32
}
}
impl Into<f64> for Fixed16_16 {
#[inline]
fn into(self) -> f64 {
f64::from(self.0) / 65536.0
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Timestamp(pub i64);
impl<'a> Extract<'a, ()> for Timestamp {
#[inline]
fn extract(stream: &mut Stream<'a>, _: ()) -> ExtractResult<'a, Self> {
stream.extract(()).map(Timestamp)
}
}
extract! {
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub Header[12] {
version: Fixed16_16 = ([extract]),
num_tables: u16 = ([extract]),
search_range: u16 = ([extract]),
entry_selector: u16 = ([extract]),
range_shift: u16 = ([extract]),
}
}
extract! {
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub Record<'a>[16] {
tag: &'a str = ([extract(4)]),
checksum: u32 = ([extract]),
offset: u32 = ([extract]),
length: u32 = ([extract]),
}
}
#[inline]
fn tail(bytes: &[u8]) -> usize {
let offset = be_u32(&bytes[8..12]);
let length = be_u32(&bytes[12..16]);
(offset + length) as usize
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Sfnt<'a> {
pub bytes: &'a [u8],
pub header: Header,
pub records: View<'a, Record<'a>, ()>,
}
impl<'a> Sfnt<'a> {
#[inline]
pub fn parse(bytes: &'a [u8]) -> ExtractResult<Self> {
let mut stream = Stream(bytes);
let header: Header = stream.extract(())?;
let records: View<Record, _> = stream.extract((header.num_tables as usize, ()))?;
let max = (0..records.len()).map(|i| tail(records.get(i).unwrap())).max().unwrap_or(0);
if bytes.len() >= max {
Ok(Sfnt { bytes, header, records })
} else {
Err(ExtractError::Insufficient(max - bytes.len()))
}
}
#[inline]
pub fn get(&self, record: Record) -> &'a [u8] {
let start = record.offset as usize;
let end = start + record.length as usize;
&self.bytes[start..end]
}
#[inline]
pub fn find(&self, tag: &str) -> Option<(Record<'a>, &'a [u8])> {
let index = self.records.binary_search_bytes_by_key(&tag.as_bytes(), |b| &b[..4]);
let record = index.map(|(i, _)| self.records.extract(i).unwrap());
record.map(|r| (r, self.get(r)))
}
#[inline]
pub fn iter(self) -> SfntIter<'a> {
let records = self.records.iter();
SfntIter(self, records)
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct SfntIter<'a>(Sfnt<'a>, ViewIter<'a, Record<'a>, ()>);
impl<'a> Iterator for SfntIter<'a> {
type Item = (Record<'a>, &'a [u8]);
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.1.size_hint()
}
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.1.next().map(|r| (r, self.0.get(r)))
}
}
impl<'a> DoubleEndedIterator for SfntIter<'a> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.1.next_back().map(|r| (r, self.0.get(r)))
}
}
impl<'a> ExactSizeIterator for SfntIter<'a> { }
#[inline]
pub fn checksum(bytes: &[u8]) -> u32 {
let (prefix, suffix) = bytes.split_at(bytes.len() - (bytes.len() % 4));
let prefix = prefix.chunks(4).map(be_u32).fold(0u32, |a, i| a.wrapping_add(i));
match *suffix {
[] => prefix,
[a] => prefix.wrapping_add(be_u32(&[a, 0, 0, 0])),
[a, b] => prefix.wrapping_add(be_u32(&[a, b, 0, 0])),
[a, b, c] => prefix.wrapping_add(be_u32(&[a, b, c, 0])),
_ => unreachable!(),
}
}