1use std::io::Read;
2
3use flate2::read::ZlibDecoder;
4
5use crate::error::{PdfError, PdfResult};
6use crate::types::{PdfStream, PdfValue};
7
8pub fn decode_stream(stream: &PdfStream) -> PdfResult<Vec<u8>> {
9 match stream.dict.get("Filter") {
10 None => Ok(stream.data.clone()),
11 Some(PdfValue::Name(name)) if name == "FlateDecode" => inflate(stream.data.as_slice()),
12 Some(PdfValue::Array(filters)) if filters.len() == 1 => match filters.first() {
13 Some(PdfValue::Name(name)) if name == "FlateDecode" => inflate(stream.data.as_slice()),
14 _ => Err(PdfError::Unsupported(
15 "only a single FlateDecode filter is supported".to_string(),
16 )),
17 },
18 Some(_) => Err(PdfError::Unsupported(
19 "unsupported stream filter configuration".to_string(),
20 )),
21 }
22}
23
24const MAX_DECOMPRESSED_SIZE: u64 = 256 * 1024 * 1024;
27
28fn inflate(data: &[u8]) -> PdfResult<Vec<u8>> {
29 let decoder = ZlibDecoder::new(data);
30 let mut output = Vec::new();
31 decoder
32 .take(MAX_DECOMPRESSED_SIZE + 1)
33 .read_to_end(&mut output)
34 .map_err(|error| PdfError::Corrupt(format!("failed to decode flate stream: {error}")))?;
35 if output.len() as u64 > MAX_DECOMPRESSED_SIZE {
36 return Err(PdfError::Corrupt(
37 "decompressed stream exceeds maximum allowed size".to_string(),
38 ));
39 }
40 Ok(output)
41}