use crate::read::{Readable, Reader};
use crate::write::{Writeable, Writer};
use std::fmt::{Debug, Formatter};
const FLOAT_STACK_LEN: usize = 64;
const END_OF_FLOAT_FLAG: u8 = 0xf;
#[derive(Clone, Copy)]
pub struct RealNumber(f32);
impl Debug for RealNumber {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Clone, Default, Eq, Copy, PartialEq)]
pub struct IntegerNumber(pub i32);
impl Debug for IntegerNumber {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Clone, Copy)]
pub struct FixedNumber(i32);
impl Debug for FixedNumber {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl FixedNumber {
pub fn as_f32(&self) -> f32 {
self.0 as f32 / 65536.0
}
pub fn parse(r: &mut Reader<'_>) -> Option<Self> {
let b0 = r.read::<u8>()?;
if b0 != 255 {
return None;
}
let num = r.read::<i32>()?;
Some(FixedNumber(num))
}
}
impl Writeable for FixedNumber {
fn write(&self, w: &mut Writer) {
w.write::<u8>(255);
w.write(self.0);
}
}
impl RealNumber {
pub fn parse(r: &mut Reader) -> Option<RealNumber> {
let mut data = [0u8; FLOAT_STACK_LEN];
let mut idx = 0;
let b0 = r.read::<u8>()?;
if b0 != 30 {
return None;
}
loop {
let b1: u8 = r.read()?;
let nibble1 = b1 >> 4;
let nibble2 = b1 & 15;
if nibble1 == END_OF_FLOAT_FLAG {
break;
}
idx = parse_float_nibble(nibble1, idx, &mut data)?;
if nibble2 == END_OF_FLOAT_FLAG {
break;
}
idx = parse_float_nibble(nibble2, idx, &mut data)?;
}
let s = core::str::from_utf8(&data[..idx]).ok()?;
let n = s.parse().ok()?;
Some(RealNumber(n))
}
}
impl Writeable for RealNumber {
fn write(&self, w: &mut Writer) {
let mut nibbles = vec![];
let string_form = format!("{}", self.0);
let mut r = Reader::new(string_form.as_bytes());
while !r.at_end() {
let byte = r.read::<u8>().unwrap();
match byte {
b'0'..=b'9' => nibbles.push(byte - 48),
b'.' => nibbles.push(0xA),
b'-' => nibbles.push(0xE),
_ => unreachable!(),
}
}
nibbles.push(0xF);
if nibbles.len() % 2 != 0 {
nibbles.push(0xF);
}
w.write::<u8>(30);
for (first, second) in nibbles.chunks(2).map(|pair| (pair[0], pair[1])) {
let num = (first << 4) | second;
w.write(num);
}
}
}
impl IntegerNumber {
pub fn parse(r: &mut Reader<'_>) -> Option<IntegerNumber> {
let b0 = r.read::<u8>()?;
match b0 {
28 => Some(IntegerNumber(i32::from(r.read::<i16>()?))),
29 => Some(IntegerNumber(r.read::<i32>()?)),
32..=246 => {
let n = i32::from(b0) - 139;
Some(IntegerNumber(n))
}
247..=250 => {
let b1 = i32::from(r.read::<u8>()?);
let n = (i32::from(b0) - 247) * 256 + b1 + 108;
Some(IntegerNumber(n))
}
251..=254 => {
let b1 = i32::from(r.read::<u8>()?);
let n = -(i32::from(b0) - 251) * 256 - b1 - 108;
Some(IntegerNumber(n))
}
_ => None,
}
}
pub fn write_as_5_bytes(&self, w: &mut Writer) {
let bytes = self.0.to_be_bytes();
w.write([29, bytes[0], bytes[1], bytes[2], bytes[3]]);
}
}
impl Writeable for IntegerNumber {
fn write(&self, w: &mut Writer) {
if (-107..=107).contains(&self.0) {
let b0 = u8::try_from(self.0 + 139).unwrap();
w.write(b0);
} else if (108..=1131).contains(&self.0) {
let temp = self.0 - 108;
let b0 = u8::try_from(temp / 256 + 247).unwrap();
let b1 = u8::try_from(temp % 256).unwrap();
w.write([b0, b1]);
} else if (-1131..=-108).contains(&self.0) {
let temp = -self.0 - 108;
let b0 = u8::try_from(temp / 256 + 251).unwrap();
let b1 = u8::try_from(temp % 256).unwrap();
w.write([b0, b1])
} else if (-32768..=32767).contains(&self.0) {
let bytes = i16::try_from(self.0).unwrap().to_be_bytes();
w.write([28, bytes[0], bytes[1]])
} else {
self.write_as_5_bytes(w)
}
}
}
#[derive(Clone, Copy)]
pub enum Number {
Real(RealNumber),
Integer(IntegerNumber),
Fixed(FixedNumber),
}
impl Default for Number {
fn default() -> Self {
Number::zero()
}
}
impl Debug for Number {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.as_f64())
}
}
impl Writeable for Number {
fn write(&self, w: &mut Writer) {
match self {
Number::Real(real_num) => real_num.write(w),
Number::Integer(int_num) => int_num.write(w),
Number::Fixed(fixed_num) => fixed_num.write(w),
}
}
}
impl Number {
pub fn parse_cff_number(r: &mut Reader) -> Option<Number> {
Self::parse_number(r, false)
}
pub fn parse_char_string_number(r: &mut Reader) -> Option<Number> {
Self::parse_number(r, true)
}
fn parse_number(r: &mut Reader, charstring_num: bool) -> Option<Number> {
match r.peak::<u8>()? {
30 => Some(Number::Real(RealNumber::parse(r)?)),
255 => {
if charstring_num {
return Some(Number::Fixed(FixedNumber::parse(r)?));
}
None
}
_ => Some(Number::Integer(IntegerNumber::parse(r)?)),
}
}
pub fn from_i32(num: i32) -> Self {
Number::Integer(IntegerNumber(num))
}
pub fn from_f32(num: f32) -> Self {
Number::Real(RealNumber(num))
}
pub fn zero() -> Self {
Number::Integer(IntegerNumber(0))
}
pub fn one() -> Self {
Number::Integer(IntegerNumber(1))
}
pub fn as_f64(&self) -> f64 {
match self {
Number::Integer(int) => int.0 as f64,
Number::Real(real) => real.0 as f64,
Number::Fixed(fixed) => fixed.as_f32() as f64,
}
}
pub fn as_i32(&self) -> Option<i32> {
match self {
Number::Integer(int) => Some(int.0),
Number::Real(rn) => {
if rn.0.fract() == 0.0 {
Some(rn.0 as i32)
} else {
None
}
}
Number::Fixed(fixn) => {
let num = fixn.as_f32();
if num.fract() == 0.0 {
Some(num as i32)
} else {
None
}
}
}
}
pub fn as_u32(&self) -> Option<u32> {
u32::try_from(self.as_i32()?).ok()
}
pub fn combine(t1: [Self; 6], t2: [Self; 6]) -> [Self; 6] {
[
Number::from_f32(
(t1[0].as_f64() * t2[0].as_f64() + t1[2].as_f64() * t2[1].as_f64())
as f32,
),
Number::from_f32(
(t1[1].as_f64() * t2[0].as_f64() + t1[3].as_f64() * t2[1].as_f64())
as f32,
),
Number::from_f32(
(t1[0].as_f64() * t2[2].as_f64() + t1[2].as_f64() * t2[3].as_f64())
as f32,
),
Number::from_f32(
(t1[1].as_f64() * t2[2].as_f64() + t1[3].as_f64() * t2[3].as_f64())
as f32,
),
Number::from_f32(
(t1[0].as_f64() * t2[4].as_f64()
+ t1[2].as_f64() * t2[5].as_f64()
+ t1[4].as_f64()) as f32,
),
Number::from_f32(
(t1[1].as_f64() * t2[4].as_f64()
+ t1[3].as_f64() * t2[5].as_f64()
+ t1[5].as_f64()) as f32,
),
]
}
}
fn parse_float_nibble(nibble: u8, mut idx: usize, data: &mut [u8]) -> Option<usize> {
if idx == FLOAT_STACK_LEN {
return None;
}
match nibble {
0..=9 => {
data[idx] = b'0' + nibble;
}
10 => {
data[idx] = b'.';
}
11 => {
data[idx] = b'E';
}
12 => {
if idx + 1 == FLOAT_STACK_LEN {
return None;
}
data[idx] = b'E';
idx += 1;
data[idx] = b'-';
}
13 => {
return None;
}
14 => {
data[idx] = b'-';
}
_ => {
return None;
}
}
idx += 1;
Some(idx)
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Debug, Hash, Ord)]
pub struct StringId(pub u16);
impl StringId {
pub const STANDARD_STRING_LEN: u16 = 391;
pub fn is_standard_string(&self) -> bool {
self.0 < Self::STANDARD_STRING_LEN
}
}
impl Readable<'_> for StringId {
const SIZE: usize = u16::SIZE;
fn read(r: &mut Reader<'_>) -> Option<Self> {
Some(Self(r.read::<u16>()?))
}
}
impl Writeable for StringId {
fn write(&self, w: &mut Writer) {
w.write::<u16>(self.0)
}
}
impl From<u16> for StringId {
fn from(value: u16) -> Self {
Self(value)
}
}
#[derive(Clone, Copy, Debug)]
pub struct U24(pub u32);
impl U24 {
pub const MAX: u32 = 16777215;
}
impl Readable<'_> for U24 {
const SIZE: usize = 3;
fn read(r: &mut Reader<'_>) -> Option<Self> {
let data = r.read::<[u8; 3]>()?;
Some(U24(u32::from_be_bytes([0, data[0], data[1], data[2]])))
}
}
impl Writeable for U24 {
fn write(&self, w: &mut Writer) {
let data = self.0.to_be_bytes();
w.write::<[u8; 3]>([data[1], data[2], data[3]]);
}
}
#[cfg(test)]
mod tests {
use crate::cff::number::*;
use crate::read::Reader;
#[test]
fn u24() {
let nums = [0u32, 45, 345, 54045, 32849324, 16777215];
for num in nums {
let wrapped = U24(num);
let mut w = Writer::new();
w.write(wrapped);
let first = w.finish();
let mut r = Reader::new(&first);
let rewritten = r.read::<U24>().unwrap();
let mut w = Writer::new();
w.write(rewritten);
let second = w.finish();
assert_eq!(first, second);
}
}
#[test]
fn size1_roundtrip() {
let nums = [0, 1, -1, 93, 107, -107];
for num in nums {
let integer = IntegerNumber(num);
let mut w = Writer::new();
w.write(integer);
let buffer = w.finish();
let mut reader = Reader::new(&buffer);
let reparsed = IntegerNumber::parse(&mut reader).unwrap();
let mut w = Writer::new();
w.write(reparsed);
let bytes = w.finish();
assert_eq!(bytes.len(), 1);
assert_eq!(reparsed.0, num);
}
}
#[test]
fn size2_roundtrip() {
let nums = [108, -108, 255, -255, 349, -349, 845, -845, 1131, -1131];
for num in nums {
let integer = IntegerNumber(num);
let mut w = Writer::new();
w.write(integer);
let buffer = w.finish();
let mut reader = Reader::new(&buffer);
let reparsed = IntegerNumber::parse(&mut reader).unwrap();
let mut w = Writer::new();
w.write(reparsed);
let bytes = w.finish();
assert_eq!(bytes.len(), 2);
assert_eq!(reparsed.0, num);
}
}
#[test]
fn size3_roundtrip() {
let nums = [1132, -1132, 2450, -2450, 4096, -4096, 8965, -8965, 32767, -32768];
for num in nums {
let integer = IntegerNumber(num);
let mut w = Writer::new();
w.write(integer);
let buffer = w.finish();
let mut reader = Reader::new(&buffer);
let reparsed = IntegerNumber::parse(&mut reader).unwrap();
let mut w = Writer::new();
w.write(reparsed);
let bytes = w.finish();
assert_eq!(bytes.len(), 3);
assert_eq!(reparsed.0, num);
}
}
#[test]
fn size5_roundtrip() {
let nums = [32768, -32769, i32::MAX, i32::MIN];
for num in nums {
let integer = IntegerNumber(num);
let mut w = Writer::new();
w.write(integer);
let buffer = w.finish();
let mut reader = Reader::new(&buffer);
let reparsed = IntegerNumber::parse(&mut reader).unwrap();
let mut w = Writer::new();
w.write(reparsed);
let bytes = w.finish();
assert_eq!(bytes.len(), 5);
assert_eq!(reparsed.0, num);
}
}
#[test]
fn parse_float() {
let num = [0x1E, 0xE2, 0x49, 0x32, 0xA1, 0x2C, 0x2F];
let mut r = Reader::new(&num);
let real = RealNumber::parse(&mut r).unwrap();
assert_eq!(-249.3212, real.0);
}
#[test]
fn float_roundtrip() {
let nums = [0.58f32, -0.21, 3.98, 16.49, 159.18, 5906.2];
for num in nums {
let float = RealNumber(num);
let mut w = Writer::new();
w.write(float);
let buffer = w.finish();
let mut reader = Reader::new(&buffer);
let reparsed = RealNumber::parse(&mut reader).unwrap();
assert_eq!(reparsed.0, num);
}
}
#[test]
fn fixed() {
let num = [255u8, 154, 104, 120, 40];
let mut r = Reader::new(&num);
let parsed = FixedNumber::parse(&mut r).unwrap();
let mut w = Writer::new();
w.write(parsed);
assert_eq!(num, w.finish().as_ref());
}
}