1use super::objects::{PdfDictionary, PdfObject};
12use super::{ParseError, ParseOptions, ParseResult};
13
14#[cfg(feature = "compression")]
15use flate2::read::ZlibDecoder;
16use std::io::Read;
17
18const MAX_DECOMPRESSED_SIZE: usize = 256 * 1024 * 1024;
27
28const MAX_COMPRESSION_RATIO: usize = 1000;
39
40const RATIO_GUARD_MIN_OUTPUT: usize = 64 * 1024 * 1024;
50
51fn read_to_end_limited<R: Read>(reader: &mut R, max_bytes: usize) -> std::io::Result<Vec<u8>> {
56 let mut result = Vec::new();
57 let mut buffer = [0u8; 16384];
58
59 loop {
60 match reader.read(&mut buffer) {
61 Ok(0) => break,
62 Ok(n) => {
63 if result.len() + n > max_bytes {
64 return Err(std::io::Error::new(
65 std::io::ErrorKind::Other,
66 format!(
67 "Decompressed size exceeds limit of {} bytes ({} MB). \
68 Possible decompression bomb.",
69 max_bytes,
70 max_bytes / (1024 * 1024)
71 ),
72 ));
73 }
74 result.extend_from_slice(&buffer[..n]);
75 }
76 Err(e) => return Err(e),
77 }
78 }
79
80 Ok(result)
81}
82
83fn check_compression_ratio(input_size: usize, output_size: usize) -> Result<(), std::io::Error> {
88 if output_size > RATIO_GUARD_MIN_OUTPUT
92 && input_size > 0
93 && output_size / input_size > MAX_COMPRESSION_RATIO
94 {
95 return Err(std::io::Error::new(
96 std::io::ErrorKind::Other,
97 format!(
98 "Suspicious compression ratio {}:1 (input={}B, output={}B). \
99 Max allowed ratio is {}:1.",
100 output_size / input_size,
101 input_size,
102 output_size,
103 MAX_COMPRESSION_RATIO
104 ),
105 ));
106 }
107 Ok(())
108}
109
110use super::filter_impls::ccitt::decode_ccitt;
112use super::filter_impls::dct::decode_dct;
113use super::filter_impls::jbig2::decode_jbig2;
114pub use super::filter_impls::ccitt::decode_ccitt as decode_ccitt_public;
116pub use super::filter_impls::dct::{parse_jpeg_info, JpegColorSpace, JpegInfo};
117pub use super::filter_impls::jbig2::decode_jbig2 as decode_jbig2_public;
118
119#[derive(Debug, Clone, PartialEq)]
121pub enum Filter {
122 ASCIIHexDecode,
124
125 ASCII85Decode,
127
128 LZWDecode,
130
131 FlateDecode,
133
134 RunLengthDecode,
136
137 CCITTFaxDecode,
139
140 JBIG2Decode,
142
143 DCTDecode,
145
146 JPXDecode,
148
149 Crypt,
151}
152
153impl Filter {
154 pub fn from_name(name: &str) -> Option<Self> {
156 match name {
157 "ASCIIHexDecode" => Some(Filter::ASCIIHexDecode),
158 "ASCII85Decode" => Some(Filter::ASCII85Decode),
159 "LZWDecode" => Some(Filter::LZWDecode),
160 "FlateDecode" => Some(Filter::FlateDecode),
161 "RunLengthDecode" => Some(Filter::RunLengthDecode),
162 "CCITTFaxDecode" => Some(Filter::CCITTFaxDecode),
163 "JBIG2Decode" => Some(Filter::JBIG2Decode),
164 "DCTDecode" => Some(Filter::DCTDecode),
165 "JPXDecode" => Some(Filter::JPXDecode),
166 "Crypt" => Some(Filter::Crypt),
167 _ => None,
168 }
169 }
170}
171
172pub fn decode_stream(
174 data: &[u8],
175 dict: &PdfDictionary,
176 _options: &ParseOptions,
177) -> ParseResult<Vec<u8>> {
178 let filters = match dict.get("Filter") {
180 Some(PdfObject::Name(name)) => vec![name.as_str()],
181 Some(PdfObject::Array(array)) => {
182 let mut filter_names = Vec::new();
183 for obj in &array.0 {
184 if let PdfObject::Name(name) = obj {
185 filter_names.push(name.as_str());
186 } else {
187 return Err(ParseError::SyntaxError {
188 position: 0,
189 message: "Invalid filter in array".to_string(),
190 });
191 }
192 }
193 filter_names
194 }
195 None => {
196 return Ok(data.to_vec());
198 }
199 _ => {
200 return Err(ParseError::SyntaxError {
201 position: 0,
202 message: "Invalid Filter type".to_string(),
203 });
204 }
205 };
206
207 let decode_params = dict.get("DecodeParms");
209
210 let mut result = data.to_vec();
212 for (i, filter_name) in filters.iter().enumerate() {
213 let filter = Filter::from_name(filter_name).ok_or_else(|| ParseError::SyntaxError {
214 position: 0,
215 message: format!("Unknown filter: {filter_name}"),
216 })?;
217
218 let filter_params = get_filter_params(decode_params, i);
220
221 result = apply_filter_with_params(&result, filter, filter_params)?;
222 }
223
224 Ok(result)
225}
226
227#[allow(dead_code)]
229pub(crate) fn apply_filter(data: &[u8], filter: Filter) -> ParseResult<Vec<u8>> {
230 match filter {
231 Filter::FlateDecode => decode_flate(data),
232 Filter::ASCIIHexDecode => decode_ascii_hex(data),
233 Filter::ASCII85Decode => decode_ascii85(data),
234 Filter::LZWDecode => decode_lzw(data, None),
235 Filter::RunLengthDecode => decode_run_length(data),
236 Filter::CCITTFaxDecode => decode_ccitt(data, None),
237 Filter::JBIG2Decode => decode_jbig2(data, None),
238 Filter::DCTDecode => decode_dct(data),
239 _ => Err(ParseError::SyntaxError {
240 position: 0,
241 message: format!("Filter {filter:?} not yet implemented"),
242 }),
243 }
244}
245
246#[cfg(feature = "compression")]
248fn decode_flate(data: &[u8]) -> ParseResult<Vec<u8>> {
249 if let Ok(result) = try_standard_zlib_decode(data) {
251 return Ok(result);
252 }
253
254 if let Ok(result) = try_raw_deflate_decode(data) {
256 return Ok(result);
257 }
258
259 if data.len() > 10 {
261 for skip_bytes in 1..=5 {
262 if let Ok(result) = try_standard_zlib_decode(&data[skip_bytes..]) {
263 return Ok(result);
264 }
265 if let Ok(result) = try_raw_deflate_decode(&data[skip_bytes..]) {
266 return Ok(result);
267 }
268 }
269 }
270
271 if data.len() > 20 {
273 for truncate_bytes in 1..=10 {
274 let truncated = &data[..data.len() - truncate_bytes];
275 if let Ok(result) = try_standard_zlib_decode(truncated) {
276 return Ok(result);
277 }
278 if let Ok(result) = try_raw_deflate_decode(truncated) {
279 return Ok(result);
280 }
281 }
282 }
283
284 if let Ok(result) = try_gzip_decode(data) {
286 return Ok(result);
287 }
288
289 if let Ok(partial) = try_partial_flate_decode(data) {
291 tracing::debug!(
292 "Warning: Using partial FlateDecode recovery, {} bytes recovered",
293 partial.len()
294 );
295 return Ok(partial);
296 }
297
298 if data.len() > 20 {
300 for predictor in [10, 11, 12, 13, 14, 15] {
301 if let Ok(result) = try_flate_decode_with_predictor(data, predictor) {
302 tracing::debug!(
303 "Warning: FlateDecode succeeded with predictor {}",
304 predictor
305 );
306 return Ok(result);
307 }
308 }
309 }
310
311 tracing::debug!("Warning: All FlateDecode strategies failed, returning empty data");
313 Ok(Vec::new())
314}
315
316#[cfg(feature = "compression")]
317fn try_standard_zlib_decode(data: &[u8]) -> Result<Vec<u8>, std::io::Error> {
318 let mut decoder = ZlibDecoder::new(data);
319 let result = read_to_end_limited(&mut decoder, MAX_DECOMPRESSED_SIZE)?;
320 check_compression_ratio(data.len(), result.len())?;
321 Ok(result)
322}
323
324#[cfg(feature = "compression")]
325fn try_raw_deflate_decode(data: &[u8]) -> Result<Vec<u8>, std::io::Error> {
326 use flate2::read::DeflateDecoder;
327 let mut decoder = DeflateDecoder::new(data);
328 let result = read_to_end_limited(&mut decoder, MAX_DECOMPRESSED_SIZE)?;
329 check_compression_ratio(data.len(), result.len())?;
330 Ok(result)
331}
332
333#[cfg(feature = "compression")]
334fn try_gzip_decode(data: &[u8]) -> Result<Vec<u8>, std::io::Error> {
335 use flate2::read::GzDecoder;
336 let mut decoder = GzDecoder::new(data);
337 let result = read_to_end_limited(&mut decoder, MAX_DECOMPRESSED_SIZE)?;
338 check_compression_ratio(data.len(), result.len())?;
339 Ok(result)
340}
341
342#[cfg(feature = "compression")]
343fn try_partial_flate_decode(data: &[u8]) -> Result<Vec<u8>, std::io::Error> {
344 use flate2::read::ZlibDecoder;
345 use std::io::ErrorKind;
346
347 let mut decoder = ZlibDecoder::new(data);
349 let mut result = Vec::new();
350 let mut buffer = [0; 8192];
351
352 loop {
353 match decoder.read(&mut buffer) {
354 Ok(0) => break, Ok(n) => {
356 if result.len() + n > MAX_DECOMPRESSED_SIZE {
357 return Err(std::io::Error::new(
358 ErrorKind::Other,
359 format!(
360 "Partial decompression exceeds {} MB limit",
361 MAX_DECOMPRESSED_SIZE / (1024 * 1024)
362 ),
363 ));
364 }
365 result.extend_from_slice(&buffer[..n]);
366 }
367 Err(e) if e.kind() == ErrorKind::UnexpectedEof => {
368 if !result.is_empty() {
370 check_compression_ratio(data.len(), result.len())?;
371 return Ok(result);
372 }
373 return Err(e);
374 }
375 Err(e) => return Err(e),
376 }
377 }
378
379 if result.is_empty() {
380 Err(std::io::Error::new(
381 ErrorKind::InvalidData,
382 "No data decoded",
383 ))
384 } else {
385 check_compression_ratio(data.len(), result.len())?;
386 Ok(result)
387 }
388}
389
390#[cfg(feature = "compression")]
391fn try_flate_decode_with_predictor(data: &[u8], predictor: u8) -> Result<Vec<u8>, std::io::Error> {
392 use flate2::read::ZlibDecoder;
393
394 let mut decoder = ZlibDecoder::new(data);
396 let raw_data = read_to_end_limited(&mut decoder, MAX_DECOMPRESSED_SIZE)?;
397 check_compression_ratio(data.len(), raw_data.len())?;
398
399 if predictor >= 10 && predictor <= 15 {
401 apply_png_predictor(&raw_data, predictor)
402 } else {
403 Ok(raw_data)
404 }
405}
406
407#[cfg(feature = "compression")]
408fn apply_png_predictor(data: &[u8], predictor: u8) -> Result<Vec<u8>, std::io::Error> {
409 if data.is_empty() {
410 return Ok(data.to_vec());
411 }
412
413 let common_widths = [1, 2, 3, 4, 8, 16, 24, 32, 48, 64, 96, 128];
416
417 for &width in &common_widths {
418 if let Ok(result) = apply_png_predictor_with_width(data, predictor, width) {
419 if result.len() > data.len() / 2 && result.len() < data.len() * 2 {
421 return Ok(result);
422 }
423 }
424 }
425
426 Ok(data.to_vec())
428}
429
430#[cfg(feature = "compression")]
431fn apply_png_predictor_with_width(
432 data: &[u8],
433 _predictor: u8,
434 width: usize,
435) -> Result<Vec<u8>, std::io::Error> {
436 use std::io::{Error, ErrorKind};
437
438 if width == 0 || data.len() % (width + 1) != 0 {
439 return Err(Error::new(ErrorKind::InvalidInput, "Invalid width"));
440 }
441
442 let mut result = Vec::new();
443 let row_len = width + 1; for row_data in data.chunks_exact(row_len) {
446 if row_data.is_empty() {
447 continue;
448 }
449
450 let predictor_byte = row_data[0];
451 let row = &row_data[1..];
452
453 match predictor_byte {
454 0 => {
455 result.extend_from_slice(row);
457 }
458 1 => {
459 result.push(row[0]);
461 for i in 1..row.len() {
462 let prev = if i >= width {
463 result[result.len() - width]
464 } else {
465 0
466 };
467 result.push(row[i].wrapping_add(prev));
468 }
469 }
470 2 => {
471 for i in 0..row.len() {
473 let up = if result.len() >= width {
474 result[result.len() - width + i]
475 } else {
476 0
477 };
478 result.push(row[i].wrapping_add(up));
479 }
480 }
481 _ => {
482 result.extend_from_slice(row);
484 }
485 }
486 }
487
488 Ok(result)
489}
490
491#[cfg(not(feature = "compression"))]
492fn decode_flate(_data: &[u8]) -> ParseResult<Vec<u8>> {
493 Err(ParseError::StreamDecodeError(
494 "FlateDecode requires 'compression' feature".to_string(),
495 ))
496}
497
498fn decode_ascii_hex(data: &[u8]) -> ParseResult<Vec<u8>> {
500 let mut result = Vec::new();
501 let mut chars = data.iter().filter(|&&b| !b.is_ascii_whitespace());
502
503 loop {
504 let high = match chars.next() {
505 Some(&b'>') => break, Some(&ch) => ch,
507 None => break,
508 };
509
510 let low = match chars.next() {
511 Some(&b'>') => {
512 b'0'
514 }
515 Some(&ch) => ch,
516 None => b'0', };
518
519 let high_val = hex_digit_value(high).ok_or_else(|| {
520 ParseError::StreamDecodeError(format!("Invalid hex digit: {}", high as char))
521 })?;
522 let low_val = hex_digit_value(low).ok_or_else(|| {
523 ParseError::StreamDecodeError(format!("Invalid hex digit: {}", low as char))
524 })?;
525
526 result.push((high_val << 4) | low_val);
527
528 if low == b'>' {
529 break;
530 }
531 }
532
533 Ok(result)
534}
535
536fn hex_digit_value(ch: u8) -> Option<u8> {
538 match ch {
539 b'0'..=b'9' => Some(ch - b'0'),
540 b'A'..=b'F' => Some(ch - b'A' + 10),
541 b'a'..=b'f' => Some(ch - b'a' + 10),
542 _ => None,
543 }
544}
545
546fn decode_ascii85(data: &[u8]) -> ParseResult<Vec<u8>> {
548 let mut result = Vec::new();
549 let mut chars = data.iter().filter(|&&b| !b.is_ascii_whitespace());
550 let mut group = Vec::with_capacity(5);
551
552 let mut ch = match chars.next() {
554 Some(&b'<') => {
555 if chars.next() == Some(&b'~') {
556 chars.next()
558 } else {
559 Some(&b'<')
561 }
562 }
563 other => other,
564 };
565
566 while let Some(&c) = ch {
567 match c {
568 b'~' => {
569 if chars.next() == Some(&b'>') {
571 break;
572 } else {
573 return Err(ParseError::StreamDecodeError(
574 "Invalid ASCII85 end marker".to_string(),
575 ));
576 }
577 }
578 b'z' if group.is_empty() => {
579 result.extend_from_slice(&[0, 0, 0, 0]);
581 }
582 b'!'..=b'u' => {
583 group.push(c);
584 if group.len() == 5 {
585 let value = group
587 .iter()
588 .enumerate()
589 .map(|(i, &ch)| (ch - b'!') as u32 * 85u32.pow(4 - i as u32))
590 .sum::<u32>();
591
592 result.push((value >> 24) as u8);
593 result.push((value >> 16) as u8);
594 result.push((value >> 8) as u8);
595 result.push(value as u8);
596
597 group.clear();
598 }
599 }
600 _ => {
601 return Err(ParseError::StreamDecodeError(format!(
602 "Invalid ASCII85 character: {}",
603 c as char
604 )));
605 }
606 }
607 ch = chars.next();
608 }
609
610 if !group.is_empty() {
612 let original_len = group.len();
614
615 while group.len() < 5 {
617 group.push(b'u');
618 }
619
620 let value = group
621 .iter()
622 .enumerate()
623 .map(|(i, &ch)| (ch - b'!') as u32 * 85u32.pow(4 - i as u32))
624 .sum::<u32>();
625
626 let output_bytes = original_len - 1;
628 for i in 0..output_bytes {
629 result.push((value >> (24 - 8 * i)) as u8);
630 }
631 }
632
633 Ok(result)
634}
635
636#[cfg(test)]
637mod tests {
638 use super::*;
639 use crate::parser::objects::{PdfArray, PdfDictionary, PdfName, PdfObject};
640
641 #[test]
642 fn test_ascii_hex_decode() {
643 let data = b"48656C6C6F>";
644 let result = decode_ascii_hex(data).unwrap();
645 assert_eq!(result, b"Hello");
646
647 let data = b"48 65 6C 6C 6F>"; let result = decode_ascii_hex(data).unwrap();
649 assert_eq!(result, b"Hello");
650
651 let data = b"48656C6C6>"; let result = decode_ascii_hex(data).unwrap();
653 assert_eq!(result, b"Hell`");
654 }
655
656 #[test]
657 fn test_ascii85_decode() {
658 let data = b"87cURD]j7BEbo80~>";
659 let result = decode_ascii85(data).unwrap();
660 assert_eq!(result, b"Hello world!");
661
662 let data = b"z~>"; let result = decode_ascii85(data).unwrap();
664 assert_eq!(result, &[0, 0, 0, 0]);
665 }
666
667 #[test]
668 fn test_filter_from_name() {
669 assert_eq!(
670 Filter::from_name("ASCIIHexDecode"),
671 Some(Filter::ASCIIHexDecode)
672 );
673 assert_eq!(
674 Filter::from_name("ASCII85Decode"),
675 Some(Filter::ASCII85Decode)
676 );
677 assert_eq!(Filter::from_name("LZWDecode"), Some(Filter::LZWDecode));
678 assert_eq!(Filter::from_name("FlateDecode"), Some(Filter::FlateDecode));
679 assert_eq!(
680 Filter::from_name("RunLengthDecode"),
681 Some(Filter::RunLengthDecode)
682 );
683 assert_eq!(
684 Filter::from_name("CCITTFaxDecode"),
685 Some(Filter::CCITTFaxDecode)
686 );
687 assert_eq!(Filter::from_name("JBIG2Decode"), Some(Filter::JBIG2Decode));
688 assert_eq!(Filter::from_name("DCTDecode"), Some(Filter::DCTDecode));
689 assert_eq!(Filter::from_name("JPXDecode"), Some(Filter::JPXDecode));
690 assert_eq!(Filter::from_name("Crypt"), Some(Filter::Crypt));
691 assert_eq!(Filter::from_name("UnknownFilter"), None);
692 }
693
694 #[test]
695 fn test_filter_equality() {
696 assert_eq!(Filter::ASCIIHexDecode, Filter::ASCIIHexDecode);
697 assert_ne!(Filter::ASCIIHexDecode, Filter::ASCII85Decode);
698 assert_ne!(Filter::FlateDecode, Filter::LZWDecode);
699 }
700
701 #[test]
702 fn test_filter_clone() {
703 let filter = Filter::FlateDecode;
704 let cloned = filter.clone();
705 assert_eq!(filter, cloned);
706 }
707
708 #[test]
709 fn test_decode_stream_no_filter() {
710 let data = b"Hello, world!";
711 let dict = PdfDictionary::new();
712
713 let result = decode_stream(data, &dict, &ParseOptions::default()).unwrap();
714 assert_eq!(result, data);
715 }
716
717 #[test]
718 fn test_decode_stream_single_filter() {
719 let data = b"48656C6C6F>";
720 let mut dict = PdfDictionary::new();
721 dict.insert(
722 "Filter".to_string(),
723 PdfObject::Name(PdfName("ASCIIHexDecode".to_string())),
724 );
725
726 let result = decode_stream(data, &dict, &ParseOptions::default()).unwrap();
727 assert_eq!(result, b"Hello");
728 }
729
730 #[test]
731 fn test_decode_stream_invalid_filter() {
732 let data = b"test data";
733 let mut dict = PdfDictionary::new();
734 dict.insert(
735 "Filter".to_string(),
736 PdfObject::Name(PdfName("UnknownFilter".to_string())),
737 );
738
739 let result = decode_stream(data, &dict, &ParseOptions::default());
740 assert!(result.is_err());
741 }
742
743 #[test]
744 fn test_decode_stream_filter_array() {
745 let data = b"48656C6C6F>";
746 let mut dict = PdfDictionary::new();
747 let filters = vec![PdfObject::Name(PdfName("ASCIIHexDecode".to_string()))];
748 dict.insert("Filter".to_string(), PdfObject::Array(PdfArray(filters)));
749
750 let result = decode_stream(data, &dict, &ParseOptions::default()).unwrap();
751 assert_eq!(result, b"Hello");
752 }
753
754 #[test]
755 fn test_decode_stream_invalid_filter_type() {
756 let data = b"test data";
757 let mut dict = PdfDictionary::new();
758 dict.insert("Filter".to_string(), PdfObject::Integer(42)); let result = decode_stream(data, &dict, &ParseOptions::default());
761 assert!(result.is_err());
762 }
763
764 #[test]
765 fn test_ascii_hex_decode_empty() {
766 let data = b">";
767 let result = decode_ascii_hex(data).unwrap();
768 assert!(result.is_empty());
769 }
770
771 #[test]
772 fn test_ascii_hex_decode_invalid() {
773 let data = b"GG>"; let result = decode_ascii_hex(data);
775 assert!(result.is_err());
776 }
777
778 #[test]
779 fn test_ascii_hex_decode_no_terminator() {
780 let data = b"48656C6C6F"; let result = decode_ascii_hex(data).unwrap();
782 assert_eq!(result, b"Hello"); }
784
785 #[test]
786 fn test_ascii85_decode_empty() {
787 let data = b"~>";
788 let result = decode_ascii85(data).unwrap();
789 assert!(result.is_empty());
790 }
791
792 #[test]
793 fn test_ascii85_decode_invalid() {
794 let data = b"invalid~>";
795 let result = decode_ascii85(data);
796 assert!(result.is_err());
797 }
798
799 #[cfg(feature = "compression")]
800 #[test]
801 fn test_flate_decode() {
802 use flate2::write::ZlibEncoder;
803 use flate2::Compression;
804 use std::io::Write;
805
806 let original = b"Hello, compressed world!";
807 let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default());
808 encoder.write_all(original).unwrap();
809 let compressed = encoder.finish().unwrap();
810
811 let result = decode_flate(&compressed).unwrap();
812 assert_eq!(result, original);
813 }
814
815 #[cfg(not(feature = "compression"))]
816 #[test]
817 fn test_flate_decode_not_supported() {
818 let data = b"compressed data";
819 let result = decode_flate(data);
820 assert!(result.is_err());
821 }
822
823 #[test]
824 fn test_apply_filter() {
825 let data = b"48656C6C6F>";
826 let result = apply_filter(data, Filter::ASCIIHexDecode).unwrap();
827 assert_eq!(result, b"Hello");
828 }
829
830 #[test]
831 fn test_apply_filter_unsupported() {
832 let data = b"test data";
833 let unsupported_filters = vec![Filter::JPXDecode, Filter::Crypt];
834
835 for filter in unsupported_filters {
836 let result = apply_filter(data, filter);
837 assert!(result.is_err());
838 }
839 }
840
841 #[test]
842 fn test_apply_filter_dct_decode() {
843 let invalid_data = b"not jpeg data";
845 let result = apply_filter(invalid_data, Filter::DCTDecode);
846 assert!(result.is_err()); let valid_jpeg = vec![
850 0xFF, 0xD8, 0xFF, 0xD9, ];
853 let result = apply_filter(&valid_jpeg, Filter::DCTDecode);
854 assert!(result.is_ok());
855 assert_eq!(result.unwrap(), valid_jpeg); }
857
858 #[test]
861 fn test_apply_filter_with_params_no_predictor() {
862 let data = b"48656C6C6F>";
863 let dict = PdfDictionary::new();
864
865 let result = apply_filter_with_params(data, Filter::ASCIIHexDecode, Some(&dict)).unwrap();
866 assert_eq!(result, b"Hello");
867 }
868
869 #[test]
870 fn test_apply_predictor_none() {
871 let data = vec![1, 2, 3, 4];
872 let dict = PdfDictionary::new();
873
874 let result = apply_predictor(&data, 1, &dict).unwrap();
875 assert_eq!(result, data);
876 }
877
878 #[test]
879 fn test_apply_predictor_unknown() {
880 let data = vec![1, 2, 3, 4];
881 let dict = PdfDictionary::new();
882
883 let result = apply_predictor(&data, 99, &dict).unwrap();
885 assert_eq!(result, data);
886 }
887
888 #[test]
889 fn test_png_predictor_sub_filter() {
890 let data = vec![1, 5, 10]; let result = apply_png_sub_filter(&data, 1);
893 assert_eq!(result, vec![1, 6, 16]); }
895
896 #[test]
897 fn test_png_predictor_up_filter() {
898 let data = vec![1, 2, 3];
900 let prev_row = vec![5, 10, 15];
901 let result = apply_png_up_filter(&data, Some(&prev_row));
902 assert_eq!(result, vec![6, 12, 18]); }
904
905 #[test]
906 fn test_png_predictor_up_filter_no_prev() {
907 let data = vec![1, 2, 3];
909 let result = apply_png_up_filter(&data, None);
910 assert_eq!(result, vec![1, 2, 3]); }
912
913 #[test]
914 fn test_png_predictor_average_filter() {
915 let data = vec![2, 4]; let prev_row = vec![6, 8];
918 let result = apply_png_average_filter(&data, Some(&prev_row), 1);
919 assert_eq!(result, vec![5, 10]);
922 }
923
924 #[test]
925 fn test_png_predictor_paeth_filter() {
926 let data = vec![1, 2]; let prev_row = vec![3, 4];
929 let result = apply_png_paeth_filter(&data, Some(&prev_row), 1);
930 assert_eq!(result.len(), 2);
932 }
933
934 #[test]
935 fn test_paeth_predictor_algorithm() {
936 assert_eq!(paeth_predictor(1, 2, 0), 2);
940
941 assert_eq!(paeth_predictor(5, 2, 3), 5);
944
945 assert_eq!(paeth_predictor(5, 8, 3), 8);
948 }
949
950 #[test]
951 fn test_apply_png_predictor_invalid_data() {
952 let mut params = PdfDictionary::new();
953 params.insert("Columns".to_string(), PdfObject::Integer(3));
954
955 let data = vec![0, 1, 2, 3, 4, 5]; let result = apply_png_predictor_with_width(&data, 10, 3);
958 assert!(result.is_err());
959 }
960
961 #[test]
962 fn test_apply_png_predictor_valid_simple() {
963 let mut params = PdfDictionary::new();
964 params.insert("Columns".to_string(), PdfObject::Integer(2));
965 params.insert("BitsPerComponent".to_string(), PdfObject::Integer(8));
966 params.insert("Colors".to_string(), PdfObject::Integer(1));
967
968 let data = vec![
970 0, 1, 2, 0, 3, 4, ];
973
974 let result = apply_png_predictor_with_width(&data, 10, 2).unwrap();
975 assert_eq!(result, vec![1, 2, 3, 4]);
976 }
977
978 #[test]
979 fn test_apply_png_predictor_with_sub_filter() {
980 let mut params = PdfDictionary::new();
981 params.insert("Columns".to_string(), PdfObject::Integer(3));
982 params.insert("BitsPerComponent".to_string(), PdfObject::Integer(8));
983 params.insert("Colors".to_string(), PdfObject::Integer(1));
984
985 let data = vec![
987 1, 1, 2, 3, ];
989
990 let result = apply_png_predictor_with_width(&data, 10, 3).unwrap();
991 assert_eq!(result, vec![1, 2, 3]); }
994
995 #[test]
996 fn test_apply_png_predictor_invalid_filter_type() {
997 let mut params = PdfDictionary::new();
998 params.insert("Columns".to_string(), PdfObject::Integer(2));
999
1000 let data = vec![5, 1, 2];
1002 let result = apply_png_predictor_with_width(&data, 10, 2);
1003 if result.is_err() {
1005 let error_msg = result.unwrap_err().to_string();
1007 assert!(
1008 error_msg.contains("filter")
1009 || error_msg.contains("predictor")
1010 || error_msg.contains("Invalid")
1011 );
1012 } else {
1013 let _decoded_data = result.unwrap();
1015 }
1016 }
1017
1018 #[test]
1019 fn test_get_filter_params_dict() {
1020 let mut dict = PdfDictionary::new();
1021 dict.insert("Predictor".to_string(), PdfObject::Integer(12));
1022 let obj = PdfObject::Dictionary(dict);
1023
1024 let result = get_filter_params(Some(&obj), 0);
1025 assert!(result.is_some());
1026 assert_eq!(
1027 result.unwrap().get("Predictor"),
1028 Some(&PdfObject::Integer(12))
1029 );
1030 }
1031
1032 #[test]
1033 fn test_get_filter_params_array() {
1034 let mut inner_dict = PdfDictionary::new();
1035 inner_dict.insert("Predictor".to_string(), PdfObject::Integer(15));
1036
1037 let array = vec![PdfObject::Dictionary(inner_dict)];
1038 let obj = PdfObject::Array(crate::parser::objects::PdfArray(array));
1039
1040 let result = get_filter_params(Some(&obj), 0);
1041 assert!(result.is_some());
1042 assert_eq!(
1043 result.unwrap().get("Predictor"),
1044 Some(&PdfObject::Integer(15))
1045 );
1046 }
1047
1048 #[test]
1049 fn test_get_filter_params_none() {
1050 let result = get_filter_params(None, 0);
1051 assert!(result.is_none());
1052 }
1053
1054 #[test]
1055 fn test_compressed_xref_integration() {
1056 use flate2::write::ZlibEncoder;
1058 use flate2::Compression;
1059 use std::io::Write;
1060
1061 #[cfg(feature = "compression")]
1062 {
1063 let original_data = vec![
1065 0, 1, 2, 0, 3, 4, ];
1068
1069 let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default());
1071 encoder.write_all(&original_data).unwrap();
1072 let compressed = encoder.finish().unwrap();
1073
1074 let mut decode_params = PdfDictionary::new();
1076 decode_params.insert("Predictor".to_string(), PdfObject::Integer(12)); decode_params.insert("Columns".to_string(), PdfObject::Integer(2));
1078 decode_params.insert("BitsPerComponent".to_string(), PdfObject::Integer(8));
1079 decode_params.insert("Colors".to_string(), PdfObject::Integer(1));
1080
1081 let result =
1083 apply_filter_with_params(&compressed, Filter::FlateDecode, Some(&decode_params))
1084 .unwrap();
1085 assert_eq!(result, vec![1, 2, 3, 4]);
1086 }
1087 }
1088
1089 fn encode_lzw_test_data(codes: &[u16]) -> Vec<u8> {
1093 let mut result = Vec::new();
1094 let mut bit_buffer = 0u32;
1095 let mut bits_in_buffer = 0;
1096 let mut code_size = 9;
1097
1098 for &code in codes {
1099 bit_buffer = (bit_buffer << code_size) | (code as u32);
1101 bits_in_buffer += code_size;
1102
1103 while bits_in_buffer >= 8 {
1105 let byte = ((bit_buffer >> (bits_in_buffer - 8)) & 0xFF) as u8;
1106 result.push(byte);
1107 bits_in_buffer -= 8;
1108 }
1109
1110 if code == 511 && code_size == 9 {
1112 code_size = 10;
1113 } else if code == 1023 && code_size == 10 {
1114 code_size = 11;
1115 } else if code == 2047 && code_size == 11 {
1116 code_size = 12;
1117 }
1118 }
1119
1120 if bits_in_buffer > 0 {
1122 let byte = ((bit_buffer << (8 - bits_in_buffer)) & 0xFF) as u8;
1123 result.push(byte);
1124 }
1125
1126 result
1127 }
1128
1129 #[test]
1130 fn test_lzw_decode_simple() {
1131 let codes = vec![65, 66, 67, 257];
1134 let data = encode_lzw_test_data(&codes);
1135 let result = decode_lzw(&data, None).unwrap();
1136 assert_eq!(result, b"ABC");
1137 }
1138
1139 #[test]
1140 fn test_lzw_decode_with_repetition() {
1141 let codes = vec![65, 65, 258, 257];
1144 let data = encode_lzw_test_data(&codes);
1145 let result = decode_lzw(&data, None).unwrap();
1146 assert_eq!(result, b"AAAA");
1147 }
1148
1149 #[test]
1150 fn test_lzw_decode_clear_code() {
1151 let codes = vec![65, 66, 256, 67, 68, 257];
1154 let data = encode_lzw_test_data(&codes);
1155 let result = decode_lzw(&data, None).unwrap();
1156 assert_eq!(result, b"ABCD");
1157 }
1158
1159 #[test]
1160 fn test_lzw_decode_growing_codes() {
1161 let mut params = PdfDictionary::new();
1165 params.insert("EarlyChange".to_string(), PdfObject::Integer(1));
1166
1167 let data = vec![0x08, 0x21, 0x08, 0x61, 0x08, 0x20, 0x80];
1169 let result = decode_lzw(&data, Some(¶ms));
1170 assert!(result.is_ok());
1171 }
1172
1173 #[test]
1174 fn test_lzw_decode_crosses_9_to_10_bit_boundary_early_change() {
1175 let payload: Vec<u8> = (0..2000u32)
1184 .map(|i| (i.wrapping_mul(2_654_435_761) >> 24) as u8)
1185 .collect();
1186 let encoded = weezl::encode::Encoder::with_tiff_size_switch(weezl::BitOrder::Msb, 8)
1187 .encode(&payload)
1188 .expect("weezl LZW encode");
1189
1190 let mut params = PdfDictionary::new();
1191 params.insert("EarlyChange".to_string(), PdfObject::Integer(1));
1192
1193 let decoded =
1194 decode_lzw(&encoded, Some(¶ms)).expect("decode LZW across 9->10 bit boundary");
1195 assert_eq!(
1196 decoded, payload,
1197 "round-trip must be byte-identical across the 9->10 bit code-width boundary"
1198 );
1199 }
1200
1201 #[test]
1202 fn test_lzw_decode_crosses_boundary_no_early_change() {
1203 let payload: Vec<u8> = (0..2000u32)
1209 .map(|i| (i.wrapping_mul(2_654_435_761) >> 24) as u8)
1210 .collect();
1211 let encoded = weezl::encode::Encoder::new(weezl::BitOrder::Msb, 8)
1212 .encode(&payload)
1213 .expect("weezl LZW encode (no early change)");
1214
1215 let mut params = PdfDictionary::new();
1216 params.insert("EarlyChange".to_string(), PdfObject::Integer(0));
1217
1218 let decoded = decode_lzw(&encoded, Some(¶ms))
1219 .expect("decode LZW (EarlyChange=0) across the code-width boundary");
1220 assert_eq!(
1221 decoded, payload,
1222 "round-trip must be byte-identical with EarlyChange=0 across the boundary"
1223 );
1224 }
1225
1226 #[test]
1227 fn test_lzw_decode_early_change_false() {
1228 let mut params = PdfDictionary::new();
1229 params.insert("EarlyChange".to_string(), PdfObject::Integer(0));
1230
1231 let codes = vec![65, 66, 67, 257];
1233 let data = encode_lzw_test_data(&codes);
1234 let result = decode_lzw(&data, Some(¶ms)).unwrap();
1235 assert_eq!(result, b"ABC");
1236 }
1237
1238 #[test]
1239 fn test_lzw_decode_invalid_code() {
1240 let data = vec![0x08, 0x21, 0xFF, 0xFF, 0x00];
1242 let result = decode_lzw(&data, None);
1243 assert!(result.is_err());
1244 }
1245
1246 #[test]
1247 fn test_lzw_decode_empty() {
1248 let codes = vec![257];
1250 let data = encode_lzw_test_data(&codes);
1251 let result = decode_lzw(&data, None).unwrap();
1252 assert!(result.is_empty());
1253 }
1254
1255 #[test]
1256 fn test_lzw_bit_reader() {
1257 let data = vec![0b10101010, 0b11001100, 0b11110000];
1258 let mut reader = LzwBitReader::new(&data);
1259
1260 assert_eq!(reader.read_bits(4), Some(0b1010));
1262
1263 assert_eq!(reader.read_bits(8), Some(0b10101100));
1265
1266 assert_eq!(reader.read_bits(6), Some(0b110011));
1268
1269 assert_eq!(reader.read_bits(6), Some(0b110000));
1271
1272 assert_eq!(reader.read_bits(8), None);
1274 }
1275
1276 #[test]
1277 fn test_lzw_bit_reader_edge_cases() {
1278 let data = vec![0xFF];
1279 let mut reader = LzwBitReader::new(&data);
1280
1281 assert_eq!(reader.read_bits(0), None);
1283
1284 assert_eq!(reader.read_bits(17), None);
1286
1287 assert_eq!(reader.read_bits(8), Some(0xFF));
1289
1290 assert_eq!(reader.read_bits(1), None);
1292 }
1293
1294 #[test]
1295 fn test_apply_filter_lzw() {
1296 let codes = vec![65, 66, 67, 257];
1298 let data = encode_lzw_test_data(&codes);
1299 let result = apply_filter(&data, Filter::LZWDecode).unwrap();
1300 assert_eq!(result, b"ABC");
1301 }
1302
1303 #[test]
1304 fn test_apply_filter_with_params_lzw() {
1305 let mut params = PdfDictionary::new();
1307 params.insert("EarlyChange".to_string(), PdfObject::Integer(0));
1308
1309 let codes = vec![65, 66, 67, 257];
1310 let data = encode_lzw_test_data(&codes);
1311 let result = apply_filter_with_params(&data, Filter::LZWDecode, Some(¶ms)).unwrap();
1312 assert_eq!(result, b"ABC");
1313 }
1314
1315 #[test]
1318 fn test_run_length_decode_literal() {
1319 let data = vec![2, b'A', b'B', b'C'];
1321 let result = decode_run_length(&data).unwrap();
1322 assert_eq!(result, b"ABC");
1323 }
1324
1325 #[test]
1326 fn test_run_length_decode_repeat() {
1327 let data = vec![253u8, b'X']; let result = decode_run_length(&data).unwrap();
1330 assert_eq!(result, b"XXXX");
1331 }
1332
1333 #[test]
1334 fn test_run_length_decode_mixed() {
1335 let data = vec![
1337 1, b'A', b'B', 254u8, b'C', 1, b'D', b'E', ];
1341 let result = decode_run_length(&data).unwrap();
1342 assert_eq!(result, b"ABCCCDE");
1343 }
1344
1345 #[test]
1346 fn test_run_length_decode_eod() {
1347 let data = vec![0, b'A', 128u8, 1, b'B', b'C']; let result = decode_run_length(&data).unwrap();
1350 assert_eq!(result, b"A"); }
1352
1353 #[test]
1354 fn test_run_length_decode_empty() {
1355 let data = vec![];
1357 let result = decode_run_length(&data).unwrap();
1358 assert!(result.is_empty());
1359 }
1360
1361 #[test]
1362 fn test_run_length_decode_single_literal() {
1363 let data = vec![0, b'Z'];
1365 let result = decode_run_length(&data).unwrap();
1366 assert_eq!(result, b"Z");
1367 }
1368
1369 #[test]
1370 fn test_run_length_decode_single_repeat() {
1371 let data = vec![255u8, b'Y']; let result = decode_run_length(&data).unwrap();
1374 assert_eq!(result, b"YY");
1375 }
1376
1377 #[test]
1378 fn test_run_length_decode_max_repeat() {
1379 let data = vec![129u8, b'M']; let result = decode_run_length(&data).unwrap();
1382 assert_eq!(result.len(), 128);
1383 assert!(result.iter().all(|&b| b == b'M'));
1384 }
1385
1386 #[test]
1387 fn test_run_length_decode_max_literal() {
1388 let mut data = vec![127];
1390 data.extend((0..128).map(|i| i as u8));
1391 let result = decode_run_length(&data).unwrap();
1392 assert_eq!(result.len(), 128);
1393 assert_eq!(result, (0..128).map(|i| i as u8).collect::<Vec<u8>>());
1394 }
1395
1396 #[test]
1397 fn test_run_length_decode_error_literal_overflow() {
1398 let data = vec![5, b'A', b'B']; let result = decode_run_length(&data);
1401 assert!(result.is_err());
1402 }
1403
1404 #[test]
1405 fn test_run_length_decode_error_missing_repeat_byte() {
1406 let data = vec![254u8]; let result = decode_run_length(&data);
1409 assert!(result.is_err());
1410 }
1411
1412 #[test]
1413 fn test_apply_filter_run_length() {
1414 let data = vec![2, b'X', b'Y', b'Z'];
1416 let result = apply_filter(&data, Filter::RunLengthDecode).unwrap();
1417 assert_eq!(result, b"XYZ");
1418 }
1419
1420 #[test]
1421 fn test_apply_filter_with_params_run_length() {
1422 let data = vec![254u8, b'A', 1, b'B', b'C']; let result = apply_filter_with_params(&data, Filter::RunLengthDecode, None).unwrap();
1425 assert_eq!(result, b"AAABC");
1426 }
1427
1428 #[test]
1431 fn test_read_to_end_limited_within_limit() {
1432 let data = vec![42u8; 1000];
1433 let mut cursor = std::io::Cursor::new(&data);
1434 let result = read_to_end_limited(&mut cursor, 2000).unwrap();
1435 assert_eq!(result.len(), 1000);
1436 }
1437
1438 #[test]
1439 fn test_read_to_end_limited_at_exact_limit() {
1440 let data = vec![42u8; 1000];
1441 let mut cursor = std::io::Cursor::new(&data);
1442 let result = read_to_end_limited(&mut cursor, 1000).unwrap();
1443 assert_eq!(result.len(), 1000);
1444 }
1445
1446 #[test]
1447 fn test_read_to_end_limited_exceeds_limit() {
1448 let data = vec![42u8; 2000];
1449 let mut cursor = std::io::Cursor::new(&data);
1450 let result = read_to_end_limited(&mut cursor, 1000);
1451 assert!(result.is_err());
1452 let err = result.unwrap_err();
1453 assert!(
1454 err.to_string().contains("exceeds limit"),
1455 "Expected decompression limit error, got: {}",
1456 err
1457 );
1458 }
1459
1460 #[test]
1461 fn test_check_compression_ratio_normal() {
1462 assert!(check_compression_ratio(100, 1000).is_ok());
1464 }
1465
1466 #[test]
1467 fn test_check_compression_ratio_small_output_high_ratio_allowed() {
1468 assert!(check_compression_ratio(1, 1001).is_ok());
1472 assert!(check_compression_ratio(1074, 1_085_400).is_ok());
1473 }
1474
1475 #[test]
1476 fn test_check_compression_ratio_large_output_high_ratio_rejected() {
1477 let big = RATIO_GUARD_MIN_OUTPUT + 1;
1479 assert!(check_compression_ratio(big / 2000, big).is_err());
1480 }
1481
1482 #[test]
1483 fn test_check_compression_ratio_large_output_low_ratio_allowed() {
1484 let big = RATIO_GUARD_MIN_OUTPUT + 1;
1486 assert!(check_compression_ratio(big / 10, big).is_ok());
1487 }
1488
1489 #[test]
1490 fn test_check_compression_ratio_at_exact_floor_allowed() {
1491 assert!(check_compression_ratio(1, RATIO_GUARD_MIN_OUTPUT).is_ok());
1494 }
1495
1496 #[test]
1497 fn test_check_compression_ratio_zero_input() {
1498 assert!(check_compression_ratio(0, 1000).is_ok());
1500 }
1501
1502 #[cfg(feature = "compression")]
1503 #[test]
1504 fn test_flate_normal_data_succeeds() {
1505 use flate2::write::ZlibEncoder;
1506 use flate2::Compression;
1507 use std::io::Write;
1508
1509 let mut original = Vec::with_capacity(100_000);
1512 for i in 0..100_000u32 {
1513 original.push((i % 256) as u8);
1514 }
1515 let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default());
1516 encoder.write_all(&original).unwrap();
1517 let compressed = encoder.finish().unwrap();
1518
1519 let result = try_standard_zlib_decode(&compressed);
1520 assert!(result.is_ok());
1521 assert_eq!(result.unwrap().len(), 100_000);
1522 }
1523
1524 #[cfg(feature = "compression")]
1525 #[test]
1526 fn test_flate_high_ratio_small_output_now_decodes() {
1527 use flate2::write::ZlibEncoder;
1528 use flate2::Compression;
1529 use std::io::Write;
1530
1531 let original = vec![0u8; 2 * 1024 * 1024];
1534 let mut encoder = ZlibEncoder::new(Vec::new(), Compression::best());
1535 encoder.write_all(&original).unwrap();
1536 let compressed = encoder.finish().unwrap();
1537
1538 let result = try_standard_zlib_decode(&compressed).expect("small output must decode");
1539 assert_eq!(result.len(), original.len());
1540 }
1541
1542 #[cfg(feature = "compression")]
1543 #[test]
1544 fn test_flate_large_high_ratio_still_rejected() {
1545 let big = RATIO_GUARD_MIN_OUTPUT + 1;
1549 let result = check_compression_ratio(big / 2000, big);
1550 assert!(result.is_err(), "large high-ratio output must be rejected");
1551 assert!(result
1552 .unwrap_err()
1553 .to_string()
1554 .contains("Suspicious compression ratio"));
1555 }
1556
1557 #[test]
1558 fn test_read_to_end_limited_empty_input() {
1559 let data: Vec<u8> = Vec::new();
1560 let mut cursor = std::io::Cursor::new(&data);
1561 let result = read_to_end_limited(&mut cursor, 1000).unwrap();
1562 assert!(result.is_empty());
1563 }
1564
1565 #[cfg(feature = "compression")]
1566 #[test]
1567 fn test_flate_high_ratio_small_output_decodes_issue_286() {
1568 use flate2::write::ZlibEncoder;
1569 use flate2::Compression;
1570 use std::io::Write;
1571
1572 let original = vec![0u8; 1_085_400];
1580 let mut encoder = ZlibEncoder::new(Vec::new(), Compression::best());
1581 encoder.write_all(&original).unwrap();
1582 let compressed = encoder.finish().unwrap();
1583 assert!(
1584 original.len() / compressed.len() > MAX_COMPRESSION_RATIO,
1585 "test premise: ratio {} must exceed the guard {}",
1586 original.len() / compressed.len(),
1587 MAX_COMPRESSION_RATIO
1588 );
1589
1590 let decoded = decode_flate(&compressed).expect("decode must succeed");
1591 assert_eq!(
1592 decoded.len(),
1593 original.len(),
1594 "must decode the full image, not return empty"
1595 );
1596 }
1597}
1598
1599pub(crate) fn apply_filter_with_params(
1601 data: &[u8],
1602 filter: Filter,
1603 params: Option<&PdfDictionary>,
1604) -> ParseResult<Vec<u8>> {
1605 let result = match filter {
1606 Filter::FlateDecode => {
1607 if let Some(decode_params) = params {
1611 if decode_params
1612 .get("Predictor")
1613 .and_then(|p| p.as_integer())
1614 .is_some()
1615 {
1616 match try_standard_zlib_decode(data) {
1618 Ok(decoded) => decoded,
1619 Err(_) => {
1620 data.to_vec()
1623 }
1624 }
1625 } else {
1626 decode_flate(data)?
1627 }
1628 } else {
1629 decode_flate(data)?
1630 }
1631 }
1632 Filter::ASCIIHexDecode => decode_ascii_hex(data)?,
1633 Filter::ASCII85Decode => decode_ascii85(data)?,
1634 Filter::LZWDecode => decode_lzw(data, params)?,
1635 Filter::RunLengthDecode => decode_run_length(data)?,
1636 Filter::CCITTFaxDecode => decode_ccitt(data, params)?,
1637 Filter::JBIG2Decode => decode_jbig2(data, params)?,
1638 Filter::DCTDecode => decode_dct(data)?,
1639 _ => {
1640 return Err(ParseError::SyntaxError {
1641 position: 0,
1642 message: format!("Filter {filter:?} not yet implemented"),
1643 });
1644 }
1645 };
1646
1647 if let Some(params_dict) = params {
1649 if let Some(predictor_obj) = params_dict.get("Predictor") {
1650 if let Some(predictor) = predictor_obj.as_integer() {
1651 match apply_predictor(&result, predictor as u32, params_dict) {
1652 Ok(predictor_result) => return Ok(predictor_result),
1653 Err(_) => {
1654 return Ok(result);
1657 }
1658 }
1659 }
1660 }
1661 }
1662
1663 Ok(result)
1664}
1665
1666fn get_filter_params(decode_params: Option<&PdfObject>, _index: usize) -> Option<&PdfDictionary> {
1668 match decode_params {
1669 Some(PdfObject::Dictionary(dict)) => Some(dict),
1670 Some(PdfObject::Array(array)) => {
1671 array.0.first().and_then(|obj| obj.as_dict())
1674 }
1675 _ => None,
1676 }
1677}
1678
1679fn apply_predictor(data: &[u8], predictor: u32, params: &PdfDictionary) -> ParseResult<Vec<u8>> {
1681 match predictor {
1682 1 => {
1683 Ok(data.to_vec())
1685 }
1686 10..=15 => {
1687 apply_png_predictor_advanced(data, predictor, params)
1689 }
1690 _ => {
1691 #[cfg(debug_assertions)]
1693 tracing::debug!("Warning: Unknown predictor {predictor}, returning data as-is");
1694 Ok(data.to_vec())
1695 }
1696 }
1697}
1698
1699fn apply_png_predictor_advanced(
1701 data: &[u8],
1702 _predictor: u32,
1703 params: &PdfDictionary,
1704) -> ParseResult<Vec<u8>> {
1705 let columns = params
1707 .get("Columns")
1708 .and_then(|obj| obj.as_integer())
1709 .unwrap_or(1) as usize;
1710
1711 let bpc = params
1713 .get("BitsPerComponent")
1714 .and_then(|obj| obj.as_integer())
1715 .unwrap_or(8) as usize;
1716
1717 let colors = params
1719 .get("Colors")
1720 .and_then(|obj| obj.as_integer())
1721 .unwrap_or(1) as usize;
1722
1723 let bytes_per_pixel = (bpc * colors).div_ceil(8);
1725
1726 let row_size = columns + 1;
1728
1729 if data.len() % row_size != 0 {
1730 return Err(ParseError::StreamDecodeError(
1731 "PNG predictor: data length not multiple of row size".to_string(),
1732 ));
1733 }
1734
1735 let num_rows = data.len() / row_size;
1736 let mut result = Vec::with_capacity(columns * num_rows);
1737
1738 for row in 0..num_rows {
1739 let row_start = row * row_size;
1740 let predictor_byte = data[row_start];
1741 let row_data = &data[row_start + 1..row_start + row_size];
1742
1743 let filtered_row = match predictor_byte {
1745 0 => {
1746 row_data.to_vec()
1748 }
1749 1 => {
1750 apply_png_sub_filter(row_data, bytes_per_pixel)
1752 }
1753 2 => {
1754 let prev_row = if row > 0 {
1756 Some(&result[(row - 1) * columns..row * columns])
1757 } else {
1758 None
1759 };
1760 apply_png_up_filter(row_data, prev_row)
1761 }
1762 3 => {
1763 let prev_row = if row > 0 {
1765 Some(&result[(row - 1) * columns..row * columns])
1766 } else {
1767 None
1768 };
1769 apply_png_average_filter(row_data, prev_row, bytes_per_pixel)
1770 }
1771 4 => {
1772 let prev_row = if row > 0 {
1774 Some(&result[(row - 1) * columns..row * columns])
1775 } else {
1776 None
1777 };
1778 apply_png_paeth_filter(row_data, prev_row, bytes_per_pixel)
1779 }
1780 _ => {
1781 return Err(ParseError::StreamDecodeError(format!(
1782 "PNG predictor: unknown filter type {predictor_byte}"
1783 )));
1784 }
1785 };
1786
1787 result.extend_from_slice(&filtered_row);
1788 }
1789
1790 Ok(result)
1791}
1792
1793fn apply_png_sub_filter(data: &[u8], bytes_per_pixel: usize) -> Vec<u8> {
1795 let mut result = Vec::with_capacity(data.len());
1796
1797 for (i, &byte) in data.iter().enumerate() {
1798 if i < bytes_per_pixel {
1799 result.push(byte);
1800 } else {
1801 result.push(byte.wrapping_add(result[i - bytes_per_pixel]));
1802 }
1803 }
1804
1805 result
1806}
1807
1808fn apply_png_up_filter(data: &[u8], prev_row: Option<&[u8]>) -> Vec<u8> {
1810 let mut result = Vec::with_capacity(data.len());
1811
1812 for (i, &byte) in data.iter().enumerate() {
1813 let up_byte = prev_row.and_then(|row| row.get(i)).unwrap_or(&0);
1814 result.push(byte.wrapping_add(*up_byte));
1815 }
1816
1817 result
1818}
1819
1820fn apply_png_average_filter(
1822 data: &[u8],
1823 prev_row: Option<&[u8]>,
1824 bytes_per_pixel: usize,
1825) -> Vec<u8> {
1826 let mut result = Vec::with_capacity(data.len());
1827
1828 for (i, &byte) in data.iter().enumerate() {
1829 let left_byte = if i < bytes_per_pixel {
1830 0
1831 } else {
1832 result[i - bytes_per_pixel]
1833 };
1834 let up_byte = prev_row.and_then(|row| row.get(i)).unwrap_or(&0);
1835 let average = ((left_byte as u16 + *up_byte as u16) / 2) as u8;
1836 result.push(byte.wrapping_add(average));
1837 }
1838
1839 result
1840}
1841
1842fn apply_png_paeth_filter(data: &[u8], prev_row: Option<&[u8]>, bytes_per_pixel: usize) -> Vec<u8> {
1844 let mut result = Vec::with_capacity(data.len());
1845
1846 for (i, &byte) in data.iter().enumerate() {
1847 let left_byte = if i < bytes_per_pixel {
1848 0
1849 } else {
1850 result[i - bytes_per_pixel]
1851 };
1852 let up_byte = prev_row.and_then(|row| row.get(i)).unwrap_or(&0);
1853 let up_left_byte = if i < bytes_per_pixel {
1854 0
1855 } else {
1856 *prev_row
1857 .and_then(|row| row.get(i - bytes_per_pixel))
1858 .unwrap_or(&0)
1859 };
1860
1861 let paeth = paeth_predictor(left_byte, *up_byte, up_left_byte);
1862 result.push(byte.wrapping_add(paeth));
1863 }
1864
1865 result
1866}
1867
1868fn paeth_predictor(left: u8, up: u8, up_left: u8) -> u8 {
1870 let p = left as i16 + up as i16 - up_left as i16;
1871 let pa = (p - left as i16).abs();
1872 let pb = (p - up as i16).abs();
1873 let pc = (p - up_left as i16).abs();
1874
1875 if pa <= pb && pa <= pc {
1876 left
1877 } else if pb <= pc {
1878 up
1879 } else {
1880 up_left
1881 }
1882}
1883
1884fn decode_lzw(data: &[u8], params: Option<&PdfDictionary>) -> ParseResult<Vec<u8>> {
1890 let early_change = params
1892 .and_then(|p| p.get("EarlyChange"))
1893 .and_then(|v| v.as_integer())
1894 .map(|v| v != 0)
1895 .unwrap_or(true); const MIN_BITS: u32 = 9;
1899 const MAX_BITS: u32 = 12;
1900 const CLEAR_CODE: u16 = 256;
1901 const EOD_CODE: u16 = 257;
1902 #[allow(dead_code)]
1903 const FIRST_CODE: u16 = 258;
1904
1905 let mut dictionary: Vec<Vec<u8>> = Vec::with_capacity(4096);
1907 for i in 0..=255 {
1908 dictionary.push(vec![i]);
1909 }
1910 dictionary.push(vec![]); dictionary.push(vec![]); let mut result = Vec::new();
1915 let mut bit_reader = LzwBitReader::new(data);
1916 let mut code_size = MIN_BITS;
1917 let mut prev_code: Option<u16> = None;
1918
1919 while let Some(c) = bit_reader.read_bits(code_size) {
1920 let code = c as u16;
1921
1922 if code == EOD_CODE {
1923 break;
1924 }
1925
1926 if code == CLEAR_CODE {
1927 dictionary.truncate(258);
1929 code_size = MIN_BITS;
1930 prev_code = None;
1931 continue;
1932 }
1933
1934 if let Some(prev) = prev_code {
1936 let string = if (code as usize) < dictionary.len() {
1937 dictionary[code as usize].clone()
1939 } else if code as usize == dictionary.len() {
1940 let mut s = dictionary[prev as usize].clone();
1942 s.push(dictionary[prev as usize][0]);
1943 s
1944 } else {
1945 return Err(ParseError::StreamDecodeError(format!(
1946 "LZW decode error: invalid code {code}"
1947 )));
1948 };
1949
1950 result.extend_from_slice(&string);
1952
1953 if result.len() > MAX_DECOMPRESSED_SIZE {
1955 return Err(ParseError::StreamDecodeError(format!(
1956 "LZW decompressed size exceeds {} MB limit",
1957 MAX_DECOMPRESSED_SIZE / (1024 * 1024)
1958 )));
1959 }
1960
1961 if dictionary.len() < 4096 {
1963 let mut new_entry = dictionary[prev as usize].clone();
1964 new_entry.push(string[0]);
1965 dictionary.push(new_entry);
1966
1967 let dict_size = dictionary.len();
1969 let threshold = if early_change {
1975 (1 << code_size) - 1
1976 } else {
1977 1 << code_size
1978 };
1979
1980 if dict_size >= threshold as usize && code_size < MAX_BITS {
1981 code_size += 1;
1982 }
1983 }
1984 } else {
1985 if (code as usize) < dictionary.len() {
1987 result.extend_from_slice(&dictionary[code as usize]);
1988 } else {
1989 return Err(ParseError::StreamDecodeError(format!(
1990 "LZW decode error: invalid first code {code}"
1991 )));
1992 }
1993 }
1994
1995 prev_code = Some(code);
1996 }
1997
1998 Ok(result)
1999}
2000
2001struct LzwBitReader<'a> {
2003 data: &'a [u8],
2004 byte_pos: usize,
2005 bit_pos: u8,
2006}
2007
2008impl<'a> LzwBitReader<'a> {
2009 fn new(data: &'a [u8]) -> Self {
2010 Self {
2011 data,
2012 byte_pos: 0,
2013 bit_pos: 0,
2014 }
2015 }
2016
2017 fn read_bits(&mut self, n: u32) -> Option<u32> {
2019 if n == 0 || n > 16 {
2020 return None;
2021 }
2022
2023 let mut result = 0u32;
2024 let mut bits_read = 0;
2025
2026 while bits_read < n {
2027 if self.byte_pos >= self.data.len() {
2028 return None;
2029 }
2030
2031 let bits_available = 8 - self.bit_pos;
2032 let bits_to_read = (n - bits_read).min(bits_available as u32);
2033
2034 let mask = ((1u32 << bits_to_read) - 1) as u8;
2036 let shift = bits_available - bits_to_read as u8;
2037 let bits = (self.data[self.byte_pos] >> shift) & mask;
2038
2039 result = (result << bits_to_read) | (bits as u32);
2040 bits_read += bits_to_read;
2041 self.bit_pos += bits_to_read as u8;
2042
2043 if self.bit_pos >= 8 {
2044 self.bit_pos = 0;
2045 self.byte_pos += 1;
2046 }
2047 }
2048
2049 Some(result)
2050 }
2051}
2052
2053fn decode_run_length(data: &[u8]) -> ParseResult<Vec<u8>> {
2058 let mut result = Vec::new();
2059 let mut i = 0;
2060
2061 while i < data.len() {
2062 let length = data[i] as i8;
2063 i += 1;
2064
2065 if length == -128 {
2066 break;
2068 } else if length >= 0 {
2069 let count = (length as usize) + 1;
2071 if i + count > data.len() {
2072 return Err(ParseError::StreamDecodeError(
2073 "RunLength decode error: insufficient data for literal copy".to_string(),
2074 ));
2075 }
2076 result.extend_from_slice(&data[i..i + count]);
2077 i += count;
2078 } else {
2079 if i >= data.len() {
2081 return Err(ParseError::StreamDecodeError(
2082 "RunLength decode error: missing byte to repeat".to_string(),
2083 ));
2084 }
2085 let repeat_byte = data[i];
2086 let count = ((-length) as usize) + 1;
2087 for _ in 0..count {
2088 result.push(repeat_byte);
2089 }
2090 i += 1;
2091 }
2092
2093 if result.len() > MAX_DECOMPRESSED_SIZE {
2095 return Err(ParseError::StreamDecodeError(format!(
2096 "RunLength decompressed size exceeds {} MB limit",
2097 MAX_DECOMPRESSED_SIZE / (1024 * 1024)
2098 )));
2099 }
2100 }
2101
2102 Ok(result)
2103}