1use crate::crypto::DecryptionTarget;
4use crate::filter::Filter;
5use crate::object;
6use crate::object::Dict;
7use crate::object::Name;
8use crate::object::dict::keys::{DECODE_PARMS, DP, F, FILTER, IDENTITY, LENGTH, NAME, TYPE};
9use crate::object::{Array, ObjectIdentifier};
10use crate::object::{Object, ObjectLike, ObjectRefLike};
11use crate::reader::Reader;
12use crate::reader::{Readable, ReaderContext, ReaderExt, Skippable};
13use crate::trivia::is_white_space_character;
14use crate::util::find_needle;
15use alloc::borrow::Cow;
16use alloc::vec::Vec;
17use core::fmt::{Debug, Display, Formatter};
18use smallvec::SmallVec;
19
20struct FiltersAndParams<'a> {
21 filters: SmallVec<[Filter; 2]>,
22 params: SmallVec<[Dict<'a>; 2]>,
23}
24
25#[derive(Clone)]
27pub struct Stream<'a> {
28 dict: Dict<'a>,
29 data: &'a [u8],
30}
31
32impl PartialEq for Stream<'_> {
33 fn eq(&self, other: &Self) -> bool {
34 self.dict == other.dict && self.data == other.data
35 }
36}
37
38#[derive(Clone, PartialEq, Default)]
40pub struct ImageDecodeParams {
41 pub is_indexed: bool,
43 pub bpc: Option<u8>,
45 pub num_components: Option<u8>,
47 pub target_dimension: Option<(u32, u32)>,
51 pub width: u32,
53 pub height: u32,
55}
56
57impl<'a> Stream<'a> {
58 pub(crate) fn new(data: &'a [u8], dict: Dict<'a>) -> Self {
59 Self { dict, data }
60 }
61
62 fn filters_and_params(&self) -> FiltersAndParams<'a> {
63 let mut collected_filters = SmallVec::new();
64 let mut collected_params = SmallVec::new();
65
66 if let Some(filter) = self
67 .dict
68 .get::<Name<'_>>(F)
69 .or_else(|| self.dict.get::<Name<'_>>(FILTER))
70 .and_then(Filter::from_name)
71 {
72 let params = self
73 .dict
74 .get::<Dict<'_>>(DP)
75 .or_else(|| self.dict.get::<Dict<'_>>(DECODE_PARMS))
76 .unwrap_or_default();
77
78 collected_filters.push(filter);
79 collected_params.push(params);
80 } else if let Some(filters) = self
81 .dict
82 .get::<Array<'_>>(F)
83 .or_else(|| self.dict.get::<Array<'_>>(FILTER))
84 {
85 let filters = filters.iter::<Name<'_>>().map(Filter::from_name);
86 let mut params = self
87 .dict
88 .get::<Array<'_>>(DP)
89 .or_else(|| self.dict.get::<Array<'_>>(DECODE_PARMS))
90 .map(|a| a.iter::<Object<'_>>());
91
92 for filter in filters {
93 let params = params
94 .as_mut()
95 .and_then(|p| p.next())
96 .and_then(|p| p.into_dict())
97 .unwrap_or_default();
98
99 if let Some(filter) = filter {
100 collected_filters.push(filter);
101 collected_params.push(params);
102 }
103 }
104 }
105
106 FiltersAndParams {
107 filters: collected_filters,
108 params: collected_params,
109 }
110 }
111
112 pub fn raw_data(&self) -> Cow<'a, [u8]> {
116 let ctx = self.dict.ctx();
117
118 if ctx.xref().needs_decryption(ctx)
119 && self
120 .dict
121 .get::<object::String<'_>>(TYPE)
122 .map(|t| t.as_ref() != b"XRef")
123 .unwrap_or(true)
124 {
125 let crypt_filter = self.crypt_filter();
126 let target = match &crypt_filter {
127 Some(name) => DecryptionTarget::Named(name),
128 None => DecryptionTarget::Stream,
129 };
130
131 match self.dict.obj_id() {
132 Some(obj_id) => Cow::Owned(
133 ctx.xref()
134 .decrypt(obj_id, self.data, target)
135 .unwrap_or_default(),
137 ),
138 None => Cow::Borrowed(self.data),
140 }
141 } else {
142 Cow::Borrowed(self.data)
143 }
144 }
145
146 pub fn dict(&self) -> &Dict<'a> {
148 &self.dict
149 }
150
151 pub fn obj_id(&self) -> ObjectIdentifier {
153 self.dict.obj_id().unwrap_or_else(|| {
154 ObjectIdentifier::new(0, 0)
157 })
158 }
159
160 pub fn filters(&self) -> SmallVec<[Filter; 2]> {
162 self.filters_and_params().filters
163 }
164
165 pub fn decoded(&self) -> Result<Cow<'a, [u8]>, DecodeFailure> {
170 self.decoded_image(&ImageDecodeParams::default())
171 .map(|r| r.data)
172 }
173
174 pub fn decoded_data(&self) -> Result<Cow<'a, [u8]>, DecodeFailure> {
180 if self.filters().iter().any(|filter| {
181 matches!(
182 filter,
183 Filter::DctDecode
184 | Filter::JpxDecode
185 | Filter::Jbig2Decode
186 | Filter::CcittFaxDecode
187 )
188 }) {
189 return Err(DecodeFailure::ImageDecode);
190 }
191
192 self.decoded()
193 }
194
195 pub fn decoded_image(
198 &self,
199 image_params: &ImageDecodeParams,
200 ) -> Result<FilterResult<'a>, DecodeFailure> {
201 if matches!(
202 self.dict.get::<Object<'_>>(F),
203 Some(Object::String(_) | Object::Dict(_))
204 ) {
205 return Err(DecodeFailure::StreamDecode);
206 }
207
208 let data = self.raw_data();
209 let filters_and_params = self.filters_and_params();
210
211 let mut current: Option<FilterResult<'a>> = None;
212
213 for (i, (filter, params)) in filters_and_params
214 .filters
215 .iter()
216 .zip(filters_and_params.params.iter())
217 .enumerate()
218 {
219 if i == 0 && *filter == Filter::Crypt {
220 continue;
221 }
222
223 let new = filter.apply(
224 current.as_ref().map(|c| c.data.as_ref()).unwrap_or(&data),
225 params,
226 image_params,
227 )?;
228 current = Some(new);
229 }
230
231 Ok(current.unwrap_or(FilterResult {
232 data,
233 image_data: None,
234 }))
235 }
236
237 fn crypt_filter(&self) -> Option<Name<'a>> {
238 let FiltersAndParams { filters, params } = self.filters_and_params();
239
240 (filters.first() == Some(&Filter::Crypt)).then(|| {
241 params
242 .first()
243 .and_then(|params| params.get::<Name<'a>>(NAME))
244 .unwrap_or(Name::new_unescaped(IDENTITY))
245 })
246 }
247}
248
249impl Debug for Stream<'_> {
250 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
251 write!(f, "Stream (len: {:?})", self.data.len())
252 }
253}
254
255impl Display for Stream<'_> {
256 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
257 write!(f, "Stream (len: {})", self.data.len())
258 }
259}
260
261impl Skippable for Stream<'_> {
262 fn skip(_: &mut Reader<'_>, _: bool) -> Option<()> {
263 None
266 }
267}
268
269impl<'a> Readable<'a> for Stream<'a> {
270 fn read(r: &mut Reader<'a>, ctx: &ReaderContext<'a>) -> Option<Self> {
271 let dict = r.read_with_context::<Dict<'_>>(ctx)?;
272 let offset = r.offset();
273 parse_proper(r, &dict).or_else(|| {
274 r.jump(offset);
275 parse_fallback(r, &dict)
276 })
277 }
278}
279
280#[derive(Debug, Copy, Clone)]
281pub enum DecodeFailure {
283 ImageDecode,
285 StreamDecode,
287 Decryption,
289 Unknown,
291}
292
293#[derive(Debug, Copy, Clone)]
295pub enum ImageColorSpace {
296 Gray,
298 Rgb,
300 Cmyk,
302 Unknown(u8),
304}
305
306pub struct ImageData {
308 pub alpha: Option<Vec<u8>>,
310 pub color_space: Option<ImageColorSpace>,
312 pub bits_per_component: u8,
314 pub width: u32,
316 pub height: u32,
318}
319
320pub struct FilterResult<'a> {
322 pub data: Cow<'a, [u8]>,
324 pub image_data: Option<ImageData>,
326}
327
328impl FilterResult<'_> {
329 pub(crate) fn from_data(data: Vec<u8>) -> Self {
330 Self {
331 data: Cow::Owned(data),
332 image_data: None,
333 }
334 }
335}
336
337fn parse_proper<'a>(r: &mut Reader<'a>, dict: &Dict<'a>) -> Option<Stream<'a>> {
338 let length = dict.get::<u32>(LENGTH)?;
339
340 r.skip_white_spaces_and_comments();
341 r.forward_tag(b"stream")?;
342 r.forward_tag(b"\n")
343 .or_else(|| r.forward_tag(b"\r\n"))
344 .or_else(|| r.forward_tag(b"\r"))?;
345 let data = r.read_bytes(length as usize)?;
346 r.skip_white_spaces();
347 r.forward_tag(b"endstream")?;
348
349 Some(Stream::new(data, dict.clone()))
350}
351
352fn parse_fallback<'a>(r: &mut Reader<'a>, dict: &Dict<'a>) -> Option<Stream<'a>> {
353 r.skip_white_spaces_and_comments();
354 r.forward_tag(b"stream")?;
355
356 r.forward_tag(b"\n")
357 .or_else(|| r.forward_tag(b"\r\n"))
358 .or_else(|| r.forward_tag(b"\r"))?;
360
361 let tail = r.tail()?;
364 let endstream_offset = find_needle(tail, b"endstream")?;
365 let data_end = trim_trailing_ascii_whitespace(&tail[..endstream_offset]);
366 let data = tail.get(..data_end)?;
367
368 r.read_bytes(endstream_offset)?;
369 r.skip_white_spaces();
370 r.forward_tag(b"endstream")?;
371
372 Some(Stream::new(data, dict.clone()))
373}
374
375fn trim_trailing_ascii_whitespace(data: &[u8]) -> usize {
376 let mut end = data.len();
377
378 while data
379 .get(end.wrapping_sub(1))
380 .copied()
381 .is_some_and(is_white_space_character)
382 {
383 end -= 1;
384 }
385
386 end
387}
388
389impl<'a> TryFrom<Object<'a>> for Stream<'a> {
390 type Error = ();
391
392 fn try_from(value: Object<'a>) -> Result<Self, Self::Error> {
393 match value {
394 Object::Stream(s) => Ok(s),
395 _ => Err(()),
396 }
397 }
398}
399
400impl<'a> ObjectLike<'a> for Stream<'a> {}
401impl<'a> ObjectRefLike<'a> for Stream<'a> {
402 fn cast_ref<'b>(obj: &'b Object<'a>) -> Option<&'b Self> {
403 match obj {
404 Object::Stream(stream) => Some(stream),
405 _ => None,
406 }
407 }
408}
409
410#[cfg(test)]
411mod tests {
412 use crate::object::Stream;
413 use crate::reader::Reader;
414 use crate::reader::{ReaderContext, ReaderExt};
415
416 #[test]
417 fn display() {
418 let mut reader = Reader::new(b"<< /Length 3 >> stream\nabc\nendstream");
419 let stream = reader
420 .read_with_context::<Stream<'_>>(&ReaderContext::dummy())
421 .unwrap();
422
423 assert_eq!(format!("{stream}"), "Stream (len: 3)");
424 }
425
426 #[test]
427 fn stream() {
428 let data = b"<< /Length 10 >> stream\nabcdefghij\nendstream";
429 let mut r = Reader::new(data);
430 let stream = r
431 .read_with_context::<Stream<'_>>(&ReaderContext::dummy())
432 .unwrap();
433
434 assert_eq!(stream.data, b"abcdefghij");
435 }
436
437 #[test]
438 fn stream_fallback() {
439 let data = b"<< /Length 999 >> stream\nabcdefghij\nendstream";
440 let mut r = Reader::new(data);
441 let stream = r
442 .read_with_context::<Stream<'_>>(&ReaderContext::dummy())
443 .unwrap();
444
445 assert_eq!(stream.data, b"abcdefghij");
446 }
447
448 #[test]
449 fn stream_with_external_file() {
450 let data = b"<< /Length 3 /F (data.bin) >> stream\nabc\nendstream";
451 let mut r = Reader::new(data);
452 let stream = r
453 .read_with_context::<Stream<'_>>(&ReaderContext::dummy())
454 .unwrap();
455
456 assert_eq!(stream.data, b"abc");
457 assert!(stream.dict().contains_key(crate::object::dict::keys::F));
458 assert!(stream.decoded().is_err());
459 }
460
461 #[test]
462 fn inline_filter_abbreviation_still_decodes() {
463 let mut r = Reader::new(b"<< /F /AHx >>");
464 let dict = r
465 .read_with_context::<crate::object::Dict<'_>>(&ReaderContext::dummy())
466 .unwrap();
467 let stream = Stream::new(b"41>", dict);
468
469 assert_eq!(stream.decoded().unwrap().as_ref(), b"A");
470 }
471}