File indexing completed on 2025-12-10 10:23:49
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034 #ifndef OBJECT_H
0035 #define OBJECT_H
0036
0037 #include <cassert>
0038 #include <set>
0039 #include <cstdio>
0040 #include <cstring>
0041 #include <climits>
0042 #include "goo/gmem.h"
0043 #include "goo/GooString.h"
0044 #include "goo/GooLikely.h"
0045 #include "Error.h"
0046 #include "poppler_private_export.h"
0047
0048 #define OBJECT_TYPE_CHECK(wanted_type) \
0049 if (unlikely(type != wanted_type)) { \
0050 error(errInternal, 0, \
0051 "Call to Object where the object was type {0:d}, " \
0052 "not the expected type {1:d}", \
0053 type, wanted_type); \
0054 abort(); \
0055 }
0056
0057 #define OBJECT_2TYPES_CHECK(wanted_type1, wanted_type2) \
0058 if (unlikely(type != wanted_type1) && unlikely(type != wanted_type2)) { \
0059 error(errInternal, 0, \
0060 "Call to Object where the object was type {0:d}, " \
0061 "not the expected type {1:d} or {2:d}", \
0062 type, wanted_type1, wanted_type2); \
0063 abort(); \
0064 }
0065
0066 #define OBJECT_3TYPES_CHECK(wanted_type1, wanted_type2, wanted_type3) \
0067 if (unlikely(type != wanted_type1) && unlikely(type != wanted_type2) && unlikely(type != wanted_type3)) { \
0068 error(errInternal, 0, \
0069 "Call to Object where the object was type {0:d}, " \
0070 "not the expected type {1:d}, {2:d} or {3:d}", \
0071 type, wanted_type1, wanted_type2, wanted_type3); \
0072 abort(); \
0073 }
0074
0075 #define CHECK_NOT_DEAD \
0076 if (unlikely(type == objDead)) { \
0077 error(errInternal, 0, "Call to dead object"); \
0078 abort(); \
0079 }
0080
0081 class XRef;
0082 class Array;
0083 class Dict;
0084 class Stream;
0085
0086
0087
0088
0089
0090 struct Ref
0091 {
0092 int num;
0093 int gen;
0094
0095 static constexpr Ref INVALID() { return { -1, -1 }; };
0096 };
0097
0098 inline bool operator==(const Ref lhs, const Ref rhs) noexcept
0099 {
0100 return lhs.num == rhs.num && lhs.gen == rhs.gen;
0101 }
0102
0103 inline bool operator!=(const Ref lhs, const Ref rhs) noexcept
0104 {
0105 return lhs.num != rhs.num || lhs.gen != rhs.gen;
0106 }
0107
0108 inline bool operator<(const Ref lhs, const Ref rhs) noexcept
0109 {
0110 if (lhs.num != rhs.num) {
0111 return lhs.num < rhs.num;
0112 }
0113 return lhs.gen < rhs.gen;
0114 }
0115
0116 namespace std {
0117
0118 template<>
0119 struct hash<Ref>
0120 {
0121 using argument_type = Ref;
0122 using result_type = size_t;
0123
0124 result_type operator()(const argument_type ref) const noexcept { return std::hash<int> {}(ref.num) ^ (std::hash<int> {}(ref.gen) << 1); }
0125 };
0126
0127 }
0128
0129
0130
0131
0132
0133 enum ObjType
0134 {
0135
0136 objBool,
0137 objInt,
0138 objReal,
0139 objString,
0140 objName,
0141 objNull,
0142
0143
0144 objArray,
0145 objDict,
0146 objStream,
0147 objRef,
0148
0149
0150 objCmd,
0151 objError,
0152 objEOF,
0153 objNone,
0154
0155
0156 objInt64,
0157 objHexString,
0158 objDead
0159 };
0160
0161 constexpr int numObjTypes = 17;
0162
0163
0164
0165
0166
0167 class POPPLER_PRIVATE_EXPORT Object
0168 {
0169 public:
0170 Object() : type(objNone) { }
0171 ~Object() { free(); }
0172
0173 explicit Object(bool boolnA)
0174 {
0175 type = objBool;
0176 booln = boolnA;
0177 }
0178 explicit Object(int intgA)
0179 {
0180 type = objInt;
0181 intg = intgA;
0182 }
0183 explicit Object(ObjType typeA) { type = typeA; }
0184 explicit Object(double realA)
0185 {
0186 type = objReal;
0187 real = realA;
0188 }
0189 explicit Object(GooString *stringA)
0190 {
0191 assert(stringA);
0192 type = objString;
0193 string = stringA;
0194 }
0195 Object(ObjType typeA, GooString *stringA)
0196 {
0197 assert(typeA == objHexString);
0198 assert(stringA);
0199 type = typeA;
0200 string = stringA;
0201 }
0202 Object(ObjType typeA, const char *stringA)
0203 {
0204 assert(typeA == objName || typeA == objCmd);
0205 assert(stringA);
0206 type = typeA;
0207 cString = copyString(stringA);
0208 }
0209 explicit Object(long long int64gA)
0210 {
0211 type = objInt64;
0212 int64g = int64gA;
0213 }
0214 explicit Object(Array *arrayA)
0215 {
0216 assert(arrayA);
0217 type = objArray;
0218 array = arrayA;
0219 }
0220 explicit Object(Dict *dictA)
0221 {
0222 assert(dictA);
0223 type = objDict;
0224 dict = dictA;
0225 }
0226 explicit Object(Stream *streamA)
0227 {
0228 assert(streamA);
0229 type = objStream;
0230 stream = streamA;
0231 }
0232 explicit Object(const Ref r)
0233 {
0234 type = objRef;
0235 ref = r;
0236 }
0237
0238 template<typename T>
0239 Object(T) = delete;
0240
0241 Object(Object &&other) noexcept
0242 {
0243 std::memcpy(reinterpret_cast<void *>(this), &other, sizeof(Object));
0244 other.type = objDead;
0245 }
0246
0247 Object &operator=(Object &&other) noexcept
0248 {
0249 free();
0250
0251 std::memcpy(reinterpret_cast<void *>(this), &other, sizeof(Object));
0252 other.type = objDead;
0253
0254 return *this;
0255 }
0256
0257 Object &operator=(const Object &other) = delete;
0258 Object(const Object &other) = delete;
0259
0260
0261 void setToNull()
0262 {
0263 free();
0264 type = objNull;
0265 }
0266
0267
0268
0269 Object copy() const;
0270
0271
0272
0273 Object deepCopy() const;
0274
0275
0276
0277 Object fetch(XRef *xref, int recursion = 0) const;
0278
0279
0280 ObjType getType() const
0281 {
0282 CHECK_NOT_DEAD;
0283 return type;
0284 }
0285 bool isBool() const
0286 {
0287 CHECK_NOT_DEAD;
0288 return type == objBool;
0289 }
0290 bool isInt() const
0291 {
0292 CHECK_NOT_DEAD;
0293 return type == objInt;
0294 }
0295 bool isReal() const
0296 {
0297 CHECK_NOT_DEAD;
0298 return type == objReal;
0299 }
0300 bool isNum() const
0301 {
0302 CHECK_NOT_DEAD;
0303 return type == objInt || type == objReal || type == objInt64;
0304 }
0305 bool isString() const
0306 {
0307 CHECK_NOT_DEAD;
0308 return type == objString;
0309 }
0310 bool isHexString() const
0311 {
0312 CHECK_NOT_DEAD;
0313 return type == objHexString;
0314 }
0315 bool isName() const
0316 {
0317 CHECK_NOT_DEAD;
0318 return type == objName;
0319 }
0320 bool isNull() const
0321 {
0322 CHECK_NOT_DEAD;
0323 return type == objNull;
0324 }
0325 bool isArray() const
0326 {
0327 CHECK_NOT_DEAD;
0328 return type == objArray;
0329 }
0330 bool isDict() const
0331 {
0332 CHECK_NOT_DEAD;
0333 return type == objDict;
0334 }
0335 bool isStream() const
0336 {
0337 CHECK_NOT_DEAD;
0338 return type == objStream;
0339 }
0340 bool isRef() const
0341 {
0342 CHECK_NOT_DEAD;
0343 return type == objRef;
0344 }
0345 bool isCmd() const
0346 {
0347 CHECK_NOT_DEAD;
0348 return type == objCmd;
0349 }
0350 bool isError() const
0351 {
0352 CHECK_NOT_DEAD;
0353 return type == objError;
0354 }
0355 bool isEOF() const
0356 {
0357 CHECK_NOT_DEAD;
0358 return type == objEOF;
0359 }
0360 bool isNone() const
0361 {
0362 CHECK_NOT_DEAD;
0363 return type == objNone;
0364 }
0365 bool isInt64() const
0366 {
0367 CHECK_NOT_DEAD;
0368 return type == objInt64;
0369 }
0370 bool isIntOrInt64() const
0371 {
0372 CHECK_NOT_DEAD;
0373 return type == objInt || type == objInt64;
0374 }
0375
0376
0377 bool isName(const char *nameA) const { return type == objName && !strcmp(cString, nameA); }
0378 bool isDict(const char *dictType) const;
0379 bool isCmd(const char *cmdA) const { return type == objCmd && !strcmp(cString, cmdA); }
0380
0381
0382 bool getBool() const
0383 {
0384 OBJECT_TYPE_CHECK(objBool);
0385 return booln;
0386 }
0387 int getInt() const
0388 {
0389 OBJECT_TYPE_CHECK(objInt);
0390 return intg;
0391 }
0392 double getReal() const
0393 {
0394 OBJECT_TYPE_CHECK(objReal);
0395 return real;
0396 }
0397
0398
0399
0400 double getNum() const
0401 {
0402 OBJECT_3TYPES_CHECK(objInt, objInt64, objReal);
0403 return type == objInt ? (double)intg : type == objInt64 ? (double)int64g : real;
0404 }
0405 double getNum(bool *ok) const
0406 {
0407 if (unlikely(type != objInt && type != objInt64 && type != objReal)) {
0408 *ok = false;
0409 return 0.;
0410 }
0411 return type == objInt ? (double)intg : type == objInt64 ? (double)int64g : real;
0412 }
0413 const GooString *getString() const
0414 {
0415 OBJECT_TYPE_CHECK(objString);
0416 return string;
0417 }
0418 const GooString *getHexString() const
0419 {
0420 OBJECT_TYPE_CHECK(objHexString);
0421 return string;
0422 }
0423 const char *getName() const
0424 {
0425 OBJECT_TYPE_CHECK(objName);
0426 return cString;
0427 }
0428 Array *getArray() const
0429 {
0430 OBJECT_TYPE_CHECK(objArray);
0431 return array;
0432 }
0433 Dict *getDict() const
0434 {
0435 OBJECT_TYPE_CHECK(objDict);
0436 return dict;
0437 }
0438 Stream *getStream() const
0439 {
0440 OBJECT_TYPE_CHECK(objStream);
0441 return stream;
0442 }
0443 Ref getRef() const
0444 {
0445 OBJECT_TYPE_CHECK(objRef);
0446 return ref;
0447 }
0448 int getRefNum() const
0449 {
0450 OBJECT_TYPE_CHECK(objRef);
0451 return ref.num;
0452 }
0453 int getRefGen() const
0454 {
0455 OBJECT_TYPE_CHECK(objRef);
0456 return ref.gen;
0457 }
0458 const char *getCmd() const
0459 {
0460 OBJECT_TYPE_CHECK(objCmd);
0461 return cString;
0462 }
0463 long long getInt64() const
0464 {
0465 OBJECT_TYPE_CHECK(objInt64);
0466 return int64g;
0467 }
0468 long long getIntOrInt64() const
0469 {
0470 OBJECT_2TYPES_CHECK(objInt, objInt64);
0471 return type == objInt ? intg : int64g;
0472 }
0473
0474
0475 int arrayGetLength() const;
0476 void arrayAdd(Object &&elem);
0477 void arrayRemove(int i);
0478 Object arrayGet(int i, int recursion) const;
0479 const Object &arrayGetNF(int i) const;
0480
0481
0482 int dictGetLength() const;
0483 void dictAdd(char *key, Object &&val) = delete;
0484 void dictAdd(const char *key, Object &&val);
0485 void dictSet(const char *key, Object &&val);
0486 void dictRemove(const char *key);
0487 bool dictIs(const char *dictType) const;
0488 Object dictLookup(const char *key, int recursion = 0) const;
0489 const Object &dictLookupNF(const char *key) const;
0490 const char *dictGetKey(int i) const;
0491 Object dictGetVal(int i) const;
0492 const Object &dictGetValNF(int i) const;
0493
0494
0495 void streamReset();
0496 void streamClose();
0497 int streamGetChar();
0498 int streamGetChars(int nChars, unsigned char *buffer);
0499 void streamSetPos(Goffset pos, int dir = 0);
0500 Dict *streamGetDict() const;
0501
0502
0503 const char *getTypeName() const;
0504 void print(FILE *f = stdout) const;
0505
0506 double getNumWithDefaultValue(double defaultValue) const
0507 {
0508 if (unlikely(type != objInt && type != objInt64 && type != objReal)) {
0509 return defaultValue;
0510 }
0511 return type == objInt ? (double)intg : type == objInt64 ? (double)int64g : real;
0512 }
0513
0514 bool getBoolWithDefaultValue(bool defaultValue) const { return (type == objBool) ? booln : defaultValue; }
0515
0516 private:
0517
0518 void free();
0519
0520 ObjType type;
0521 union {
0522 bool booln;
0523 int intg;
0524 long long int64g;
0525 double real;
0526 GooString *string;
0527 char *cString;
0528 Array *array;
0529 Dict *dict;
0530 Stream *stream;
0531 Ref ref;
0532 };
0533 };
0534
0535
0536
0537
0538
0539 #include "Array.h"
0540
0541 inline int Object::arrayGetLength() const
0542 {
0543 OBJECT_TYPE_CHECK(objArray);
0544 return array->getLength();
0545 }
0546
0547 inline void Object::arrayAdd(Object &&elem)
0548 {
0549 OBJECT_TYPE_CHECK(objArray);
0550 array->add(std::move(elem));
0551 }
0552
0553 inline void Object::arrayRemove(int i)
0554 {
0555 OBJECT_TYPE_CHECK(objArray);
0556 array->remove(i);
0557 }
0558
0559 inline Object Object::arrayGet(int i, int recursion = 0) const
0560 {
0561 OBJECT_TYPE_CHECK(objArray);
0562 return array->get(i, recursion);
0563 }
0564
0565 inline const Object &Object::arrayGetNF(int i) const
0566 {
0567 OBJECT_TYPE_CHECK(objArray);
0568 return array->getNF(i);
0569 }
0570
0571
0572
0573
0574
0575 #include "Dict.h"
0576
0577 inline int Object::dictGetLength() const
0578 {
0579 OBJECT_TYPE_CHECK(objDict);
0580 return dict->getLength();
0581 }
0582
0583 inline void Object::dictAdd(const char *key, Object &&val)
0584 {
0585 OBJECT_TYPE_CHECK(objDict);
0586 dict->add(key, std::move(val));
0587 }
0588
0589 inline void Object::dictSet(const char *key, Object &&val)
0590 {
0591 OBJECT_TYPE_CHECK(objDict);
0592 dict->set(key, std::move(val));
0593 }
0594
0595 inline void Object::dictRemove(const char *key)
0596 {
0597 OBJECT_TYPE_CHECK(objDict);
0598 dict->remove(key);
0599 }
0600
0601 inline bool Object::dictIs(const char *dictType) const
0602 {
0603 OBJECT_TYPE_CHECK(objDict);
0604 return dict->is(dictType);
0605 }
0606
0607 inline bool Object::isDict(const char *dictType) const
0608 {
0609 return type == objDict && dictIs(dictType);
0610 }
0611
0612 inline Object Object::dictLookup(const char *key, int recursion) const
0613 {
0614 OBJECT_TYPE_CHECK(objDict);
0615 return dict->lookup(key, recursion);
0616 }
0617
0618 inline const Object &Object::dictLookupNF(const char *key) const
0619 {
0620 OBJECT_TYPE_CHECK(objDict);
0621 return dict->lookupNF(key);
0622 }
0623
0624 inline const char *Object::dictGetKey(int i) const
0625 {
0626 OBJECT_TYPE_CHECK(objDict);
0627 return dict->getKey(i);
0628 }
0629
0630 inline Object Object::dictGetVal(int i) const
0631 {
0632 OBJECT_TYPE_CHECK(objDict);
0633 return dict->getVal(i);
0634 }
0635
0636 inline const Object &Object::dictGetValNF(int i) const
0637 {
0638 OBJECT_TYPE_CHECK(objDict);
0639 return dict->getValNF(i);
0640 }
0641
0642
0643
0644
0645
0646 #include "Stream.h"
0647
0648 inline void Object::streamReset()
0649 {
0650 OBJECT_TYPE_CHECK(objStream);
0651 stream->reset();
0652 }
0653
0654 inline void Object::streamClose()
0655 {
0656 OBJECT_TYPE_CHECK(objStream);
0657 stream->close();
0658 }
0659
0660 inline int Object::streamGetChar()
0661 {
0662 OBJECT_TYPE_CHECK(objStream);
0663 return stream->getChar();
0664 }
0665
0666 inline int Object::streamGetChars(int nChars, unsigned char *buffer)
0667 {
0668 OBJECT_TYPE_CHECK(objStream);
0669 return stream->doGetChars(nChars, buffer);
0670 }
0671
0672 inline Dict *Object::streamGetDict() const
0673 {
0674 OBJECT_TYPE_CHECK(objStream);
0675 return stream->getDict();
0676 }
0677
0678 #endif