blob: 15bea159857b7557b2416b15a6ba2a6985793ce2 [file] [log] [blame]
//========================================================================
//
// Object.h
//
// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
//========================================================================
//
// Modified under the Poppler project - http://poppler.freedesktop.org
//
// All changes made under the Poppler project to this file are licensed
// under GPL version 2 or later
//
// Copyright (C) 2007 Julien Rebetez <julienr@svn.gnome.org>
// Copyright (C) 2008 Kees Cook <kees@outflux.net>
// Copyright (C) 2008, 2010 Albert Astals Cid <aacid@kde.org>
// Copyright (C) 2009 Jakub Wilk <ubanus@users.sf.net>
// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
// Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
// Copyright (C) 2013 Adrian Perez de Castro <aperez@igalia.com>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
//
//========================================================================
#ifndef OBJECT_H
#define OBJECT_H
#ifdef USE_GCC_PRAGMAS
#pragma interface
#endif
#include <set>
#include <stdio.h>
#include <string.h>
#include "goo/gtypes.h"
#include "goo/gmem.h"
#include "goo/GooString.h"
#include "goo/GooLikely.h"
#include "Error.h"
#define OBJECT_TYPE_CHECK(wanted_type) \
if (unlikely(type != wanted_type)) { \
error(errInternal, 0, "Call to Object where the object was type {0:d}, " \
"not the expected type {1:d}", type, wanted_type); \
abort(); \
}
#define OBJECT_3TYPES_CHECK(wanted_type1, wanted_type2, wanted_type3) \
if (unlikely(type != wanted_type1) && unlikely(type != wanted_type2) && unlikely(type != wanted_type3)) { \
error(errInternal, 0, "Call to Object where the object was type {0:d}, " \
"not the expected type {1:d}, {2:d} or {3:d}", type, wanted_type1, wanted_type2, wanted_type3); \
abort(); \
}
class XRef;
class Array;
class Dict;
class Stream;
//------------------------------------------------------------------------
// Ref
//------------------------------------------------------------------------
struct Ref {
int num; // object number
int gen; // generation number
};
//------------------------------------------------------------------------
// object types
//------------------------------------------------------------------------
enum ObjType {
// simple objects
objBool, // boolean
objInt, // integer
objReal, // real
objString, // string
objName, // name
objNull, // null
// complex objects
objArray, // array
objDict, // dictionary
objStream, // stream
objRef, // indirect reference
// special objects
objCmd, // command name
objError, // error return from Lexer
objEOF, // end of file return from Lexer
objNone, // uninitialized object
// poppler-only objects
objInt64 // integer with at least 64-bits
};
#define numObjTypes 15 // total number of object types
//------------------------------------------------------------------------
// Object
//------------------------------------------------------------------------
#ifdef DEBUG_MEM
#define initObj(t) zeroUnion(); ++numAlloc[type = t]
#else
#define initObj(t) zeroUnion(); type = t
#endif
class Object {
public:
// clear the anonymous union as best we can -- clear at least a pointer
void zeroUnion() { this->name = NULL; }
// Default constructor.
Object():
type(objNone) { zeroUnion(); }
// Initialize an object.
Object *initBool(GBool boolnA)
{ initObj(objBool); booln = boolnA; return this; }
Object *initInt(int intgA)
{ initObj(objInt); intg = intgA; return this; }
Object *initReal(double realA)
{ initObj(objReal); real = realA; return this; }
Object *initString(GooString *stringA)
{ initObj(objString); string = stringA; return this; }
Object *initName(const char *nameA)
{ initObj(objName); name = copyString(nameA); return this; }
Object *initNull()
{ initObj(objNull); return this; }
Object *initArray(XRef *xref);
Object *initDict(XRef *xref);
Object *initDict(Dict *dictA);
Object *initStream(Stream *streamA);
Object *initRef(int numA, int genA)
{ initObj(objRef); ref.num = numA; ref.gen = genA; return this; }
Object *initCmd(char *cmdA)
{ initObj(objCmd); cmd = copyString(cmdA); return this; }
Object *initError()
{ initObj(objError); return this; }
Object *initEOF()
{ initObj(objEOF); return this; }
Object *initInt64(long long int64gA)
{ initObj(objInt64); int64g = int64gA; return this; }
// Copy an object.
Object *copy(Object *obj);
Object *shallowCopy(Object *obj) {
*obj = *this;
return obj;
}
// If object is a Ref, fetch and return the referenced object.
// Otherwise, return a copy of the object.
Object *fetch(XRef *xref, Object *obj, int recursion = 0);
// Free object contents.
void free();
// Type checking.
ObjType getType() { return type; }
GBool isBool() { return type == objBool; }
GBool isInt() { return type == objInt; }
GBool isReal() { return type == objReal; }
GBool isNum() { return type == objInt || type == objReal || type == objInt64; }
GBool isString() { return type == objString; }
GBool isName() { return type == objName; }
GBool isNull() { return type == objNull; }
GBool isArray() { return type == objArray; }
GBool isDict() { return type == objDict; }
GBool isStream() { return type == objStream; }
GBool isRef() { return type == objRef; }
GBool isCmd() { return type == objCmd; }
GBool isError() { return type == objError; }
GBool isEOF() { return type == objEOF; }
GBool isNone() { return type == objNone; }
GBool isInt64() { return type == objInt64; }
// Special type checking.
GBool isName(const char *nameA)
{ return type == objName && !strcmp(name, nameA); }
GBool isDict(const char *dictType);
GBool isStream(char *dictType);
GBool isCmd(const char *cmdA)
{ return type == objCmd && !strcmp(cmd, cmdA); }
// Accessors.
GBool getBool() { OBJECT_TYPE_CHECK(objBool); return booln; }
int getInt() { OBJECT_TYPE_CHECK(objInt); return intg; }
double getReal() { OBJECT_TYPE_CHECK(objReal); return real; }
// Note: integers larger than 2^53 can not be exactly represented by a double.
// Where the exact value of integers up to 2^63 is required, use isInt64()/getInt64().
double getNum() { OBJECT_3TYPES_CHECK(objInt, objInt64, objReal);
return type == objInt ? (double)intg : type == objInt64 ? (double)int64g : real; }
GooString *getString() { OBJECT_TYPE_CHECK(objString); return string; }
// After takeString() the only method that should be called for the object is free()
// because the object it's not expected to have a NULL string.
GooString *takeString() {
OBJECT_TYPE_CHECK(objString); GooString *s = string; string = NULL; return s; }
char *getName() { OBJECT_TYPE_CHECK(objName); return name; }
Array *getArray() { OBJECT_TYPE_CHECK(objArray); return array; }
Dict *getDict() { OBJECT_TYPE_CHECK(objDict); return dict; }
Stream *getStream() { OBJECT_TYPE_CHECK(objStream); return stream; }
Ref getRef() { OBJECT_TYPE_CHECK(objRef); return ref; }
int getRefNum() { OBJECT_TYPE_CHECK(objRef); return ref.num; }
int getRefGen() { OBJECT_TYPE_CHECK(objRef); return ref.gen; }
char *getCmd() { OBJECT_TYPE_CHECK(objCmd); return cmd; }
long long getInt64() { OBJECT_TYPE_CHECK(objInt64); return int64g; }
// Array accessors.
int arrayGetLength();
void arrayAdd(Object *elem);
void arrayRemove(int i);
Object *arrayGet(int i, Object *obj, int recursion);
Object *arrayGetNF(int i, Object *obj);
// Dict accessors.
int dictGetLength();
void dictAdd(char *key, Object *val);
void dictSet(const char *key, Object *val);
GBool dictIs(const char *dictType);
Object *dictLookup(const char *key, Object *obj, int recursion = 0);
Object *dictLookupNF(const char *key, Object *obj);
char *dictGetKey(int i);
Object *dictGetVal(int i, Object *obj);
Object *dictGetValNF(int i, Object *obj);
// Stream accessors.
GBool streamIs(char *dictType);
void streamReset();
void streamClose();
int streamGetChar();
int streamGetChars(int nChars, Guchar *buffer);
int streamLookChar();
char *streamGetLine(char *buf, int size);
Goffset streamGetPos();
void streamSetPos(Goffset pos, int dir = 0);
Dict *streamGetDict();
// Output.
const char *getTypeName();
void print(FILE *f = stdout);
// Memory testing.
static void memCheck(FILE *f);
private:
ObjType type; // object type
union { // value for each type:
GBool booln; // boolean
int intg; // integer
long long int64g; // 64-bit integer
double real; // real
GooString *string; // string
char *name; // name
Array *array; // array
Dict *dict; // dictionary
Stream *stream; // stream
Ref ref; // indirect reference
char *cmd; // command
};
#ifdef DEBUG_MEM
static int // number of each type of object
numAlloc[numObjTypes]; // currently allocated
#endif
};
//------------------------------------------------------------------------
// Array accessors.
//------------------------------------------------------------------------
#include "Array.h"
inline int Object::arrayGetLength()
{ OBJECT_TYPE_CHECK(objArray); return array->getLength(); }
inline void Object::arrayAdd(Object *elem)
{ OBJECT_TYPE_CHECK(objArray); array->add(elem); }
inline void Object::arrayRemove(int i)
{ OBJECT_TYPE_CHECK(objArray); array->remove(i); }
inline Object *Object::arrayGet(int i, Object *obj, int recursion = 0)
{ OBJECT_TYPE_CHECK(objArray); return array->get(i, obj, recursion); }
inline Object *Object::arrayGetNF(int i, Object *obj)
{ OBJECT_TYPE_CHECK(objArray); return array->getNF(i, obj); }
//------------------------------------------------------------------------
// Dict accessors.
//------------------------------------------------------------------------
#include "Dict.h"
inline int Object::dictGetLength()
{ OBJECT_TYPE_CHECK(objDict); return dict->getLength(); }
inline void Object::dictAdd(char *key, Object *val)
{ OBJECT_TYPE_CHECK(objDict); dict->add(key, val); }
inline void Object::dictSet(const char *key, Object *val)
{ OBJECT_TYPE_CHECK(objDict); dict->set(key, val); }
inline GBool Object::dictIs(const char *dictType)
{ OBJECT_TYPE_CHECK(objDict); return dict->is(dictType); }
inline GBool Object::isDict(const char *dictType)
{ return type == objDict && dictIs(dictType); }
inline Object *Object::dictLookup(const char *key, Object *obj, int recursion)
{ OBJECT_TYPE_CHECK(objDict); return dict->lookup(key, obj, recursion); }
inline Object *Object::dictLookupNF(const char *key, Object *obj)
{ OBJECT_TYPE_CHECK(objDict); return dict->lookupNF(key, obj); }
inline char *Object::dictGetKey(int i)
{ OBJECT_TYPE_CHECK(objDict); return dict->getKey(i); }
inline Object *Object::dictGetVal(int i, Object *obj)
{ OBJECT_TYPE_CHECK(objDict); return dict->getVal(i, obj); }
inline Object *Object::dictGetValNF(int i, Object *obj)
{ OBJECT_TYPE_CHECK(objDict); return dict->getValNF(i, obj); }
//------------------------------------------------------------------------
// Stream accessors.
//------------------------------------------------------------------------
#include "Stream.h"
inline GBool Object::streamIs(char *dictType)
{ OBJECT_TYPE_CHECK(objStream); return stream->getDict()->is(dictType); }
inline GBool Object::isStream(char *dictType)
{ return type == objStream && streamIs(dictType); }
inline void Object::streamReset()
{ OBJECT_TYPE_CHECK(objStream); stream->reset(); }
inline void Object::streamClose()
{ OBJECT_TYPE_CHECK(objStream); stream->close(); }
inline int Object::streamGetChar()
{ OBJECT_TYPE_CHECK(objStream); return stream->getChar(); }
inline int Object::streamGetChars(int nChars, Guchar *buffer)
{ OBJECT_TYPE_CHECK(objStream); return stream->doGetChars(nChars, buffer); }
inline int Object::streamLookChar()
{ OBJECT_TYPE_CHECK(objStream); return stream->lookChar(); }
inline char *Object::streamGetLine(char *buf, int size)
{ OBJECT_TYPE_CHECK(objStream); return stream->getLine(buf, size); }
inline Goffset Object::streamGetPos()
{ OBJECT_TYPE_CHECK(objStream); return stream->getPos(); }
inline void Object::streamSetPos(Goffset pos, int dir)
{ OBJECT_TYPE_CHECK(objStream); stream->setPos(pos, dir); }
inline Dict *Object::streamGetDict()
{ OBJECT_TYPE_CHECK(objStream); return stream->getDict(); }
#endif