use crate::tag::Tag;
use crate::Result;
table! {
@write
#[doc = "An offset table."]
pub Offsets {
header (Header),
records (Vec<Record>) |this, tape| {
tape.take_given(this.header.table_count as usize)
},
}
}
table! {
@write
#[doc = "The header of an offset table."]
#[derive(Copy)]
pub Header {
version (u32) |_, tape| { let value = tape.take()?;
if !Header::accept(&value) {
raise!("found an unknown font format");
}
Ok(value.into())
},
table_count (u16), search_range (u16), entry_selector (u16), range_shift (u16), }
}
table! {
@write
#[doc = "A record of an offset table."]
#[derive(Copy)]
pub Record {
tag (Tag), checksum (u32), offset (u32), size (u32), }
}
dereference! { Offsets::records => [Record] }
impl Header {
#[inline]
pub fn accept(tag: &Tag) -> bool {
matches!(&tag.0, [0, 1, 0, 0] | b"OTTO" | b"true" | b"typ1")
}
}
impl Record {
pub fn checksum<T: crate::tape::Read>(&self, tape: &mut T) -> Result<u32> {
let head = self.tag.0 == *b"head";
let count = ((self.size + 4 - 1) & !(4 - 1)) / 4;
let excess = 4 * count - self.size;
debug_assert!(excess < 4);
tape.jump(self.offset as u64)?;
let mut total: u32 = 0;
for i in 0..count {
let mut value: u32 = tape.take()?;
if i + 1 == count {
value &= !((1u32 << (8 * excess)) - 1);
}
if !head || i != 2 {
total = total.wrapping_add(value);
}
}
Ok(total)
}
}
#[cfg(test)]
mod tests {
use std::io::Cursor;
use super::Record;
use crate::Tag;
macro_rules! ok(($result:expr) => ($result.unwrap()));
#[test]
fn record_checksum() {
macro_rules! checksum(
($size:expr, $checksum:expr, $data:expr,) => ({
let data: &[u8] = $data;
let mut reader = Cursor::new(data);
let table = Record {
tag: Tag(*b"true"),
size: $size,
offset: 0,
checksum: $checksum,
};
table.checksum == ok!(table.checksum(&mut reader))
})
);
assert!(!checksum!(
3 * 4,
1 + 2 + 4,
&[0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3],
));
assert!(checksum!(
3 * 4,
1 + 2 + 3,
&[0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3],
));
}
}