aboutsummaryrefslogtreecommitdiffstats
path: root/libqpdf/QPDFObjectHandle.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libqpdf/QPDFObjectHandle.cc')
-rw-r--r--libqpdf/QPDFObjectHandle.cc1084
1 files changed, 265 insertions, 819 deletions
diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc
index 135b7c39..19a85034 100644
--- a/libqpdf/QPDFObjectHandle.cc
+++ b/libqpdf/QPDFObjectHandle.cc
@@ -8,6 +8,7 @@
#include <qpdf/QPDFLogger.hh>
#include <qpdf/QPDFMatrix.hh>
#include <qpdf/QPDFPageObjectHelper.hh>
+#include <qpdf/QPDFParser.hh>
#include <qpdf/QPDF_Array.hh>
#include <qpdf/QPDF_Bool.hh>
#include <qpdf/QPDF_Dictionary.hh>
@@ -20,6 +21,7 @@
#include <qpdf/QPDF_Reserved.hh>
#include <qpdf/QPDF_Stream.hh>
#include <qpdf/QPDF_String.hh>
+#include <qpdf/QPDF_Unresolved.hh>
#include <qpdf/SparseOHArray.hh>
#include <qpdf/QIntC.hh>
@@ -233,29 +235,6 @@ LastChar::getLastChar()
return this->last_char;
}
-QPDFObjectHandle::QPDFObjectHandle() :
- initialized(false),
- qpdf(nullptr),
- reserved(false)
-{
-}
-
-QPDFObjectHandle::QPDFObjectHandle(QPDF* qpdf, QPDFObjGen const& og) :
- initialized(true),
- qpdf(qpdf),
- og(og),
- reserved(false)
-{
-}
-
-QPDFObjectHandle::QPDFObjectHandle(std::shared_ptr<QPDFObject> const& data) :
- initialized(true),
- qpdf(nullptr),
- obj(data),
- reserved(false)
-{
-}
-
void
QPDFObjectHandle::releaseResolved()
{
@@ -272,26 +251,6 @@ QPDFObjectHandle::releaseResolved()
}
}
-void
-QPDFObjectHandle::setObjectDescriptionFromInput(
- QPDFObjectHandle object,
- QPDF* context,
- std::string const& description,
- std::shared_ptr<InputSource> input,
- qpdf_offset_t offset)
-{
- object.setObjectDescription(
- context,
- (input->getName() + ", " + description + " at offset " +
- QUtil::int_to_string(offset)));
-}
-
-bool
-QPDFObjectHandle::isInitialized() const
-{
- return this->initialized;
-}
-
QPDFObject::object_type_e
QPDFObjectHandle::getTypeCode()
{
@@ -305,24 +264,90 @@ QPDFObjectHandle::getTypeName()
return dereference() ? this->obj->getTypeName() : "uninitialized";
}
-namespace
+QPDF_Array*
+QPDFObjectHandle::asArray()
{
- template <class T>
- class QPDFObjectTypeAccessor
- {
- public:
- static bool
- check(std::shared_ptr<QPDFObject> const& o)
- {
- return (o && dynamic_cast<T const*>(o.get()));
- }
- };
-} // namespace
+ return dereference() ? obj->as<QPDF_Array>() : nullptr;
+}
+
+QPDF_Bool*
+QPDFObjectHandle::asBool()
+{
+ return dereference() ? obj->as<QPDF_Bool>() : nullptr;
+}
+
+QPDF_Dictionary*
+QPDFObjectHandle::asDictionary()
+{
+ return dereference() ? obj->as<QPDF_Dictionary>() : nullptr;
+}
+
+QPDF_InlineImage*
+QPDFObjectHandle::asInlineImage()
+{
+ return dereference() ? obj->as<QPDF_InlineImage>() : nullptr;
+}
+
+QPDF_Integer*
+QPDFObjectHandle::asInteger()
+{
+ return dereference() ? obj->as<QPDF_Integer>() : nullptr;
+}
+
+QPDF_Name*
+QPDFObjectHandle::asName()
+{
+ return dereference() ? obj->as<QPDF_Name>() : nullptr;
+}
+
+QPDF_Null*
+QPDFObjectHandle::asNull()
+{
+ return dereference() ? obj->as<QPDF_Null>() : nullptr;
+}
+
+QPDF_Operator*
+QPDFObjectHandle::asOperator()
+{
+ return dereference() ? obj->as<QPDF_Operator>() : nullptr;
+}
+
+QPDF_Real*
+QPDFObjectHandle::asReal()
+{
+ return dereference() ? obj->as<QPDF_Real>() : nullptr;
+}
+
+QPDF_Reserved*
+QPDFObjectHandle::asReserved()
+{
+ return dereference() ? obj->as<QPDF_Reserved>() : nullptr;
+}
+
+QPDF_Stream*
+QPDFObjectHandle::asStream()
+{
+ return dereference() ? obj->as<QPDF_Stream>() : nullptr;
+}
+
+QPDF_Stream*
+QPDFObjectHandle::asStreamWithAssert()
+{
+ auto stream = asStream();
+ assertType("stream", stream);
+ return stream;
+}
+
+QPDF_String*
+QPDFObjectHandle::asString()
+{
+ return dereference() ? obj->as<QPDF_String>() : nullptr;
+}
bool
QPDFObjectHandle::isBool()
{
- return dereference() && QPDFObjectTypeAccessor<QPDF_Bool>::check(obj);
+ return dereference() && (obj->getTypeCode() == QPDFObject::ot_boolean);
}
bool
@@ -331,26 +356,26 @@ QPDFObjectHandle::isDirectNull() const
// Don't call dereference() -- this is a const method, and we know
// objid == 0, so there's nothing to resolve.
return (
- this->initialized && (getObjectID() == 0) &&
- QPDFObjectTypeAccessor<QPDF_Null>::check(obj));
+ isInitialized() && (getObjectID() == 0) &&
+ (obj->getTypeCode() == QPDFObject::ot_null));
}
bool
QPDFObjectHandle::isNull()
{
- return dereference() && QPDFObjectTypeAccessor<QPDF_Null>::check(obj);
+ return dereference() && (obj->getTypeCode() == QPDFObject::ot_null);
}
bool
QPDFObjectHandle::isInteger()
{
- return dereference() && QPDFObjectTypeAccessor<QPDF_Integer>::check(obj);
+ return dereference() && (obj->getTypeCode() == QPDFObject::ot_integer);
}
bool
QPDFObjectHandle::isReal()
{
- return dereference() && QPDFObjectTypeAccessor<QPDF_Real>::check(obj);
+ return dereference() && (obj->getTypeCode() == QPDFObject::ot_real);
}
bool
@@ -387,57 +412,49 @@ QPDFObjectHandle::getValueAsNumber(double& value)
bool
QPDFObjectHandle::isName()
{
- return dereference() && QPDFObjectTypeAccessor<QPDF_Name>::check(obj);
+ return dereference() && (obj->getTypeCode() == QPDFObject::ot_name);
}
bool
QPDFObjectHandle::isString()
{
- return dereference() && QPDFObjectTypeAccessor<QPDF_String>::check(obj);
+ return dereference() && (obj->getTypeCode() == QPDFObject::ot_string);
}
bool
QPDFObjectHandle::isOperator()
{
- return dereference() && QPDFObjectTypeAccessor<QPDF_Operator>::check(obj);
+ return dereference() && (obj->getTypeCode() == QPDFObject::ot_operator);
}
bool
QPDFObjectHandle::isInlineImage()
{
- return dereference() &&
- QPDFObjectTypeAccessor<QPDF_InlineImage>::check(obj);
+ return dereference() && (obj->getTypeCode() == QPDFObject::ot_inlineimage);
}
bool
QPDFObjectHandle::isArray()
{
- return dereference() && QPDFObjectTypeAccessor<QPDF_Array>::check(obj);
+ return dereference() && (obj->getTypeCode() == QPDFObject::ot_array);
}
bool
QPDFObjectHandle::isDictionary()
{
- return dereference() && QPDFObjectTypeAccessor<QPDF_Dictionary>::check(obj);
+ return dereference() && (obj->getTypeCode() == QPDFObject::ot_dictionary);
}
bool
QPDFObjectHandle::isStream()
{
- return dereference() && QPDFObjectTypeAccessor<QPDF_Stream>::check(obj);
+ return dereference() && (obj->getTypeCode() == QPDFObject::ot_stream);
}
bool
QPDFObjectHandle::isReserved()
{
- // dereference will clear reserved if this has been replaced
- return dereference() && this->reserved;
-}
-
-bool
-QPDFObjectHandle::isIndirect()
-{
- return this->initialized && (getObjectID() != 0);
+ return dereference() && (obj->getTypeCode() == QPDFObject::ot_reserved);
}
bool
@@ -475,8 +492,9 @@ QPDFObjectHandle::isStreamOfType(
bool
QPDFObjectHandle::getBoolValue()
{
- if (isBool()) {
- return dynamic_cast<QPDF_Bool*>(obj.get())->getVal();
+ auto boolean = asBool();
+ if (boolean) {
+ return boolean->getVal();
} else {
typeWarning("boolean", "returning false");
QTC::TC("qpdf", "QPDFObjectHandle boolean returning false");
@@ -487,10 +505,11 @@ QPDFObjectHandle::getBoolValue()
bool
QPDFObjectHandle::getValueAsBool(bool& value)
{
- if (!isBool()) {
+ auto boolean = asBool();
+ if (boolean == nullptr) {
return false;
}
- value = dynamic_cast<QPDF_Bool*>(obj.get())->getVal();
+ value = boolean->getVal();
return true;
}
@@ -499,8 +518,9 @@ QPDFObjectHandle::getValueAsBool(bool& value)
long long
QPDFObjectHandle::getIntValue()
{
- if (isInteger()) {
- return dynamic_cast<QPDF_Integer*>(obj.get())->getVal();
+ auto integer = asInteger();
+ if (integer) {
+ return integer->getVal();
} else {
typeWarning("integer", "returning 0");
QTC::TC("qpdf", "QPDFObjectHandle integer returning 0");
@@ -511,10 +531,11 @@ QPDFObjectHandle::getIntValue()
bool
QPDFObjectHandle::getValueAsInt(long long& value)
{
- if (!isInteger()) {
+ auto integer = asInteger();
+ if (integer == nullptr) {
return false;
}
- value = dynamic_cast<QPDF_Integer*>(obj.get())->getVal();
+ value = integer->getVal();
return true;
}
@@ -610,8 +631,9 @@ QPDFObjectHandle::getValueAsUInt(unsigned int& value)
std::string
QPDFObjectHandle::getRealValue()
{
- if (isReal()) {
- return dynamic_cast<QPDF_Real*>(obj.get())->getVal();
+ auto real = asReal();
+ if (real) {
+ return real->getVal();
} else {
typeWarning("real", "returning 0.0");
QTC::TC("qpdf", "QPDFObjectHandle real returning 0.0");
@@ -622,10 +644,11 @@ QPDFObjectHandle::getRealValue()
bool
QPDFObjectHandle::getValueAsReal(std::string& value)
{
- if (!isReal()) {
+ auto real = asReal();
+ if (real == nullptr) {
return false;
}
- value = dynamic_cast<QPDF_Real*>(obj.get())->getVal();
+ value = real->getVal();
return true;
}
@@ -634,8 +657,9 @@ QPDFObjectHandle::getValueAsReal(std::string& value)
std::string
QPDFObjectHandle::getName()
{
- if (isName()) {
- return dynamic_cast<QPDF_Name*>(obj.get())->getName();
+ auto name = asName();
+ if (name) {
+ return name->getName();
} else {
typeWarning("name", "returning dummy name");
QTC::TC("qpdf", "QPDFObjectHandle name returning dummy name");
@@ -646,10 +670,11 @@ QPDFObjectHandle::getName()
bool
QPDFObjectHandle::getValueAsName(std::string& value)
{
- if (!isName()) {
+ auto name = asName();
+ if (name == nullptr) {
return false;
}
- value = dynamic_cast<QPDF_Name*>(obj.get())->getName();
+ value = name->getName();
return true;
}
@@ -658,8 +683,9 @@ QPDFObjectHandle::getValueAsName(std::string& value)
std::string
QPDFObjectHandle::getStringValue()
{
- if (isString()) {
- return dynamic_cast<QPDF_String*>(obj.get())->getVal();
+ auto str = asString();
+ if (str) {
+ return str->getVal();
} else {
typeWarning("string", "returning empty string");
QTC::TC("qpdf", "QPDFObjectHandle string returning empty string");
@@ -670,18 +696,20 @@ QPDFObjectHandle::getStringValue()
bool
QPDFObjectHandle::getValueAsString(std::string& value)
{
- if (!isString()) {
+ auto str = asString();
+ if (str == nullptr) {
return false;
}
- value = dynamic_cast<QPDF_String*>(obj.get())->getVal();
+ value = str->getVal();
return true;
}
std::string
QPDFObjectHandle::getUTF8Value()
{
- if (isString()) {
- return dynamic_cast<QPDF_String*>(obj.get())->getUTF8Val();
+ auto str = asString();
+ if (str) {
+ return str->getUTF8Val();
} else {
typeWarning("string", "returning empty string");
QTC::TC("qpdf", "QPDFObjectHandle string returning empty utf8");
@@ -692,10 +720,11 @@ QPDFObjectHandle::getUTF8Value()
bool
QPDFObjectHandle::getValueAsUTF8(std::string& value)
{
- if (!isString()) {
+ auto str = asString();
+ if (str == nullptr) {
return false;
}
- value = dynamic_cast<QPDF_String*>(obj.get())->getUTF8Val();
+ value = str->getUTF8Val();
return true;
}
@@ -704,8 +733,9 @@ QPDFObjectHandle::getValueAsUTF8(std::string& value)
std::string
QPDFObjectHandle::getOperatorValue()
{
- if (isOperator()) {
- return dynamic_cast<QPDF_Operator*>(obj.get())->getVal();
+ auto op = asOperator();
+ if (op) {
+ return op->getVal();
} else {
typeWarning("operator", "returning fake value");
QTC::TC("qpdf", "QPDFObjectHandle operator returning fake value");
@@ -716,18 +746,20 @@ QPDFObjectHandle::getOperatorValue()
bool
QPDFObjectHandle::getValueAsOperator(std::string& value)
{
- if (!isOperator()) {
+ auto op = asOperator();
+ if (op == nullptr) {
return false;
}
- value = dynamic_cast<QPDF_Operator*>(obj.get())->getVal();
+ value = op->getVal();
return true;
}
std::string
QPDFObjectHandle::getInlineImageValue()
{
- if (isInlineImage()) {
- return dynamic_cast<QPDF_InlineImage*>(obj.get())->getVal();
+ auto image = asInlineImage();
+ if (image) {
+ return image->getVal();
} else {
typeWarning("inlineimage", "returning empty data");
QTC::TC("qpdf", "QPDFObjectHandle inlineimage returning empty data");
@@ -738,10 +770,11 @@ QPDFObjectHandle::getInlineImageValue()
bool
QPDFObjectHandle::getValueAsInlineImage(std::string& value)
{
- if (!isInlineImage()) {
+ auto image = asInlineImage();
+ if (image == nullptr) {
return false;
}
- value = dynamic_cast<QPDF_InlineImage*>(obj.get())->getVal();
+ value = image->getVal();
return true;
}
@@ -756,8 +789,9 @@ QPDFObjectHandle::aitems()
int
QPDFObjectHandle::getArrayNItems()
{
- if (isArray()) {
- return dynamic_cast<QPDF_Array*>(obj.get())->getNItems();
+ auto array = asArray();
+ if (array) {
+ return array->getNItems();
} else {
typeWarning("array", "treating as empty");
QTC::TC("qpdf", "QPDFObjectHandle array treating as empty");
@@ -769,11 +803,12 @@ QPDFObjectHandle
QPDFObjectHandle::getArrayItem(int n)
{
QPDFObjectHandle result;
- if (isArray() && (n < getArrayNItems()) && (n >= 0)) {
- result = dynamic_cast<QPDF_Array*>(obj.get())->getItem(n);
+ auto array = asArray();
+ if (array && (n < array->getNItems()) && (n >= 0)) {
+ result = array->getItem(n);
} else {
result = newNull();
- if (isArray()) {
+ if (array) {
objectWarning("returning null for out of bounds array access");
QTC::TC("qpdf", "QPDFObjectHandle array bounds");
} else {
@@ -782,7 +817,7 @@ QPDFObjectHandle::getArrayItem(int n)
}
QPDF* context = nullptr;
std::string description;
- if (this->obj->getDescription(context, description)) {
+ if (obj->getDescription(context, description)) {
result.setObjectDescription(
context,
description + " -> null returned from invalid array access");
@@ -794,14 +829,12 @@ QPDFObjectHandle::getArrayItem(int n)
bool
QPDFObjectHandle::isRectangle()
{
- if (!isArray()) {
- return false;
- }
- if (getArrayNItems() != 4) {
+ auto array = asArray();
+ if ((array == nullptr) || (array->getNItems() != 4)) {
return false;
}
for (int i = 0; i < 4; ++i) {
- if (!getArrayItem(i).isNumber()) {
+ if (!array->getItem(i).isNumber()) {
return false;
}
}
@@ -811,14 +844,12 @@ QPDFObjectHandle::isRectangle()
bool
QPDFObjectHandle::isMatrix()
{
- if (!isArray()) {
- return false;
- }
- if (getArrayNItems() != 6) {
+ auto array = asArray();
+ if ((array == nullptr) || (array->getNItems() != 6)) {
return false;
}
for (int i = 0; i < 6; ++i) {
- if (!getArrayItem(i).isNumber()) {
+ if (!array->getItem(i).isNumber()) {
return false;
}
}
@@ -830,13 +861,14 @@ QPDFObjectHandle::getArrayAsRectangle()
{
Rectangle result;
if (isRectangle()) {
+ auto array = asArray();
// Rectangle coordinates are always supposed to be llx, lly,
// urx, ury, but files have been found in the wild where
// llx > urx or lly > ury.
- double i0 = getArrayItem(0).getNumericValue();
- double i1 = getArrayItem(1).getNumericValue();
- double i2 = getArrayItem(2).getNumericValue();
- double i3 = getArrayItem(3).getNumericValue();
+ double i0 = array->getItem(0).getNumericValue();
+ double i1 = array->getItem(1).getNumericValue();
+ double i2 = array->getItem(2).getNumericValue();
+ double i3 = array->getItem(3).getNumericValue();
result = Rectangle(
std::min(i0, i2),
std::min(i1, i3),
@@ -851,13 +883,14 @@ QPDFObjectHandle::getArrayAsMatrix()
{
Matrix result;
if (isMatrix()) {
+ auto array = asArray();
result = Matrix(
- getArrayItem(0).getNumericValue(),
- getArrayItem(1).getNumericValue(),
- getArrayItem(2).getNumericValue(),
- getArrayItem(3).getNumericValue(),
- getArrayItem(4).getNumericValue(),
- getArrayItem(5).getNumericValue());
+ array->getItem(0).getNumericValue(),
+ array->getItem(1).getNumericValue(),
+ array->getItem(2).getNumericValue(),
+ array->getItem(3).getNumericValue(),
+ array->getItem(4).getNumericValue(),
+ array->getItem(5).getNumericValue());
}
return result;
}
@@ -866,8 +899,9 @@ std::vector<QPDFObjectHandle>
QPDFObjectHandle::getArrayAsVector()
{
std::vector<QPDFObjectHandle> result;
- if (isArray()) {
- dynamic_cast<QPDF_Array*>(obj.get())->getAsVector(result);
+ auto array = asArray();
+ if (array) {
+ array->getAsVector(result);
} else {
typeWarning("array", "treating as empty");
QTC::TC("qpdf", "QPDFObjectHandle array treating as empty vector");
@@ -880,9 +914,10 @@ QPDFObjectHandle::getArrayAsVector()
void
QPDFObjectHandle::setArrayItem(int n, QPDFObjectHandle const& item)
{
- if (isArray()) {
+ auto array = asArray();
+ if (array) {
checkOwnership(item);
- dynamic_cast<QPDF_Array*>(obj.get())->setItem(n, item);
+ array->setItem(n, item);
} else {
typeWarning("array", "ignoring attempt to set item");
QTC::TC("qpdf", "QPDFObjectHandle array ignoring set item");
@@ -892,11 +927,12 @@ QPDFObjectHandle::setArrayItem(int n, QPDFObjectHandle const& item)
void
QPDFObjectHandle::setArrayFromVector(std::vector<QPDFObjectHandle> const& items)
{
- if (isArray()) {
+ auto array = asArray();
+ if (array) {
for (auto const& item: items) {
checkOwnership(item);
}
- dynamic_cast<QPDF_Array*>(obj.get())->setFromVector(items);
+ array->setFromVector(items);
} else {
typeWarning("array", "ignoring attempt to replace items");
QTC::TC("qpdf", "QPDFObjectHandle array ignoring replace items");
@@ -906,8 +942,9 @@ QPDFObjectHandle::setArrayFromVector(std::vector<QPDFObjectHandle> const& items)
void
QPDFObjectHandle::insertItem(int at, QPDFObjectHandle const& item)
{
- if (isArray()) {
- dynamic_cast<QPDF_Array*>(obj.get())->insertItem(at, item);
+ auto array = asArray();
+ if (array) {
+ array->insertItem(at, item);
} else {
typeWarning("array", "ignoring attempt to insert item");
QTC::TC("qpdf", "QPDFObjectHandle array ignoring insert item");
@@ -924,9 +961,10 @@ QPDFObjectHandle::insertItemAndGetNew(int at, QPDFObjectHandle const& item)
void
QPDFObjectHandle::appendItem(QPDFObjectHandle const& item)
{
- if (isArray()) {
+ auto array = asArray();
+ if (array) {
checkOwnership(item);
- dynamic_cast<QPDF_Array*>(obj.get())->appendItem(item);
+ array->appendItem(item);
} else {
typeWarning("array", "ignoring attempt to append item");
QTC::TC("qpdf", "QPDFObjectHandle array ignoring append item");
@@ -943,10 +981,11 @@ QPDFObjectHandle::appendItemAndGetNew(QPDFObjectHandle const& item)
void
QPDFObjectHandle::eraseItem(int at)
{
- if (isArray() && (at < getArrayNItems()) && (at >= 0)) {
- dynamic_cast<QPDF_Array*>(obj.get())->eraseItem(at);
+ auto array = asArray();
+ if (array && (at < array->getNItems()) && (at >= 0)) {
+ array->eraseItem(at);
} else {
- if (isArray()) {
+ if (array) {
objectWarning("ignoring attempt to erase out of bounds array item");
QTC::TC("qpdf", "QPDFObjectHandle erase array bounds");
} else {
@@ -960,8 +999,9 @@ QPDFObjectHandle
QPDFObjectHandle::eraseItemAndGetOld(int at)
{
auto result = QPDFObjectHandle::newNull();
- if (isArray() && (at < getArrayNItems()) && (at >= 0)) {
- result = getArrayItem(at);
+ auto array = asArray();
+ if (array && (at < array->getNItems()) && (at >= 0)) {
+ result = array->getItem(at);
}
eraseItem(at);
return result;
@@ -978,8 +1018,9 @@ QPDFObjectHandle::ditems()
bool
QPDFObjectHandle::hasKey(std::string const& key)
{
- if (isDictionary()) {
- return dynamic_cast<QPDF_Dictionary*>(obj.get())->hasKey(key);
+ auto dict = asDictionary();
+ if (dict) {
+ return dict->hasKey(key);
} else {
typeWarning(
"dictionary", "returning false for a key containment request");
@@ -992,15 +1033,16 @@ QPDFObjectHandle
QPDFObjectHandle::getKey(std::string const& key)
{
QPDFObjectHandle result;
- if (isDictionary()) {
- result = dynamic_cast<QPDF_Dictionary*>(obj.get())->getKey(key);
+ auto dict = asDictionary();
+ if (dict) {
+ result = dict->getKey(key);
} else {
typeWarning("dictionary", "returning null for attempted key retrieval");
QTC::TC("qpdf", "QPDFObjectHandle dictionary null for getKey");
result = newNull();
QPDF* qpdf = nullptr;
std::string description;
- if (this->obj->getDescription(qpdf, description)) {
+ if (obj->getDescription(qpdf, description)) {
result.setObjectDescription(
qpdf,
(description + " -> null returned from getting key " + key +
@@ -1020,8 +1062,9 @@ std::set<std::string>
QPDFObjectHandle::getKeys()
{
std::set<std::string> result;
- if (isDictionary()) {
- result = dynamic_cast<QPDF_Dictionary*>(obj.get())->getKeys();
+ auto dict = asDictionary();
+ if (dict) {
+ result = dict->getKeys();
} else {
typeWarning("dictionary", "treating as empty");
QTC::TC("qpdf", "QPDFObjectHandle dictionary empty set for getKeys");
@@ -1033,8 +1076,9 @@ std::map<std::string, QPDFObjectHandle>
QPDFObjectHandle::getDictAsMap()
{
std::map<std::string, QPDFObjectHandle> result;
- if (isDictionary()) {
- result = dynamic_cast<QPDF_Dictionary*>(obj.get())->getAsMap();
+ auto dict = asDictionary();
+ if (dict) {
+ result = dict->getAsMap();
} else {
typeWarning("dictionary", "treating as empty");
QTC::TC("qpdf", "QPDFObjectHandle dictionary empty map for asMap");
@@ -1219,23 +1263,16 @@ QPDFObjectHandle::getUniqueResourceName(
" QPDFObjectHandle::getUniqueResourceName");
}
-// Indirect object accessors
-QPDF*
-QPDFObjectHandle::getOwningQPDF()
-{
- // Will be null for direct objects
- return this->qpdf;
-}
-
// Dictionary mutators
void
QPDFObjectHandle::replaceKey(
std::string const& key, QPDFObjectHandle const& value)
{
- if (isDictionary()) {
+ auto dict = asDictionary();
+ if (dict) {
checkOwnership(value);
- dynamic_cast<QPDF_Dictionary*>(obj.get())->replaceKey(key, value);
+ dict->replaceKey(key, value);
} else {
typeWarning("dictionary", "ignoring key replacement request");
QTC::TC("qpdf", "QPDFObjectHandle dictionary ignoring replaceKey");
@@ -1262,8 +1299,9 @@ QPDFObjectHandle::replaceKeyAndGetOld(
void
QPDFObjectHandle::removeKey(std::string const& key)
{
- if (isDictionary()) {
- dynamic_cast<QPDF_Dictionary*>(obj.get())->removeKey(key);
+ auto dict = asDictionary();
+ if (dict) {
+ dict->removeKey(key);
} else {
typeWarning("dictionary", "ignoring key removal request");
QTC::TC("qpdf", "QPDFObjectHandle dictionary ignoring removeKey");
@@ -1274,8 +1312,9 @@ QPDFObjectHandle
QPDFObjectHandle::removeKeyAndGetOld(std::string const& key)
{
auto result = QPDFObjectHandle::newNull();
- if (isDictionary()) {
- result = getKey(key);
+ auto dict = asDictionary();
+ if (dict) {
+ result = dict->getKey(key);
}
removeKey(key);
return result;
@@ -1292,50 +1331,43 @@ QPDFObjectHandle::replaceOrRemoveKey(
QPDFObjectHandle
QPDFObjectHandle::getDict()
{
- assertStream();
- return dynamic_cast<QPDF_Stream*>(obj.get())->getDict();
+ return asStreamWithAssert()->getDict();
}
void
QPDFObjectHandle::setFilterOnWrite(bool val)
{
- assertStream();
- dynamic_cast<QPDF_Stream*>(obj.get())->setFilterOnWrite(val);
+ asStreamWithAssert()->setFilterOnWrite(val);
}
bool
QPDFObjectHandle::getFilterOnWrite()
{
- assertStream();
- return dynamic_cast<QPDF_Stream*>(obj.get())->getFilterOnWrite();
+ return asStreamWithAssert()->getFilterOnWrite();
}
bool
QPDFObjectHandle::isDataModified()
{
- assertStream();
- return dynamic_cast<QPDF_Stream*>(obj.get())->isDataModified();
+ return asStreamWithAssert()->isDataModified();
}
void
QPDFObjectHandle::replaceDict(QPDFObjectHandle const& new_dict)
{
- assertStream();
- dynamic_cast<QPDF_Stream*>(obj.get())->replaceDict(new_dict);
+ asStreamWithAssert()->replaceDict(new_dict);
}
std::shared_ptr<Buffer>
QPDFObjectHandle::getStreamData(qpdf_stream_decode_level_e level)
{
- assertStream();
- return dynamic_cast<QPDF_Stream*>(obj.get())->getStreamData(level);
+ return asStreamWithAssert()->getStreamData(level);
}
std::shared_ptr<Buffer>
QPDFObjectHandle::getRawStreamData()
{
- assertStream();
- return dynamic_cast<QPDF_Stream*>(obj.get())->getRawStreamData();
+ return asStreamWithAssert()->getRawStreamData();
}
bool
@@ -1347,8 +1379,7 @@ QPDFObjectHandle::pipeStreamData(
bool suppress_warnings,
bool will_retry)
{
- assertStream();
- return dynamic_cast<QPDF_Stream*>(obj.get())->pipeStreamData(
+ return asStreamWithAssert()->pipeStreamData(
p,
filtering_attempted,
encode_flags,
@@ -1365,9 +1396,8 @@ QPDFObjectHandle::pipeStreamData(
bool suppress_warnings,
bool will_retry)
{
- assertStream();
bool filtering_attempted;
- dynamic_cast<QPDF_Stream*>(obj.get())->pipeStreamData(
+ asStreamWithAssert()->pipeStreamData(
p,
&filtering_attempted,
encode_flags,
@@ -1401,9 +1431,7 @@ QPDFObjectHandle::replaceStreamData(
QPDFObjectHandle const& filter,
QPDFObjectHandle const& decode_parms)
{
- assertStream();
- dynamic_cast<QPDF_Stream*>(obj.get())->replaceStreamData(
- data, filter, decode_parms);
+ asStreamWithAssert()->replaceStreamData(data, filter, decode_parms);
}
void
@@ -1412,14 +1440,12 @@ QPDFObjectHandle::replaceStreamData(
QPDFObjectHandle const& filter,
QPDFObjectHandle const& decode_parms)
{
- assertStream();
auto b = std::make_shared<Buffer>(data.length());
unsigned char* bp = b->getBuffer();
if (bp) {
memcpy(bp, data.c_str(), data.length());
}
- dynamic_cast<QPDF_Stream*>(obj.get())->replaceStreamData(
- b, filter, decode_parms);
+ asStreamWithAssert()->replaceStreamData(b, filter, decode_parms);
}
void
@@ -1428,9 +1454,7 @@ QPDFObjectHandle::replaceStreamData(
QPDFObjectHandle const& filter,
QPDFObjectHandle const& decode_parms)
{
- assertStream();
- dynamic_cast<QPDF_Stream*>(obj.get())->replaceStreamData(
- provider, filter, decode_parms);
+ asStreamWithAssert()->replaceStreamData(provider, filter, decode_parms);
}
namespace
@@ -1479,11 +1503,9 @@ QPDFObjectHandle::replaceStreamData(
QPDFObjectHandle const& filter,
QPDFObjectHandle const& decode_parms)
{
- assertStream();
auto sdp =
std::shared_ptr<StreamDataProvider>(new FunctionProvider(provider));
- dynamic_cast<QPDF_Stream*>(obj.get())->replaceStreamData(
- sdp, filter, decode_parms);
+ asStreamWithAssert()->replaceStreamData(sdp, filter, decode_parms);
}
void
@@ -1492,29 +1514,9 @@ QPDFObjectHandle::replaceStreamData(
QPDFObjectHandle const& filter,
QPDFObjectHandle const& decode_parms)
{
- assertStream();
auto sdp =
std::shared_ptr<StreamDataProvider>(new FunctionProvider(provider));
- dynamic_cast<QPDF_Stream*>(obj.get())->replaceStreamData(
- sdp, filter, decode_parms);
-}
-
-QPDFObjGen
-QPDFObjectHandle::getObjGen() const
-{
- return og;
-}
-
-int
-QPDFObjectHandle::getObjectID() const
-{
- return og.getObj();
-}
-
-int
-QPDFObjectHandle::getGeneration() const
-{
- return og.getGen();
+ asStreamWithAssert()->replaceStreamData(sdp, filter, decode_parms);
}
std::map<std::string, QPDFObjectHandle>
@@ -1529,10 +1531,11 @@ QPDFObjectHandle::arrayOrStreamToStreamArray(
{
all_description = description;
std::vector<QPDFObjectHandle> result;
- if (isArray()) {
- int n_items = getArrayNItems();
+ auto array = asArray();
+ if (array) {
+ int n_items = array->getNItems();
for (int i = 0; i < n_items; ++i) {
- QPDFObjectHandle item = getArrayItem(i);
+ QPDFObjectHandle item = array->getItem(i);
if (item.isStream()) {
result.push_back(item);
} else {
@@ -1664,16 +1667,15 @@ QPDFObjectHandle::coalesceContentStreams()
// files may have pages that are invalid in other ways.
return;
}
- QPDF* qpdf = getOwningQPDF();
- if (qpdf == nullptr) {
- // Should not be possible for a page object to not have an
- // owning PDF unless it was manually constructed in some
- // incorrect way. However, it can happen in a PDF file whose
- // page structure is direct, which is against spec but still
- // possible to hand construct, as in fuzz issue 27393.
- throw std::runtime_error("coalesceContentStreams called on object"
- " with no associated PDF file");
- }
+ // Should not be possible for a page object to not have an
+ // owning PDF unless it was manually constructed in some
+ // incorrect way. However, it can happen in a PDF file whose
+ // page structure is direct, which is against spec but still
+ // possible to hand construct, as in fuzz issue 27393.
+ QPDF* qpdf = getOwningQPDF(
+ false,
+ "coalesceContentStreams called on object with no associated PDF file");
+
QPDFObjectHandle new_contents = newStream(qpdf);
this->replaceKey("/Contents", new_contents);
@@ -1700,18 +1702,16 @@ QPDFObjectHandle::unparseResolved()
if (!dereference()) {
throw std::logic_error(
"attempted to dereference an uninitialized QPDFObjectHandle");
- } else if (this->reserved) {
- throw std::logic_error(
- "QPDFObjectHandle: attempting to unparse a reserved object");
}
- return this->obj->unparse();
+ return obj->unparse();
}
std::string
QPDFObjectHandle::unparseBinary()
{
- if (this->isString()) {
- return dynamic_cast<QPDF_String*>(this->obj.get())->unparse(true);
+ auto str = asString();
+ if (str) {
+ return str->unparse(true);
} else {
return unparse();
}
@@ -1727,16 +1727,13 @@ QPDFObjectHandle::getJSON(bool dereference_indirect)
JSON
QPDFObjectHandle::getJSON(int json_version, bool dereference_indirect)
{
- if ((!dereference_indirect) && this->isIndirect()) {
+ if ((!dereference_indirect) && isIndirect()) {
return JSON::makeString(unparse());
} else if (!dereference()) {
throw std::logic_error(
"attempted to dereference an uninitialized QPDFObjectHandle");
- } else if (this->reserved) {
- throw std::logic_error(
- "QPDFObjectHandle: attempting to unparse a reserved object");
} else {
- return this->obj->getJSON(json_version);
+ return obj->getJSON(json_version);
}
}
@@ -1748,8 +1745,7 @@ QPDFObjectHandle::getStreamJSON(
Pipeline* p,
std::string const& data_filename)
{
- assertStream();
- return dynamic_cast<QPDF_Stream*>(obj.get())->getStreamJSON(
+ return asStreamWithAssert()->getStreamJSON(
json_version, json_data, decode_level, p, data_filename);
}
@@ -1918,8 +1914,8 @@ QPDFObjectHandle::parseContentStream_data(
tokenizer.readToken(input, "content", true);
qpdf_offset_t offset = input->getLastOffset();
input->seek(offset, SEEK_SET);
- QPDFObjectHandle obj = parseInternal(
- input, "content", tokenizer, empty, nullptr, context, true);
+ auto obj = QPDFParser(input, "content", tokenizer, nullptr, context)
+ .parse(empty, true);
if (!obj.isInitialized()) {
// EOF
break;
@@ -1969,8 +1965,7 @@ QPDFObjectHandle::addContentTokenFilter(std::shared_ptr<TokenFilter> filter)
void
QPDFObjectHandle::addTokenFilter(std::shared_ptr<TokenFilter> filter)
{
- assertStream();
- return dynamic_cast<QPDF_Stream*>(obj.get())->addTokenFilter(filter);
+ return asStreamWithAssert()->addTokenFilter(filter);
}
QPDFObjectHandle
@@ -1982,497 +1977,8 @@ QPDFObjectHandle::parse(
StringDecrypter* decrypter,
QPDF* context)
{
- return parseInternal(
- input, object_description, tokenizer, empty, decrypter, context, false);
-}
-
-QPDFObjectHandle
-QPDFObjectHandle::parseInternal(
- std::shared_ptr<InputSource> input,
- std::string const& object_description,
- QPDFTokenizer& tokenizer,
- bool& empty,
- StringDecrypter* decrypter,
- QPDF* context,
- bool content_stream)
-{
- // This method must take care not to resolve any objects. Don't
- // check the type of any object without first ensuring that it is
- // a direct object. Otherwise, doing so may have the side effect
- // of reading the object and changing the file pointer. If you do
- // this, it will cause a logic error to be thrown from
- // QPDF::inParse().
-
- QPDF::ParseGuard pg(context);
-
- empty = false;
-
- QPDFObjectHandle object;
- bool set_offset = false;
-
- std::vector<SparseOHArray> olist_stack;
- olist_stack.push_back(SparseOHArray());
- std::vector<parser_state_e> state_stack;
- state_stack.push_back(st_top);
- std::vector<qpdf_offset_t> offset_stack;
- qpdf_offset_t offset = input->tell();
- offset_stack.push_back(offset);
- bool done = false;
- int bad_count = 0;
- int good_count = 0;
- bool b_contents = false;
- std::vector<std::string> contents_string_stack;
- contents_string_stack.push_back("");
- std::vector<qpdf_offset_t> contents_offset_stack;
- contents_offset_stack.push_back(-1);
- while (!done) {
- bool bad = false;
- SparseOHArray& olist = olist_stack.back();
- parser_state_e state = state_stack.back();
- offset = offset_stack.back();
- std::string& contents_string = contents_string_stack.back();
- qpdf_offset_t& contents_offset = contents_offset_stack.back();
-
- object = QPDFObjectHandle();
- set_offset = false;
-
- QPDFTokenizer::Token token =
- tokenizer.readToken(input, object_description, true);
- std::string const& token_error_message = token.getErrorMessage();
- if (!token_error_message.empty()) {
- // Tokens other than tt_bad can still generate warnings.
- warn(
- context,
- QPDFExc(
- qpdf_e_damaged_pdf,
- input->getName(),
- object_description,
- input->getLastOffset(),
- token_error_message));
- }
-
- switch (token.getType()) {
- case QPDFTokenizer::tt_eof:
- if (!content_stream) {
- QTC::TC("qpdf", "QPDFObjectHandle eof in parseInternal");
- warn(
- context,
- QPDFExc(
- qpdf_e_damaged_pdf,
- input->getName(),
- object_description,
- input->getLastOffset(),
- "unexpected EOF"));
- }
- bad = true;
- state = st_eof;
- break;
-
- case QPDFTokenizer::tt_bad:
- QTC::TC("qpdf", "QPDFObjectHandle bad token in parse");
- bad = true;
- object = newNull();
- break;
-
- case QPDFTokenizer::tt_brace_open:
- case QPDFTokenizer::tt_brace_close:
- QTC::TC("qpdf", "QPDFObjectHandle bad brace");
- warn(
- context,
- QPDFExc(
- qpdf_e_damaged_pdf,
- input->getName(),
- object_description,
- input->getLastOffset(),
- "treating unexpected brace token as null"));
- bad = true;
- object = newNull();
- break;
-
- case QPDFTokenizer::tt_array_close:
- if (state == st_array) {
- state = st_stop;
- } else {
- QTC::TC("qpdf", "QPDFObjectHandle bad array close");
- warn(
- context,
- QPDFExc(
- qpdf_e_damaged_pdf,
- input->getName(),
- object_description,
- input->getLastOffset(),
- "treating unexpected array close token as null"));
- bad = true;
- object = newNull();
- }
- break;
-
- case QPDFTokenizer::tt_dict_close:
- if (state == st_dictionary) {
- state = st_stop;
- } else {
- QTC::TC("qpdf", "QPDFObjectHandle bad dictionary close");
- warn(
- context,
- QPDFExc(
- qpdf_e_damaged_pdf,
- input->getName(),
- object_description,
- input->getLastOffset(),
- "unexpected dictionary close token"));
- bad = true;
- object = newNull();
- }
- break;
-
- case QPDFTokenizer::tt_array_open:
- case QPDFTokenizer::tt_dict_open:
- if (olist_stack.size() > 500) {
- QTC::TC("qpdf", "QPDFObjectHandle too deep");
- warn(
- context,
- QPDFExc(
- qpdf_e_damaged_pdf,
- input->getName(),
- object_description,
- input->getLastOffset(),
- "ignoring excessively deeply nested data structure"));
- bad = true;
- object = newNull();
- state = st_top;
- } else {
- olist_stack.push_back(SparseOHArray());
- state = st_start;
- offset_stack.push_back(input->tell());
- state_stack.push_back(
- (token.getType() == QPDFTokenizer::tt_array_open)
- ? st_array
- : st_dictionary);
- b_contents = false;
- contents_string_stack.push_back("");
- contents_offset_stack.push_back(-1);
- }
- break;
-
- case QPDFTokenizer::tt_bool:
- object = newBool((token.getValue() == "true"));
- break;
-
- case QPDFTokenizer::tt_null:
- object = newNull();
- break;
-
- case QPDFTokenizer::tt_integer:
- object = newInteger(QUtil::string_to_ll(token.getValue().c_str()));
- break;
-
- case QPDFTokenizer::tt_real:
- object = newReal(token.getValue());
- break;
-
- case QPDFTokenizer::tt_name:
- {
- std::string name = token.getValue();
- object = newName(name);
-
- if (name == "/Contents") {
- b_contents = true;
- } else {
- b_contents = false;
- }
- }
- break;
-
- case QPDFTokenizer::tt_word:
- {
- std::string const& value = token.getValue();
- if (content_stream) {
- object = QPDFObjectHandle::newOperator(value);
- } else if (
- (value == "R") && (state != st_top) &&
- (olist.size() >= 2) &&
- (!olist.at(olist.size() - 1).isIndirect()) &&
- (olist.at(olist.size() - 1).isInteger()) &&
- (!olist.at(olist.size() - 2).isIndirect()) &&
- (olist.at(olist.size() - 2).isInteger())) {
- if (context == nullptr) {
- QTC::TC(
- "qpdf",
- "QPDFObjectHandle indirect without context");
- throw std::logic_error(
- "QPDFObjectHandle::parse called without context"
- " on an object with indirect references");
- }
- // Try to resolve indirect objects
- object = newIndirect(
- context,
- QPDFObjGen(
- olist.at(olist.size() - 2).getIntValueAsInt(),
- olist.at(olist.size() - 1).getIntValueAsInt()));
- olist.remove_last();
- olist.remove_last();
- } else if ((value == "endobj") && (state == st_top)) {
- // We just saw endobj without having read
- // anything. Treat this as a null and do not move
- // the input source's offset.
- object = newNull();
- input->seek(input->getLastOffset(), SEEK_SET);
- empty = true;
- } else {
- QTC::TC("qpdf", "QPDFObjectHandle treat word as string");
- warn(
- context,
- QPDFExc(
- qpdf_e_damaged_pdf,
- input->getName(),
- object_description,
- input->getLastOffset(),
- "unknown token while reading object;"
- " treating as string"));
- bad = true;
- object = newString(value);
- }
- }
- break;
-
- case QPDFTokenizer::tt_string:
- {
- std::string val = token.getValue();
- if (decrypter) {
- if (b_contents) {
- contents_string = val;
- contents_offset = input->getLastOffset();
- b_contents = false;
- }
- decrypter->decryptString(val);
- }
- object = QPDFObjectHandle::newString(val);
- }
-
- break;
-
- default:
- warn(
- context,
- QPDFExc(
- qpdf_e_damaged_pdf,
- input->getName(),
- object_description,
- input->getLastOffset(),
- "treating unknown token type as null while "
- "reading object"));
- bad = true;
- object = newNull();
- break;
- }
-
- if ((!object.isInitialized()) &&
- (!((state == st_start) || (state == st_stop) ||
- (state == st_eof)))) {
- throw std::logic_error("QPDFObjectHandle::parseInternal: "
- "unexpected uninitialized object");
- object = newNull();
- }
-
- if (bad) {
- ++bad_count;
- good_count = 0;
- } else {
- ++good_count;
- if (good_count > 3) {
- bad_count = 0;
- }
- }
- if (bad_count > 5) {
- // We had too many consecutive errors without enough
- // intervening successful objects. Give up.
- warn(
- context,
- QPDFExc(
- qpdf_e_damaged_pdf,
- input->getName(),
- object_description,
- input->getLastOffset(),
- "too many errors; giving up on reading object"));
- state = st_top;
- object = newNull();
- }
-
- switch (state) {
- case st_eof:
- if (state_stack.size() > 1) {
- warn(
- context,
- QPDFExc(
- qpdf_e_damaged_pdf,
- input->getName(),
- object_description,
- input->getLastOffset(),
- "parse error while reading object"));
- }
- done = true;
- // In content stream mode, leave object uninitialized to
- // indicate EOF
- if (!content_stream) {
- object = newNull();
- }
- break;
-
- case st_dictionary:
- case st_array:
- setObjectDescriptionFromInput(
- object,
- context,
- object_description,
- input,
- input->getLastOffset());
- object.setParsedOffset(input->getLastOffset());
- set_offset = true;
- olist.append(object);
- break;
-
- case st_top:
- done = true;
- break;
-
- case st_start:
- break;
-
- case st_stop:
- if ((state_stack.size() < 2) || (olist_stack.size() < 2)) {
- throw std::logic_error(
- "QPDFObjectHandle::parseInternal: st_stop encountered"
- " with insufficient elements in stack");
- }
- parser_state_e old_state = state_stack.back();
- state_stack.pop_back();
- if (old_state == st_array) {
- // There's no newArray(SparseOHArray) since
- // SparseOHArray is not part of the public API.
- object = QPDFObjectHandle(QPDF_Array::create(olist));
- setObjectDescriptionFromInput(
- object, context, object_description, input, offset);
- // The `offset` points to the next of "[". Set the
- // rewind offset to point to the beginning of "[".
- // This has been explicitly tested with whitespace
- // surrounding the array start delimiter.
- // getLastOffset points to the array end token and
- // therefore can't be used here.
- object.setParsedOffset(offset - 1);
- set_offset = true;
- } else if (old_state == st_dictionary) {
- // Convert list to map. Alternating elements are keys.
- // Attempt to recover more or less gracefully from
- // invalid dictionaries.
- std::set<std::string> names;
- size_t n_elements = olist.size();
- for (size_t i = 0; i < n_elements; ++i) {
- QPDFObjectHandle oh = olist.at(i);
- if ((!oh.isIndirect()) && oh.isName()) {
- names.insert(oh.getName());
- }
- }
-
- std::map<std::string, QPDFObjectHandle> dict;
- int next_fake_key = 1;
- for (unsigned int i = 0; i < olist.size(); ++i) {
- QPDFObjectHandle key_obj = olist.at(i);
- QPDFObjectHandle val;
- if (key_obj.isIndirect() || (!key_obj.isName())) {
- bool found_fake = false;
- std::string candidate;
- while (!found_fake) {
- candidate = "/QPDFFake" +
- QUtil::int_to_string(next_fake_key++);
- found_fake = (names.count(candidate) == 0);
- QTC::TC(
- "qpdf",
- "QPDFObjectHandle found fake",
- (found_fake ? 0 : 1));
- }
- warn(
- context,
- QPDFExc(
- qpdf_e_damaged_pdf,
- input->getName(),
- object_description,
- offset,
- "expected dictionary key but found"
- " non-name object; inserting key " +
- candidate));
- val = key_obj;
- key_obj = newName(candidate);
- } else if (i + 1 >= olist.size()) {
- QTC::TC("qpdf", "QPDFObjectHandle no val for last key");
- warn(
- context,
- QPDFExc(
- qpdf_e_damaged_pdf,
- input->getName(),
- object_description,
- offset,
- "dictionary ended prematurely; "
- "using null as value for last key"));
- val = newNull();
- setObjectDescriptionFromInput(
- val, context, object_description, input, offset);
- } else {
- val = olist.at(++i);
- }
- std::string key = key_obj.getName();
- if (dict.count(key) > 0) {
- QTC::TC("qpdf", "QPDFObjectHandle duplicate dict key");
- warn(
- context,
- QPDFExc(
- qpdf_e_damaged_pdf,
- input->getName(),
- object_description,
- offset,
- "dictionary has duplicated key " + key +
- "; last occurrence overrides earlier "
- "ones"));
- }
- dict[key] = val;
- }
- if (!contents_string.empty() && dict.count("/Type") &&
- dict["/Type"].isNameAndEquals("/Sig") &&
- dict.count("/ByteRange") && dict.count("/Contents") &&
- dict["/Contents"].isString()) {
- dict["/Contents"] =
- QPDFObjectHandle::newString(contents_string);
- dict["/Contents"].setParsedOffset(contents_offset);
- }
- object = newDictionary(dict);
- setObjectDescriptionFromInput(
- object, context, object_description, input, offset);
- // The `offset` points to the next of "<<". Set the
- // rewind offset to point to the beginning of "<<".
- // This has been explicitly tested with whitespace
- // surrounding the dictionary start delimiter.
- // getLastOffset points to the dictionary end token
- // and therefore can't be used here.
- object.setParsedOffset(offset - 2);
- set_offset = true;
- }
- olist_stack.pop_back();
- offset_stack.pop_back();
- if (state_stack.back() == st_top) {
- done = true;
- } else {
- olist_stack.back().append(object);
- }
- contents_string_stack.pop_back();
- contents_offset_stack.pop_back();
- }
- }
-
- if (!set_offset) {
- setObjectDescriptionFromInput(
- object, context, object_description, input, offset);
- object.setParsedOffset(offset);
- }
- return object;
+ return QPDFParser(input, object_description, tokenizer, decrypter, context)
+ .parse(empty, false);
}
qpdf_offset_t
@@ -2485,31 +1991,6 @@ QPDFObjectHandle::getParsedOffset()
}
}
-void
-QPDFObjectHandle::setParsedOffset(qpdf_offset_t offset)
-{
- // This is called during parsing on newly created direct objects,
- // so we can't call dereference() here.
- if (this->obj.get()) {
- this->obj->setParsedOffset(offset);
- }
-}
-
-QPDFObjectHandle
-QPDFObjectHandle::newIndirect(QPDF* qpdf, QPDFObjGen const& og)
-{
- if (!og.isIndirect()) {
- // Special case: QPDF uses objid 0 as a sentinel for direct
- // objects, and the PDF specification doesn't allow for object
- // 0. Treat indirect references to object 0 as null so that we
- // never create an indirect object with objid 0.
- QTC::TC("qpdf", "QPDFObjectHandle indirect with 0 objid");
- return newNull();
- }
-
- return QPDFObjectHandle(qpdf, og);
-}
-
QPDFObjectHandle
QPDFObjectHandle::newBool(bool value)
{
@@ -2679,8 +2160,7 @@ QPDFObjectHandle::newStream(QPDF* qpdf)
QPDFObjectHandle stream_dict = newDictionary();
QPDFObjectHandle result = qpdf->makeIndirectObject(QPDFObjectHandle(
QPDF_Stream::create(qpdf, QPDFObjGen(), stream_dict, 0, 0)));
- result.dereference();
- QPDF_Stream* stream = dynamic_cast<QPDF_Stream*>(result.obj.get());
+ auto stream = result.asStream();
stream->setObjGen(result.getObjGen());
return result;
}
@@ -2706,18 +2186,7 @@ QPDFObjectHandle::newStream(QPDF* qpdf, std::string const& data)
QPDFObjectHandle
QPDFObjectHandle::newReserved(QPDF* qpdf)
{
- // Reserve a spot for this object by assigning it an object
- // number, but then return an unresolved handle to the object.
- QPDFObjectHandle reserved = qpdf->makeIndirectObject(makeReserved());
- QPDFObjectHandle result = newIndirect(qpdf, reserved.getObjGen());
- result.reserved = true;
- return result;
-}
-
-QPDFObjectHandle
-QPDFObjectHandle::makeReserved()
-{
- return QPDFObjectHandle(QPDF_Reserved::create());
+ return qpdf->makeIndirectObject(QPDFObjectHandle(QPDF_Reserved::create()));
}
void
@@ -2763,12 +2232,7 @@ QPDFObjectHandle::shallowCopyInternal(
QTC::TC("qpdf", "QPDFObjectHandle ERR shallow copy stream");
throw std::runtime_error("attempt to make a shallow copy of a stream");
}
-
- if (isArray() || isDictionary()) {
- new_obj = QPDFObjectHandle(obj->shallowCopy());
- } else {
- new_obj = *this;
- }
+ new_obj = QPDFObjectHandle(obj->shallowCopy());
std::set<QPDFObjGen> visited;
new_obj.copyObject(visited, false, first_level_only, false);
@@ -2809,9 +2273,6 @@ QPDFObjectHandle::copyObject(
" reserved object handle direct");
}
- qpdf = nullptr;
- og = QPDFObjGen();
-
std::shared_ptr<QPDFObject> new_obj;
if (isBool() || isInteger() || isName() || isNull() || isReal() ||
@@ -2819,9 +2280,10 @@ QPDFObjectHandle::copyObject(
new_obj = obj->shallowCopy();
} else if (isArray()) {
std::vector<QPDFObjectHandle> items;
- int n = getArrayNItems();
+ auto array = asArray();
+ int n = array->getNItems();
for (int i = 0; i < n; ++i) {
- items.push_back(getArrayItem(i));
+ items.push_back(array->getItem(i));
if ((!first_level_only) &&
(cross_indirect || (!items.back().isIndirect()))) {
items.back().copyObject(
@@ -2831,8 +2293,9 @@ QPDFObjectHandle::copyObject(
new_obj = QPDF_Array::create(items);
} else if (isDictionary()) {
std::map<std::string, QPDFObjectHandle> items;
+ auto dict = asDictionary();
for (auto const& key: getKeys()) {
- items[key] = getKey(key);
+ items[key] = dict->getKey(key);
if ((!first_level_only) &&
(cross_indirect || (!items[key].isIndirect()))) {
items[key].copyObject(
@@ -2880,7 +2343,7 @@ QPDFObjectHandle::makeDirect(bool allow_streams)
void
QPDFObjectHandle::assertInitialized() const
{
- if (!this->initialized) {
+ if (!isInitialized()) {
throw std::logic_error("operation attempted on uninitialized "
"QPDFObjectHandle");
}
@@ -3095,8 +2558,9 @@ QPDFObjectHandle::isImage(bool exclude_imagemask)
void
QPDFObjectHandle::checkOwnership(QPDFObjectHandle const& item) const
{
- if ((this->qpdf != nullptr) && (item.qpdf != nullptr) &&
- (this->qpdf != item.qpdf)) {
+ auto qpdf = getOwningQPDF();
+ auto item_qpdf = item.getOwningQPDF();
+ if ((qpdf != nullptr) && (item_qpdf != nullptr) && (qpdf != item_qpdf)) {
QTC::TC("qpdf", "QPDFObjectHandle check ownership");
throw std::logic_error(
"Attempting to add an object from a different QPDF."
@@ -3115,28 +2579,10 @@ QPDFObjectHandle::assertPageObject()
bool
QPDFObjectHandle::dereference()
{
- if (!this->initialized) {
+ if (!isInitialized()) {
return false;
}
- if (this->obj.get() && getObjectID() &&
- QPDF::Resolver::objectChanged(this->qpdf, getObjGen(), this->obj)) {
- this->obj = nullptr;
- }
- if (this->obj.get() == nullptr) {
- std::shared_ptr<QPDFObject> obj =
- QPDF::Resolver::resolve(this->qpdf, getObjGen());
- if (obj.get() == nullptr) {
- // QPDF::resolve never returns an uninitialized object, but
- // check just in case.
- this->obj = QPDF_Null::create();
- } else if (dynamic_cast<QPDF_Reserved*>(obj.get())) {
- // Do not resolve
- this->reserved = true;
- } else {
- this->reserved = false;
- this->obj = obj;
- }
- }
+ this->obj->resolve();
return true;
}