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