1use std::collections::HashMap;
9
10pub use rpdfium_core::error::ObjectId;
11use rpdfium_core::{Name, PdfString};
12
13#[derive(Debug, Clone)]
18pub enum StreamData {
19 Raw { offset: u64, length: u64 },
21 Decoded { data: Vec<u8> },
23}
24
25#[derive(Debug, Clone)]
30pub enum Object {
31 Null,
33 Boolean(bool),
35 Integer(i64),
37 Real(f64),
39 String(PdfString),
41 Name(Name),
43 Array(Vec<Object>),
45 Dictionary(HashMap<Name, Object>),
47 Stream {
49 dict: HashMap<Name, Object>,
50 data: StreamData,
51 },
52 Reference(ObjectId),
54}
55
56impl Object {
57 pub fn as_bool(&self) -> Option<bool> {
59 match self {
60 Object::Boolean(b) => Some(*b),
61 _ => None,
62 }
63 }
64
65 #[inline]
69 pub fn as_boolean(&self) -> Option<bool> {
70 self.as_bool()
71 }
72
73 pub fn as_i64(&self) -> Option<i64> {
75 match self {
76 Object::Integer(n) => Some(*n),
77 _ => None,
78 }
79 }
80
81 pub fn as_f64(&self) -> Option<f64> {
83 match self {
84 Object::Real(f) => Some(*f),
85 Object::Integer(n) => Some(*n as f64),
86 _ => None,
87 }
88 }
89
90 pub fn as_string(&self) -> Option<&PdfString> {
92 match self {
93 Object::String(s) => Some(s),
94 _ => None,
95 }
96 }
97
98 pub fn as_name(&self) -> Option<&Name> {
100 match self {
101 Object::Name(n) => Some(n),
102 _ => None,
103 }
104 }
105
106 pub fn as_array(&self) -> Option<&[Object]> {
108 match self {
109 Object::Array(a) => Some(a),
110 _ => None,
111 }
112 }
113
114 pub fn as_dict(&self) -> Option<&HashMap<Name, Object>> {
116 match self {
117 Object::Dictionary(d) => Some(d),
118 _ => None,
119 }
120 }
121
122 #[inline]
126 pub fn as_dictionary(&self) -> Option<&HashMap<Name, Object>> {
127 self.as_dict()
128 }
129
130 pub fn as_stream_dict(&self) -> Option<&HashMap<Name, Object>> {
132 match self {
133 Object::Stream { dict, .. } => Some(dict),
134 _ => None,
135 }
136 }
137
138 pub fn as_reference(&self) -> Option<ObjectId> {
140 match self {
141 Object::Reference(id) => Some(*id),
142 _ => None,
143 }
144 }
145
146 pub fn as_dict_mut(&mut self) -> Option<&mut HashMap<Name, Object>> {
148 match self {
149 Object::Dictionary(d) => Some(d),
150 _ => None,
151 }
152 }
153
154 pub fn as_array_mut(&mut self) -> Option<&mut Vec<Object>> {
156 match self {
157 Object::Array(a) => Some(a),
158 _ => None,
159 }
160 }
161
162 pub fn is_null(&self) -> bool {
164 matches!(self, Object::Null)
165 }
166
167 pub fn is_reference(&self) -> bool {
169 matches!(self, Object::Reference(_))
170 }
171
172 pub fn is_boolean(&self) -> bool {
176 matches!(self, Object::Boolean(_))
177 }
178
179 pub fn is_number(&self) -> bool {
183 matches!(self, Object::Integer(_) | Object::Real(_))
184 }
185
186 pub fn is_string(&self) -> bool {
190 matches!(self, Object::String(_))
191 }
192
193 pub fn is_name(&self) -> bool {
197 matches!(self, Object::Name(_))
198 }
199
200 pub fn is_array(&self) -> bool {
204 matches!(self, Object::Array(_))
205 }
206
207 pub fn is_dictionary(&self) -> bool {
211 matches!(self, Object::Dictionary(_))
212 }
213
214 pub fn is_stream(&self) -> bool {
218 matches!(self, Object::Stream { .. })
219 }
220
221 #[inline]
226 pub fn get_integer(&self) -> Option<i64> {
227 self.as_i64()
228 }
229
230 #[inline]
235 pub fn get_number(&self) -> Option<f64> {
236 self.as_f64()
237 }
238
239 #[inline]
244 pub fn get_string(&self) -> Option<&PdfString> {
245 self.as_string()
246 }
247
248 pub fn unicode_text(&self) -> Option<String> {
253 match self {
254 Object::String(s) => Some(s.to_string_lossy()),
255 Object::Name(n) => Some(n.as_str().to_string()),
256 _ => None,
257 }
258 }
259
260 #[inline]
264 pub fn get_unicode_text(&self) -> Option<String> {
265 self.unicode_text()
266 }
267
268 pub fn is_integer(&self) -> bool {
276 matches!(self, Object::Integer(_))
277 }
278
279 pub fn ref_obj_num(&self) -> Option<u32> {
288 match self {
289 Object::Reference(id) => Some(id.number),
290 _ => None,
291 }
292 }
293
294 #[inline]
298 pub fn get_ref_obj_num(&self) -> Option<u32> {
299 self.ref_obj_num()
300 }
301
302 pub fn raw_size(&self) -> Option<u64> {
314 match self {
315 Object::Stream { data, .. } => match data {
316 StreamData::Raw { length, .. } => Some(*length),
317 StreamData::Decoded { data } => Some(data.len() as u64),
318 },
319 _ => None,
320 }
321 }
322
323 #[inline]
327 pub fn get_raw_size(&self) -> Option<u64> {
328 self.raw_size()
329 }
330
331 pub fn has_filter(&self) -> bool {
335 match self {
336 Object::Stream { dict, .. } => dict.contains_key(&Name::filter()),
337 _ => false,
338 }
339 }
340
341 pub fn array_len(&self) -> Option<usize> {
349 match self {
350 Object::Array(a) => Some(a.len()),
351 _ => None,
352 }
353 }
354
355 #[inline]
361 #[deprecated(since = "0.0.0", note = "use `array_len()`")]
362 pub fn array_size(&self) -> Option<usize> {
363 self.array_len()
364 }
365
366 pub fn array_is_empty(&self) -> bool {
370 match self {
371 Object::Array(a) => a.is_empty(),
372 _ => false,
373 }
374 }
375
376 pub fn dict_len(&self) -> Option<usize> {
385 match self {
386 Object::Dictionary(d) => Some(d.len()),
387 _ => None,
388 }
389 }
390
391 #[inline]
397 #[deprecated(since = "0.0.0", note = "use `dict_len()`")]
398 pub fn dict_size(&self) -> Option<usize> {
399 self.dict_len()
400 }
401
402 pub fn key_exist(&self, key: &Name) -> bool {
408 match self {
409 Object::Dictionary(d) => d.contains_key(key),
410 _ => false,
411 }
412 }
413
414 pub fn keys(&self) -> Option<Vec<&Name>> {
418 match self {
419 Object::Dictionary(d) => Some(d.keys().collect()),
420 _ => None,
421 }
422 }
423
424 #[inline]
428 pub fn get_keys(&self) -> Option<Vec<&Name>> {
429 self.keys()
430 }
431
432 pub fn dict(&self) -> Option<&HashMap<Name, Object>> {
443 match self {
444 Object::Dictionary(d) => Some(d),
445 Object::Stream { dict, .. } => Some(dict),
446 _ => None,
447 }
448 }
449
450 #[inline]
454 pub fn get_dict(&self) -> Option<&HashMap<Name, Object>> {
455 self.dict()
456 }
457}
458
459#[cfg(test)]
460mod tests {
461 use super::*;
462
463 #[test]
464 fn test_object_id_display_format() {
465 let id = ObjectId::new(42, 0);
466 assert_eq!(format!("{}", id), "42 0 R");
467 }
468
469 #[test]
470 fn test_object_id_equality() {
471 let a = ObjectId::new(1, 0);
472 let b = ObjectId::new(1, 0);
473 let c = ObjectId::new(1, 1);
474 assert_eq!(a, b);
475 assert_ne!(a, c);
476 }
477
478 #[test]
479 fn test_object_null() {
480 let obj = Object::Null;
481 assert!(obj.is_null());
482 assert_eq!(obj.as_bool(), None);
483 assert_eq!(obj.as_i64(), None);
484 }
485
486 #[test]
487 fn test_object_boolean() {
488 let obj = Object::Boolean(true);
489 assert_eq!(obj.as_bool(), Some(true));
490 assert_eq!(obj.as_i64(), None);
491 }
492
493 #[test]
494 fn test_object_integer() {
495 let obj = Object::Integer(42);
496 assert_eq!(obj.as_i64(), Some(42));
497 assert_eq!(obj.as_f64(), Some(42.0));
498 assert_eq!(obj.as_bool(), None);
499 }
500
501 #[test]
502 #[allow(clippy::approx_constant)]
503 fn test_object_real() {
504 let obj = Object::Real(3.14);
505 assert_eq!(obj.as_f64(), Some(3.14));
506 assert_eq!(obj.as_i64(), None);
507 }
508
509 #[test]
510 fn test_object_string() {
511 let obj = Object::String(PdfString::from_bytes(b"hello".to_vec()));
512 assert!(obj.as_string().is_some());
513 assert_eq!(obj.as_string().unwrap().as_bytes(), b"hello");
514 }
515
516 #[test]
517 fn test_object_name() {
518 let obj = Object::Name(Name::from_bytes(b"Type".to_vec()));
519 assert!(obj.as_name().is_some());
520 }
521
522 #[test]
523 fn test_object_array() {
524 let obj = Object::Array(vec![Object::Integer(1), Object::Integer(2)]);
525 assert_eq!(obj.as_array().unwrap().len(), 2);
526 }
527
528 #[test]
529 fn test_object_dictionary() {
530 let mut dict = HashMap::new();
531 dict.insert(
532 Name::r#type(),
533 Object::Name(Name::from_bytes(b"Catalog".to_vec())),
534 );
535 let obj = Object::Dictionary(dict);
536 assert!(obj.as_dict().is_some());
537 }
538
539 #[test]
540 fn test_object_stream() {
541 let dict = HashMap::new();
542 let data = StreamData::Raw {
543 offset: 0,
544 length: 100,
545 };
546 let obj = Object::Stream { dict, data };
547 assert!(obj.as_stream_dict().is_some());
548 }
549
550 #[test]
551 fn test_object_reference() {
552 let id = ObjectId::new(5, 0);
553 let obj = Object::Reference(id);
554 assert!(obj.is_reference());
555 assert_eq!(obj.as_reference(), Some(id));
556 }
557
558 #[test]
559 fn test_object_unicode_text() {
560 let str_obj = Object::String(PdfString::from_bytes(b"hello".to_vec()));
561 assert_eq!(str_obj.unicode_text(), Some("hello".to_string()));
562 assert_eq!(str_obj.get_unicode_text(), Some("hello".to_string()));
563
564 let name_obj = Object::Name(Name::from("Foo"));
565 assert_eq!(name_obj.unicode_text(), Some("Foo".to_string()));
566
567 let int_obj = Object::Integer(42);
568 assert_eq!(int_obj.unicode_text(), None);
569 }
570
571 #[test]
572 fn test_object_get_aliases_delegate_to_as_methods() {
573 let int_obj = Object::Integer(99);
574 assert_eq!(int_obj.get_integer(), Some(99));
575 assert_eq!(int_obj.get_number(), Some(99.0));
576 assert_eq!(int_obj.get_string(), None);
577 assert_eq!(int_obj.as_name(), None);
578
579 let real_obj = Object::Real(3.14);
580 assert_eq!(real_obj.get_number(), Some(3.14));
581 assert_eq!(real_obj.get_integer(), None);
582
583 let str_obj = Object::String(PdfString::from_bytes(b"hello".to_vec()));
584 assert!(str_obj.get_string().is_some());
585 assert_eq!(str_obj.get_integer(), None);
586
587 let name_obj = Object::Name(Name::from("Foo"));
588 assert!(name_obj.as_name().is_some());
589 assert_eq!(name_obj.get_string(), None);
590 }
591
592 #[test]
597 fn test_is_integer_distinguishes_integer_from_real() {
598 assert!(Object::Integer(5).is_integer());
600 assert!(!Object::Real(5.0).is_integer());
601 assert!(!Object::Null.is_integer());
602 assert!(!Object::Boolean(true).is_integer());
603 }
604
605 #[test]
606 fn test_ref_obj_num_and_alias() {
607 let id = ObjectId::new(7, 0);
608 let obj = Object::Reference(id);
609 assert_eq!(obj.ref_obj_num(), Some(7));
610 assert_eq!(obj.get_ref_obj_num(), Some(7));
611
612 assert_eq!(Object::Integer(1).ref_obj_num(), None);
614 assert_eq!(Object::Null.get_ref_obj_num(), None);
615 }
616
617 #[test]
618 fn test_raw_size_and_alias() {
619 let raw_stream = Object::Stream {
621 dict: HashMap::new(),
622 data: StreamData::Raw {
623 offset: 0,
624 length: 42,
625 },
626 };
627 assert_eq!(raw_stream.raw_size(), Some(42));
628 assert_eq!(raw_stream.get_raw_size(), Some(42));
629
630 let decoded_stream = Object::Stream {
632 dict: HashMap::new(),
633 data: StreamData::Decoded {
634 data: vec![0u8; 10],
635 },
636 };
637 assert_eq!(decoded_stream.raw_size(), Some(10));
638 assert_eq!(decoded_stream.get_raw_size(), Some(10));
639
640 assert_eq!(Object::Integer(1).raw_size(), None);
642 }
643
644 #[test]
645 fn test_has_filter_detects_filter_key() {
646 let mut dict_with_filter = HashMap::new();
647 dict_with_filter.insert(Name::filter(), Object::Name(Name::from("FlateDecode")));
648 let stream_with_filter = Object::Stream {
649 dict: dict_with_filter,
650 data: StreamData::Raw {
651 offset: 0,
652 length: 0,
653 },
654 };
655 assert!(stream_with_filter.has_filter());
656
657 let stream_without_filter = Object::Stream {
658 dict: HashMap::new(),
659 data: StreamData::Raw {
660 offset: 0,
661 length: 0,
662 },
663 };
664 assert!(!stream_without_filter.has_filter());
665
666 assert!(!Object::Integer(1).has_filter());
668 }
669
670 #[test]
671 #[allow(deprecated)]
672 fn test_array_len_size_is_empty() {
673 let arr = Object::Array(vec![Object::Integer(1), Object::Integer(2)]);
674 assert_eq!(arr.array_len(), Some(2));
675 assert_eq!(arr.array_size(), Some(2));
676 assert!(!arr.array_is_empty());
677
678 let empty_arr = Object::Array(vec![]);
679 assert_eq!(empty_arr.array_len(), Some(0));
680 assert!(empty_arr.array_is_empty());
681
682 assert_eq!(Object::Integer(1).array_len(), None);
684 assert_eq!(Object::Integer(1).array_size(), None);
685 assert!(!Object::Integer(1).array_is_empty());
686 }
687
688 #[test]
689 #[allow(deprecated)]
690 fn test_dict_len_size() {
691 let mut map = HashMap::new();
692 map.insert(Name::r#type(), Object::Name(Name::from("Page")));
693 let dict = Object::Dictionary(map);
694 assert_eq!(dict.dict_len(), Some(1));
695 assert_eq!(dict.dict_size(), Some(1));
696
697 let empty_dict = Object::Dictionary(HashMap::new());
698 assert_eq!(empty_dict.dict_len(), Some(0));
699
700 assert_eq!(Object::Integer(1).dict_len(), None);
702 }
703
704 #[test]
705 fn test_key_exist_on_dictionary() {
706 let mut map = HashMap::new();
707 let type_name = Name::r#type();
708 map.insert(type_name.clone(), Object::Name(Name::from("Page")));
709 let dict = Object::Dictionary(map);
710
711 assert!(dict.key_exist(&type_name));
712 assert!(!dict.key_exist(&Name::from("Missing")));
713
714 assert!(!Object::Integer(1).key_exist(&type_name));
716 }
717
718 #[test]
719 fn test_keys_and_get_keys_on_dictionary() {
720 let mut map = HashMap::new();
721 map.insert(Name::r#type(), Object::Name(Name::from("Page")));
722 let dict = Object::Dictionary(map);
723
724 let ks = dict.keys().expect("should return keys for dict");
725 assert_eq!(ks.len(), 1);
726 let gks = dict.get_keys().expect("get_keys alias should also work");
727 assert_eq!(gks.len(), 1);
728
729 assert!(Object::Integer(1).keys().is_none());
731 assert!(Object::Integer(1).get_keys().is_none());
732 }
733
734 #[test]
735 fn test_dict_method_returns_dict_and_stream_dict() {
736 let mut map = HashMap::new();
738 map.insert(Name::r#type(), Object::Name(Name::from("Page")));
739 let dict_obj = Object::Dictionary(map.clone());
740 assert!(dict_obj.dict().is_some());
741 assert!(dict_obj.get_dict().is_some());
742
743 let stream_obj = Object::Stream {
745 dict: map,
746 data: StreamData::Raw {
747 offset: 0,
748 length: 0,
749 },
750 };
751 assert!(stream_obj.dict().is_some());
752 assert!(stream_obj.get_dict().is_some());
753
754 assert!(Object::Integer(1).dict().is_none());
756 assert!(Object::Null.get_dict().is_none());
757 }
758
759 #[test]
769 fn test_number_float_values() {
770 let n = Object::Real(0.0);
772 assert_eq!(n.as_f64(), Some(0.0));
773 assert!(n.is_number());
774 assert!(!n.is_integer());
775
776 let n = Object::Real(1.0);
778 assert_eq!(n.as_f64(), Some(1.0));
779
780 let n = Object::Real(-7.5);
782 assert_eq!(n.as_f64(), Some(-7.5));
783
784 let n = Object::Real(38.895285_f64);
786 let val = n.as_f64().unwrap();
787 assert!((val - 38.895285).abs() < 0.001);
788
789 let n = Object::Real(f32::MAX as f64);
791 assert!(n.as_f64().unwrap() > 0.0);
792
793 let n = Object::Real(f32::MIN_POSITIVE as f64);
795 let val = n.as_f64().unwrap();
796 assert!(val > 0.0);
797 assert!(val < 0.001);
798 }
799
800 #[test]
804 fn test_number_integer_values() {
805 let n = Object::Integer(0);
807 assert_eq!(n.as_i64(), Some(0));
808 assert!(n.is_integer());
809 assert!(n.is_number());
810
811 let n = Object::Integer(1);
813 assert_eq!(n.as_i64(), Some(1));
814
815 let n = Object::Integer(-99);
817 assert_eq!(n.as_i64(), Some(-99));
818
819 let n = Object::Integer(1234);
821 assert_eq!(n.as_i64(), Some(1234));
822
823 let n = Object::Integer(-54321);
825 assert_eq!(n.as_i64(), Some(-54321));
826
827 let n = Object::Integer(i32::MAX as i64);
829 assert_eq!(n.as_i64(), Some(i32::MAX as i64));
830 assert_eq!(n.as_f64(), Some(i32::MAX as f64));
831
832 let n = Object::Integer(i32::MIN as i64);
834 assert_eq!(n.as_i64(), Some(i32::MIN as i64));
835 assert_eq!(n.as_f64(), Some(i32::MIN as f64));
836 }
837
838 #[test]
847 fn test_dictionary_iterators() {
848 let mut dict = HashMap::new();
849 dict.insert(
850 Name::from("the-dictionary"),
851 Object::Dictionary(HashMap::new()),
852 );
853 dict.insert(Name::from("the-array"), Object::Array(vec![]));
854 dict.insert(Name::from("the-number"), Object::Integer(42));
855
856 let obj = Object::Dictionary(dict);
857 let d = obj.as_dict().unwrap();
858
859 assert_eq!(d.len(), 3);
861
862 let dict_val = d.get(&Name::from("the-dictionary")).unwrap();
864 assert!(dict_val.is_dictionary());
865
866 let arr_val = d.get(&Name::from("the-array")).unwrap();
867 assert!(arr_val.is_array());
868
869 let num_val = d.get(&Name::from("the-number")).unwrap();
870 assert!(num_val.is_number());
871 assert_eq!(num_val.as_i64(), Some(42));
872
873 let keys: Vec<&Name> = d.keys().collect();
875 assert_eq!(keys.len(), 3);
876 assert!(keys.contains(&&Name::from("the-dictionary")));
877 assert!(keys.contains(&&Name::from("the-array")));
878 assert!(keys.contains(&&Name::from("the-number")));
879
880 }
883
884 fn make_direct_objects() -> Vec<Object> {
890 let mut dict = HashMap::new();
891 dict.insert(Name::from("bool"), Object::Boolean(false));
892 dict.insert(Name::from("num"), Object::Real(0.23));
893
894 let mut stream_dict = HashMap::new();
895 stream_dict.insert(
896 Name::from("key1"),
897 Object::String(PdfString::from_bytes(b" test dict".to_vec())),
898 );
899 stream_dict.insert(Name::from("key2"), Object::Integer(-1));
900
901 vec![
902 Object::Boolean(false), Object::Boolean(true), Object::Integer(1245), Object::Real(9.00345_f64), Object::String(PdfString::from_bytes(b"A simple test".to_vec())), Object::String(PdfString::from_bytes(b"\t\n".to_vec())), Object::Name(Name::from("space")), Object::Array(vec![
910 Object::Integer(8902),
911 Object::Name(Name::from("address")),
912 ]), Object::Dictionary(dict), Object::Stream {
915 dict: stream_dict,
916 data: StreamData::Decoded {
917 data: b"abcdefghijklmnopqrstuvwxyz".to_vec(),
918 },
919 }, Object::Null, ]
922 }
923
924 #[test]
928 fn test_pdf_objects_get_type() {
929 let objs = make_direct_objects();
930 assert!(objs[0].is_boolean());
931 assert!(objs[1].is_boolean());
932 assert!(objs[2].is_number());
933 assert!(objs[2].is_integer());
934 assert!(objs[3].is_number());
935 assert!(!objs[3].is_integer());
936 assert!(objs[4].is_string());
937 assert!(objs[5].is_string());
938 assert!(objs[6].is_name());
939 assert!(objs[7].is_array());
940 assert!(objs[8].is_dictionary());
941 assert!(objs[9].is_stream());
942 assert!(objs[10].is_null());
943 }
944
945 #[test]
949 fn test_pdf_objects_get_integer() {
950 let objs = make_direct_objects();
951 assert_eq!(objs[0].get_integer(), None);
952 assert_eq!(objs[1].get_integer(), None);
953 assert_eq!(objs[2].get_integer(), Some(1245));
954 assert_eq!(objs[3].get_integer(), None);
955 assert_eq!(objs[4].get_integer(), None);
956 assert_eq!(objs[6].get_integer(), None);
957 assert_eq!(objs[7].get_integer(), None);
958 assert_eq!(objs[8].get_integer(), None);
959 assert_eq!(objs[10].get_integer(), None);
960 }
961
962 #[test]
966 fn test_pdf_objects_get_number() {
967 let objs = make_direct_objects();
968 assert_eq!(objs[0].get_number(), None);
969 assert_eq!(objs[2].get_number(), Some(1245.0));
970 assert!(objs[3].get_number().is_some());
971 assert_eq!(objs[4].get_number(), None);
972 assert_eq!(objs[6].get_number(), None);
973 assert_eq!(objs[10].get_number(), None);
974 }
975
976 #[test]
980 fn test_pdf_objects_get_string() {
981 let objs = make_direct_objects();
982 assert_eq!(objs[0].get_string(), None);
983 assert_eq!(objs[1].get_string(), None);
984 assert_eq!(objs[2].get_string(), None);
985 assert_eq!(objs[3].get_string(), None);
986 assert!(objs[4].get_string().is_some());
987 assert_eq!(objs[4].get_string().unwrap().as_bytes(), b"A simple test");
988 assert!(objs[5].get_string().is_some());
989 assert_eq!(objs[5].get_string().unwrap().as_bytes(), b"\t\n");
990 assert_eq!(objs[6].get_string(), None);
991 assert_eq!(objs[7].get_string(), None);
992 assert_eq!(objs[10].get_string(), None);
993 }
994
995 #[test]
999 fn test_pdf_objects_get_dict() {
1000 let objs = make_direct_objects();
1001 assert!(objs[0].dict().is_none());
1002 assert!(objs[2].dict().is_none());
1003 assert!(objs[4].dict().is_none());
1004 assert!(objs[6].dict().is_none());
1005 assert!(objs[7].dict().is_none());
1006 assert!(objs[8].dict().is_some());
1007 assert!(objs[9].dict().is_some());
1008 assert!(objs[10].dict().is_none());
1009 }
1010
1011 #[test]
1015 fn test_pdf_objects_get_array() {
1016 let objs = make_direct_objects();
1017 assert!(objs[0].as_array().is_none());
1018 assert!(objs[2].as_array().is_none());
1019 assert!(objs[4].as_array().is_none());
1020 assert!(objs[6].as_array().is_none());
1021 assert!(objs[7].as_array().is_some());
1022 assert_eq!(objs[7].as_array().unwrap().len(), 2);
1023 assert!(objs[8].as_array().is_none());
1024 assert!(objs[9].as_array().is_none());
1025 assert!(objs[10].as_array().is_none());
1026 }
1027
1028 #[test]
1032 fn test_pdf_objects_is_type_and_as_type() {
1033 let objs = make_direct_objects();
1034
1035 for (i, obj) in objs.iter().enumerate() {
1036 if i <= 1 {
1037 assert!(obj.is_boolean(), "obj[{i}] should be boolean");
1038 assert!(obj.as_bool().is_some());
1039 } else {
1040 assert!(!obj.is_boolean(), "obj[{i}] should not be boolean");
1041 assert!(obj.as_bool().is_none());
1042 }
1043
1044 if i == 2 || i == 3 {
1045 assert!(obj.is_number(), "obj[{i}] should be number");
1046 } else {
1047 assert!(!obj.is_number(), "obj[{i}] should not be number");
1048 }
1049
1050 if i == 4 || i == 5 {
1051 assert!(obj.is_string(), "obj[{i}] should be string");
1052 assert!(obj.as_string().is_some());
1053 } else {
1054 assert!(!obj.is_string(), "obj[{i}] should not be string");
1055 assert!(obj.as_string().is_none());
1056 }
1057
1058 if i == 6 {
1059 assert!(obj.is_name(), "obj[{i}] should be name");
1060 assert!(obj.as_name().is_some());
1061 } else {
1062 assert!(!obj.is_name(), "obj[{i}] should not be name");
1063 assert!(obj.as_name().is_none());
1064 }
1065
1066 if i == 7 {
1067 assert!(obj.is_array(), "obj[{i}] should be array");
1068 assert!(obj.as_array().is_some());
1069 } else {
1070 assert!(!obj.is_array(), "obj[{i}] should not be array");
1071 assert!(obj.as_array().is_none());
1072 }
1073
1074 if i == 8 {
1075 assert!(obj.is_dictionary(), "obj[{i}] should be dictionary");
1076 assert!(obj.as_dict().is_some());
1077 } else {
1078 assert!(!obj.is_dictionary(), "obj[{i}] should not be dictionary");
1079 if i != 9 {
1080 assert!(obj.as_dict().is_none());
1081 }
1082 }
1083
1084 if i == 9 {
1085 assert!(obj.is_stream(), "obj[{i}] should be stream");
1086 assert!(obj.as_stream_dict().is_some());
1087 } else {
1088 assert!(!obj.is_stream(), "obj[{i}] should not be stream");
1089 assert!(obj.as_stream_dict().is_none());
1090 }
1091
1092 assert!(!obj.is_reference(), "obj[{i}] should not be reference");
1093 assert!(obj.as_reference().is_none());
1094 }
1095 }
1096
1097 #[test]
1101 fn test_pdf_objects_reference_deref() {
1102 let id = ObjectId::new(42, 0);
1103 let ref_obj = Object::Reference(id);
1104 assert!(ref_obj.is_reference());
1105 assert_eq!(ref_obj.as_reference(), Some(id));
1106 assert_eq!(ref_obj.ref_obj_num(), Some(42));
1107 }
1108
1109 #[test]
1117 fn test_pdf_array_get_matrix_elements() {
1118 let elems: Vec<[f64; 6]> = vec![
1119 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
1120 [1.0, 2.0, 3.0, 4.0, 5.0, 6.0],
1121 [2.3, 4.05, 3.0, -2.0, -3.0, 0.0],
1122 [0.05, 0.1, 0.56, 0.67, 1.34, 99.9],
1123 ];
1124 for elem in &elems {
1125 let arr = Object::Array(elem.iter().map(|&f| Object::Real(f)).collect());
1126 let items = arr.as_array().unwrap();
1127 assert_eq!(items.len(), 6);
1128 for (i, &val) in elem.iter().enumerate() {
1129 assert_eq!(items[i].as_f64(), Some(val), "mismatch at index {i}");
1130 }
1131 }
1132 }
1133
1134 #[test]
1138 fn test_pdf_array_get_rect_elements() {
1139 let elems: Vec<[f64; 4]> = vec![
1140 [0.0, 0.0, 0.0, 0.0],
1141 [1.0, 2.0, 5.0, 6.0],
1142 [2.3, 4.05, -3.0, 0.0],
1143 [0.05, 0.1, 1.34, 99.9],
1144 ];
1145 for elem in &elems {
1146 let arr = Object::Array(elem.iter().map(|&f| Object::Real(f)).collect());
1147 let items = arr.as_array().unwrap();
1148 assert_eq!(items.len(), 4);
1149 for (i, &val) in elem.iter().enumerate() {
1150 assert_eq!(items[i].as_f64(), Some(val), "mismatch at index {i}");
1151 }
1152 }
1153 }
1154
1155 #[test]
1157 fn test_pdf_array_get_type_at_boolean() {
1158 let vals = [true, false, false, true, true];
1159 let arr = Object::Array(vals.iter().map(|&b| Object::Boolean(b)).collect());
1160 let items = arr.as_array().unwrap();
1161 for (i, &expected) in vals.iter().enumerate() {
1162 assert_eq!(items[i].as_bool(), Some(expected), "bool mismatch at {i}");
1163 assert_eq!(items[i].as_i64(), None);
1164 assert_eq!(items[i].as_f64(), None);
1165 assert!(items[i].as_array().is_none());
1166 assert!(items[i].as_dict().is_none());
1167 }
1168 }
1169
1170 #[test]
1172 fn test_pdf_array_get_type_at_integer() {
1173 let vals: Vec<i64> = vec![10, 0, -345, 2089345456, -1000000000, 567, 93658767];
1174 let arr = Object::Array(vals.iter().map(|&n| Object::Integer(n)).collect());
1175 let items = arr.as_array().unwrap();
1176 for (i, &val) in vals.iter().enumerate() {
1177 assert_eq!(items[i].as_i64(), Some(val), "int mismatch at {i}");
1178 assert_eq!(items[i].as_f64(), Some(val as f64), "float mismatch at {i}");
1179 assert!(items[i].as_array().is_none());
1180 assert!(items[i].as_dict().is_none());
1181 }
1182 }
1183
1184 #[test]
1186 fn test_pdf_array_get_type_at_name() {
1187 let vals = [
1188 "this",
1189 "adsde$%^",
1190 "\r\t",
1191 "\"012",
1192 ".",
1193 "EYREW",
1194 "It is a joke :)",
1195 ];
1196 let arr = Object::Array(vals.iter().map(|&s| Object::Name(Name::from(s))).collect());
1197 let items = arr.as_array().unwrap();
1198 for (i, &val) in vals.iter().enumerate() {
1199 let name = items[i].as_name().unwrap();
1200 assert_eq!(name.as_str().as_ref(), val, "name mismatch at {i}");
1201 assert_eq!(items[i].as_i64(), None);
1202 assert_eq!(items[i].as_f64(), None);
1203 }
1204 }
1205
1206 #[test]
1208 fn test_pdf_array_get_type_at_null() {
1209 let arr = Object::Array(vec![Object::Null, Object::Null, Object::Null]);
1210 let items = arr.as_array().unwrap();
1211 for i in 0..3 {
1212 assert!(items[i].is_null());
1213 assert_eq!(items[i].as_i64(), None);
1214 assert_eq!(items[i].as_f64(), None);
1215 assert!(items[i].as_array().is_none());
1216 assert!(items[i].as_dict().is_none());
1217 assert!(items[i].as_string().is_none());
1218 }
1219 }
1220
1221 #[test]
1223 fn test_pdf_array_get_type_at_mixed() {
1224 let arr = Object::Array(vec![
1225 Object::Boolean(true),
1226 Object::Boolean(false),
1227 Object::Integer(0),
1228 Object::Integer(-1234),
1229 Object::Real(2345.0),
1230 Object::Real(0.05),
1231 Object::String(PdfString::from_bytes(b"".to_vec())),
1232 Object::String(PdfString::from_bytes(b"It is a test!".to_vec())),
1233 Object::Name(Name::from("NAME")),
1234 Object::Name(Name::from("test")),
1235 Object::Null,
1236 ]);
1237 let items = arr.as_array().unwrap();
1238 assert_eq!(items.len(), 11);
1239 assert_eq!(items[0].as_bool(), Some(true));
1240 assert_eq!(items[1].as_bool(), Some(false));
1241 assert_eq!(items[2].as_i64(), Some(0));
1242 assert_eq!(items[3].as_i64(), Some(-1234));
1243 assert_eq!(items[4].as_f64(), Some(2345.0));
1244 assert_eq!(items[5].as_f64(), Some(0.05));
1245 assert_eq!(items[6].as_string().unwrap().as_bytes(), b"");
1246 assert_eq!(items[7].as_string().unwrap().as_bytes(), b"It is a test!");
1247 assert_eq!(items[8].as_name().unwrap().as_str().as_ref(), "NAME");
1248 assert_eq!(items[9].as_name().unwrap().as_str().as_ref(), "test");
1249 assert!(items[10].is_null());
1250 }
1251
1252 #[test]
1254 fn test_pdf_array_nested_arrays() {
1255 let inner: Vec<Object> = (0..3)
1256 .map(|_| Object::Array((100..103).map(Object::Integer).collect()))
1257 .collect();
1258 let arr = Object::Array(inner);
1259 let items = arr.as_array().unwrap();
1260 assert_eq!(items.len(), 3);
1261 for i in 0..3 {
1262 let sub = items[i].as_array().unwrap();
1263 assert_eq!(sub.len(), 3);
1264 assert_eq!(sub[0].as_i64(), Some(100));
1265 assert_eq!(sub[1].as_i64(), Some(101));
1266 assert_eq!(sub[2].as_i64(), Some(102));
1267 }
1268 }
1269
1270 #[test]
1272 fn test_pdf_array_of_dicts() {
1273 let inner: Vec<Object> = (0..3)
1274 .map(|_| {
1275 let mut d = HashMap::new();
1276 for j in 0..3i64 {
1277 d.insert(
1278 Name::from(format!("key{j}").as_str()),
1279 Object::Integer(j + 200),
1280 );
1281 }
1282 Object::Dictionary(d)
1283 })
1284 .collect();
1285 let arr = Object::Array(inner);
1286 let items = arr.as_array().unwrap();
1287 assert_eq!(items.len(), 3);
1288 for i in 0..3 {
1289 let d = items[i].as_dict().unwrap();
1290 assert_eq!(d.len(), 3);
1291 assert_eq!(d.get(&Name::from("key0")).unwrap().as_i64(), Some(200));
1292 }
1293 }
1294
1295 #[test]
1299 fn test_pdf_array_iterator() {
1300 let elems: Vec<i64> = vec![
1301 -23, -11, 3, 455, 2345877, 0, 7895330, -12564334, 10000, -100000,
1302 ];
1303 let arr = Object::Array(elems.iter().map(|&n| Object::Integer(n)).collect());
1304 let items = arr.as_array().unwrap();
1305 for (i, item) in items.iter().enumerate() {
1306 assert_eq!(item.as_i64(), Some(elems[i]), "mismatch at index {i}");
1307 }
1308 }
1309
1310 #[test]
1314 fn test_pdf_objects_dict_name_for() {
1315 let mut d = HashMap::new();
1316 d.insert(Name::from("bool"), Object::Boolean(false));
1317 d.insert(Name::from("num"), Object::Real(0.23));
1318 d.insert(
1319 Name::from("string"),
1320 Object::String(PdfString::from_bytes(b"ium".to_vec())),
1321 );
1322 d.insert(Name::from("name"), Object::Name(Name::from("Pdf")));
1323 let dict = Object::Dictionary(d);
1324 let d = dict.as_dict().unwrap();
1325
1326 assert_eq!(
1328 d.get(&Name::from("name"))
1329 .and_then(|o| o.as_name())
1330 .map(|n| n.as_str().to_string()),
1331 Some("Pdf".to_string())
1332 );
1333 assert!(
1335 d.get(&Name::from("bool"))
1336 .and_then(|o| o.as_name())
1337 .is_none()
1338 );
1339 assert!(d.get(&Name::from("invalid")).is_none());
1341 }
1342
1343 #[test]
1355 fn test_pdf_objects_get_unicode_text() {
1356 let objs = make_direct_objects();
1357 assert!(objs[0].unicode_text().is_none());
1359 assert!(objs[1].unicode_text().is_none());
1360 assert!(objs[2].unicode_text().is_none());
1362 assert!(objs[3].unicode_text().is_none());
1363 assert_eq!(objs[4].unicode_text(), Some("A simple test".to_string()));
1365 assert!(objs[5].unicode_text().is_some());
1367 assert_eq!(objs[6].unicode_text(), Some("space".to_string()));
1369 assert!(objs[7].unicode_text().is_none());
1371 assert!(objs[8].unicode_text().is_none());
1373 assert!(objs[10].unicode_text().is_none());
1375 }
1376
1377 #[test]
1387 fn test_pdf_array_get_boolean_at() {
1388 let arr = Object::Array(vec![
1389 Object::Boolean(true),
1390 Object::Boolean(false),
1391 Object::Integer(100),
1392 Object::Integer(0),
1393 ]);
1394 let items = arr.as_array().unwrap();
1395 assert_eq!(items.len(), 4);
1396
1397 assert_eq!(items[0].as_bool(), Some(true));
1399 assert_eq!(items[1].as_bool(), Some(false));
1401 assert_eq!(items[2].as_bool(), None);
1403 assert_eq!(items[3].as_bool(), None);
1405 }
1406
1407 #[test]
1411 fn test_pdf_array_add_number() {
1412 let vals: Vec<f64> = vec![1.0, -1.0, 0.0, 0.456734, 12345.54321, 0.5, 1000.0, 0.000045];
1413 let arr = Object::Array(vals.iter().map(|&f| Object::Real(f)).collect());
1414 let items = arr.as_array().unwrap();
1415 assert_eq!(items.len(), vals.len());
1416 for (i, &val) in vals.iter().enumerate() {
1417 assert!(items[i].is_number());
1418 assert_eq!(items[i].as_f64(), Some(val), "mismatch at index {i}");
1419 }
1420 }
1421
1422 #[test]
1426 fn test_pdf_array_add_integer() {
1427 let vals: Vec<i64> = vec![0, 1, 934435456, 876, 10000, -1, -24354656, -100];
1428 let arr = Object::Array(vals.iter().map(|&n| Object::Integer(n)).collect());
1429 let items = arr.as_array().unwrap();
1430 assert_eq!(items.len(), vals.len());
1431 for (i, &val) in vals.iter().enumerate() {
1432 assert!(items[i].is_number());
1433 assert_eq!(items[i].as_i64(), Some(val), "mismatch at index {i}");
1434 }
1435 }
1436
1437 #[test]
1441 fn test_pdf_array_add_string_and_name() {
1442 let vals = [
1443 "",
1444 "a",
1445 "ehjhRIOYTTFdfcdnv",
1446 "122323",
1447 "$#%^&**",
1448 " ",
1449 "This is a test.\r\n",
1450 ];
1451 let string_arr = Object::Array(
1452 vals.iter()
1453 .map(|&s| Object::String(PdfString::from_bytes(s.as_bytes().to_vec())))
1454 .collect(),
1455 );
1456 let name_arr = Object::Array(vals.iter().map(|&s| Object::Name(Name::from(s))).collect());
1457 let str_items = string_arr.as_array().unwrap();
1458 let name_items = name_arr.as_array().unwrap();
1459 for (i, &val) in vals.iter().enumerate() {
1460 assert!(str_items[i].is_string(), "string item {i} should be string");
1461 assert_eq!(
1462 str_items[i].as_string().unwrap().as_bytes(),
1463 val.as_bytes(),
1464 "string mismatch at {i}"
1465 );
1466 assert!(name_items[i].is_name(), "name item {i} should be name");
1467 assert_eq!(
1468 name_items[i].as_name().unwrap().as_str().as_ref(),
1469 val,
1470 "name mismatch at {i}"
1471 );
1472 }
1473 }
1474
1475 #[test]
1479 fn test_pdf_array_get_type_at_float() {
1480 let vals: Vec<f64> = vec![
1481 0.0, 0.0, 10.0, 10.0, 0.0345, 897.34, -2.5, -1.0, -345.0, -0.0,
1482 ];
1483 let arr = Object::Array(vals.iter().map(|&f| Object::Real(f)).collect());
1484 let items = arr.as_array().unwrap();
1485 assert_eq!(items.len(), vals.len());
1486 for (i, &val) in vals.iter().enumerate() {
1487 assert_eq!(items[i].as_f64(), Some(val), "float mismatch at {i}");
1488 assert!(items[i].as_array().is_none());
1489 assert!(items[i].as_dict().is_none());
1490 }
1491 }
1492
1493 #[test]
1505 fn test_pdf_array_find() {
1506 let arr = Object::Array(vec![
1507 Object::Integer(10),
1508 Object::Integer(20),
1509 Object::Integer(30),
1510 ]);
1511 let items = arr.as_array().unwrap();
1512
1513 let pos = items.iter().position(|o| o.as_i64() == Some(20));
1515 assert_eq!(pos, Some(1));
1516
1517 let pos = items.iter().position(|o| o.as_i64() == Some(99));
1518 assert_eq!(pos, None);
1519 }
1520
1521 #[test]
1525 fn test_pdf_array_contains() {
1526 let arr = Object::Array(vec![Object::Integer(10), Object::Integer(20)]);
1527 let items = arr.as_array().unwrap();
1528 assert!(items.iter().any(|o| o.as_i64() == Some(10)));
1529 assert!(items.iter().any(|o| o.as_i64() == Some(20)));
1530 assert!(!items.iter().any(|o| o.as_i64() == Some(30)));
1531 }
1532
1533 #[test]
1540 fn test_pdf_array_set_at_beyond() {
1541 let mut arr = vec![Object::Integer(0)];
1542 arr[0] = Object::Integer(42);
1544 assert_eq!(arr[0].as_i64(), Some(42));
1545 assert_eq!(arr.len(), 1);
1548 }
1549
1550 #[test]
1556 fn test_pdf_array_insert_at_beyond() {
1557 let mut arr: Vec<Object> = Vec::new();
1558 arr.insert(0, Object::Integer(0));
1560 assert_eq!(arr.len(), 1);
1561 arr.insert(1, Object::Integer(1));
1563 assert_eq!(arr.len(), 2);
1564 assert_eq!(arr[0].as_i64(), Some(0));
1565 assert_eq!(arr[1].as_i64(), Some(1));
1566 }
1567
1568 #[test]
1572 fn test_pdf_array_get_type_at_string() {
1573 let vals = [
1574 "this",
1575 "adsde$%^",
1576 "\r\t",
1577 "\"012",
1578 ".",
1579 "EYREW",
1580 "It is a joke :)",
1581 ];
1582 let arr = Object::Array(
1583 vals.iter()
1584 .map(|&s| Object::String(PdfString::from_bytes(s.as_bytes().to_vec())))
1585 .collect(),
1586 );
1587 let items = arr.as_array().unwrap();
1588 for (i, &val) in vals.iter().enumerate() {
1589 assert_eq!(
1590 items[i].as_string().unwrap().as_bytes(),
1591 val.as_bytes(),
1592 "string mismatch at {i}"
1593 );
1594 assert_eq!(items[i].as_i64(), None);
1595 assert_eq!(items[i].as_f64(), None);
1596 assert!(items[i].as_array().is_none());
1597 assert!(items[i].as_dict().is_none());
1598 }
1599 }
1600}