mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2025-04-10 19:15:13 +00:00
679 lines
21 KiB
Plaintext
679 lines
21 KiB
Plaintext
//========================================================================
|
|
//
|
|
// 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, 2017-2021 Albert Astals Cid <aacid@kde.org>
|
|
// Copyright (C) 2009 Jakub Wilk <jwilk@jwilk.net>
|
|
// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
|
|
// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
|
|
// Copyright (C) 2013, 2017, 2018 Adrian Johnson <ajohnson@redneon.com>
|
|
// Copyright (C) 2013 Adrian Perez de Castro <aperez@igalia.com>
|
|
// Copyright (C) 2016, 2020 Jakub Alba <jakubalba@gmail.com>
|
|
// 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
|
|
// Copyright (C) 2018 Adam Reichold <adam.reichold@t-online.de>
|
|
// Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, <info@kdab.com>. Work sponsored by Technische Universität Dresden
|
|
//
|
|
// 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
|
|
|
|
#include <cassert>
|
|
#include <set>
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
#include <climits>
|
|
#include "goo/gmem.h"
|
|
#include "goo/GooString.h"
|
|
#include "goo/GooLikely.h"
|
|
#include "Error.h"
|
|
#include "poppler_private_export.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_2TYPES_CHECK(wanted_type1, wanted_type2) \
|
|
if (unlikely(type != wanted_type1) && unlikely(type != wanted_type2)) { \
|
|
error(errInternal, 0, \
|
|
"Call to Object where the object was type {0:d}, " \
|
|
"not the expected type {1:d} or {2:d}", \
|
|
type, wanted_type1, wanted_type2); \
|
|
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(); \
|
|
}
|
|
|
|
#define CHECK_NOT_DEAD \
|
|
if (unlikely(type == objDead)) { \
|
|
error(errInternal, 0, "Call to dead object"); \
|
|
abort(); \
|
|
}
|
|
|
|
class XRef;
|
|
class Array;
|
|
class Dict;
|
|
class Stream;
|
|
|
|
//------------------------------------------------------------------------
|
|
// Ref
|
|
//------------------------------------------------------------------------
|
|
|
|
struct Ref
|
|
{
|
|
int num; // object number
|
|
int gen; // generation number
|
|
|
|
static constexpr Ref INVALID() { return { -1, -1 }; };
|
|
};
|
|
|
|
inline bool operator==(const Ref lhs, const Ref rhs) noexcept
|
|
{
|
|
return lhs.num == rhs.num && lhs.gen == rhs.gen;
|
|
}
|
|
|
|
inline bool operator!=(const Ref lhs, const Ref rhs) noexcept
|
|
{
|
|
return lhs.num != rhs.num || lhs.gen != rhs.gen;
|
|
}
|
|
|
|
inline bool operator<(const Ref lhs, const Ref rhs) noexcept
|
|
{
|
|
if (lhs.num != rhs.num) {
|
|
return lhs.num < rhs.num;
|
|
}
|
|
return lhs.gen < rhs.gen;
|
|
}
|
|
|
|
namespace std {
|
|
|
|
template<>
|
|
struct hash<Ref>
|
|
{
|
|
using argument_type = Ref;
|
|
using result_type = size_t;
|
|
|
|
result_type operator()(const argument_type ref) const noexcept { return std::hash<int> {}(ref.num) ^ (std::hash<int> {}(ref.gen) << 1); }
|
|
};
|
|
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// 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
|
|
objHexString, // hex string
|
|
objDead // and object after shallowCopy
|
|
};
|
|
|
|
constexpr int numObjTypes = 17; // total number of object types
|
|
|
|
//------------------------------------------------------------------------
|
|
// Object
|
|
//------------------------------------------------------------------------
|
|
|
|
class POPPLER_PRIVATE_EXPORT Object
|
|
{
|
|
public:
|
|
Object() : type(objNone) { }
|
|
~Object() { free(); }
|
|
|
|
explicit Object(bool boolnA)
|
|
{
|
|
type = objBool;
|
|
booln = boolnA;
|
|
}
|
|
explicit Object(int intgA)
|
|
{
|
|
type = objInt;
|
|
intg = intgA;
|
|
}
|
|
explicit Object(ObjType typeA) { type = typeA; }
|
|
explicit Object(double realA)
|
|
{
|
|
type = objReal;
|
|
real = realA;
|
|
}
|
|
explicit Object(GooString *stringA)
|
|
{
|
|
assert(stringA);
|
|
type = objString;
|
|
string = stringA;
|
|
}
|
|
Object(ObjType typeA, GooString *stringA)
|
|
{
|
|
assert(typeA == objHexString);
|
|
assert(stringA);
|
|
type = typeA;
|
|
string = stringA;
|
|
}
|
|
Object(ObjType typeA, const char *stringA)
|
|
{
|
|
assert(typeA == objName || typeA == objCmd);
|
|
assert(stringA);
|
|
type = typeA;
|
|
cString = copyString(stringA);
|
|
}
|
|
explicit Object(long long int64gA)
|
|
{
|
|
type = objInt64;
|
|
int64g = int64gA;
|
|
}
|
|
explicit Object(Array *arrayA)
|
|
{
|
|
assert(arrayA);
|
|
type = objArray;
|
|
array = arrayA;
|
|
}
|
|
explicit Object(Dict *dictA)
|
|
{
|
|
assert(dictA);
|
|
type = objDict;
|
|
dict = dictA;
|
|
}
|
|
explicit Object(Stream *streamA)
|
|
{
|
|
assert(streamA);
|
|
type = objStream;
|
|
stream = streamA;
|
|
}
|
|
explicit Object(const Ref r)
|
|
{
|
|
type = objRef;
|
|
ref = r;
|
|
}
|
|
|
|
template<typename T>
|
|
Object(T) = delete;
|
|
|
|
Object(Object &&other) noexcept
|
|
{
|
|
std::memcpy(reinterpret_cast<void *>(this), &other, sizeof(Object));
|
|
other.type = objDead;
|
|
}
|
|
|
|
Object &operator=(Object &&other) noexcept
|
|
{
|
|
free();
|
|
|
|
std::memcpy(reinterpret_cast<void *>(this), &other, sizeof(Object));
|
|
other.type = objDead;
|
|
|
|
return *this;
|
|
}
|
|
|
|
Object &operator=(const Object &other) = delete;
|
|
Object(const Object &other) = delete;
|
|
|
|
// Set object to null.
|
|
void setToNull()
|
|
{
|
|
free();
|
|
type = objNull;
|
|
}
|
|
|
|
// Copies all object types except
|
|
// objArray, objDict, objStream whose refcount is increased by 1
|
|
Object copy() const;
|
|
|
|
// Deep copies all object types (recursively)
|
|
// except objStream whose refcount is increased by 1
|
|
Object deepCopy() const;
|
|
|
|
// If object is a Ref, fetch and return the referenced object.
|
|
// Otherwise, return a copy of the object.
|
|
Object fetch(XRef *xref, int recursion = 0) const;
|
|
|
|
// Type checking.
|
|
ObjType getType() const
|
|
{
|
|
CHECK_NOT_DEAD;
|
|
return type;
|
|
}
|
|
bool isBool() const
|
|
{
|
|
CHECK_NOT_DEAD;
|
|
return type == objBool;
|
|
}
|
|
bool isInt() const
|
|
{
|
|
CHECK_NOT_DEAD;
|
|
return type == objInt;
|
|
}
|
|
bool isReal() const
|
|
{
|
|
CHECK_NOT_DEAD;
|
|
return type == objReal;
|
|
}
|
|
bool isNum() const
|
|
{
|
|
CHECK_NOT_DEAD;
|
|
return type == objInt || type == objReal || type == objInt64;
|
|
}
|
|
bool isString() const
|
|
{
|
|
CHECK_NOT_DEAD;
|
|
return type == objString;
|
|
}
|
|
bool isHexString() const
|
|
{
|
|
CHECK_NOT_DEAD;
|
|
return type == objHexString;
|
|
}
|
|
bool isName() const
|
|
{
|
|
CHECK_NOT_DEAD;
|
|
return type == objName;
|
|
}
|
|
bool isNull() const
|
|
{
|
|
CHECK_NOT_DEAD;
|
|
return type == objNull;
|
|
}
|
|
bool isArray() const
|
|
{
|
|
CHECK_NOT_DEAD;
|
|
return type == objArray;
|
|
}
|
|
bool isDict() const
|
|
{
|
|
CHECK_NOT_DEAD;
|
|
return type == objDict;
|
|
}
|
|
bool isStream() const
|
|
{
|
|
CHECK_NOT_DEAD;
|
|
return type == objStream;
|
|
}
|
|
bool isRef() const
|
|
{
|
|
CHECK_NOT_DEAD;
|
|
return type == objRef;
|
|
}
|
|
bool isCmd() const
|
|
{
|
|
CHECK_NOT_DEAD;
|
|
return type == objCmd;
|
|
}
|
|
bool isError() const
|
|
{
|
|
CHECK_NOT_DEAD;
|
|
return type == objError;
|
|
}
|
|
bool isEOF() const
|
|
{
|
|
CHECK_NOT_DEAD;
|
|
return type == objEOF;
|
|
}
|
|
bool isNone() const
|
|
{
|
|
CHECK_NOT_DEAD;
|
|
return type == objNone;
|
|
}
|
|
bool isInt64() const
|
|
{
|
|
CHECK_NOT_DEAD;
|
|
return type == objInt64;
|
|
}
|
|
bool isIntOrInt64() const
|
|
{
|
|
CHECK_NOT_DEAD;
|
|
return type == objInt || type == objInt64;
|
|
}
|
|
|
|
// Special type checking.
|
|
bool isName(const char *nameA) const { return type == objName && !strcmp(cString, nameA); }
|
|
bool isDict(const char *dictType) const;
|
|
bool isCmd(const char *cmdA) const { return type == objCmd && !strcmp(cString, cmdA); }
|
|
|
|
// Accessors.
|
|
bool getBool() const
|
|
{
|
|
OBJECT_TYPE_CHECK(objBool);
|
|
return booln;
|
|
}
|
|
int getInt() const
|
|
{
|
|
OBJECT_TYPE_CHECK(objInt);
|
|
return intg;
|
|
}
|
|
double getReal() const
|
|
{
|
|
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() const
|
|
{
|
|
OBJECT_3TYPES_CHECK(objInt, objInt64, objReal);
|
|
return type == objInt ? (double)intg : type == objInt64 ? (double)int64g : real;
|
|
}
|
|
double getNum(bool *ok) const
|
|
{
|
|
if (unlikely(type != objInt && type != objInt64 && type != objReal)) {
|
|
*ok = false;
|
|
return 0.;
|
|
}
|
|
return type == objInt ? (double)intg : type == objInt64 ? (double)int64g : real;
|
|
}
|
|
const GooString *getString() const
|
|
{
|
|
OBJECT_TYPE_CHECK(objString);
|
|
return string;
|
|
}
|
|
const GooString *getHexString() const
|
|
{
|
|
OBJECT_TYPE_CHECK(objHexString);
|
|
return string;
|
|
}
|
|
const char *getName() const
|
|
{
|
|
OBJECT_TYPE_CHECK(objName);
|
|
return cString;
|
|
}
|
|
Array *getArray() const
|
|
{
|
|
OBJECT_TYPE_CHECK(objArray);
|
|
return array;
|
|
}
|
|
Dict *getDict() const
|
|
{
|
|
OBJECT_TYPE_CHECK(objDict);
|
|
return dict;
|
|
}
|
|
Stream *getStream() const
|
|
{
|
|
OBJECT_TYPE_CHECK(objStream);
|
|
return stream;
|
|
}
|
|
Ref getRef() const
|
|
{
|
|
OBJECT_TYPE_CHECK(objRef);
|
|
return ref;
|
|
}
|
|
int getRefNum() const
|
|
{
|
|
OBJECT_TYPE_CHECK(objRef);
|
|
return ref.num;
|
|
}
|
|
int getRefGen() const
|
|
{
|
|
OBJECT_TYPE_CHECK(objRef);
|
|
return ref.gen;
|
|
}
|
|
const char *getCmd() const
|
|
{
|
|
OBJECT_TYPE_CHECK(objCmd);
|
|
return cString;
|
|
}
|
|
long long getInt64() const
|
|
{
|
|
OBJECT_TYPE_CHECK(objInt64);
|
|
return int64g;
|
|
}
|
|
long long getIntOrInt64() const
|
|
{
|
|
OBJECT_2TYPES_CHECK(objInt, objInt64);
|
|
return type == objInt ? intg : int64g;
|
|
}
|
|
|
|
// Array accessors.
|
|
int arrayGetLength() const;
|
|
void arrayAdd(Object &&elem);
|
|
void arrayRemove(int i);
|
|
Object arrayGet(int i, int recursion) const;
|
|
const Object &arrayGetNF(int i) const;
|
|
|
|
// Dict accessors.
|
|
int dictGetLength() const;
|
|
void dictAdd(char *key, Object &&val) = delete;
|
|
void dictAdd(const char *key, Object &&val);
|
|
void dictSet(const char *key, Object &&val);
|
|
void dictRemove(const char *key);
|
|
bool dictIs(const char *dictType) const;
|
|
Object dictLookup(const char *key, int recursion = 0) const;
|
|
const Object &dictLookupNF(const char *key) const;
|
|
const char *dictGetKey(int i) const;
|
|
Object dictGetVal(int i) const;
|
|
const Object &dictGetValNF(int i) const;
|
|
|
|
// Stream accessors.
|
|
void streamReset();
|
|
void streamClose();
|
|
int streamGetChar();
|
|
int streamGetChars(int nChars, unsigned char *buffer);
|
|
void streamSetPos(Goffset pos, int dir = 0);
|
|
Dict *streamGetDict() const;
|
|
|
|
// Output.
|
|
const char *getTypeName() const;
|
|
void print(FILE *f = stdout) const;
|
|
|
|
double getNumWithDefaultValue(double defaultValue) const
|
|
{
|
|
if (unlikely(type != objInt && type != objInt64 && type != objReal)) {
|
|
return defaultValue;
|
|
}
|
|
return type == objInt ? (double)intg : type == objInt64 ? (double)int64g : real;
|
|
}
|
|
|
|
bool getBoolWithDefaultValue(bool defaultValue) const { return (type == objBool) ? booln : defaultValue; }
|
|
|
|
private:
|
|
// Free object contents.
|
|
void free();
|
|
|
|
ObjType type; // object type
|
|
union { // value for each type:
|
|
bool booln; // boolean
|
|
int intg; // integer
|
|
long long int64g; // 64-bit integer
|
|
double real; // real
|
|
GooString *string; // [hex] string
|
|
char *cString; // name or command, depending on objType
|
|
Array *array; // array
|
|
Dict *dict; // dictionary
|
|
Stream *stream; // stream
|
|
Ref ref; // indirect reference
|
|
};
|
|
};
|
|
|
|
//------------------------------------------------------------------------
|
|
// Array accessors.
|
|
//------------------------------------------------------------------------
|
|
|
|
#include "Array.h"
|
|
|
|
inline int Object::arrayGetLength() const
|
|
{
|
|
OBJECT_TYPE_CHECK(objArray);
|
|
return array->getLength();
|
|
}
|
|
|
|
inline void Object::arrayAdd(Object &&elem)
|
|
{
|
|
OBJECT_TYPE_CHECK(objArray);
|
|
array->add(std::move(elem));
|
|
}
|
|
|
|
inline void Object::arrayRemove(int i)
|
|
{
|
|
OBJECT_TYPE_CHECK(objArray);
|
|
array->remove(i);
|
|
}
|
|
|
|
inline Object Object::arrayGet(int i, int recursion = 0) const
|
|
{
|
|
OBJECT_TYPE_CHECK(objArray);
|
|
return array->get(i, recursion);
|
|
}
|
|
|
|
inline const Object &Object::arrayGetNF(int i) const
|
|
{
|
|
OBJECT_TYPE_CHECK(objArray);
|
|
return array->getNF(i);
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// Dict accessors.
|
|
//------------------------------------------------------------------------
|
|
|
|
#include "Dict.h"
|
|
|
|
inline int Object::dictGetLength() const
|
|
{
|
|
OBJECT_TYPE_CHECK(objDict);
|
|
return dict->getLength();
|
|
}
|
|
|
|
inline void Object::dictAdd(const char *key, Object &&val)
|
|
{
|
|
OBJECT_TYPE_CHECK(objDict);
|
|
dict->add(key, std::move(val));
|
|
}
|
|
|
|
inline void Object::dictSet(const char *key, Object &&val)
|
|
{
|
|
OBJECT_TYPE_CHECK(objDict);
|
|
dict->set(key, std::move(val));
|
|
}
|
|
|
|
inline void Object::dictRemove(const char *key)
|
|
{
|
|
OBJECT_TYPE_CHECK(objDict);
|
|
dict->remove(key);
|
|
}
|
|
|
|
inline bool Object::dictIs(const char *dictType) const
|
|
{
|
|
OBJECT_TYPE_CHECK(objDict);
|
|
return dict->is(dictType);
|
|
}
|
|
|
|
inline bool Object::isDict(const char *dictType) const
|
|
{
|
|
return type == objDict && dictIs(dictType);
|
|
}
|
|
|
|
inline Object Object::dictLookup(const char *key, int recursion) const
|
|
{
|
|
OBJECT_TYPE_CHECK(objDict);
|
|
return dict->lookup(key, recursion);
|
|
}
|
|
|
|
inline const Object &Object::dictLookupNF(const char *key) const
|
|
{
|
|
OBJECT_TYPE_CHECK(objDict);
|
|
return dict->lookupNF(key);
|
|
}
|
|
|
|
inline const char *Object::dictGetKey(int i) const
|
|
{
|
|
OBJECT_TYPE_CHECK(objDict);
|
|
return dict->getKey(i);
|
|
}
|
|
|
|
inline Object Object::dictGetVal(int i) const
|
|
{
|
|
OBJECT_TYPE_CHECK(objDict);
|
|
return dict->getVal(i);
|
|
}
|
|
|
|
inline const Object &Object::dictGetValNF(int i) const
|
|
{
|
|
OBJECT_TYPE_CHECK(objDict);
|
|
return dict->getValNF(i);
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// Stream accessors.
|
|
//------------------------------------------------------------------------
|
|
|
|
#include "Stream.h"
|
|
|
|
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, unsigned char *buffer)
|
|
{
|
|
OBJECT_TYPE_CHECK(objStream);
|
|
return stream->doGetChars(nChars, buffer);
|
|
}
|
|
|
|
inline Dict *Object::streamGetDict() const
|
|
{
|
|
OBJECT_TYPE_CHECK(objStream);
|
|
return stream->getDict();
|
|
}
|
|
|
|
#endif
|