1use std::convert::TryFrom;
2use std::marker::PhantomData;
3use std::mem::ManuallyDrop;
4use std::num::NonZeroI32;
5
6use super::*;
7
8pub trait Primitive {
10 fn write(self, buf: &mut Vec<u8>);
12}
13
14impl<T: Primitive> Primitive for &T
15where
16 T: Copy,
17{
18 #[inline]
19 fn write(self, buf: &mut Vec<u8>) {
20 (*self).write(buf);
21 }
22}
23
24impl Primitive for bool {
25 #[inline]
26 fn write(self, buf: &mut Vec<u8>) {
27 if self {
28 buf.extend(b"true");
29 } else {
30 buf.extend(b"false");
31 }
32 }
33}
34
35impl Primitive for i32 {
36 #[inline]
37 fn write(self, buf: &mut Vec<u8>) {
38 buf.push_int(self);
39 }
40}
41
42impl Primitive for f32 {
43 #[inline]
44 fn write(self, buf: &mut Vec<u8>) {
45 buf.push_float(self);
46 }
47}
48
49#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
53pub struct Str<'a>(pub &'a [u8]);
54
55impl Str<'_> {
56 fn is_balanced(self) -> bool {
58 let mut depth = 0;
59 for &byte in self.0 {
60 match byte {
61 b'(' => depth += 1,
62 b')' if depth > 0 => depth -= 1,
63 b')' => return false,
64 _ => {}
65 }
66 }
67 depth == 0
68 }
69}
70
71impl Primitive for Str<'_> {
72 fn write(self, buf: &mut Vec<u8>) {
73 if self.0.iter().all(|b| b.is_ascii()) {
79 buf.reserve(self.0.len());
80 buf.push(b'(');
81
82 let mut balanced = None;
83 for &byte in self.0 {
84 match byte {
85 b'(' | b')' => {
86 if !*balanced
87 .get_or_insert_with(|| byte != b')' && self.is_balanced())
88 {
89 buf.push(b'\\');
90 }
91 buf.push(byte);
92 }
93 b'\\' => buf.extend(br"\\"),
94 b' '..=b'~' => buf.push(byte),
95 b'\n' => buf.extend(br"\n"),
96 b'\r' => buf.extend(br"\r"),
97 b'\t' => buf.extend(br"\t"),
98 b'\x08' => buf.extend(br"\b"),
99 b'\x0c' => buf.extend(br"\f"),
100 _ => {
101 buf.push(b'\\');
102 buf.push_octal(byte);
103 }
104 }
105 }
106
107 buf.push(b')');
108 } else {
109 buf.reserve(2 + 2 * self.0.len());
110 buf.push(b'<');
111
112 for &byte in self.0 {
113 buf.push_hex(byte);
114 }
115
116 buf.push(b'>');
117 }
118 }
119}
120
121#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
126pub struct TextStr<'a>(pub &'a str);
127
128impl Primitive for TextStr<'_> {
129 fn write(self, buf: &mut Vec<u8>) {
130 if self.0.bytes().all(|b| matches!(b, 32..=126)) {
132 Str(self.0.as_bytes()).write(buf);
133 } else {
134 buf.reserve(6 + 4 * self.0.len());
135 buf.push(b'<');
136 buf.push_hex(254);
137 buf.push_hex(255);
138 for value in self.0.encode_utf16() {
139 buf.push_hex_u16(value);
140 }
141 buf.push(b'>');
142 }
143 }
144}
145
146#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
150pub struct Name<'a>(pub &'a [u8]);
151
152impl Primitive for Name<'_> {
153 fn write(self, buf: &mut Vec<u8>) {
154 buf.reserve(1 + self.0.len());
155 buf.push(b'/');
156 for &byte in self.0 {
157 if byte != b'#' && matches!(byte, b'!'..=b'~') && is_regular_character(byte) {
161 buf.push(byte);
162 } else {
163 buf.push(b'#');
164 buf.push_hex(byte);
165 }
166 }
167 }
168}
169
170fn is_regular_character(byte: u8) -> bool {
172 !matches!(
173 byte,
174 b'\0'
175 | b'\t'
176 | b'\n'
177 | b'\x0C'
178 | b'\r'
179 | b' '
180 | b'('
181 | b')'
182 | b'<'
183 | b'>'
184 | b'['
185 | b']'
186 | b'{'
187 | b'}'
188 | b'/'
189 | b'%'
190 )
191}
192
193#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
195pub struct Null;
196
197impl Primitive for Null {
198 #[inline]
199 fn write(self, buf: &mut Vec<u8>) {
200 buf.extend(b"null");
201 }
202}
203
204#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
206pub struct Ref(NonZeroI32);
207
208impl Ref {
209 #[inline]
215 #[track_caller]
216 pub const fn new(id: i32) -> Ref {
217 let option = if id > 0 { NonZeroI32::new(id) } else { None };
218 match option {
219 Some(val) => Self(val),
220 None => panic!("indirect reference out of valid range"),
221 }
222 }
223
224 #[inline]
226 pub const fn get(self) -> i32 {
227 self.0.get()
228 }
229
230 #[inline]
232 pub const fn next(self) -> Self {
233 Self::new(self.get() + 1)
234 }
235
236 #[inline]
239 pub fn bump(&mut self) -> Self {
240 let prev = *self;
241 *self = self.next();
242 prev
243 }
244}
245
246impl Primitive for Ref {
247 #[inline]
248 fn write(self, buf: &mut Vec<u8>) {
249 buf.push_int(self.0.get());
250 buf.extend(b" 0 R");
251 }
252}
253
254#[derive(Debug, Copy, Clone, PartialEq)]
256pub struct Rect {
257 pub x1: f32,
259 pub y1: f32,
261 pub x2: f32,
263 pub y2: f32,
265}
266
267impl Rect {
268 #[inline]
270 pub fn new(x1: f32, y1: f32, x2: f32, y2: f32) -> Self {
271 Self { x1, y1, x2, y2 }
272 }
273
274 #[inline]
277 pub fn to_quad_points(self) -> [f32; 8] {
278 [self.x1, self.y1, self.x2, self.y1, self.x2, self.y2, self.x1, self.y2]
279 }
280}
281
282impl Primitive for Rect {
283 #[inline]
284 fn write(self, buf: &mut Vec<u8>) {
285 buf.push(b'[');
286 buf.push_val(self.x1);
287 buf.push(b' ');
288 buf.push_val(self.y1);
289 buf.push(b' ');
290 buf.push_val(self.x2);
291 buf.push(b' ');
292 buf.push_val(self.y2);
293 buf.push(b']');
294 }
295}
296
297#[derive(Debug, Copy, Clone, Eq, PartialEq)]
305pub struct Date {
306 year: u16,
308 month: Option<u8>,
310 day: Option<u8>,
312 hour: Option<u8>,
314 minute: Option<u8>,
316 second: Option<u8>,
318 utc_offset_hour: Option<i8>,
320 utc_offset_minute: u8,
323}
324
325impl Date {
326 #[inline]
329 pub fn new(year: u16) -> Self {
330 Self {
331 year: year.min(9999),
332 month: None,
333 day: None,
334 hour: None,
335 minute: None,
336 second: None,
337 utc_offset_hour: None,
338 utc_offset_minute: 0,
339 }
340 }
341
342 #[inline]
344 pub fn month(mut self, month: u8) -> Self {
345 self.month = Some(month.clamp(1, 12));
346 self
347 }
348
349 #[inline]
351 pub fn day(mut self, day: u8) -> Self {
352 self.day = Some(day.clamp(1, 31));
353 self
354 }
355
356 #[inline]
358 pub fn hour(mut self, hour: u8) -> Self {
359 self.hour = Some(hour.min(23));
360 self
361 }
362
363 #[inline]
365 pub fn minute(mut self, minute: u8) -> Self {
366 self.minute = Some(minute.min(59));
367 self
368 }
369
370 #[inline]
372 pub fn second(mut self, second: u8) -> Self {
373 self.second = Some(second.min(59));
374 self
375 }
376
377 #[inline]
381 pub fn utc_offset_hour(mut self, hour: i8) -> Self {
382 self.utc_offset_hour = Some(hour.clamp(-23, 23));
383 self
384 }
385
386 #[inline]
389 pub fn utc_offset_minute(mut self, minute: u8) -> Self {
390 self.utc_offset_minute = minute.min(59);
391 self
392 }
393}
394
395impl Primitive for Date {
396 fn write(self, buf: &mut Vec<u8>) {
397 buf.extend(b"(D:");
398
399 (|| {
400 write!(buf, "{:04}", self.year).unwrap();
401 write!(buf, "{:02}", self.month?).unwrap();
402 write!(buf, "{:02}", self.day?).unwrap();
403 write!(buf, "{:02}", self.hour?).unwrap();
404 write!(buf, "{:02}", self.minute?).unwrap();
405 write!(buf, "{:02}", self.second?).unwrap();
406 let utc_offset_hour = self.utc_offset_hour?;
407 if utc_offset_hour == 0 && self.utc_offset_minute == 0 {
408 buf.push(b'Z');
409 } else {
410 write!(buf, "{:+03}'{:02}", utc_offset_hour, self.utc_offset_minute)
411 .unwrap();
412 }
413 Some(())
414 })();
415
416 buf.push(b')');
417 }
418}
419
420#[must_use = "not consuming this leaves the writer in an inconsistent state"]
422pub struct Obj<'a> {
423 buf: &'a mut Vec<u8>,
424 indirect: bool,
425 indent: u8,
426}
427
428impl<'a> Obj<'a> {
429 #[inline]
431 pub(crate) fn direct(buf: &'a mut Vec<u8>, indent: u8) -> Self {
432 Self { buf, indirect: false, indent }
433 }
434
435 #[inline]
437 pub(crate) fn indirect(buf: &'a mut Vec<u8>, id: Ref) -> Self {
438 buf.push_int(id.get());
439 buf.extend(b" 0 obj\n");
440 Self { buf, indirect: true, indent: 0 }
441 }
442
443 #[inline]
445 pub fn primitive<T: Primitive>(self, value: T) {
446 value.write(self.buf);
447 if self.indirect {
448 self.buf.extend(b"\nendobj\n\n");
449 }
450 }
451
452 #[inline]
454 pub fn array(self) -> Array<'a> {
455 self.start()
456 }
457
458 #[inline]
460 pub fn dict(self) -> Dict<'a> {
461 self.start()
462 }
463
464 #[inline]
480 pub fn start<W: Writer<'a>>(self) -> W {
481 W::start(self)
482 }
483}
484
485pub trait Writer<'a> {
487 fn start(obj: Obj<'a>) -> Self;
489}
490
491pub trait Rewrite<'a> {
497 type Output: Writer<'a>;
499}
500
501pub struct Array<'a> {
503 buf: &'a mut Vec<u8>,
504 indirect: bool,
505 indent: u8,
506 len: i32,
507}
508
509writer!(Array: |obj| {
510 obj.buf.push(b'[');
511 Self {
512 buf: obj.buf,
513 indirect: obj.indirect,
514 indent: obj.indent,
515 len: 0,
516 }
517});
518
519impl<'a> Array<'a> {
520 #[inline]
522 pub fn len(&self) -> i32 {
523 self.len
524 }
525
526 #[inline]
528 pub fn is_empty(&self) -> bool {
529 self.len == 0
530 }
531
532 #[inline]
534 pub fn push(&mut self) -> Obj<'_> {
535 if self.len != 0 {
536 self.buf.push(b' ');
537 }
538 self.len += 1;
539 Obj::direct(self.buf, self.indent)
540 }
541
542 #[inline]
546 pub fn item<T: Primitive>(&mut self, value: T) -> &mut Self {
547 self.push().primitive(value);
548 self
549 }
550
551 #[inline]
553 pub fn items<T: Primitive>(
554 &mut self,
555 values: impl IntoIterator<Item = T>,
556 ) -> &mut Self {
557 for value in values {
558 self.item(value);
559 }
560 self
561 }
562
563 #[inline]
565 pub fn typed<T>(self) -> TypedArray<'a, T> {
566 TypedArray::wrap(self)
567 }
568}
569
570impl Drop for Array<'_> {
571 #[inline]
572 fn drop(&mut self) {
573 self.buf.push(b']');
574 if self.indirect {
575 self.buf.extend(b"\nendobj\n\n");
576 }
577 }
578}
579
580pub struct TypedArray<'a, T> {
582 array: Array<'a>,
583 phantom: PhantomData<fn() -> T>,
584}
585
586impl<'a, T> Writer<'a> for TypedArray<'a, T> {
587 fn start(obj: Obj<'a>) -> Self {
588 Self { array: obj.array(), phantom: PhantomData }
589 }
590}
591
592impl<'a, T> Rewrite<'a> for TypedArray<'_, T> {
593 type Output = TypedArray<'a, T>;
594}
595
596impl<'a, T> TypedArray<'a, T> {
597 #[inline]
599 pub fn wrap(array: Array<'a>) -> Self {
600 Self { array, phantom: PhantomData }
601 }
602
603 #[inline]
605 pub fn len(&self) -> i32 {
606 self.array.len()
607 }
608
609 #[inline]
611 pub fn is_empty(&self) -> bool {
612 self.len() == 0
613 }
614
615 #[inline]
617 pub fn item(&mut self, value: T) -> &mut Self
618 where
619 T: Primitive,
620 {
621 self.array.item(value);
622 self
623 }
624
625 #[inline]
627 pub fn items(&mut self, values: impl IntoIterator<Item = T>) -> &mut Self
628 where
629 T: Primitive,
630 {
631 self.array.items(values);
632 self
633 }
634
635 #[inline]
639 pub fn push<'b>(&'b mut self) -> <T as Rewrite<'b>>::Output
640 where
641 T: Writer<'a> + Rewrite<'b>,
642 {
643 <T as Rewrite>::Output::start(self.array.push())
644 }
645}
646
647pub struct Dict<'a> {
649 buf: &'a mut Vec<u8>,
650 indirect: bool,
651 indent: u8,
652 len: i32,
653}
654
655writer!(Dict: |obj| {
656 obj.buf.extend(b"<<");
657 Self {
658 buf: obj.buf,
659 indirect: obj.indirect,
660 indent: obj.indent.saturating_add(2),
661 len: 0,
662 }
663});
664
665impl<'a> Dict<'a> {
666 #[inline]
668 pub fn len(&self) -> i32 {
669 self.len
670 }
671
672 #[inline]
674 pub fn is_empty(&self) -> bool {
675 self.len == 0
676 }
677
678 #[inline]
680 pub fn insert(&mut self, key: Name) -> Obj<'_> {
681 self.len += 1;
682 self.buf.push(b'\n');
683
684 for _ in 0..self.indent {
685 self.buf.push(b' ');
686 }
687
688 self.buf.push_val(key);
689 self.buf.push(b' ');
690
691 Obj::direct(self.buf, self.indent)
692 }
693
694 #[inline]
698 pub fn pair<T: Primitive>(&mut self, key: Name, value: T) -> &mut Self {
699 self.insert(key).primitive(value);
700 self
701 }
702
703 pub fn pairs<'n, T: Primitive>(
705 &mut self,
706 pairs: impl IntoIterator<Item = (Name<'n>, T)>,
707 ) -> &mut Self {
708 for (key, value) in pairs {
709 self.pair(key, value);
710 }
711 self
712 }
713
714 #[inline]
716 pub fn typed<T>(self) -> TypedDict<'a, T> {
717 TypedDict::wrap(self)
718 }
719}
720
721impl Drop for Dict<'_> {
722 #[inline]
723 fn drop(&mut self) {
724 if self.len != 0 {
725 self.buf.push(b'\n');
726 for _ in 0..self.indent - 2 {
727 self.buf.push(b' ');
728 }
729 }
730 self.buf.extend(b">>");
731 if self.indirect {
732 self.buf.extend(b"\nendobj\n\n");
733 }
734 }
735}
736
737pub struct TypedDict<'a, T> {
739 dict: Dict<'a>,
740 phantom: PhantomData<fn() -> T>,
741}
742
743impl<'a, T> Writer<'a> for TypedDict<'a, T> {
744 fn start(obj: Obj<'a>) -> Self {
745 Self { dict: obj.dict(), phantom: PhantomData }
746 }
747}
748
749impl<'a, T> Rewrite<'a> for TypedDict<'_, T> {
750 type Output = TypedDict<'a, T>;
751}
752
753impl<'a, T> TypedDict<'a, T> {
754 #[inline]
756 pub fn wrap(dict: Dict<'a>) -> Self {
757 Self { dict, phantom: PhantomData }
758 }
759
760 #[inline]
762 pub fn len(&self) -> i32 {
763 self.dict.len()
764 }
765
766 #[inline]
768 pub fn is_empty(&self) -> bool {
769 self.len() == 0
770 }
771
772 #[inline]
774 pub fn pair(&mut self, key: Name, value: T) -> &mut Self
775 where
776 T: Primitive,
777 {
778 self.dict.pair(key, value);
779 self
780 }
781
782 #[inline]
784 pub fn pairs<'n>(
785 &mut self,
786 pairs: impl IntoIterator<Item = (Name<'n>, T)>,
787 ) -> &mut Self
788 where
789 T: Primitive,
790 {
791 self.dict.pairs(pairs);
792 self
793 }
794
795 #[inline]
799 pub fn insert<'b>(&'b mut self, key: Name) -> <T as Rewrite<'b>>::Output
800 where
801 T: Writer<'a> + Rewrite<'b>,
802 {
803 <T as Rewrite>::Output::start(self.dict.insert(key))
804 }
805}
806
807pub struct Stream<'a> {
809 dict: ManuallyDrop<Dict<'a>>,
810 data: &'a [u8],
811}
812
813impl<'a> Stream<'a> {
814 pub(crate) fn start(obj: Obj<'a>, data: &'a [u8]) -> Self {
819 assert!(obj.indirect);
820
821 let mut dict = obj.dict();
822 dict.pair(
823 Name(b"Length"),
824 i32::try_from(data.len()).unwrap_or_else(|_| {
825 panic!("data length (is `{}`) must be <= i32::MAX", data.len());
826 }),
827 );
828
829 Self { dict: ManuallyDrop::new(dict), data }
830 }
831
832 pub fn filter(&mut self, filter: Filter) -> &mut Self {
834 self.pair(Name(b"Filter"), filter.to_name());
835 self
836 }
837
838 pub fn decode_parms(&mut self) -> DecodeParms<'_> {
844 self.insert(Name(b"DecodeParms")).start()
845 }
846}
847
848impl Drop for Stream<'_> {
849 fn drop(&mut self) {
850 self.dict.buf.extend(b"\n>>");
851 self.dict.buf.extend(b"\nstream\n");
852 self.dict.buf.extend(self.data.as_ref());
853 self.dict.buf.extend(b"\nendstream");
854 self.dict.buf.extend(b"\nendobj\n\n");
855 }
856}
857
858deref!('a, Stream<'a> => Dict<'a>, dict);
859
860#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
862#[allow(missing_docs)]
863pub enum Filter {
864 AsciiHexDecode,
865 Ascii85Decode,
866 LzwDecode,
870 FlateDecode,
871 RunLengthDecode,
872 CcittFaxDecode,
873 Jbig2Decode,
874 DctDecode,
878 JpxDecode,
882 Crypt,
886}
887
888impl Filter {
889 pub(crate) fn to_name(self) -> Name<'static> {
890 match self {
891 Self::AsciiHexDecode => Name(b"ASCIIHexDecode"),
892 Self::Ascii85Decode => Name(b"ASCII85Decode"),
893 Self::LzwDecode => Name(b"LZWDecode"),
894 Self::FlateDecode => Name(b"FlateDecode"),
895 Self::RunLengthDecode => Name(b"RunLengthDecode"),
896 Self::CcittFaxDecode => Name(b"CCITTFaxDecode"),
897 Self::Jbig2Decode => Name(b"JBIG2Decode"),
898 Self::DctDecode => Name(b"DCTDecode"),
899 Self::JpxDecode => Name(b"JPXDecode"),
900 Self::Crypt => Name(b"Crypt"),
901 }
902 }
903}
904
905pub struct DecodeParms<'a> {
909 dict: Dict<'a>,
910}
911
912writer!(DecodeParms: |obj| Self { dict: obj.dict() });
913
914impl DecodeParms<'_> {
916 pub fn predictor(&mut self, predictor: Predictor) -> &mut Self {
920 self.pair(Name(b"Predictor"), predictor.to_i32());
921 self
922 }
923
924 pub fn colors(&mut self, colors: i32) -> &mut Self {
929 if colors <= 0 {
930 panic!("`Colors` must be greater than 0");
931 }
932
933 self.pair(Name(b"Colors"), colors);
934 self
935 }
936
937 pub fn bits_per_component(&mut self, bits: i32) -> &mut Self {
943 if ![1, 2, 4, 8, 16].contains(&bits) {
944 panic!("`BitsPerComponent` must be one of 1, 2, 4, 8, or 16");
945 }
946
947 self.pair(Name(b"BitsPerComponent"), bits);
948 self
949 }
950
951 pub fn columns(&mut self, columns: i32) -> &mut Self {
961 self.pair(Name(b"Columns"), columns);
962 self
963 }
964
965 pub fn early_change(&mut self, early_change: bool) -> &mut Self {
972 self.pair(Name(b"EarlyChange"), if early_change { 1 } else { 0 });
973 self
974 }
975}
976
977impl DecodeParms<'_> {
979 pub fn k(&mut self, k: i32) -> &mut Self {
983 self.pair(Name(b"K"), k);
984 self
985 }
986
987 pub fn end_of_line(&mut self, eol: bool) -> &mut Self {
992 self.pair(Name(b"EndOfLine"), eol);
993 self
994 }
995
996 pub fn encoded_byte_align(&mut self, encoded_byte_align: bool) -> &mut Self {
1001 self.pair(Name(b"EncodedByteAlign"), encoded_byte_align);
1002 self
1003 }
1004
1005 pub fn rows(&mut self, rows: i32) -> &mut Self {
1009 self.pair(Name(b"Rows"), rows);
1010 self
1011 }
1012
1013 pub fn end_of_block(&mut self, end_of_block: bool) -> &mut Self {
1018 self.pair(Name(b"EndOfBlock"), end_of_block);
1019 self
1020 }
1021
1022 pub fn black_is_1(&mut self, black_is_1: bool) -> &mut Self {
1026 self.pair(Name(b"BlackIs1"), black_is_1);
1027 self
1028 }
1029
1030 pub fn damaged_rows_before_error(&mut self, count: i32) -> &mut Self {
1035 self.pair(Name(b"DamagedRowsBeforeError"), count);
1036 self
1037 }
1038}
1039
1040impl DecodeParms<'_> {
1042 pub fn jbig2_globals(&mut self, globals: Ref) -> &mut Self {
1046 self.pair(Name(b"JBIG2Globals"), globals);
1047 self
1048 }
1049}
1050
1051impl DecodeParms<'_> {
1053 pub fn color_transform(&mut self, color_transform: bool) -> &mut Self {
1061 self.pair(Name(b"ColorTransform"), if color_transform { 1 } else { 0 });
1062 self
1063 }
1064}
1065
1066impl DecodeParms<'_> {
1068 pub fn crypt_type(&mut self) -> &mut Self {
1070 self.pair(Name(b"Type"), Name(b"CryptFilterDecodeParms"));
1071 self
1072 }
1073
1074 pub fn name(&mut self, name: Name) -> &mut Self {
1079 self.pair(Name(b"Name"), name);
1080 self
1081 }
1082}
1083
1084deref!('a, DecodeParms<'a> => Dict<'a>, dict);
1085
1086#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
1088#[allow(missing_docs)]
1089pub enum Predictor {
1090 None,
1092 Tiff,
1094 PngNone,
1095 PngSub,
1096 PngUp,
1097 PngAverage,
1098 PngPaeth,
1099 PngOptimum,
1100}
1101
1102impl Predictor {
1103 fn to_i32(self) -> i32 {
1106 match self {
1107 Self::None => 1,
1108 Self::Tiff => 2,
1109 Self::PngNone => 10,
1110 Self::PngSub => 11,
1111 Self::PngUp => 12,
1112 Self::PngAverage => 13,
1113 Self::PngPaeth => 14,
1114 Self::PngOptimum => 15,
1115 }
1116 }
1117}
1118
1119pub struct NameTree<'a, T> {
1129 dict: Dict<'a>,
1130 phantom: PhantomData<T>,
1131}
1132
1133impl<'a, T> Writer<'a> for NameTree<'a, T> {
1134 fn start(obj: Obj<'a>) -> Self {
1135 Self { dict: obj.dict(), phantom: PhantomData }
1136 }
1137}
1138
1139impl<'a, T> Rewrite<'a> for NameTree<'_, T> {
1140 type Output = NameTree<'a, T>;
1141}
1142
1143impl<T> NameTree<'_, T> {
1144 pub fn kids(&mut self) -> TypedArray<'_, Ref> {
1146 self.dict.insert(Name(b"Kids")).array().typed()
1147 }
1148
1149 pub fn names(&mut self) -> NameTreeEntries<'_, T> {
1152 self.dict.insert(Name(b"Names")).start()
1153 }
1154
1155 pub fn limits(&mut self, min: Name, max: Name) -> &mut Self {
1158 self.dict.insert(Name(b"Limits")).array().typed().items([min, max]);
1159 self
1160 }
1161}
1162
1163pub struct NameTreeEntries<'a, T> {
1169 arr: Array<'a>,
1170 phantom: PhantomData<T>,
1171}
1172
1173impl<'a, T> Writer<'a> for NameTreeEntries<'a, T> {
1174 fn start(obj: Obj<'a>) -> Self {
1175 Self { arr: obj.array(), phantom: PhantomData }
1176 }
1177}
1178
1179impl<'a, T> Rewrite<'a> for NameTreeEntries<'_, T> {
1180 type Output = NameTreeEntries<'a, T>;
1181}
1182
1183impl<T> NameTreeEntries<'_, T>
1184where
1185 T: Primitive,
1186{
1187 pub fn insert(&mut self, key: Str, value: T) -> &mut Self {
1189 self.arr.item(key);
1190 self.arr.item(value);
1191 self
1192 }
1193}
1194
1195pub struct NumberTree<'a, T> {
1205 dict: Dict<'a>,
1206 phantom: PhantomData<T>,
1207}
1208
1209impl<'a, T> Writer<'a> for NumberTree<'a, T> {
1210 fn start(obj: Obj<'a>) -> Self {
1211 Self { dict: obj.dict(), phantom: PhantomData }
1212 }
1213}
1214
1215impl<'a, T> Rewrite<'a> for NumberTree<'_, T> {
1216 type Output = NumberTree<'a, T>;
1217}
1218
1219impl<T> NumberTree<'_, T> {
1220 pub fn kids(&mut self) -> TypedArray<'_, Ref> {
1222 self.dict.insert(Name(b"Kids")).array().typed()
1223 }
1224
1225 pub fn nums(&mut self) -> NumberTreeEntries<'_, T> {
1228 self.dict.insert(Name(b"Nums")).start()
1229 }
1230
1231 pub fn limits(&mut self, min: i32, max: i32) -> &mut Self {
1234 self.dict.insert(Name(b"Limits")).array().typed().items([min, max]);
1235 self
1236 }
1237}
1238
1239pub struct NumberTreeEntries<'a, T> {
1245 arr: Array<'a>,
1246 phantom: PhantomData<T>,
1247}
1248
1249impl<'a, T> Writer<'a> for NumberTreeEntries<'a, T> {
1250 fn start(obj: Obj<'a>) -> Self {
1251 Self { arr: obj.array(), phantom: PhantomData }
1252 }
1253}
1254
1255impl<'a, T> Rewrite<'a> for NumberTreeEntries<'_, T> {
1256 type Output = NumberTreeEntries<'a, T>;
1257}
1258
1259impl<T> NumberTreeEntries<'_, T>
1260where
1261 T: Primitive,
1262{
1263 pub fn insert(&mut self, key: i32, value: T) -> &mut Self {
1265 self.arr.item(key);
1266 self.arr.item(value);
1267 self
1268 }
1269}
1270
1271pub trait Finish: Sized {
1292 #[inline]
1294 fn finish(self) {}
1295}
1296
1297impl<T> Finish for T {}
1298
1299#[cfg(test)]
1300mod tests {
1301 use super::*;
1302
1303 #[test]
1304 fn test_primitive_objects() {
1305 test_primitive!(true, b"true");
1307 test_primitive!(false, b"false");
1308 test_primitive!(78, b"78");
1309 test_primitive!(4.22, b"4.22");
1310 test_primitive!(1.184e-7, b"0.0000001184");
1311 test_primitive!(4.2e13, b"42000000000000");
1312 test_primitive!(Ref::new(7), b"7 0 R");
1313 test_primitive!(Null, b"null");
1314
1315 test_primitive!(Str(b"Hello, World!"), b"(Hello, World!)");
1317 test_primitive!(Str(b"()"), br"(())");
1318 test_primitive!(Str(b")()"), br"(\)\(\))");
1319 test_primitive!(Str(b"()(())"), br"(()(()))");
1320 test_primitive!(Str(b"(()))"), br"(\(\(\)\)\))");
1321 test_primitive!(Str(b"\\"), br"(\\)");
1322 test_primitive!(Str(b"\n\ta"), br"(\n\ta)");
1323 test_primitive!(Str(br"\n"), br"(\\n)");
1324 test_primitive!(Str(b"a\x14b"), br"(a\024b)");
1325 test_primitive!(Str(b"\xFF\xAA"), b"<FFAA>");
1326 test_primitive!(Str(b"\x0A\x7F\x1F"), br"(\n\177\037)");
1327
1328 test_primitive!(TextStr("Hallo"), b"(Hallo)");
1330 test_primitive!(TextStr("😀!"), b"<FEFFD83DDE000021>");
1331
1332 test_primitive!(Name(b"Filter"), b"/Filter");
1334 test_primitive!(Name(b"A B"), br"/A#20B");
1335 test_primitive!(Name(b"~+c"), br"/~+c");
1336 test_primitive!(Name(b"/A-B"), br"/#2FA-B");
1337 test_primitive!(Name(b"<A>"), br"/#3CA#3E");
1338 test_primitive!(Name(b"#"), br"/#23");
1339 test_primitive!(Name(b"\n"), br"/#0A");
1340 }
1341
1342 #[test]
1343 fn test_dates() {
1344 test_primitive!(Date::new(2021), b"(D:2021)");
1345 test_primitive!(Date::new(2021).month(30), b"(D:202112)");
1346
1347 let date = Date::new(2020).month(3).day(17).hour(1).minute(2).second(3);
1348 test_primitive!(date, b"(D:20200317010203)");
1349 test_primitive!(date.utc_offset_hour(0), b"(D:20200317010203Z)");
1350 test_primitive!(date.utc_offset_hour(4), b"(D:20200317010203+04'00)");
1351 test_primitive!(
1352 date.utc_offset_hour(-17).utc_offset_minute(10),
1353 b"(D:20200317010203-17'10)"
1354 );
1355 }
1356
1357 #[test]
1358 fn test_arrays() {
1359 test_obj!(|obj| obj.array(), b"[]");
1360 test_obj!(|obj| obj.array().item(12).item(Null), b"[12 null]");
1361 test_obj!(|obj| obj.array().typed().items(vec![1, 2, 3]), b"[1 2 3]");
1362 test_obj!(
1363 |obj| {
1364 let mut array = obj.array();
1365 array.push().array().typed().items(vec![1, 2]);
1366 array.item(3);
1367 },
1368 b"[[1 2] 3]",
1369 );
1370 }
1371
1372 #[test]
1373 fn test_dicts() {
1374 test_obj!(|obj| obj.dict(), b"<<>>");
1375 test_obj!(
1376 |obj| obj.dict().pair(Name(b"Quality"), Name(b"Good")),
1377 b"<<\n /Quality /Good\n>>",
1378 );
1379 test_obj!(
1380 |obj| {
1381 obj.dict().pair(Name(b"A"), 1).pair(Name(b"B"), 2);
1382 },
1383 b"<<\n /A 1\n /B 2\n>>",
1384 );
1385 }
1386
1387 #[test]
1388 fn test_streams() {
1389 let mut w = Pdf::new();
1390 w.stream(Ref::new(1), &b"Hi there!"[..]).filter(Filter::Crypt);
1391 test!(
1392 w.finish(),
1393 b"%PDF-1.7\n%\x80\x80\x80\x80\n",
1394 b"1 0 obj",
1395 b"<<\n /Length 9\n /Filter /Crypt\n>>",
1396 b"stream",
1397 b"Hi there!",
1398 b"endstream",
1399 b"endobj\n",
1400 b"xref",
1401 b"0 2",
1402 b"0000000000 65535 f\r",
1403 b"0000000016 00000 n\r",
1404 b"trailer",
1405 b"<<\n /Size 2\n>>",
1406 b"startxref\n94\n%%EOF",
1407 )
1408 }
1409}