1 //========================================================================
2 //
3 // Object.h
4 //
5 // Copyright 1996-2003 Glyph & Cog, LLC
6 //
7 //========================================================================
8 
9 //========================================================================
10 //
11 // Modified under the Poppler project - http://poppler.freedesktop.org
12 //
13 // All changes made under the Poppler project to this file are licensed
14 // under GPL version 2 or later
15 //
16 // Copyright (C) 2007 Julien Rebetez <julienr@svn.gnome.org>
17 // Copyright (C) 2008 Kees Cook <kees@outflux.net>
18 // Copyright (C) 2008, 2010, 2017-2021 Albert Astals Cid <aacid@kde.org>
19 // Copyright (C) 2009 Jakub Wilk <jwilk@jwilk.net>
20 // Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
21 // Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
22 // Copyright (C) 2013, 2017, 2018 Adrian Johnson <ajohnson@redneon.com>
23 // Copyright (C) 2013 Adrian Perez de Castro <aperez@igalia.com>
24 // Copyright (C) 2016, 2020 Jakub Alba <jakubalba@gmail.com>
25 // Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, <info@kdab.com>. Work sponsored by the LiMux project of the city of Munich
26 // Copyright (C) 2018 Adam Reichold <adam.reichold@t-online.de>
27 // Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, <info@kdab.com>. Work sponsored by Technische Universität Dresden
28 //
29 // To see a description of the changes please see the Changelog file that
30 // came with your tarball or type make ChangeLog if you are building from git
31 //
32 //========================================================================
33 
34 #ifndef OBJECT_H
35 #define OBJECT_H
36 
37 #include <cassert>
38 #include <set>
39 #include <cstdio>
40 #include <cstring>
41 #include <climits>
42 #include "goo/gmem.h"
43 #include "goo/GooString.h"
44 #include "goo/GooLikely.h"
45 #include "Error.h"
46 #include "poppler_private_export.h"
47 
48 #define OBJECT_TYPE_CHECK(wanted_type)                                                                                                                                                                                                         \
49     if (unlikely(type != wanted_type)) {                                                                                                                                                                                                       \
50         error(errInternal, 0,                                                                                                                                                                                                                  \
51               "Call to Object where the object was type {0:d}, "                                                                                                                                                                               \
52               "not the expected type {1:d}",                                                                                                                                                                                                   \
53               type, wanted_type);                                                                                                                                                                                                              \
54         abort();                                                                                                                                                                                                                               \
55     }
56 
57 #define OBJECT_2TYPES_CHECK(wanted_type1, wanted_type2)                                                                                                                                                                                        \
58     if (unlikely(type != wanted_type1) && unlikely(type != wanted_type2)) {                                                                                                                                                                    \
59         error(errInternal, 0,                                                                                                                                                                                                                  \
60               "Call to Object where the object was type {0:d}, "                                                                                                                                                                               \
61               "not the expected type {1:d} or {2:d}",                                                                                                                                                                                          \
62               type, wanted_type1, wanted_type2);                                                                                                                                                                                               \
63         abort();                                                                                                                                                                                                                               \
64     }
65 
66 #define OBJECT_3TYPES_CHECK(wanted_type1, wanted_type2, wanted_type3)                                                                                                                                                                          \
67     if (unlikely(type != wanted_type1) && unlikely(type != wanted_type2) && unlikely(type != wanted_type3)) {                                                                                                                                  \
68         error(errInternal, 0,                                                                                                                                                                                                                  \
69               "Call to Object where the object was type {0:d}, "                                                                                                                                                                               \
70               "not the expected type {1:d}, {2:d} or {3:d}",                                                                                                                                                                                   \
71               type, wanted_type1, wanted_type2, wanted_type3);                                                                                                                                                                                 \
72         abort();                                                                                                                                                                                                                               \
73     }
74 
75 #define CHECK_NOT_DEAD                                                                                                                                                                                                                         \
76     if (unlikely(type == objDead)) {                                                                                                                                                                                                           \
77         error(errInternal, 0, "Call to dead object");                                                                                                                                                                                          \
78         abort();                                                                                                                                                                                                                               \
79     }
80 
81 class XRef;
82 class Array;
83 class Dict;
84 class Stream;
85 
86 //------------------------------------------------------------------------
87 // Ref
88 //------------------------------------------------------------------------
89 
90 struct Ref
91 {
92     int num; // object number
93     int gen; // generation number
94 
INVALIDRef95     static constexpr Ref INVALID() { return { -1, -1 }; };
96 };
97 
98 inline bool operator==(const Ref lhs, const Ref rhs) noexcept
99 {
100     return lhs.num == rhs.num && lhs.gen == rhs.gen;
101 }
102 
103 inline bool operator!=(const Ref lhs, const Ref rhs) noexcept
104 {
105     return lhs.num != rhs.num || lhs.gen != rhs.gen;
106 }
107 
108 inline bool operator<(const Ref lhs, const Ref rhs) noexcept
109 {
110     if (lhs.num != rhs.num)
111         return lhs.num < rhs.num;
112     return lhs.gen < rhs.gen;
113 }
114 
115 namespace std {
116 
117 template<>
118 struct hash<Ref>
119 {
120     using argument_type = Ref;
121     using result_type = size_t;
122 
123     result_type operator()(const argument_type ref) const noexcept { return std::hash<int> {}(ref.num) ^ (std::hash<int> {}(ref.gen) << 1); }
124 };
125 
126 }
127 
128 //------------------------------------------------------------------------
129 // object types
130 //------------------------------------------------------------------------
131 
132 enum ObjType
133 {
134     // simple objects
135     objBool, // boolean
136     objInt, // integer
137     objReal, // real
138     objString, // string
139     objName, // name
140     objNull, // null
141 
142     // complex objects
143     objArray, // array
144     objDict, // dictionary
145     objStream, // stream
146     objRef, // indirect reference
147 
148     // special objects
149     objCmd, // command name
150     objError, // error return from Lexer
151     objEOF, // end of file return from Lexer
152     objNone, // uninitialized object
153 
154     // poppler-only objects
155     objInt64, // integer with at least 64-bits
156     objHexString, // hex string
157     objDead // and object after shallowCopy
158 };
159 
160 constexpr int numObjTypes = 17; // total number of object types
161 
162 //------------------------------------------------------------------------
163 // Object
164 //------------------------------------------------------------------------
165 
166 class POPPLER_PRIVATE_EXPORT Object
167 {
168 public:
169     Object() : type(objNone) { }
170     ~Object() { free(); }
171 
172     explicit Object(bool boolnA)
173     {
174         type = objBool;
175         booln = boolnA;
176     }
177     explicit Object(int intgA)
178     {
179         type = objInt;
180         intg = intgA;
181     }
182     explicit Object(ObjType typeA) { type = typeA; }
183     explicit Object(double realA)
184     {
185         type = objReal;
186         real = realA;
187     }
188     explicit Object(GooString *stringA)
189     {
190         assert(stringA);
191         type = objString;
192         string = stringA;
193     }
194     Object(ObjType typeA, GooString *stringA)
195     {
196         assert(typeA == objHexString);
197         assert(stringA);
198         type = typeA;
199         string = stringA;
200     }
201     Object(ObjType typeA, const char *stringA)
202     {
203         assert(typeA == objName || typeA == objCmd);
204         assert(stringA);
205         type = typeA;
206         cString = copyString(stringA);
207     }
208     explicit Object(long long int64gA)
209     {
210         type = objInt64;
211         int64g = int64gA;
212     }
213     explicit Object(Array *arrayA)
214     {
215         assert(arrayA);
216         type = objArray;
217         array = arrayA;
218     }
219     explicit Object(Dict *dictA)
220     {
221         assert(dictA);
222         type = objDict;
223         dict = dictA;
224     }
225     explicit Object(Stream *streamA)
226     {
227         assert(streamA);
228         type = objStream;
229         stream = streamA;
230     }
231     explicit Object(const Ref r)
232     {
233         type = objRef;
234         ref = r;
235     }
236 
237     template<typename T>
238     Object(T) = delete;
239 
240     Object(Object &&other) noexcept
241     {
242         std::memcpy(reinterpret_cast<void *>(this), &other, sizeof(Object));
243         other.type = objDead;
244     }
245 
246     Object &operator=(Object &&other) noexcept
247     {
248         free();
249 
250         std::memcpy(reinterpret_cast<void *>(this), &other, sizeof(Object));
251         other.type = objDead;
252 
253         return *this;
254     }
255 
256     Object &operator=(const Object &other) = delete;
257     Object(const Object &other) = delete;
258 
259     // Set object to null.
260     void setToNull()
261     {
262         free();
263         type = objNull;
264     }
265 
266     // Copies all object types except
267     // objArray, objDict, objStream whose refcount is increased by 1
268     Object copy() const;
269 
270     // Deep copies all object types (recursively)
271     // except objStream whose refcount is increased by 1
272     Object deepCopy() const;
273 
274     // If object is a Ref, fetch and return the referenced object.
275     // Otherwise, return a copy of the object.
276     Object fetch(XRef *xref, int recursion = 0) const;
277 
278     // Type checking.
279     ObjType getType() const
280     {
281         CHECK_NOT_DEAD;
282         return type;
283     }
284     bool isBool() const
285     {
286         CHECK_NOT_DEAD;
287         return type == objBool;
288     }
289     bool isInt() const
290     {
291         CHECK_NOT_DEAD;
292         return type == objInt;
293     }
294     bool isReal() const
295     {
296         CHECK_NOT_DEAD;
297         return type == objReal;
298     }
299     bool isNum() const
300     {
301         CHECK_NOT_DEAD;
302         return type == objInt || type == objReal || type == objInt64;
303     }
304     bool isString() const
305     {
306         CHECK_NOT_DEAD;
307         return type == objString;
308     }
309     bool isHexString() const
310     {
311         CHECK_NOT_DEAD;
312         return type == objHexString;
313     }
314     bool isName() const
315     {
316         CHECK_NOT_DEAD;
317         return type == objName;
318     }
319     bool isNull() const
320     {
321         CHECK_NOT_DEAD;
322         return type == objNull;
323     }
324     bool isArray() const
325     {
326         CHECK_NOT_DEAD;
327         return type == objArray;
328     }
329     bool isDict() const
330     {
331         CHECK_NOT_DEAD;
332         return type == objDict;
333     }
334     bool isStream() const
335     {
336         CHECK_NOT_DEAD;
337         return type == objStream;
338     }
339     bool isRef() const
340     {
341         CHECK_NOT_DEAD;
342         return type == objRef;
343     }
344     bool isCmd() const
345     {
346         CHECK_NOT_DEAD;
347         return type == objCmd;
348     }
349     bool isError() const
350     {
351         CHECK_NOT_DEAD;
352         return type == objError;
353     }
354     bool isEOF() const
355     {
356         CHECK_NOT_DEAD;
357         return type == objEOF;
358     }
359     bool isNone() const
360     {
361         CHECK_NOT_DEAD;
362         return type == objNone;
363     }
364     bool isInt64() const
365     {
366         CHECK_NOT_DEAD;
367         return type == objInt64;
368     }
369     bool isIntOrInt64() const
370     {
371         CHECK_NOT_DEAD;
372         return type == objInt || type == objInt64;
373     }
374 
375     // Special type checking.
376     bool isName(const char *nameA) const { return type == objName && !strcmp(cString, nameA); }
377     bool isDict(const char *dictType) const;
378     bool isCmd(const char *cmdA) const { return type == objCmd && !strcmp(cString, cmdA); }
379 
380     // Accessors.
381     bool getBool() const
382     {
383         OBJECT_TYPE_CHECK(objBool);
384         return booln;
385     }
386     int getInt() const
387     {
388         OBJECT_TYPE_CHECK(objInt);
389         return intg;
390     }
391     double getReal() const
392     {
393         OBJECT_TYPE_CHECK(objReal);
394         return real;
395     }
396 
397     // Note: integers larger than 2^53 can not be exactly represented by a double.
398     // Where the exact value of integers up to 2^63 is required, use isInt64()/getInt64().
399     double getNum() const
400     {
401         OBJECT_3TYPES_CHECK(objInt, objInt64, objReal);
402         return type == objInt ? (double)intg : type == objInt64 ? (double)int64g : real;
403     }
404     double getNum(bool *ok) const
405     {
406         if (unlikely(type != objInt && type != objInt64 && type != objReal)) {
407             *ok = false;
408             return 0.;
409         }
410         return type == objInt ? (double)intg : type == objInt64 ? (double)int64g : real;
411     }
412     const GooString *getString() const
413     {
414         OBJECT_TYPE_CHECK(objString);
415         return string;
416     }
417     // After takeString() the only method that should be called for the object is free().
418     GooString *takeString()
419     {
420         OBJECT_TYPE_CHECK(objString);
421         type = objDead;
422         return string;
423     }
424     const GooString *getHexString() const
425     {
426         OBJECT_TYPE_CHECK(objHexString);
427         return string;
428     }
429     GooString *takeHexString()
430     {
431         OBJECT_TYPE_CHECK(objHexString);
432         type = objDead;
433         return string;
434     }
435     const char *getName() const
436     {
437         OBJECT_TYPE_CHECK(objName);
438         return cString;
439     }
440     Array *getArray() const
441     {
442         OBJECT_TYPE_CHECK(objArray);
443         return array;
444     }
445     Dict *getDict() const
446     {
447         OBJECT_TYPE_CHECK(objDict);
448         return dict;
449     }
450     Stream *getStream() const
451     {
452         OBJECT_TYPE_CHECK(objStream);
453         return stream;
454     }
455     Ref getRef() const
456     {
457         OBJECT_TYPE_CHECK(objRef);
458         return ref;
459     }
460     int getRefNum() const
461     {
462         OBJECT_TYPE_CHECK(objRef);
463         return ref.num;
464     }
465     int getRefGen() const
466     {
467         OBJECT_TYPE_CHECK(objRef);
468         return ref.gen;
469     }
470     const char *getCmd() const
471     {
472         OBJECT_TYPE_CHECK(objCmd);
473         return cString;
474     }
475     long long getInt64() const
476     {
477         OBJECT_TYPE_CHECK(objInt64);
478         return int64g;
479     }
480     long long getIntOrInt64() const
481     {
482         OBJECT_2TYPES_CHECK(objInt, objInt64);
483         return type == objInt ? intg : int64g;
484     }
485 
486     // Array accessors.
487     int arrayGetLength() const;
488     void arrayAdd(Object &&elem);
489     void arrayRemove(int i);
490     Object arrayGet(int i, int recursion) const;
491     const Object &arrayGetNF(int i) const;
492 
493     // Dict accessors.
494     int dictGetLength() const;
495     void dictAdd(char *key, Object &&val) = delete;
496     void dictAdd(const char *key, Object &&val);
497     void dictSet(const char *key, Object &&val);
498     void dictRemove(const char *key);
499     bool dictIs(const char *dictType) const;
500     Object dictLookup(const char *key, int recursion = 0) const;
501     const Object &dictLookupNF(const char *key) const;
502     const char *dictGetKey(int i) const;
503     Object dictGetVal(int i) const;
504     const Object &dictGetValNF(int i) const;
505 
506     // Stream accessors.
507     void streamReset();
508     void streamClose();
509     int streamGetChar();
510     int streamGetChars(int nChars, unsigned char *buffer);
511     void streamSetPos(Goffset pos, int dir = 0);
512     Dict *streamGetDict() const;
513 
514     // Output.
515     const char *getTypeName() const;
516     void print(FILE *f = stdout) const;
517 
518     double getNumWithDefaultValue(double defaultValue) const
519     {
520         if (unlikely(type != objInt && type != objInt64 && type != objReal)) {
521             return defaultValue;
522         }
523         return type == objInt ? (double)intg : type == objInt64 ? (double)int64g : real;
524     }
525 
526     bool getBoolWithDefaultValue(bool defaultValue) const { return (type == objBool) ? booln : defaultValue; }
527 
528 private:
529     // Free object contents.
530     void free();
531 
532     ObjType type; // object type
533     union { // value for each type:
534         bool booln; //   boolean
535         int intg; //   integer
536         long long int64g; //   64-bit integer
537         double real; //   real
538         GooString *string; // [hex] string
539         char *cString; //   name or command, depending on objType
540         Array *array; //   array
541         Dict *dict; //   dictionary
542         Stream *stream; //   stream
543         Ref ref; //   indirect reference
544     };
545 };
546 
547 //------------------------------------------------------------------------
548 // Array accessors.
549 //------------------------------------------------------------------------
550 
551 #include "Array.h"
552 
553 inline int Object::arrayGetLength() const
554 {
555     OBJECT_TYPE_CHECK(objArray);
556     return array->getLength();
557 }
558 
559 inline void Object::arrayAdd(Object &&elem)
560 {
561     OBJECT_TYPE_CHECK(objArray);
562     array->add(std::move(elem));
563 }
564 
565 inline void Object::arrayRemove(int i)
566 {
567     OBJECT_TYPE_CHECK(objArray);
568     array->remove(i);
569 }
570 
571 inline Object Object::arrayGet(int i, int recursion = 0) const
572 {
573     OBJECT_TYPE_CHECK(objArray);
574     return array->get(i, recursion);
575 }
576 
577 inline const Object &Object::arrayGetNF(int i) const
578 {
579     OBJECT_TYPE_CHECK(objArray);
580     return array->getNF(i);
581 }
582 
583 //------------------------------------------------------------------------
584 // Dict accessors.
585 //------------------------------------------------------------------------
586 
587 #include "Dict.h"
588 
589 inline int Object::dictGetLength() const
590 {
591     OBJECT_TYPE_CHECK(objDict);
592     return dict->getLength();
593 }
594 
595 inline void Object::dictAdd(const char *key, Object &&val)
596 {
597     OBJECT_TYPE_CHECK(objDict);
598     dict->add(key, std::move(val));
599 }
600 
601 inline void Object::dictSet(const char *key, Object &&val)
602 {
603     OBJECT_TYPE_CHECK(objDict);
604     dict->set(key, std::move(val));
605 }
606 
607 inline void Object::dictRemove(const char *key)
608 {
609     OBJECT_TYPE_CHECK(objDict);
610     dict->remove(key);
611 }
612 
613 inline bool Object::dictIs(const char *dictType) const
614 {
615     OBJECT_TYPE_CHECK(objDict);
616     return dict->is(dictType);
617 }
618 
619 inline bool Object::isDict(const char *dictType) const
620 {
621     return type == objDict && dictIs(dictType);
622 }
623 
624 inline Object Object::dictLookup(const char *key, int recursion) const
625 {
626     OBJECT_TYPE_CHECK(objDict);
627     return dict->lookup(key, recursion);
628 }
629 
630 inline const Object &Object::dictLookupNF(const char *key) const
631 {
632     OBJECT_TYPE_CHECK(objDict);
633     return dict->lookupNF(key);
634 }
635 
636 inline const char *Object::dictGetKey(int i) const
637 {
638     OBJECT_TYPE_CHECK(objDict);
639     return dict->getKey(i);
640 }
641 
642 inline Object Object::dictGetVal(int i) const
643 {
644     OBJECT_TYPE_CHECK(objDict);
645     return dict->getVal(i);
646 }
647 
648 inline const Object &Object::dictGetValNF(int i) const
649 {
650     OBJECT_TYPE_CHECK(objDict);
651     return dict->getValNF(i);
652 }
653 
654 //------------------------------------------------------------------------
655 // Stream accessors.
656 //------------------------------------------------------------------------
657 
658 #include "Stream.h"
659 
660 inline void Object::streamReset()
661 {
662     OBJECT_TYPE_CHECK(objStream);
663     stream->reset();
664 }
665 
666 inline void Object::streamClose()
667 {
668     OBJECT_TYPE_CHECK(objStream);
669     stream->close();
670 }
671 
672 inline int Object::streamGetChar()
673 {
674     OBJECT_TYPE_CHECK(objStream);
675     return stream->getChar();
676 }
677 
678 inline int Object::streamGetChars(int nChars, unsigned char *buffer)
679 {
680     OBJECT_TYPE_CHECK(objStream);
681     return stream->doGetChars(nChars, buffer);
682 }
683 
684 inline Dict *Object::streamGetDict() const
685 {
686     OBJECT_TYPE_CHECK(objStream);
687     return stream->getDict();
688 }
689 
690 #endif
691