Skip to main content

hayro_syntax/object/
dict.rs

1//! Dictionaries.
2
3use crate::object::macros::object;
4use crate::object::r#ref::{MaybeRef, ObjRef};
5use crate::object::{Name, ObjectIdentifier};
6use crate::object::{Object, ObjectLike};
7use crate::reader::Reader;
8use crate::reader::{Readable, ReaderContext, ReaderExt, Skippable};
9use crate::sync::Arc;
10use crate::sync::FxHashMap;
11use alloc::format;
12use alloc::vec::Vec;
13use core::fmt::{Debug, Display, Formatter};
14use core::ops::Deref;
15
16/// A dictionary, which is a key-value map, keys being names, and values being any PDF object or
17/// objetc reference.
18#[derive(Clone)]
19pub struct Dict<'a>(Inner<'a>);
20
21#[derive(Clone)]
22enum Inner<'a> {
23    Empty,
24    Some(Arc<Repr<'a>>),
25}
26
27impl Default for Dict<'_> {
28    fn default() -> Self {
29        Self::empty()
30    }
31}
32
33// Note that this is not structural equality, i.e. two dictionaries with the same
34// items are still considered different if they have different whitespaces.
35impl PartialEq for Dict<'_> {
36    fn eq(&self, other: &Self) -> bool {
37        self.data() == other.data()
38    }
39}
40
41impl<'a> Dict<'a> {
42    /// Create a new empty dictionary.
43    pub fn empty() -> Self {
44        Self(Inner::Empty)
45    }
46
47    /// Get the raw bytes underlying to the dictionary.
48    pub fn data(&self) -> &'a [u8] {
49        match &self.0 {
50            Inner::Empty => &[],
51            Inner::Some(repr) => repr.data,
52        }
53    }
54
55    /// Returns the number of entries in the dictionary.
56    pub fn len(&self) -> usize {
57        self.offsets().map_or(0, FxHashMap::len)
58    }
59
60    /// Return whether the dictionary is empty.
61    pub fn is_empty(&self) -> bool {
62        self.offsets().is_none_or(FxHashMap::is_empty)
63    }
64
65    /// Checks whether the dictionary contains an entry with a specific key.
66    pub fn contains_key(&self, key: impl AsRef<[u8]>) -> bool {
67        self.offsets()
68            .is_some_and(|offsets| offsets.contains_key(key.as_ref()))
69    }
70
71    /// Returns the entry of a key as a specific object, or try to resolve it in case it's
72    /// an object reference.
73    #[allow(
74        private_bounds,
75        reason = "users shouldn't be able to implement `ObjectLike` for custom objects."
76    )]
77    pub fn get<T>(&self, key: impl AsRef<[u8]>) -> Option<T>
78    where
79        T: ObjectLike<'a>,
80    {
81        self.get_raw::<T>(key.as_ref())?.resolve(self.ctx())
82    }
83
84    /// Get the object reference linked to a key.
85    pub fn get_ref(&self, key: impl AsRef<[u8]>) -> Option<ObjRef> {
86        let offset = *self.offsets()?.get(key.as_ref())?;
87
88        Reader::new(&self.data()[offset..]).read_with_context::<ObjRef>(self.ctx())
89    }
90
91    /// Returns an iterator over all keys in the dictionary.
92    pub fn keys(&self) -> impl Iterator<Item = Name<'a>> + '_ {
93        self.offsets()
94            .into_iter()
95            .flat_map(|offsets| offsets.keys().cloned())
96    }
97
98    /// An iterator over all entries in the dictionary, sorted by key.
99    pub fn entries(&self) -> impl Iterator<Item = (Name<'a>, MaybeRef<Object<'a>>)> + '_ {
100        let mut sorted_keys = self.keys().collect::<Vec<_>>();
101        sorted_keys.sort_by(|n1, n2| n1.as_ref().cmp(n2.as_ref()));
102        sorted_keys.into_iter().map(|k| {
103            let obj = self.get_raw(k.deref()).unwrap();
104            (k, obj)
105        })
106    }
107
108    /// Return the object identifier of the dict, if it's an indirect object.
109    pub fn obj_id(&self) -> Option<ObjectIdentifier> {
110        self.ctx().obj_number()
111    }
112
113    /// Return the raw entry for a specific key.
114    #[allow(private_bounds)]
115    pub fn get_raw<T>(&self, key: impl AsRef<[u8]>) -> Option<MaybeRef<T>>
116    where
117        T: Readable<'a>,
118    {
119        let offset = *self.offsets()?.get(key.as_ref())?;
120
121        Reader::new(&self.data()[offset..]).read_with_context::<MaybeRef<T>>(self.ctx())
122    }
123
124    pub(crate) fn ctx(&self) -> &ReaderContext<'a> {
125        match &self.0 {
126            Inner::Empty => ReaderContext::dummy_ref(),
127            Inner::Some(repr) => &repr.ctx,
128        }
129    }
130
131    fn offsets(&self) -> Option<&FxHashMap<Name<'a>, usize>> {
132        match &self.0 {
133            Inner::Empty => None,
134            Inner::Some(repr) => Some(&repr.offsets),
135        }
136    }
137}
138
139impl Debug for Dict<'_> {
140    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
141        let mut debug_struct = f.debug_struct("Dict");
142
143        if let Some(offsets) = self.offsets() {
144            let mut r = Reader::new(self.data());
145
146            for (key, val) in offsets {
147                r.jump(*val);
148                debug_struct.field(
149                    &format!("{:?}", key.as_str()),
150                    &r.read_with_context::<MaybeRef<Object<'_>>>(&ReaderContext::dummy())
151                        .unwrap(),
152                );
153            }
154        }
155
156        debug_struct.finish()
157    }
158}
159
160impl Display for Dict<'_> {
161    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
162        f.write_str("<<")?;
163        for (key, value) in self.entries() {
164            f.write_str(" ")?;
165            Display::fmt(&key, f)?;
166            f.write_str(" ")?;
167            Display::fmt(&value, f)?;
168        }
169        if !self.is_empty() {
170            f.write_str(" ")?;
171        }
172        f.write_str(">>")
173    }
174}
175
176impl Skippable for Dict<'_> {
177    fn skip(r: &mut Reader<'_>, is_content_stream: bool) -> Option<()> {
178        Self::skip_with_depth(r, is_content_stream, 0)
179    }
180
181    fn skip_with_depth(r: &mut Reader<'_>, is_content_stream: bool, depth: usize) -> Option<()> {
182        if depth >= super::MAX_OBJECT_NESTING_DEPTH {
183            return None;
184        }
185
186        r.forward_tag(b"<<")?;
187
188        loop {
189            r.skip_white_spaces_and_comments();
190
191            if let Some(()) = r.forward_tag(b">>") {
192                break Some(());
193            } else {
194                let Some(_) = r.skip::<Name<'_>>(is_content_stream) else {
195                    // In case there is garbage in-between, be lenient and just try to skip it.
196                    r.skip_with_depth::<Object<'_>>(is_content_stream, depth + 1)?;
197                    continue;
198                };
199
200                r.skip_white_spaces_and_comments();
201
202                if is_content_stream {
203                    r.skip_with_depth::<Object<'_>>(is_content_stream, depth + 1)?;
204                } else {
205                    r.skip_with_depth::<MaybeRef<Object<'_>>>(is_content_stream, depth + 1)?;
206                }
207            }
208        }
209    }
210}
211
212impl<'a> Readable<'a> for Dict<'a> {
213    fn read(r: &mut Reader<'a>, ctx: &ReaderContext<'a>) -> Option<Self> {
214        read_inner(r, ctx, Some(b"<<"), b">>")
215    }
216}
217
218fn read_inner<'a>(
219    r: &mut Reader<'a>,
220    ctx: &ReaderContext<'a>,
221    start_tag: Option<&[u8]>,
222    end_tag: &[u8],
223) -> Option<Dict<'a>> {
224    // TODO: Figure out how to
225    // 1) Make dictionaries easily cloneable without wrapping in Arc.
226    // 2) Maybe have an efficient per-document allocator pool for hashmaps
227    // that can be reused.
228    #[cfg(feature = "std")]
229    let mut offsets = FxHashMap::with_capacity_and_hasher(8, rustc_hash::FxBuildHasher);
230    #[cfg(not(feature = "std"))]
231    let mut offsets = FxHashMap::new();
232
233    let data = parse_dict_with(
234        r,
235        ctx,
236        start_tag,
237        end_tag,
238        #[inline]
239        |name, offset, _| {
240            offsets.insert(name, offset);
241            Some(())
242        },
243    )?;
244
245    Some(Dict(Inner::Some(Arc::new(Repr {
246        data,
247        offsets,
248        ctx: ctx.clone(),
249    }))))
250}
251
252pub(crate) struct DictProbe<'a> {
253    pub(crate) data: &'a [u8],
254    pub(crate) has_root: bool,
255    pub(crate) has_type: bool,
256}
257
258// We use that method during fallback xref parsing, so that we can search for
259// the dictionaries we need without allocating the whole hash map.
260// If the above TODOs are ever resolved, we can probably remove this method.
261pub(crate) fn probe_dict<'a>(
262    r: &mut Reader<'a>,
263    ctx: &ReaderContext<'a>,
264    start_tag: Option<&[u8]>,
265    end_tag: &[u8],
266) -> Option<DictProbe<'a>> {
267    let mut has_root = false;
268    let mut has_type = false;
269
270    let data = parse_dict_with(
271        r,
272        ctx,
273        start_tag,
274        end_tag,
275        #[inline]
276        |name, _, _value_reader| {
277            if name.as_ref() == keys::ROOT {
278                has_root = true;
279            } else if name.as_ref() == keys::TYPE {
280                has_type = true;
281            }
282
283            Some(())
284        },
285    )?;
286
287    Some(DictProbe {
288        data,
289        has_root,
290        has_type,
291    })
292}
293
294fn parse_dict_with<'a, F>(
295    r: &mut Reader<'a>,
296    ctx: &ReaderContext<'a>,
297    start_tag: Option<&[u8]>,
298    end_tag: &[u8],
299    mut on_entry: F,
300) -> Option<&'a [u8]>
301where
302    F: FnMut(Name<'a>, usize, &Reader<'a>) -> Option<()>,
303{
304    let depth = usize::from(start_tag.is_some());
305    let dict_data = r.tail()?;
306    let start_offset = r.offset();
307
308    // Inline image dictionaries don't start with '<<'.
309    if let Some(start_tag) = start_tag {
310        r.forward_tag(start_tag)?;
311    }
312
313    loop {
314        r.skip_white_spaces_and_comments();
315
316        // Normal dictionaries end with '>>', inline image dictionaries end with BD.
317        if let Some(()) = r.peek_tag(end_tag) {
318            r.forward_tag(end_tag)?;
319            let end_offset = r.offset() - start_offset;
320
321            break Some(&dict_data[..end_offset]);
322        } else {
323            let Some(name) = r.read_without_context::<Name<'_>>() else {
324                if start_tag.is_some() {
325                    // In case there is garbage in-between, be lenient and just try to skip it.
326                    // But only do this if we are parsing a proper dictionary as opposed to an
327                    // inline dictionary.
328                    r.skip_with_depth::<Object<'_>>(ctx.in_content_stream(), depth)?;
329                    continue;
330                } else {
331                    return None;
332                }
333            };
334            r.skip_white_spaces_and_comments();
335
336            let offset = r.offset() - start_offset;
337            // Do note that we are including objects in our dictionary even if they
338            // are the null object, meaning that a call to `contains_key` will return `true`
339            // even if the object is the null object. The PDF reference in theory requires
340            // us to treat them as non-existing. Previously, we included a check to determine
341            // whether the object is `null` before inserting it, but that caused problems
342            // in some test cases where encryption + object streams are involved (as we would
343            // attempt to read an object stream before having resolved the encryption dictionary).
344            on_entry(name, offset, r)?;
345
346            if ctx.in_content_stream() {
347                r.skip_with_depth::<Object<'_>>(ctx.in_content_stream(), depth)?;
348            } else {
349                r.skip_with_depth::<MaybeRef<Object<'_>>>(ctx.in_content_stream(), depth)?;
350            }
351        }
352    }
353}
354
355object!(Dict<'a>, Dict);
356
357struct Repr<'a> {
358    data: &'a [u8],
359    offsets: FxHashMap<Name<'a>, usize>,
360    ctx: ReaderContext<'a>,
361}
362
363pub(crate) struct InlineImageDict<'a>(Dict<'a>);
364
365impl<'a> InlineImageDict<'a> {
366    pub(crate) fn get_dict(&self) -> &Dict<'a> {
367        &self.0
368    }
369}
370
371impl<'a> Readable<'a> for InlineImageDict<'a> {
372    fn read(r: &mut Reader<'a>, ctx: &ReaderContext<'a>) -> Option<Self> {
373        Some(Self(read_inner(r, ctx, None, b"ID")?))
374    }
375}
376
377/// A collection of possible keys in a PDF dictionary. Copied and adapted from `PDFBox`.
378#[allow(missing_docs)]
379pub mod keys {
380    macro_rules! key {
381        ($i:ident, $e:expr) => {
382            pub const $i: &'static [u8] = $e;
383        };
384    }
385
386    // A
387    key!(A, b"A");
388    key!(AA, b"AA");
389    key!(ABSOLUTE_COLORIMETRIC, b"AbsoluteColorimetric");
390    key!(AC, b"AC");
391    key!(ACRO_FORM, b"AcroForm");
392    key!(ACTUAL_TEXT, b"ActualText");
393    key!(ADBE, b"ADBE");
394    key!(ADBE_PKCS7_DETACHED, b"adbe.pkcs7.detached");
395    key!(ADBE_PKCS7_SHA1, b"adbe.pkcs7.sha1");
396    key!(ADBE_X509_RSA_SHA1, b"adbe.x509.rsa_sha1");
397    key!(ADOBE_PPKLITE, b"Adobe.PPKLite");
398    key!(AESV2, b"AESV2");
399    key!(AESV3, b"AESV3");
400    key!(AF, b"AF");
401    key!(AF_RELATIONSHIP, b"AFRelationship");
402    key!(AFTER, b"After");
403    key!(AI_META_DATA, b"AIMetaData");
404    key!(AIS, b"AIS");
405    key!(ALL_OFF, b"AllOff");
406    key!(ALL_ON, b"AllOn");
407    key!(ALT, b"Alt");
408    key!(ALPHA, b"Alpha");
409    key!(ALTERNATE, b"Alternate");
410    key!(ANNOT, b"Annot");
411    key!(ANNOTS, b"Annots");
412    key!(ANTI_ALIAS, b"AntiAlias");
413    key!(ANY_OFF, b"AnyOff");
414    key!(ANY_ON, b"AnyOn");
415    key!(AP, b"AP");
416    key!(AP_REF, b"APRef");
417    key!(APP, b"App");
418    key!(ART_BOX, b"ArtBox");
419    key!(ARTIFACT, b"Artifact");
420    key!(AS, b"AS");
421    key!(ASCENT, b"Ascent");
422    key!(ASCII_HEX_DECODE, b"ASCIIHexDecode");
423    key!(ASCII_HEX_DECODE_ABBREVIATION, b"AHx");
424    key!(ASCII85_DECODE, b"ASCII85Decode");
425    key!(ASCII85_DECODE_ABBREVIATION, b"A85");
426    key!(ATTACHED, b"Attached");
427    key!(AUTHOR, b"Author");
428    key!(AVG_WIDTH, b"AvgWidth");
429
430    // B
431    key!(B, b"B");
432    key!(BACKGROUND, b"Background");
433    key!(BASE_ENCODING, b"BaseEncoding");
434    key!(BASE_FONT, b"BaseFont");
435    key!(BASE_STATE, b"BaseState");
436    key!(BASE_VERSION, b"BaseVersion");
437    key!(BBOX, b"BBox");
438    key!(BC, b"BC");
439    key!(BE, b"BE");
440    key!(BEAD, b"BEAD");
441    key!(BEFORE, b"Before");
442    key!(BG, b"BG");
443    key!(BITS_PER_COMPONENT, b"BitsPerComponent");
444    key!(BITS_PER_COORDINATE, b"BitsPerCoordinate");
445    key!(BITS_PER_FLAG, b"BitsPerFlag");
446    key!(BITS_PER_SAMPLE, b"BitsPerSample");
447    key!(BL, b"Bl");
448    key!(BLACK_IS_1, b"BlackIs1");
449    key!(BLACK_POINT, b"BlackPoint");
450    key!(BLEED_BOX, b"BleedBox");
451    key!(BM, b"BM");
452    key!(BORDER, b"Border");
453    key!(BOUNDS, b"Bounds");
454    key!(BPC, b"BPC");
455    key!(BS, b"BS");
456    key!(BTN, b"Btn");
457    key!(BYTERANGE, b"ByteRange");
458
459    // C
460    key!(C, b"C");
461    key!(C0, b"C0");
462    key!(C1, b"C1");
463    key!(CA, b"CA");
464    key!(CA_NS, b"ca");
465    key!(CALGRAY, b"CalGray");
466    key!(CALRGB, b"CalRGB");
467    key!(CALCMYK, b"CalCMYK");
468    key!(CAP, b"Cap");
469    key!(CAP_HEIGHT, b"CapHeight");
470    key!(CATALOG, b"Catalog");
471    key!(CCITTFAX_DECODE, b"CCITTFaxDecode");
472    key!(CCITTFAX_DECODE_ABBREVIATION, b"CCF");
473    key!(CENTER_WINDOW, b"CenterWindow");
474    key!(CERT, b"Cert");
475    key!(CERTS, b"Certs");
476    key!(CF, b"CF");
477    key!(CFM, b"CFM");
478    key!(CH, b"Ch");
479    key!(CHAR_PROCS, b"CharProcs");
480    key!(CHAR_SET, b"CharSet");
481    key!(CHECK_SUM, b"CheckSum");
482    key!(CI, b"CI");
483    key!(CICI_SIGNIT, b"CICI.SignIt");
484    key!(CID_FONT_TYPE0, b"CIDFontType0");
485    key!(CID_FONT_TYPE0C, b"CIDFontType0C");
486    key!(CID_FONT_TYPE2, b"CIDFontType2");
487    key!(CID_TO_GID_MAP, b"CIDToGIDMap");
488    key!(CID_SET, b"CIDSet");
489    key!(CIDSYSTEMINFO, b"CIDSystemInfo");
490    key!(CL, b"CL");
491    key!(CLASS_MAP, b"ClassMap");
492    key!(CLR_F, b"ClrF");
493    key!(CLR_FF, b"ClrFf");
494    key!(CMAP, b"CMap");
495    key!(CMAPNAME, b"CMapName");
496    key!(CMYK, b"CMYK");
497    key!(CO, b"CO");
498    key!(COLOR, b"Color");
499    key!(COLLECTION, b"Collection");
500    key!(COLLECTION_ITEM, b"CollectionItem");
501    key!(COLLECTION_FIELD, b"CollectionField");
502    key!(COLLECTION_SCHEMA, b"CollectionSchema");
503    key!(COLLECTION_SORT, b"CollectionSort");
504    key!(COLLECTION_SUBITEM, b"CollectionSubitem");
505    key!(COLOR_BURN, b"ColorBurn");
506    key!(COLOR_DODGE, b"ColorDodge");
507    key!(COLORANTS, b"Colorants");
508    key!(COLORS, b"Colors");
509    key!(COLORSPACE, b"ColorSpace");
510    key!(COLOR_TRANSFORM, b"ColorTransform");
511    key!(COLUMNS, b"Columns");
512    key!(COMPATIBLE, b"Compatible");
513    key!(COMPONENTS, b"Components");
514    key!(CONTACT_INFO, b"ContactInfo");
515    key!(CONTENTS, b"Contents");
516    key!(COORDS, b"Coords");
517    key!(COUNT, b"Count");
518    key!(CP, b"CP");
519    key!(CREATION_DATE, b"CreationDate");
520    key!(CREATOR, b"Creator");
521    key!(CRL, b"CRL");
522    key!(CRLS, b"CRLS");
523    key!(CROP_BOX, b"CropBox");
524    key!(CRYPT, b"Crypt");
525    key!(CS, b"CS");
526    key!(CYX, b"CYX");
527
528    // D
529    key!(D, b"D");
530    key!(DA, b"DA");
531    key!(DARKEN, b"Darken");
532    key!(DATE, b"Date");
533    key!(DCT_DECODE, b"DCTDecode");
534    key!(DCT_DECODE_ABBREVIATION, b"DCT");
535    key!(DECODE, b"Decode");
536    key!(DECODE_PARMS, b"DecodeParms");
537    key!(DEFAULT, b"default");
538    key!(DEFAULT_CMYK, b"DefaultCMYK");
539    key!(DEFAULT_CRYPT_FILTER, b"DefaultCryptFilter");
540    key!(DEFAULT_GRAY, b"DefaultGray");
541    key!(DEFAULT_RGB, b"DefaultRGB");
542    key!(DESC, b"Desc");
543    key!(DESCENDANT_FONTS, b"DescendantFonts");
544    key!(DESCENT, b"Descent");
545    key!(DEST, b"Dest");
546    key!(DEST_OUTPUT_PROFILE, b"DestOutputProfile");
547    key!(DESTS, b"Dests");
548    key!(DEVICE_CMYK, b"DeviceCMYK");
549    key!(DEVICE_GRAY, b"DeviceGray");
550    key!(DEVICE_N, b"DeviceN");
551    key!(DEVICE_RGB, b"DeviceRGB");
552    key!(DI, b"Di");
553    key!(DIFFERENCE, b"Difference");
554    key!(DIFFERENCES, b"Differences");
555    key!(DIGEST_METHOD, b"DigestMethod");
556    key!(DIGEST_RIPEMD160, b"RIPEMD160");
557    key!(DIGEST_SHA1, b"SHA1");
558    key!(DIGEST_SHA256, b"SHA256");
559    key!(DIGEST_SHA384, b"SHA384");
560    key!(DIGEST_SHA512, b"SHA512");
561    key!(DIRECTION, b"Direction");
562    key!(DISPLAY_DOC_TITLE, b"DisplayDocTitle");
563    key!(DL, b"DL");
564    key!(DM, b"Dm");
565    key!(DOC, b"Doc");
566    key!(DOC_CHECKSUM, b"DocChecksum");
567    key!(DOC_TIME_STAMP, b"DocTimeStamp");
568    key!(DOCMDP, b"DocMDP");
569    key!(DOCUMENT, b"Document");
570    key!(DOMAIN, b"Domain");
571    key!(DOS, b"DOS");
572    key!(DP, b"DP");
573    key!(DR, b"DR");
574    key!(DS, b"DS");
575    key!(DSS, b"DSS");
576    key!(DUPLEX, b"Duplex");
577    key!(DUR, b"Dur");
578    key!(DV, b"DV");
579    key!(DW, b"DW");
580    key!(DW2, b"DW2");
581
582    // E
583    key!(E, b"E");
584    key!(EARLY_CHANGE, b"EarlyChange");
585    key!(EF, b"EF");
586    key!(EMBEDDED_FDFS, b"EmbeddedFDFs");
587    key!(EMBEDDED_FILE, b"EmbeddedFile");
588    key!(EMBEDDED_FILES, b"EmbeddedFiles");
589    key!(EMPTY, b"");
590    key!(ENCODE, b"Encode");
591    key!(ENCODED_BYTE_ALIGN, b"EncodedByteAlign");
592    key!(ENCODING, b"Encoding");
593    key!(ENCODING_90MS_RKSJ_H, b"90ms-RKSJ-H");
594    key!(ENCODING_90MS_RKSJ_V, b"90ms-RKSJ-V");
595    key!(ENCODING_ETEN_B5_H, b"ETen-B5-H");
596    key!(ENCODING_ETEN_B5_V, b"ETen-B5-V");
597    key!(ENCRYPT, b"Encrypt");
598    key!(ENCRYPT_META_DATA, b"EncryptMetadata");
599    key!(ENCRYPTED_PAYLOAD, b"EncryptedPayload");
600    key!(END_OF_BLOCK, b"EndOfBlock");
601    key!(END_OF_LINE, b"EndOfLine");
602    key!(ENTRUST_PPKEF, b"Entrust.PPKEF");
603    key!(EXCLUSION, b"Exclusion");
604    key!(EXTENSIONS, b"Extensions");
605    key!(EXTENSION_LEVEL, b"ExtensionLevel");
606    key!(EX_DATA, b"ExData");
607    key!(EXPORT, b"Export");
608    key!(EXPORT_STATE, b"ExportState");
609    key!(EXT_G_STATE, b"ExtGState");
610    key!(EXTEND, b"Extend");
611    key!(EXTENDS, b"Extends");
612
613    // F
614    key!(F, b"F");
615    key!(F_DECODE_PARMS, b"FDecodeParms");
616    key!(F_FILTER, b"FFilter");
617    key!(FB, b"FB");
618    key!(FDF, b"FDF");
619    key!(FF, b"Ff");
620    key!(FIELDS, b"Fields");
621    key!(FILESPEC, b"Filespec");
622    key!(FILTER, b"Filter");
623    key!(FIRST, b"First");
624    key!(FIRST_CHAR, b"FirstChar");
625    key!(FIT_WINDOW, b"FitWindow");
626    key!(FL, b"FL");
627    key!(FLAGS, b"Flags");
628    key!(FLATE_DECODE, b"FlateDecode");
629    key!(FLATE_DECODE_ABBREVIATION, b"Fl");
630    key!(FO, b"Fo");
631    key!(FOLDERS, b"Folders");
632    key!(FONT, b"Font");
633    key!(FONT_BBOX, b"FontBBox");
634    key!(FONT_DESC, b"FontDescriptor");
635    key!(FONT_FAMILY, b"FontFamily");
636    key!(FONT_FILE, b"FontFile");
637    key!(FONT_FILE2, b"FontFile2");
638    key!(FONT_FILE3, b"FontFile3");
639    key!(FONT_MATRIX, b"FontMatrix");
640    key!(FONT_NAME, b"FontName");
641    key!(FONT_STRETCH, b"FontStretch");
642    key!(FONT_WEIGHT, b"FontWeight");
643    key!(FORM, b"Form");
644    key!(FORMTYPE, b"FormType");
645    key!(FRM, b"FRM");
646    key!(FS, b"FS");
647    key!(FT, b"FT");
648    key!(FUNCTION, b"Function");
649    key!(FUNCTION_TYPE, b"FunctionType");
650    key!(FUNCTIONS, b"Functions");
651
652    // G
653    key!(G, b"G");
654    key!(GAMMA, b"Gamma");
655    key!(GROUP, b"Group");
656    key!(GTS_PDFA1, b"GTS_PDFA1");
657
658    // H
659    key!(H, b"H");
660    key!(HARD_LIGHT, b"HardLight");
661    key!(HEIGHT, b"Height");
662    key!(HELV, b"Helv");
663    key!(HIDE_MENUBAR, b"HideMenubar");
664    key!(HIDE_TOOLBAR, b"HideToolbar");
665    key!(HIDE_WINDOWUI, b"HideWindowUI");
666    key!(HUE, b"Hue");
667
668    // I
669    key!(I, b"I");
670    key!(IC, b"IC");
671    key!(ICC_BASED, b"ICCBased");
672    key!(ID, b"ID");
673    key!(ID_TREE, b"IDTree");
674    key!(IDENTITY, b"Identity");
675    key!(IDENTITY_H, b"Identity-H");
676    key!(IDENTITY_V, b"Identity-V");
677    key!(IF, b"IF");
678    key!(ILLUSTRATOR, b"Illustrator");
679    key!(IM, b"IM");
680    key!(IMAGE, b"Image");
681    key!(IMAGE_MASK, b"ImageMask");
682    key!(INDEX, b"Index");
683    key!(INDEXED, b"Indexed");
684    key!(INFO, b"Info");
685    key!(INKLIST, b"InkList");
686    key!(INTENT, b"Intent");
687    key!(INTERPOLATE, b"Interpolate");
688    key!(IRT, b"IRT");
689    key!(IT, b"IT");
690    key!(ITALIC_ANGLE, b"ItalicAngle");
691    key!(ISSUER, b"Issuer");
692    key!(IX, b"IX");
693
694    // J
695    key!(JAVA_SCRIPT, b"JavaScript");
696    key!(JBIG2_DECODE, b"JBIG2Decode");
697    key!(JBIG2_GLOBALS, b"JBIG2Globals");
698    key!(JPX_DECODE, b"JPXDecode");
699    key!(JS, b"JS");
700
701    // K
702    key!(K, b"K");
703    key!(KEYWORDS, b"Keywords");
704    key!(KEY_USAGE, b"KeyUsage");
705    key!(KIDS, b"Kids");
706
707    // L
708    key!(L, b"L");
709    key!(LAB, b"Lab");
710    key!(LANG, b"Lang");
711    key!(LAST, b"Last");
712    key!(LAST_CHAR, b"LastChar");
713    key!(LAST_MODIFIED, b"LastModified");
714    key!(LC, b"LC");
715    key!(LE, b"LE");
716    key!(LEADING, b"Leading");
717    key!(LEGAL_ATTESTATION, b"LegalAttestation");
718    key!(LENGTH, b"Length");
719    key!(LENGTH1, b"Length1");
720    key!(LENGTH2, b"Length2");
721    key!(LENGTH3, b"Length3");
722    key!(LIGHTEN, b"Lighten");
723    key!(LIMITS, b"Limits");
724    key!(LINEARIZED, b"Linearized");
725    key!(LJ, b"LJ");
726    key!(LL, b"LL");
727    key!(LLE, b"LLE");
728    key!(LLO, b"LLO");
729    key!(LOCATION, b"Location");
730    key!(LUMINOSITY, b"Luminosity");
731    key!(LW, b"LW");
732    key!(LZW_DECODE, b"LZWDecode");
733    key!(LZW_DECODE_ABBREVIATION, b"LZW");
734
735    // M
736    key!(M, b"M");
737    key!(MAC, b"Mac");
738    key!(MAC_EXPERT_ENCODING, b"MacExpertEncoding");
739    key!(MAC_ROMAN_ENCODING, b"MacRomanEncoding");
740    key!(MARK_INFO, b"MarkInfo");
741    key!(MASK, b"Mask");
742    key!(MATRIX, b"Matrix");
743    key!(MATTE, b"Matte");
744    key!(MAX_LEN, b"MaxLen");
745    key!(MAX_WIDTH, b"MaxWidth");
746    key!(MCID, b"MCID");
747    key!(MDP, b"MDP");
748    key!(MEDIA_BOX, b"MediaBox");
749    key!(MEASURE, b"Measure");
750    key!(METADATA, b"Metadata");
751    key!(MISSING_WIDTH, b"MissingWidth");
752    key!(MIX, b"Mix");
753    key!(MK, b"MK");
754    key!(ML, b"ML");
755    key!(MM_TYPE1, b"MMType1");
756    key!(MOD_DATE, b"ModDate");
757    key!(MULTIPLY, b"Multiply");
758
759    // N
760    key!(N, b"N");
761    key!(NAME, b"Name");
762    key!(NAMES, b"Names");
763    key!(NAVIGATOR, b"Navigator");
764    key!(NEED_APPEARANCES, b"NeedAppearances");
765    key!(NEW_WINDOW, b"NewWindow");
766    key!(NEXT, b"Next");
767    key!(NM, b"NM");
768    key!(NON_EFONT_NO_WARN, b"NonEFontNoWarn");
769    key!(NON_FULL_SCREEN_PAGE_MODE, b"NonFullScreenPageMode");
770    key!(NONE, b"None");
771    key!(NORMAL, b"Normal");
772    key!(NUMS, b"Nums");
773
774    // O
775    key!(O, b"O");
776    key!(OBJ, b"Obj");
777    key!(OBJR, b"OBJR");
778    key!(OBJ_STM, b"ObjStm");
779    key!(OC, b"OC");
780    key!(OCG, b"OCG");
781    key!(OCGS, b"OCGs");
782    key!(OCMD, b"OCMD");
783    key!(OCPROPERTIES, b"OCProperties");
784    key!(OCSP, b"OCSP");
785    key!(OCSPS, b"OCSPs");
786    key!(OE, b"OE");
787    key!(OID, b"OID");
788    key!(OFF, b"OFF");
789    key!(ON, b"ON");
790    key!(OP, b"OP");
791    key!(OP_NS, b"op");
792    key!(OPEN_ACTION, b"OpenAction");
793    key!(OPEN_TYPE, b"OpenType");
794    key!(OPI, b"OPI");
795    key!(OPM, b"OPM");
796    key!(OPT, b"Opt");
797    key!(ORDER, b"Order");
798    key!(ORDERING, b"Ordering");
799    key!(OS, b"OS");
800    key!(OUTLINES, b"Outlines");
801    key!(OUTPUT_CONDITION, b"OutputCondition");
802    key!(OUTPUT_CONDITION_IDENTIFIER, b"OutputConditionIdentifier");
803    key!(OUTPUT_INTENT, b"OutputIntent");
804    key!(OUTPUT_INTENTS, b"OutputIntents");
805    key!(OVERLAY, b"Overlay");
806
807    // P
808    key!(P, b"P");
809    key!(PA, b"PA");
810    key!(PAGE, b"Page");
811    key!(PAGE_LABELS, b"PageLabels");
812    key!(PAGE_LAYOUT, b"PageLayout");
813    key!(PAGE_MODE, b"PageMode");
814    key!(PAGES, b"Pages");
815    key!(PAINT_TYPE, b"PaintType");
816    key!(PANOSE, b"Panose");
817    key!(PARAMS, b"Params");
818    key!(PARENT, b"Parent");
819    key!(PARENT_TREE, b"ParentTree");
820    key!(PARENT_TREE_NEXT_KEY, b"ParentTreeNextKey");
821    key!(PART, b"Part");
822    key!(PATH, b"Path");
823    key!(PATTERN, b"Pattern");
824    key!(PATTERN_TYPE, b"PatternType");
825    key!(PC, b"PC");
826    key!(PDF_DOC_ENCODING, b"PDFDocEncoding");
827    key!(PERMS, b"Perms");
828    key!(PERCEPTUAL, b"Perceptual");
829    key!(PIECE_INFO, b"PieceInfo");
830    key!(PG, b"Pg");
831    key!(PI, b"PI");
832    key!(PO, b"PO");
833    key!(POPUP, b"Popup");
834    key!(PRE_RELEASE, b"PreRelease");
835    key!(PREDICTOR, b"Predictor");
836    key!(PREV, b"Prev");
837    key!(PRINT, b"Print");
838    key!(PRINT_AREA, b"PrintArea");
839    key!(PRINT_CLIP, b"PrintClip");
840    key!(PRINT_SCALING, b"PrintScaling");
841    key!(PRINT_STATE, b"PrintState");
842    key!(PRIVATE, b"Private");
843    key!(PROC_SET, b"ProcSet");
844    key!(PROCESS, b"Process");
845    key!(PRODUCER, b"Producer");
846    key!(PROP_BUILD, b"Prop_Build");
847    key!(PROPERTIES, b"Properties");
848    key!(PS, b"PS");
849    key!(PT_DATA, b"PtData");
850    key!(PUB_SEC, b"PubSec");
851    key!(PV, b"PV");
852
853    // Q
854    key!(Q, b"Q");
855    key!(QUADPOINTS, b"QuadPoints");
856
857    // R
858    key!(R, b"R");
859    key!(RANGE, b"Range");
860    key!(RC, b"RC");
861    key!(RD, b"RD");
862    key!(REASON, b"Reason");
863    key!(REASONS, b"Reasons");
864    key!(RECIPIENTS, b"Recipients");
865    key!(RECT, b"Rect");
866    key!(REF, b"Ref");
867    key!(REFERENCE, b"Reference");
868    key!(REGISTRY, b"Registry");
869    key!(REGISTRY_NAME, b"RegistryName");
870    key!(RELATIVE_COLORIMETRIC, b"RelativeColorimetric");
871    key!(RENAME, b"Rename");
872    key!(REPEAT, b"Repeat");
873    key!(RES_FORK, b"ResFork");
874    key!(RESOURCES, b"Resources");
875    key!(RGB, b"RGB");
876    key!(RI, b"RI");
877    key!(ROLE_MAP, b"RoleMap");
878    key!(ROOT, b"Root");
879    key!(ROTATE, b"Rotate");
880    key!(ROWS, b"Rows");
881    key!(RT, b"RT");
882    key!(RUN_LENGTH_DECODE, b"RunLengthDecode");
883    key!(RUN_LENGTH_DECODE_ABBREVIATION, b"RL");
884    key!(RV, b"RV");
885
886    // S
887    key!(S, b"S");
888    key!(SA, b"SA");
889    key!(SATURATION, b"Saturation");
890    key!(SCHEMA, b"Schema");
891    key!(SCREEN, b"Screen");
892    key!(SE, b"SE");
893    key!(SEPARATION, b"Separation");
894    key!(SET_F, b"SetF");
895    key!(SET_FF, b"SetFf");
896    key!(SHADING, b"Shading");
897    key!(SHADING_TYPE, b"ShadingType");
898    key!(SIG, b"Sig");
899    key!(SIG_FLAGS, b"SigFlags");
900    key!(SIG_REF, b"SigRef");
901    key!(SIZE, b"Size");
902    key!(SM, b"SM");
903    key!(SMASK, b"SMask");
904    key!(SMASK_IN_DATA, b"SMaskInData");
905    key!(SOFT_LIGHT, b"SoftLight");
906    key!(SORT, b"Sort");
907    key!(SOUND, b"Sound");
908    key!(SPLIT, b"Split");
909    key!(SS, b"SS");
910    key!(ST, b"St");
911    key!(STANDARD_ENCODING, b"StandardEncoding");
912    key!(STATE, b"State");
913    key!(STATE_MODEL, b"StateModel");
914    key!(STATUS, b"Status");
915    key!(STD_CF, b"StdCF");
916    key!(STEM_H, b"StemH");
917    key!(STEM_V, b"StemV");
918    key!(STM_F, b"StmF");
919    key!(STR_F, b"StrF");
920    key!(STRUCT_ELEM, b"StructElem");
921    key!(STRUCT_PARENT, b"StructParent");
922    key!(STRUCT_PARENTS, b"StructParents");
923    key!(STRUCT_TREE_ROOT, b"StructTreeRoot");
924    key!(STYLE, b"Style");
925    key!(SUB_FILTER, b"SubFilter");
926    key!(SUBJ, b"Subj");
927    key!(SUBJECT, b"Subject");
928    key!(SUBJECT_DN, b"SubjectDN");
929    key!(SUBTYPE, b"Subtype");
930    key!(SUPPLEMENT, b"Supplement");
931    key!(SV, b"SV");
932    key!(SV_CERT, b"SVCert");
933    key!(SW, b"SW");
934    key!(SY, b"Sy");
935    key!(SYNCHRONOUS, b"Synchronous");
936    key!(T, b"T");
937    key!(TARGET, b"Target");
938    key!(TEMPLATES, b"Templates");
939    key!(THREAD, b"Thread");
940    key!(THREADS, b"Threads");
941    key!(THREE_DD, b"3DD");
942    key!(THUMB, b"Thumb");
943    key!(TI, b"TI");
944    key!(TILING_TYPE, b"TilingType");
945    key!(TIME_STAMP, b"TimeStamp");
946    key!(TITLE, b"Title");
947    key!(TK, b"TK");
948    key!(TM, b"TM");
949    key!(TO_UNICODE, b"ToUnicode");
950    key!(TR, b"TR");
951    key!(TR2, b"TR2");
952    key!(TRAPPED, b"Trapped");
953    key!(TRANS, b"Trans");
954    key!(TRANSFORM_METHOD, b"TransformMethod");
955    key!(TRANSFORM_PARAMS, b"TransformParams");
956    key!(TRANSPARENCY, b"Transparency");
957    key!(TREF, b"TRef");
958    key!(TRIM_BOX, b"TrimBox");
959    key!(TRUE_TYPE, b"TrueType");
960    key!(TRUSTED_MODE, b"TrustedMode");
961    key!(TU, b"TU");
962    key!(TX, b"Tx");
963    key!(TYPE, b"Type");
964    key!(TYPE0, b"Type0");
965    key!(TYPE1, b"Type1");
966    key!(TYPE1C, b"Type1C");
967    key!(TYPE3, b"Type3");
968
969    // U
970    key!(U, b"U");
971    key!(UE, b"UE");
972    key!(UF, b"UF");
973    key!(UNCHANGED, b"Unchanged");
974    key!(UNIX, b"Unix");
975    key!(URI, b"URI");
976    key!(URL, b"URL");
977    key!(URL_TYPE, b"URLType");
978    key!(USAGE, b"Usage");
979    key!(USE_CMAP, b"UseCMap");
980    key!(USER_UNIT, b"UserUnit");
981
982    // V
983    key!(V, b"V");
984    key!(VE, b"VE");
985    key!(VERISIGN_PPKVS, b"VeriSign.PPKVS");
986    key!(VERSION, b"Version");
987    key!(VERTICES, b"Vertices");
988    key!(VERTICES_PER_ROW, b"VerticesPerRow");
989    key!(VIEW, b"View");
990    key!(VIEW_AREA, b"ViewArea");
991    key!(VIEW_CLIP, b"ViewClip");
992    key!(VIEW_STATE, b"ViewState");
993    key!(VIEWER_PREFERENCES, b"ViewerPreferences");
994    key!(VOLUME, b"Volume");
995    key!(VP, b"VP");
996    key!(VRI, b"VRI");
997
998    // W
999    key!(W, b"W");
1000    key!(W2, b"W2");
1001    key!(WC, b"WC");
1002    key!(WHITE_POINT, b"WhitePoint");
1003    key!(WIDGET, b"Widget");
1004    key!(WIDTH, b"Width");
1005    key!(WIDTHS, b"Widths");
1006    key!(WIN, b"Win");
1007    key!(WIN_ANSI_ENCODING, b"WinAnsiEncoding");
1008    key!(WMODE, b"WMode");
1009    key!(WP, b"WP");
1010    key!(WS, b"WS");
1011
1012    // X
1013    key!(X, b"X");
1014    key!(XFA, b"XFA");
1015    key!(X_STEP, b"XStep");
1016    key!(XHEIGHT, b"XHeight");
1017    key!(XOBJECT, b"XObject");
1018    key!(XREF, b"XRef");
1019    key!(XREF_STM, b"XRefStm");
1020
1021    // Y
1022    key!(Y, b"Y");
1023    key!(Y_STEP, b"YStep");
1024    key!(YES, b"Yes");
1025
1026    // Z
1027    key!(ZA_DB, b"ZaDb");
1028}
1029
1030#[cfg(test)]
1031mod tests {
1032    use crate::object::dict::keys::{COLORSPACE, EXT_G_STATE, FONT, PROC_SET};
1033    use crate::object::dict::{Dict, InlineImageDict};
1034    use crate::object::string;
1035    use crate::object::{FromBytes, Number};
1036    use crate::object::{Name, ObjRef};
1037    use crate::reader::Reader;
1038    use crate::reader::{ReaderContext, ReaderExt};
1039
1040    fn dict_impl(data: &[u8]) -> Option<Dict<'_>> {
1041        Reader::new(data).read_with_context::<Dict<'_>>(&ReaderContext::dummy())
1042    }
1043
1044    #[test]
1045    fn empty_dict_1() {
1046        let dict_data = b"<<>>";
1047        let dict = dict_impl(dict_data).unwrap();
1048
1049        assert_eq!(dict.len(), 0);
1050    }
1051
1052    #[test]
1053    fn empty_dict_2() {
1054        let dict_data = b"<<   \n >>";
1055        let dict = dict_impl(dict_data).unwrap();
1056
1057        assert_eq!(dict.len(), 0);
1058    }
1059
1060    #[test]
1061    fn dict_1() {
1062        let dict_data = b"<<  /Hi 34.0 >>";
1063        let dict = dict_impl(dict_data).unwrap();
1064
1065        assert_eq!(dict.len(), 1);
1066        assert!(dict.get::<Number>(Name::new_unescaped(b"Hi")).is_some());
1067    }
1068
1069    #[test]
1070    fn dict_2() {
1071        let dict_data = b"<<  /Hi \n 34.0 /Second true >>";
1072        let dict = dict_impl(dict_data).unwrap();
1073
1074        assert_eq!(dict.len(), 2);
1075        assert!(dict.get::<Number>(Name::new_unescaped(b"Hi")).is_some());
1076        assert!(dict.get::<bool>(Name::new_unescaped(b"Second")).is_some());
1077    }
1078
1079    #[test]
1080    fn dict_complex() {
1081        let data = "<< /Type /Example
1082/Subtype /DictionaryExample
1083/Version 0.01
1084/IntegerItem 12
1085/StringItem ( a string )
1086/Subdictionary << /Item1 0.4
1087                /Item2 true
1088                /LastItem ( not ! )
1089                /VeryLastItem ( OK )
1090                >>
1091>>";
1092
1093        let dict = Reader::new(data.as_bytes())
1094            .read_with_context::<Dict<'_>>(&ReaderContext::dummy())
1095            .unwrap();
1096        assert_eq!(dict.len(), 6);
1097        assert!(dict.get::<Name<'_>>(Name::new_unescaped(b"Type")).is_some());
1098        assert!(
1099            dict.get::<Name<'_>>(Name::new_unescaped(b"Subtype"))
1100                .is_some()
1101        );
1102        assert!(
1103            dict.get::<Number>(Name::new_unescaped(b"Version"))
1104                .is_some()
1105        );
1106        assert!(
1107            dict.get::<i32>(Name::new_unescaped(b"IntegerItem"))
1108                .is_some()
1109        );
1110        assert!(
1111            dict.get::<string::String<'_>>(Name::new_unescaped(b"StringItem"))
1112                .is_some()
1113        );
1114        assert!(
1115            dict.get::<Dict<'_>>(Name::new_unescaped(b"Subdictionary"))
1116                .is_some()
1117        );
1118    }
1119
1120    #[test]
1121    fn dict_with_trailing() {
1122        let dict_data = b"<<  /Hi 67.0  >>trailing data";
1123        let dict = dict_impl(dict_data).unwrap();
1124
1125        assert_eq!(dict.len(), 1);
1126    }
1127
1128    #[test]
1129    fn dict_with_comment() {
1130        let dict_data = b"<<  /Hi % A comment \n 67.0 % Another comment \n >>";
1131        let dict = dict_impl(dict_data).unwrap();
1132
1133        assert_eq!(dict.len(), 1);
1134    }
1135
1136    #[test]
1137    fn inline_dict() {
1138        let dict_data = b"/W 17 /H 17 /CS /RGB /BPC 8 /F [ /A85 /LZW ] ID ";
1139
1140        let dict = Reader::new(&dict_data[..])
1141            .read_with_context::<InlineImageDict<'_>>(&ReaderContext::dummy())
1142            .unwrap();
1143
1144        assert_eq!(dict.get_dict().len(), 5);
1145    }
1146
1147    #[test]
1148    fn dict_with_escaped_name() {
1149        let dict_data = b"<< /PANTONE#20104#20C 234 >>";
1150        let dict = dict_impl(dict_data).unwrap();
1151
1152        assert!(dict.contains_key("PANTONE 104 C"));
1153    }
1154
1155    #[test]
1156    fn garbage_in_between() {
1157        let dict_data = b"<< 
1158/ProcSet [ /PDF /Text ] 
1159/Font << /F4 31 0 R /F6 23 0 R >> 
1160/ExtGState << /GS2 14 0 R
11612000
1162 /GS3 15 0 R >> 
1163/ColorSpace << /Cs5 13 0 R >> 
1164>> ";
1165        let dict = dict_impl(dict_data).unwrap();
1166
1167        assert!(dict.contains_key(PROC_SET));
1168        assert!(dict.contains_key(FONT));
1169        assert!(dict.contains_key(EXT_G_STATE));
1170        assert!(dict.contains_key(COLORSPACE));
1171
1172        let Some(dict) = dict.get::<Dict<'_>>(EXT_G_STATE) else {
1173            panic!("failed to parse ext g state");
1174        };
1175
1176        assert_eq!(dict.get_ref("GS2"), Some(ObjRef::new(14, 0)));
1177        assert_eq!(dict.get_ref("GS3"), Some(ObjRef::new(15, 0)));
1178    }
1179
1180    #[test]
1181    fn dict_repr() {
1182        let dict = Dict::from_bytes(b"<< /Hi 34 >>").unwrap();
1183
1184        assert_eq!(
1185            format!("{dict:?}"),
1186            "Dict { \"Hi\": Number(Number(Integer(34))) }"
1187        );
1188    }
1189
1190    #[test]
1191    fn display() {
1192        let dict = Dict::from_bytes(b"<< /B [1   2] % comment\n /A << /X   true >> >>").unwrap();
1193
1194        assert_eq!(format!("{dict}"), "<< /A << /X true >> /B [1 2] >>");
1195        assert_eq!(format!("{}", Dict::empty()), "<<>>");
1196    }
1197}