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 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 Adrian Johnson <ajohnson@redneon.com>
23 // Copyright (C) 2013 Adrian Perez de Castro <aperez@igalia.com>
24 //
25 // To see a description of the changes please see the Changelog file that
26 // came with your tarball or type make ChangeLog if you are building from git
27 //
28 //========================================================================
29
30 #ifndef OBJECT_H
31 #define OBJECT_H
32
33 #ifdef USE_GCC_PRAGMAS
34 #pragma interface
35 #endif
36
37 #include <set>
38 #include <stdio.h>
39 #include <string.h>
40 #include "goo/gtypes.h"
41 #include "goo/gmem.h"
42 #include "goo/GooString.h"
43 #include "goo/GooLikely.h"
44 #include "Error.h"
45
46 #define OBJECT_TYPE_CHECK(wanted_type) \
47 if (unlikely(type != wanted_type)) { \
48 error(errInternal, 0, "Call to Object where the object was type {0:d}, " \
49 "not the expected type {1:d}", type, wanted_type); \
50 abort(); \
51 }
52
53 #define OBJECT_2TYPES_CHECK(wanted_type1, wanted_type2) \
54 if (unlikely(type != wanted_type1) && unlikely(type != wanted_type2)) { \
55 error(errInternal, 0, "Call to Object where the object was type {0:d}, " \
56 "not the expected type {1:d} or {2:d}", type, wanted_type1, wanted_type2); \
57 abort(); \
58 }
59
60 #define OBJECT_3TYPES_CHECK(wanted_type1, wanted_type2, wanted_type3) \
61 if (unlikely(type != wanted_type1) && unlikely(type != wanted_type2) && unlikely(type != wanted_type3)) { \
62 error(errInternal, 0, "Call to Object where the object was type {0:d}, " \
63 "not the expected type {1:d}, {2:d} or {3:d}", type, wanted_type1, wanted_type2, wanted_type3); \
64 abort(); \
65 }
66
67 class XRef;
68 class Array;
69 class Dict;
70 class Stream;
71
72 //------------------------------------------------------------------------
73 // Ref
74 //------------------------------------------------------------------------
75
76 struct Ref {
77 int num; // object number
78 int gen; // generation number
79 };
80
81 //------------------------------------------------------------------------
82 // object types
83 //------------------------------------------------------------------------
84
85 enum ObjType {
86 // simple objects
87 objBool, // boolean
88 objInt, // integer
89 objReal, // real
90 objString, // string
91 objName, // name
92 objNull, // null
93
94 // complex objects
95 objArray, // array
96 objDict, // dictionary
97 objStream, // stream
98 objRef, // indirect reference
99
100 // special objects
101 objCmd, // command name
102 objError, // error return from Lexer
103 objEOF, // end of file return from Lexer
104 objNone, // uninitialized object
105
106 // poppler-only objects
107 objInt64 // integer with at least 64-bits
108 };
109
110 #define numObjTypes 15 // total number of object types
111
112 //------------------------------------------------------------------------
113 // Object
114 //------------------------------------------------------------------------
115
116 #ifdef DEBUG_MEM
117 #define initObj(t) zeroUnion(); ++numAlloc[type = t]
118 #else
119 #define initObj(t) zeroUnion(); type = t
120 #endif
121
122 class Object {
123 public:
124 // clear the anonymous union as best we can -- clear at least a pointer
zeroUnion()125 void zeroUnion() { this->name = NULL; }
126
127 // Default constructor.
Object()128 Object():
129 type(objNone) { zeroUnion(); }
130
131 // Initialize an object.
initBool(GBool boolnA)132 Object *initBool(GBool boolnA)
133 { initObj(objBool); booln = boolnA; return this; }
initInt(int intgA)134 Object *initInt(int intgA)
135 { initObj(objInt); intg = intgA; return this; }
initReal(double realA)136 Object *initReal(double realA)
137 { initObj(objReal); real = realA; return this; }
initString(GooString * stringA)138 Object *initString(GooString *stringA)
139 { initObj(objString); string = stringA; return this; }
initName(const char * nameA)140 Object *initName(const char *nameA)
141 { initObj(objName); name = copyString(nameA); return this; }
initNull()142 Object *initNull()
143 { initObj(objNull); return this; }
144 Object *initArray(XRef *xref);
145 Object *initDict(XRef *xref);
146 Object *initDict(Dict *dictA);
147 Object *initStream(Stream *streamA);
initRef(int numA,int genA)148 Object *initRef(int numA, int genA)
149 { initObj(objRef); ref.num = numA; ref.gen = genA; return this; }
initCmd(char * cmdA)150 Object *initCmd(char *cmdA)
151 { initObj(objCmd); cmd = copyString(cmdA); return this; }
initError()152 Object *initError()
153 { initObj(objError); return this; }
initEOF()154 Object *initEOF()
155 { initObj(objEOF); return this; }
initInt64(long long int64gA)156 Object *initInt64(long long int64gA)
157 { initObj(objInt64); int64g = int64gA; return this; }
158
159 // Copy an object.
160 Object *copy(Object *obj);
shallowCopy(Object * obj)161 Object *shallowCopy(Object *obj) {
162 *obj = *this;
163 return obj;
164 }
165
166 // If object is a Ref, fetch and return the referenced object.
167 // Otherwise, return a copy of the object.
168 Object *fetch(XRef *xref, Object *obj, int recursion = 0);
169
170 // Free object contents.
171 void free();
172
173 // Type checking.
getType()174 ObjType getType() { return type; }
isBool()175 GBool isBool() { return type == objBool; }
isInt()176 GBool isInt() { return type == objInt; }
isReal()177 GBool isReal() { return type == objReal; }
isNum()178 GBool isNum() { return type == objInt || type == objReal || type == objInt64; }
isString()179 GBool isString() { return type == objString; }
isName()180 GBool isName() { return type == objName; }
isNull()181 GBool isNull() { return type == objNull; }
isArray()182 GBool isArray() { return type == objArray; }
isDict()183 GBool isDict() { return type == objDict; }
isStream()184 GBool isStream() { return type == objStream; }
isRef()185 GBool isRef() { return type == objRef; }
isCmd()186 GBool isCmd() { return type == objCmd; }
isError()187 GBool isError() { return type == objError; }
isEOF()188 GBool isEOF() { return type == objEOF; }
isNone()189 GBool isNone() { return type == objNone; }
isInt64()190 GBool isInt64() { return type == objInt64; }
isIntOrInt64()191 GBool isIntOrInt64() { return type == objInt || type == objInt64; }
192
193 // Special type checking.
isName(const char * nameA)194 GBool isName(const char *nameA)
195 { return type == objName && !strcmp(name, nameA); }
196 GBool isDict(const char *dictType);
197 GBool isStream(char *dictType);
isCmd(const char * cmdA)198 GBool isCmd(const char *cmdA)
199 { return type == objCmd && !strcmp(cmd, cmdA); }
200
201 // Accessors.
getBool()202 GBool getBool() { OBJECT_TYPE_CHECK(objBool); return booln; }
getInt()203 int getInt() { OBJECT_TYPE_CHECK(objInt); return intg; }
getReal()204 double getReal() { OBJECT_TYPE_CHECK(objReal); return real; }
205
206 // Note: integers larger than 2^53 can not be exactly represented by a double.
207 // Where the exact value of integers up to 2^63 is required, use isInt64()/getInt64().
getNum()208 double getNum() { OBJECT_3TYPES_CHECK(objInt, objInt64, objReal);
209 return type == objInt ? (double)intg : type == objInt64 ? (double)int64g : real; }
getString()210 GooString *getString() { OBJECT_TYPE_CHECK(objString); return string; }
211 // After takeString() the only method that should be called for the object is free()
212 // because the object it's not expected to have a NULL string.
takeString()213 GooString *takeString() {
214 OBJECT_TYPE_CHECK(objString); GooString *s = string; string = NULL; return s; }
getName()215 char *getName() { OBJECT_TYPE_CHECK(objName); return name; }
getArray()216 Array *getArray() { OBJECT_TYPE_CHECK(objArray); return array; }
getDict()217 Dict *getDict() { OBJECT_TYPE_CHECK(objDict); return dict; }
getStream()218 Stream *getStream() { OBJECT_TYPE_CHECK(objStream); return stream; }
getRef()219 Ref getRef() { OBJECT_TYPE_CHECK(objRef); return ref; }
getRefNum()220 int getRefNum() { OBJECT_TYPE_CHECK(objRef); return ref.num; }
getRefGen()221 int getRefGen() { OBJECT_TYPE_CHECK(objRef); return ref.gen; }
getCmd()222 char *getCmd() { OBJECT_TYPE_CHECK(objCmd); return cmd; }
getInt64()223 long long getInt64() { OBJECT_TYPE_CHECK(objInt64); return int64g; }
getIntOrInt64()224 long long getIntOrInt64() { OBJECT_2TYPES_CHECK(objInt, objInt64);
225 return type == objInt ? intg : int64g; }
226
227 // Array accessors.
228 int arrayGetLength();
229 void arrayAdd(Object *elem);
230 void arrayRemove(int i);
231 Object *arrayGet(int i, Object *obj, int recursion);
232 Object *arrayGetNF(int i, Object *obj);
233
234 // Dict accessors.
235 int dictGetLength();
236 void dictAdd(char *key, Object *val);
237 void dictSet(const char *key, Object *val);
238 GBool dictIs(const char *dictType);
239 Object *dictLookup(const char *key, Object *obj, int recursion = 0);
240 Object *dictLookupNF(const char *key, Object *obj);
241 char *dictGetKey(int i);
242 Object *dictGetVal(int i, Object *obj);
243 Object *dictGetValNF(int i, Object *obj);
244
245 // Stream accessors.
246 GBool streamIs(char *dictType);
247 void streamReset();
248 void streamClose();
249 int streamGetChar();
250 int streamGetChars(int nChars, Guchar *buffer);
251 int streamLookChar();
252 char *streamGetLine(char *buf, int size);
253 Goffset streamGetPos();
254 void streamSetPos(Goffset pos, int dir = 0);
255 Dict *streamGetDict();
256
257 // Output.
258 const char *getTypeName();
259 void print(FILE *f = stdout);
260
261 // Memory testing.
262 static void memCheck(FILE *f);
263
264 private:
265
266 ObjType type; // object type
267 union { // value for each type:
268 GBool booln; // boolean
269 int intg; // integer
270 long long int64g; // 64-bit integer
271 double real; // real
272 GooString *string; // string
273 char *name; // name
274 Array *array; // array
275 Dict *dict; // dictionary
276 Stream *stream; // stream
277 Ref ref; // indirect reference
278 char *cmd; // command
279 };
280
281 #ifdef DEBUG_MEM
282 static int // number of each type of object
283 numAlloc[numObjTypes]; // currently allocated
284 #endif
285 };
286
287 //------------------------------------------------------------------------
288 // Array accessors.
289 //------------------------------------------------------------------------
290
291 #include "Array.h"
292
arrayGetLength()293 inline int Object::arrayGetLength()
294 { OBJECT_TYPE_CHECK(objArray); return array->getLength(); }
295
arrayAdd(Object * elem)296 inline void Object::arrayAdd(Object *elem)
297 { OBJECT_TYPE_CHECK(objArray); array->add(elem); }
298
arrayRemove(int i)299 inline void Object::arrayRemove(int i)
300 { OBJECT_TYPE_CHECK(objArray); array->remove(i); }
301
302 inline Object *Object::arrayGet(int i, Object *obj, int recursion = 0)
303 { OBJECT_TYPE_CHECK(objArray); return array->get(i, obj, recursion); }
304
arrayGetNF(int i,Object * obj)305 inline Object *Object::arrayGetNF(int i, Object *obj)
306 { OBJECT_TYPE_CHECK(objArray); return array->getNF(i, obj); }
307
308 //------------------------------------------------------------------------
309 // Dict accessors.
310 //------------------------------------------------------------------------
311
312 #include "Dict.h"
313
dictGetLength()314 inline int Object::dictGetLength()
315 { OBJECT_TYPE_CHECK(objDict); return dict->getLength(); }
316
dictAdd(char * key,Object * val)317 inline void Object::dictAdd(char *key, Object *val)
318 { OBJECT_TYPE_CHECK(objDict); dict->add(key, val); }
319
dictSet(const char * key,Object * val)320 inline void Object::dictSet(const char *key, Object *val)
321 { OBJECT_TYPE_CHECK(objDict); dict->set(key, val); }
322
dictIs(const char * dictType)323 inline GBool Object::dictIs(const char *dictType)
324 { OBJECT_TYPE_CHECK(objDict); return dict->is(dictType); }
325
isDict(const char * dictType)326 inline GBool Object::isDict(const char *dictType)
327 { return type == objDict && dictIs(dictType); }
328
dictLookup(const char * key,Object * obj,int recursion)329 inline Object *Object::dictLookup(const char *key, Object *obj, int recursion)
330 { OBJECT_TYPE_CHECK(objDict); return dict->lookup(key, obj, recursion); }
331
dictLookupNF(const char * key,Object * obj)332 inline Object *Object::dictLookupNF(const char *key, Object *obj)
333 { OBJECT_TYPE_CHECK(objDict); return dict->lookupNF(key, obj); }
334
dictGetKey(int i)335 inline char *Object::dictGetKey(int i)
336 { OBJECT_TYPE_CHECK(objDict); return dict->getKey(i); }
337
dictGetVal(int i,Object * obj)338 inline Object *Object::dictGetVal(int i, Object *obj)
339 { OBJECT_TYPE_CHECK(objDict); return dict->getVal(i, obj); }
340
dictGetValNF(int i,Object * obj)341 inline Object *Object::dictGetValNF(int i, Object *obj)
342 { OBJECT_TYPE_CHECK(objDict); return dict->getValNF(i, obj); }
343
344 //------------------------------------------------------------------------
345 // Stream accessors.
346 //------------------------------------------------------------------------
347
348 #include "Stream.h"
349
streamIs(char * dictType)350 inline GBool Object::streamIs(char *dictType)
351 { OBJECT_TYPE_CHECK(objStream); return stream->getDict()->is(dictType); }
352
isStream(char * dictType)353 inline GBool Object::isStream(char *dictType)
354 { return type == objStream && streamIs(dictType); }
355
streamReset()356 inline void Object::streamReset()
357 { OBJECT_TYPE_CHECK(objStream); stream->reset(); }
358
streamClose()359 inline void Object::streamClose()
360 { OBJECT_TYPE_CHECK(objStream); stream->close(); }
361
streamGetChar()362 inline int Object::streamGetChar()
363 { OBJECT_TYPE_CHECK(objStream); return stream->getChar(); }
364
streamGetChars(int nChars,Guchar * buffer)365 inline int Object::streamGetChars(int nChars, Guchar *buffer)
366 { OBJECT_TYPE_CHECK(objStream); return stream->doGetChars(nChars, buffer); }
367
streamLookChar()368 inline int Object::streamLookChar()
369 { OBJECT_TYPE_CHECK(objStream); return stream->lookChar(); }
370
streamGetLine(char * buf,int size)371 inline char *Object::streamGetLine(char *buf, int size)
372 { OBJECT_TYPE_CHECK(objStream); return stream->getLine(buf, size); }
373
streamGetPos()374 inline Goffset Object::streamGetPos()
375 { OBJECT_TYPE_CHECK(objStream); return stream->getPos(); }
376
streamSetPos(Goffset pos,int dir)377 inline void Object::streamSetPos(Goffset pos, int dir)
378 { OBJECT_TYPE_CHECK(objStream); stream->setPos(pos, dir); }
379
streamGetDict()380 inline Dict *Object::streamGetDict()
381 { OBJECT_TYPE_CHECK(objStream); return stream->getDict(); }
382
383 #endif
384