#![deny(missing_copy_implementations, missing_debug_implementations, missing_docs)]
#![no_std]
use core::ops::{Deref};
use tarrasque::*;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Fixed2_14(pub u16);
impl<'s> Extract<'s, ()> for Fixed2_14 {
#[inline]
fn extract(stream: &mut Stream<'s>, _: ()) -> ExtractResult<'s, Self> {
stream.extract(()).map(Fixed2_14)
}
}
impl Span for Fixed2_14 {
const SPAN: usize = 2;
}
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<'s> Extract<'s, ()> for Fixed16_16 {
#[inline]
fn extract(stream: &mut Stream<'s>, _: ()) -> ExtractResult<'s, Self> {
stream.extract(()).map(Fixed16_16)
}
}
impl Span for Fixed16_16 {
const SPAN: usize = 4;
}
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, Hash)]
pub struct Tag<'s>(pub &'s [u8]);
impl<'s> Extract<'s, ()> for Tag<'s> {
fn extract(stream: &mut Stream<'s>, _: ()) -> ExtractResult<'s, Self> {
stream.extract(4).map(Tag)
}
}
impl<'s> Span for Tag<'s> {
const SPAN: usize = 4;
}
impl<'s> Deref for Tag<'s> {
type Target = [u8];
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'s> PartialEq<&[u8]> for Tag<'s> {
fn eq(&self, other: &&[u8]) -> bool {
self.0 == *other
}
}
impl<'s> PartialEq<&[u8; 4]> for Tag<'s> {
fn eq(&self, other: &&[u8; 4]) -> bool {
self.0 == *other
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Timestamp(pub i64);
impl<'s> Extract<'s, ()> for Timestamp {
#[inline]
fn extract(stream: &mut Stream<'s>, _: ()) -> ExtractResult<'s, Self> {
stream.extract(()).map(Timestamp)
}
}
impl Span for Timestamp {
const SPAN: usize = 8;
}
extract! {
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Header[12] {
pub version: Fixed16_16 = [],
pub num_tables: u16 = [],
pub search_range: u16 = [],
pub entry_selector: u16 = [],
pub range_shift: u16 = [],
}
}
extract! {
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Record<'s>[16] {
pub tag: Tag<'s> = [],
pub checksum: u32 = [],
pub offset: u32 = [],
pub length: u32 = [],
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Sfnt<'s> {
pub bytes: &'s [u8],
pub header: Header,
pub records: View<'s, Record<'s>, ()>,
}
impl<'s> Sfnt<'s> {
#[inline]
pub fn parse(bytes: &'s [u8]) -> ExtractResult<Self> {
let mut stream = Stream(bytes);
let header: Header = stream.extract(())?;
let records = stream.extract((header.num_tables as usize, ()))?;
let size = size(&records);
if bytes.len() >= size {
Ok(Sfnt { bytes, header, records })
} else {
Err(ExtractError::Insufficient(size))
}
}
#[inline]
pub fn get(&self, record: Record) -> &'s [u8] {
let start = record.offset as usize;
let end = start + record.length as usize;
&self.bytes[start..end]
}
#[inline]
pub fn find(&self, tag: &[u8]) -> Option<(Record<'s>, &'s [u8])> {
let (index, _) = self.records.binary_search_bytes_by_key(&tag, |b| &b[..4])?;
let record = self.records.extract(index).unwrap();
Some((record, self.get(record)))
}
#[inline]
pub fn tables(self) -> TableIter<'s> {
let records = self.records.iter();
TableIter(self, records)
}
}
#[derive(Copy, Clone, Debug)]
pub struct TableIter<'s>(Sfnt<'s>, ViewIter<'s, Record<'s>, ()>);
impl<'s> Iterator for TableIter<'s> {
type Item = (Record<'s>, &'s [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<'s> DoubleEndedIterator for TableIter<'s> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.1.next_back().map(|r| (r, self.0.get(r)))
}
}
impl<'s> ExactSizeIterator for TableIter<'s> { }
#[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!(),
}
}
#[inline]
fn size<'s>(records: &View<'s, Record<'s>, ()>) -> usize {
(0..records.len()).map(|i| {
let bytes = records.get(i).unwrap();
let offset = be_u32(&bytes[8..12]);
let length = be_u32(&bytes[12..16]);
(offset + length) as usize
}).max().unwrap_or(0)
}