use crate::cff::dict::DictionaryParser;
use crate::cff::index::{create_index, parse_index};
use crate::cff::number::{Number, StringId};
use crate::cff::remapper::SidRemapper;
use crate::cff::{Offsets, DUMMY_VALUE};
use crate::read::Reader;
use crate::write::Writer;
use crate::Error::SubsetError;
use crate::Result;
use std::array;
use std::ops::Range;
#[derive(Default, Debug, Clone)]
pub struct TopDictData {
pub charset: Option<usize>,
pub char_strings: Option<usize>,
pub private: Option<Range<usize>>,
pub fd_array: Option<usize>,
pub fd_select: Option<usize>,
pub notice: Option<StringId>,
pub copyright: Option<StringId>,
pub font_name: Option<StringId>,
pub has_ros: bool,
pub font_matrix: Option<[Number; 6]>,
pub font_bbox: Option<[Number; 4]>,
}
pub fn parse_top_dict_index(r: &mut Reader) -> Option<TopDictData> {
use super::operators::*;
let mut top_dict = TopDictData::default();
let index = parse_index::<u16>(r)?;
let data = index.get(0)?;
let mut operands_buffer: [Number; 48] = array::from_fn(|_| Number::zero());
let mut dict_parser = DictionaryParser::new(data, &mut operands_buffer);
while let Some(operator) = dict_parser.parse_next() {
match operator {
NOTICE => top_dict.notice = Some(dict_parser.parse_sid()?),
COPYRIGHT => top_dict.copyright = Some(dict_parser.parse_sid()?),
FONT_NAME => top_dict.font_name = Some(dict_parser.parse_sid()?),
CHARSET => top_dict.charset = Some(dict_parser.parse_offset()?),
ENCODING => {}
CHAR_STRINGS => top_dict.char_strings = Some(dict_parser.parse_offset()?),
PRIVATE => top_dict.private = Some(dict_parser.parse_range()?),
ROS => top_dict.has_ros = true,
FD_ARRAY => top_dict.fd_array = Some(dict_parser.parse_offset()?),
FD_SELECT => top_dict.fd_select = Some(dict_parser.parse_offset()?),
FONT_MATRIX => top_dict.font_matrix = Some(dict_parser.parse_font_matrix()?),
FONT_BBOX => top_dict.font_bbox = Some(dict_parser.parse_font_bbox()?),
_ => {}
}
}
Some(top_dict)
}
pub fn rewrite_top_dict_index(
top_dict_data: &TopDictData,
offsets: &mut Offsets,
sid_remapper: &SidRemapper,
w: &mut Writer,
) -> Result<()> {
use super::operators::*;
let mut sub_w = Writer::new();
sub_w
.write(Number::from_i32(sid_remapper.get(b"Adobe").ok_or(SubsetError)?.0 as i32));
sub_w.write(Number::from_i32(
sid_remapper.get(b"Identity").ok_or(SubsetError)?.0 as i32,
));
sub_w.write(Number::zero());
sub_w.write(ROS);
if let Some(copyright) =
top_dict_data.copyright.and_then(|s| sid_remapper.get_new_sid(s))
{
sub_w.write(Number::from_i32(copyright.0 as i32));
sub_w.write(COPYRIGHT);
}
if let Some(notice) = top_dict_data.notice.and_then(|s| sid_remapper.get_new_sid(s)) {
sub_w.write(Number::from_i32(notice.0 as i32));
sub_w.write(NOTICE);
}
if let Some(font_name) =
top_dict_data.font_name.and_then(|s| sid_remapper.get_new_sid(s))
{
sub_w.write(Number::from_i32(font_name.0 as i32));
sub_w.write(FONT_NAME);
}
sub_w.write(top_dict_data.font_matrix.as_ref().unwrap_or(&[
Number::from_f32(0.001),
Number::zero(),
Number::zero(),
Number::from_f32(0.001),
Number::zero(),
Number::zero(),
]));
sub_w.write(FONT_MATRIX);
sub_w.write(top_dict_data.font_bbox.as_ref().unwrap_or(&[
Number::zero(),
Number::zero(),
Number::zero(),
Number::zero(),
]));
sub_w.write(FONT_BBOX);
offsets.charset_offset.update_location(sub_w.len() + w.len());
DUMMY_VALUE.write_as_5_bytes(&mut sub_w);
sub_w.write(CHARSET);
offsets.char_strings_offset.update_location(sub_w.len() + w.len());
DUMMY_VALUE.write_as_5_bytes(&mut sub_w);
sub_w.write(CHAR_STRINGS);
sub_w.write(Number::from_i32(u16::MAX as i32));
sub_w.write(CID_COUNT);
offsets.fd_array_offset.update_location(sub_w.len() + w.len());
DUMMY_VALUE.write_as_5_bytes(&mut sub_w);
sub_w.write(FD_ARRAY);
offsets.fd_select_offset.update_location(sub_w.len() + w.len());
DUMMY_VALUE.write_as_5_bytes(&mut sub_w);
sub_w.write(FD_SELECT);
let finished = sub_w.finish();
let index = create_index(vec![finished])?;
offsets.charset_offset.adjust_location(index.header_size);
offsets.char_strings_offset.adjust_location(index.header_size);
offsets.fd_array_offset.adjust_location(index.header_size);
offsets.fd_select_offset.adjust_location(index.header_size);
w.write(index);
Ok(())
}