use std::collections::HashMap;
use istring::SmallString;
use crate as pdf;
use crate::object::{Object, Resolve, ObjectWrite, DeepClone};
use crate::primitive::{Primitive, Dictionary};
use crate::error::{Result};
use datasize::DataSize;
#[derive(Debug, Clone, DataSize)]
pub struct Encoding {
pub base: BaseEncoding,
pub differences: HashMap<u32, SmallString>,
}
#[derive(Object, ObjectWrite, Debug, Clone, Eq, PartialEq, DataSize)]
pub enum BaseEncoding {
StandardEncoding,
SymbolEncoding,
MacRomanEncoding,
WinAnsiEncoding,
MacExpertEncoding,
#[pdf(name = "Identity-H")]
IdentityH,
None,
#[pdf(other)]
Other(String),
}
impl Object for Encoding {
fn from_primitive(p: Primitive, resolve: &impl Resolve) -> Result<Self> {
match p {
name @ Primitive::Name(_) => {
Ok(Encoding {
base: BaseEncoding::from_primitive(name, resolve)?,
differences: HashMap::new(),
})
}
Primitive::Dictionary(mut dict) => {
let base = match dict.remove("BaseEncoding") {
Some(p) => BaseEncoding::from_primitive(p, resolve)?,
None => BaseEncoding::None
};
let mut gid = 0;
let mut differences = HashMap::new();
if let Some(p) = dict.remove("Differences") {
for part in p.resolve(resolve)?.into_array()? {
match part {
Primitive::Integer(code) => {
gid = code as u32;
}
Primitive::Name(name) => {
differences.insert(gid, name);
gid += 1;
}
_ => bail!("Unknown part primitive in dictionary: {:?}", part),
}
}
}
Ok(Encoding { base, differences })
}
Primitive::Reference(r) => Self::from_primitive(resolve.resolve(r)?, resolve),
Primitive::Stream(s) => Self::from_primitive(Primitive::Dictionary(s.info), resolve),
_ => bail!("Unknown element: {:?}", p),
}
}
}
impl ObjectWrite for Encoding {
fn to_primitive(&self, update: &mut impl pdf::object::Updater) -> Result<Primitive> {
let base = self.base.to_primitive(update)?;
if self.differences.len() == 0 {
Ok(base)
} else {
let mut list = vec![];
let mut diff_list: Vec<_> = self.differences.iter().collect();
diff_list.sort();
let mut last = None;
for &(&gid, name) in diff_list.iter() {
if !last.map(|n| n + 1 == gid).unwrap_or(false) {
list.push(Primitive::Integer(gid as i32));
}
list.push(Primitive::Name(name.clone()));
last = Some(gid);
}
let mut dict = Dictionary::new();
dict.insert("BaseEncoding", base);
dict.insert("Differences", Primitive::Array(list));
Ok(Primitive::Dictionary(dict))
}
}
}
impl Encoding {
pub fn standard() -> Encoding {
Encoding {
base: BaseEncoding::StandardEncoding,
differences: HashMap::new()
}
}
}
impl DeepClone for Encoding {
fn deep_clone(&self, cloner: &mut impl pdf::object::Cloner) -> Result<Self> {
Ok(self.clone())
}
}