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