use datasize::DataSize;
use crate as pdf;
use crate::object::*;
use crate::primitive::*;
use crate::error::*;
use crate::parser::Lexer;
use crate::enc::{StreamFilter, decode};
use std::borrow::Cow;
use std::ops::{Deref, Range};
use std::fmt;
#[derive(Clone)]
pub (crate) enum StreamData {
Generated(Arc<[u8]>),
Original(Range<usize>, PlainRef),
}
datasize::non_dynamic_const_heap_size!(StreamData, std::mem::size_of::<StreamData>());
pub fn encode_text(s: &str) -> Vec<u8> {
if s.chars().all(|c| (32..127).contains(&(c as u32))) {
s.as_bytes().into()
} else {
let mut buf = Vec::with_capacity(2 * s.len() + 2);
buf.extend_from_slice(&(0xFE_FFu16.to_be_bytes()));
for cp in s.encode_utf16() {
buf.extend_from_slice(&cp.to_be_bytes());
}
buf
}
}
#[derive(Clone, DataSize)]
pub struct Stream<I> {
pub info: StreamInfo<I>,
pub (crate) inner_data: StreamData,
}
impl<I: Object> Stream<I> {
pub fn from_stream(s: PdfStream, resolve: &impl Resolve) -> Result<Self> {
let PdfStream {info, inner} = s;
let info = StreamInfo::<I>::from_primitive(Primitive::Dictionary (info), resolve)?;
let inner_data = match inner {
StreamInner::InFile { id, file_range } => StreamData::Original(file_range, id),
StreamInner::Pending { data } => StreamData::Generated(data)
};
Ok(Stream { info, inner_data })
}
pub fn new_with_filters(i: I, data: &[u8], filters: Vec<StreamFilter>) -> Result<Stream<I>> {
let mut data = Cow::Borrowed(data);
for f in &filters {
data = encode(&data, f)?.into();
}
Ok(Stream {
info: StreamInfo {
filters,
file: None,
file_filters: Vec::new(),
info: i
},
inner_data: StreamData::Generated(data.into()),
})
}
pub fn new(i: I, data: &[u8]) -> Result<Stream<I>> {
Stream::new_with_filters(i, data, vec![StreamFilter::FlateDecode(Default::default())])
}
pub fn from_compressed(i: I, data: impl Into<Arc<[u8]>>, filters: Vec<StreamFilter>) -> Stream<I> {
Stream {
info: StreamInfo {
filters: filters.clone(),
file: None,
file_filters: Vec::new(),
info: i
},
inner_data: StreamData::Generated(data.into()),
}
}
pub fn new_compressed(info: I, data: &[u8], encoding: StreamFilter) -> Result<Self> {
let data = encode(data, &encoding)?;
Ok(Self::from_compressed(info, data, vec![encoding]))
}
pub fn data(&self, resolve: &impl Resolve) -> Result<Arc<[u8]>> {
match self.inner_data {
StreamData::Generated(ref data) => {
let filters = &self.info.filters;
if filters.len() == 0 {
Ok(data.clone())
} else {
use std::borrow::Cow;
let mut data: Cow<[u8]> = (&**data).into();
for filter in filters {
data = t!(decode(&data, filter), filter).into();
}
Ok(data.into())
}
}
StreamData::Original(ref file_range, id) => {
resolve.get_data_or_decode(id, file_range.clone(), &self.info.filters)
}
}
}
pub fn len(&self) -> usize {
match self.inner_data {
StreamData::Generated(ref data) => data.len(),
StreamData::Original(ref range, _) => range.len()
}
}
}
impl<I: Object + fmt::Debug> fmt::Debug for Stream<I> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "Stream info={:?}, len={}", self.info.info, self.len())
}
}
impl<I: Object> Object for Stream<I> {
fn from_primitive(p: Primitive, resolve: &impl Resolve) -> Result<Self> {
let s = PdfStream::from_primitive(p, resolve)?;
Stream::from_stream(s, resolve)
}
}
impl<I: ObjectWrite> Stream<I> {
pub fn to_pdf_stream(&self, update: &mut impl Updater) -> Result<PdfStream> {
let mut info = match self.info.info.to_primitive(update)? {
Primitive::Dictionary(dict) => dict,
Primitive::Null => Dictionary::new(),
p => bail!("stream info has to be a dictionary (found {:?})", p)
};
let mut params = None;
if self.info.filters.len() > 0 {
for f in self.info.filters.iter() {
if let Some(para) = match f {
StreamFilter::LZWDecode(ref p) => Some(p.to_primitive(update)?),
StreamFilter::FlateDecode(ref p) => Some(p.to_primitive(update)?),
StreamFilter::DCTDecode(ref p) => Some(p.to_primitive(update)?),
StreamFilter::CCITTFaxDecode(ref p) => Some(p.to_primitive(update)?),
StreamFilter::JBIG2Decode(ref p) => Some(p.to_primitive(update)?),
_ => None
} {
assert!(params.is_none());
params = Some(para);
}
}
let mut filters = self.info.filters.iter().map(|filter| match filter {
StreamFilter::ASCIIHexDecode => "ASCIIHexDecode",
StreamFilter::ASCII85Decode => "ASCII85Decode",
StreamFilter::LZWDecode(ref _p) => "LZWDecode",
StreamFilter::FlateDecode(ref _p) => "FlateDecode",
StreamFilter::JPXDecode => "JPXDecode",
StreamFilter::DCTDecode(ref _p) => "DCTDecode",
StreamFilter::CCITTFaxDecode(ref _p) => "CCITTFaxDecode",
StreamFilter::JBIG2Decode(ref _p) => "JBIG2Decode",
StreamFilter::Crypt => "Crypt",
StreamFilter::RunLengthDecode => "RunLengthDecode",
})
.map(|s| Primitive::Name(s.into()));
match self.info.filters.len() {
0 => {},
1 => {
info.insert("Filter", filters.next().unwrap().to_primitive(update)?);
}
_ => {
info.insert("Filter", Primitive::array::<Primitive, _, _, _>(filters, update)?);
}
}
}
if let Some(para) = params {
info.insert("DecodeParms", para);
}
let inner = match self.inner_data {
StreamData::Generated(ref data) => {
info.insert("Length", Primitive::Integer(data.len() as _));
StreamInner::Pending { data: data.clone() }
},
StreamData::Original(ref file_range, id) => {
info.insert("Length", Primitive::Integer(file_range.len() as _));
StreamInner::InFile { id, file_range: file_range.clone() }
}
};
Ok(PdfStream { info, inner })
}
}
impl<I: ObjectWrite> ObjectWrite for Stream<I> {
fn to_primitive(&self, update: &mut impl Updater) -> Result<Primitive> {
match self.inner_data {
StreamData::Original(_, id) => Ok(Primitive::Reference(id)),
_ => self.to_pdf_stream(update).map(Primitive::Stream),
}
}
}
impl<I: DeepClone> DeepClone for Stream<I> {
fn deep_clone(&self, cloner: &mut impl Cloner) -> Result<Self> {
let data = match self.inner_data {
StreamData::Generated(ref data) => data.clone(),
StreamData::Original(ref range, id) => cloner.stream_data(id, range.clone())?
};
Ok(Stream {
info: self.info.deep_clone(cloner)?,
inner_data: StreamData::Generated(data),
})
}
}
impl<I: Object> Deref for Stream<I> {
type Target = StreamInfo<I>;
fn deref(&self) -> &StreamInfo<I> {
&self.info
}
}
#[derive(Debug, Clone, DataSize, DeepClone)]
pub struct StreamInfo<I> {
pub filters: Vec<StreamFilter>,
pub file: Option<FileSpec>,
pub file_filters: Vec<StreamFilter>,
pub info: I,
}
impl<I> Deref for StreamInfo<I> {
type Target = I;
fn deref(&self) -> &I {
&self.info
}
}
impl<I: Default> Default for StreamInfo<I> {
fn default() -> StreamInfo<I> {
StreamInfo {
filters: Vec::new(),
file: None,
file_filters: Vec::new(),
info: I::default(),
}
}
}
impl<T> StreamInfo<T> {
pub fn get_filters(&self) -> &[StreamFilter] {
&self.filters
}
}
impl<T: Object> Object for StreamInfo<T> {
fn from_primitive(p: Primitive, resolve: &impl Resolve) -> Result<Self> {
let mut dict = Dictionary::from_primitive(p, resolve)?;
let _length = usize::from_primitive(
dict.remove("Length").ok_or(PdfError::MissingEntry{ typ: "StreamInfo", field: "Length".into() })?,
resolve)?;
let filters = Vec::<Name>::from_primitive(
dict.remove("Filter").unwrap_or(Primitive::Null),
resolve)?;
let decode_params = Vec::<Option<Dictionary>>::from_primitive(
dict.remove("DecodeParms").unwrap_or(Primitive::Null),
resolve)?;
let file = Option::<FileSpec>::from_primitive(
dict.remove("F").unwrap_or(Primitive::Null),
resolve)?;
let file_filters = Vec::<Name>::from_primitive(
dict.remove("FFilter").unwrap_or(Primitive::Null),
resolve)?;
let file_decode_params = Vec::<Dictionary>::from_primitive(
dict.remove("FDecodeParms").unwrap_or(Primitive::Null),
resolve)?;
let mut new_filters = Vec::new();
let mut new_file_filters = Vec::new();
for (i, filter) in filters.iter().enumerate() {
let params = match decode_params.get(i) {
Some(Some(params)) => params.clone(),
_ => Dictionary::default(),
};
new_filters.push(StreamFilter::from_kind_and_params(filter, params, resolve)?);
}
for (i, filter) in file_filters.iter().enumerate() {
let params = match file_decode_params.get(i) {
Some(params) => params.clone(),
None => Dictionary::default(),
};
new_file_filters.push(StreamFilter::from_kind_and_params(filter, params, resolve)?);
}
Ok(StreamInfo {
filters: new_filters,
file,
file_filters: new_file_filters,
info: T::from_primitive(Primitive::Dictionary (dict), resolve)?,
})
}
}
#[derive(Object, Default, Debug, DataSize)]
#[pdf(Type = "ObjStm")]
pub struct ObjStmInfo {
#[pdf(key = "N")]
pub num_objects: usize,
#[pdf(key = "First")]
pub first: usize,
#[pdf(key = "Extends")]
pub extends: Option<Ref<Stream<()>>>,
}
#[derive(DataSize)]
pub struct ObjectStream {
offsets: Vec<usize>,
_id: ObjNr,
inner: Stream<ObjStmInfo>
}
impl Object for ObjectStream {
fn from_primitive(p: Primitive, resolve: &impl Resolve) -> Result<ObjectStream> {
let stream: Stream<ObjStmInfo> = Stream::from_primitive(p, resolve)?;
let mut offsets = Vec::new();
{
debug!("parsing stream");
let data = stream.data(resolve)?;
let mut lexer = Lexer::new(&data);
for _ in 0..(stream.info.num_objects as ObjNr) {
let _obj_nr = lexer.next()?.to::<ObjNr>()?;
let offset = lexer.next()?.to::<usize>()?;
offsets.push(offset);
}
}
Ok(ObjectStream {
offsets,
_id: 0, inner: stream
})
}
}
impl ObjectStream {
pub fn get_object_slice(&self, index: usize, resolve: &impl Resolve) -> Result<(Arc<[u8]>, Range<usize>)> {
if index >= self.offsets.len() {
err!(PdfError::ObjStmOutOfBounds {index, max: self.offsets.len()});
}
let start = self.inner.info.first + self.offsets[index];
let data = self.inner.data(resolve)?;
let end = if index == self.offsets.len() - 1 {
data.len()
} else {
self.inner.info.first + self.offsets[index + 1]
};
Ok((data, start..end))
}
pub fn n_objects(&self) -> usize {
self.offsets.len()
}
pub fn _data(&self, resolve: &impl Resolve) -> Result<Arc<[u8]>> {
self.inner.data(resolve)
}
}