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