Skip to content

Commit

Permalink
(CFF) Fix large tables parsing.
Browse files Browse the repository at this point in the history
Closes #104
  • Loading branch information
RazrFalcon committed Sep 28, 2022
1 parent 88aaffa commit c9e9637
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 19 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]
### Fixed
- (CFF) Fix large tables parsing.

## [0.16.0] - 2022-09-18
### Added
Expand Down
32 changes: 24 additions & 8 deletions src/tables/cff/cff1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,12 +178,12 @@ fn parse_top_dict(s: &mut Stream) -> Option<TopDict> {
let operands = dict_parser.operands();
if operands.len() == 6 {
top_dict.matrix = Matrix {
sx: operands[0],
ky: operands[1],
kx: operands[2],
sy: operands[3],
tx: operands[4],
ty: operands[5],
sx: operands[0] as f32,
ky: operands[1] as f32,
kx: operands[2] as f32,
sy: operands[3] as f32,
tx: operands[4] as f32,
ty: operands[5] as f32,
};
}
}
Expand All @@ -208,6 +208,22 @@ fn parse_top_dict(s: &mut Stream) -> Option<TopDict> {
mod tests {
use super::*;

#[test]
fn private_dict_size_overflow() {
let data = &[
0x00, 0x01, // count: 1
0x01, // offset size: 1
0x01, // index [0]: 1
0x0C, // index [1]: 14
0x1D, 0x7F, 0xFF, 0xFF, 0xFF, // length: i32::MAX
0x1D, 0x7F, 0xFF, 0xFF, 0xFF, // offset: i32::MAX
0x12 // operator: 18 (private)
];

let top_dict = parse_top_dict(&mut Stream::new(data)).unwrap();
assert_eq!(top_dict.private_dict_range, Some(2147483647..4294967294));
}

#[test]
fn private_dict_negative_char_strings_offset() {
let data = &[
Expand Down Expand Up @@ -271,9 +287,9 @@ fn parse_private_dict(data: &[u8]) -> PrivateDict {
if operator.get() == private_dict_operator::LOCAL_SUBROUTINES_OFFSET {
dict.local_subroutines_offset = dict_parser.parse_offset();
} else if operator.get() == private_dict_operator::DEFAULT_WIDTH {
dict.default_width = dict_parser.parse_number();
dict.default_width = dict_parser.parse_number().map(|n| n as f32);
} else if operator.get() == private_dict_operator::NOMINAL_WIDTH {
dict.nominal_width = dict_parser.parse_number();
dict.nominal_width = dict_parser.parse_number().map(|n| n as f32);
}
}

Expand Down
27 changes: 16 additions & 11 deletions src/tables/cff/dict.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,19 @@ pub struct DictionaryParser<'a> {
// Offset to the last operands start.
operands_offset: usize,
// Actual operands.
operands: &'a mut [f32],
//
// While CFF can contain only i32 and f32 values, we have to store operands as f64
// since f32 cannot represent the whole i32 range.
// Meaning we have a choice of storing operands as f64 or as enum of i32/f32.
// In both cases the type size would be 8 bytes, so it's easier to simply use f64.
operands: &'a mut [f64],
// An amount of operands in the `operands` array.
operands_len: u16,
}

impl<'a> DictionaryParser<'a> {
#[inline]
pub fn new(data: &'a [u8], operands_buffer: &'a mut [f32]) -> Self {
pub fn new(data: &'a [u8], operands_buffer: &'a mut [f64]) -> Self {
DictionaryParser {
data,
offset: 0,
Expand Down Expand Up @@ -101,12 +106,12 @@ impl<'a> DictionaryParser<'a> {
}

#[inline]
pub fn operands(&self) -> &[f32] {
pub fn operands(&self) -> &[f64] {
&self.operands[..usize::from(self.operands_len)]
}

#[inline]
pub fn parse_number(&mut self) -> Option<f32> {
pub fn parse_number(&mut self) -> Option<f64> {
self.parse_operands()?;
self.operands().get(0).cloned()
}
Expand Down Expand Up @@ -150,38 +155,38 @@ pub fn is_dict_one_byte_op(b: u8) -> bool {
}

// Adobe Technical Note #5177, Table 3 Operand Encoding
pub fn parse_number(b0: u8, s: &mut Stream) -> Option<f32> {
pub fn parse_number(b0: u8, s: &mut Stream) -> Option<f64> {
match b0 {
28 => {
let n = i32::from(s.read::<i16>()?);
Some(n as f32)
Some(f64::from(n))
}
29 => {
let n = s.read::<i32>()?;
Some(n as f32)
Some(f64::from(n))
}
30 => {
parse_float(s)
}
32..=246 => {
let n = i32::from(b0) - 139;
Some(n as f32)
Some(f64::from(n))
}
247..=250 => {
let b1 = i32::from(s.read::<u8>()?);
let n = (i32::from(b0) - 247) * 256 + b1 + 108;
Some(n as f32)
Some(f64::from(n))
}
251..=254 => {
let b1 = i32::from(s.read::<u8>()?);
let n = -(i32::from(b0) - 251) * 256 - b1 - 108;
Some(n as f32)
Some(f64::from(n))
}
_ => None,
}
}

fn parse_float(s: &mut Stream) -> Option<f32> {
fn parse_float(s: &mut Stream) -> Option<f64> {
let mut data = [0u8; FLOAT_STACK_LEN];
let mut idx = 0;

Expand Down

0 comments on commit c9e9637

Please sign in to comment.