aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJay Berkenbilt <jberkenbilt@users.noreply.github.com>2022-09-01 19:14:56 +0200
committerGitHub <noreply@github.com>2022-09-01 19:14:56 +0200
commitf8fd7d60e301b9b1bf4d705ce747e281c320487e (patch)
tree4aba6da08ae9d441ecf57eabefdc76185137d28d
parenta078202c1b5823f1c13a4c559619158054029e73 (diff)
parent805c1ad47968e33e1296af9a31492f6916ad9113 (diff)
downloadqpdf-f8fd7d60e301b9b1bf4d705ce747e281c320487e.tar.zst
Merge pull request #726 from m-holger/tidy3
Split QPDFObject into QPDFObject and QPDFValue
-rw-r--r--include/qpdf/Constants.h2
-rw-r--r--include/qpdf/QPDF.hh25
-rw-r--r--include/qpdf/QPDFObject.hh140
-rw-r--r--include/qpdf/QPDFObjectHandle.hh84
-rw-r--r--include/qpdf/QPDFValue.hh130
-rw-r--r--libqpdf/CMakeLists.txt2
-rw-r--r--libqpdf/QPDF.cc155
-rw-r--r--libqpdf/QPDFObject.cc45
-rw-r--r--libqpdf/QPDFObjectHandle.cc505
-rw-r--r--libqpdf/QPDFParser.cc23
-rw-r--r--libqpdf/QPDFValue.cc11
-rw-r--r--libqpdf/QPDF_Array.cc16
-rw-r--r--libqpdf/QPDF_Bool.cc13
-rw-r--r--libqpdf/QPDF_Dictionary.cc14
-rw-r--r--libqpdf/QPDF_InlineImage.cc13
-rw-r--r--libqpdf/QPDF_Integer.cc13
-rw-r--r--libqpdf/QPDF_Name.cc13
-rw-r--r--libqpdf/QPDF_Null.cc17
-rw-r--r--libqpdf/QPDF_Operator.cc15
-rw-r--r--libqpdf/QPDF_Real.cc14
-rw-r--r--libqpdf/QPDF_Reserved.cc23
-rw-r--r--libqpdf/QPDF_Stream.cc15
-rw-r--r--libqpdf/QPDF_String.cc13
-rw-r--r--libqpdf/QPDF_Unresolved.cc36
-rw-r--r--libqpdf/QPDF_linearization.cc3
-rw-r--r--libqpdf/qpdf/QPDF_Array.hh6
-rw-r--r--libqpdf/qpdf/QPDF_Bool.hh6
-rw-r--r--libqpdf/qpdf/QPDF_Dictionary.hh6
-rw-r--r--libqpdf/qpdf/QPDF_InlineImage.hh6
-rw-r--r--libqpdf/qpdf/QPDF_Integer.hh6
-rw-r--r--libqpdf/qpdf/QPDF_Name.hh6
-rw-r--r--libqpdf/qpdf/QPDF_Null.hh8
-rw-r--r--libqpdf/qpdf/QPDF_Operator.hh6
-rw-r--r--libqpdf/qpdf/QPDF_Real.hh6
-rw-r--r--libqpdf/qpdf/QPDF_Reserved.hh8
-rw-r--r--libqpdf/qpdf/QPDF_Stream.hh6
-rw-r--r--libqpdf/qpdf/QPDF_String.hh6
-rw-r--r--libqpdf/qpdf/QPDF_Unresolved.hh19
-rw-r--r--qpdf/qpdf.testcov2
-rw-r--r--qpdf/qtest/qpdf/issue-51.out1
-rw-r--r--qpdf/qtest/type-checks.test6
-rw-r--r--qpdf/test_driver.cc19
42 files changed, 825 insertions, 638 deletions
diff --git a/include/qpdf/Constants.h b/include/qpdf/Constants.h
index 5d2113bd..cf6bdaef 100644
--- a/include/qpdf/Constants.h
+++ b/include/qpdf/Constants.h
@@ -82,6 +82,8 @@ enum qpdf_object_type_e {
/* Additional object types that can occur in content streams */
ot_operator,
ot_inlineimage,
+ /* Object types internal to qpdf */
+ ot_unresolved,
/* NOTE: if adding to this list, update QPDFObject.hh */
};
diff --git a/include/qpdf/QPDF.hh b/include/qpdf/QPDF.hh
index 12d41eff..bcd85cd2 100644
--- a/include/qpdf/QPDF.hh
+++ b/include/qpdf/QPDF.hh
@@ -843,19 +843,13 @@ class QPDF
// it can resolve indirect references.
class Resolver
{
- friend class QPDFObjectHandle;
+ friend class QPDFObject;
private:
- static std::shared_ptr<QPDFObject>
+ static void
resolve(QPDF* qpdf, QPDFObjGen const& og)
{
- return qpdf->resolve(og);
- }
- static bool
- objectChanged(
- QPDF* qpdf, QPDFObjGen const& og, std::shared_ptr<QPDFObject>& oph)
- {
- return qpdf->objectChanged(og, oph);
+ qpdf->resolve(og);
}
};
friend class Resolver;
@@ -1174,12 +1168,20 @@ class QPDF
std::string const& description,
QPDFObjGen const& exp_og,
QPDFObjGen& og);
- bool objectChanged(QPDFObjGen const& og, std::shared_ptr<QPDFObject>& oph);
- std::shared_ptr<QPDFObject> resolve(QPDFObjGen const& og);
+ void resolve(QPDFObjGen const& og);
void resolveObjectsInStream(int obj_stream_number);
void stopOnError(std::string const& message);
QPDFObjectHandle reserveObjectIfNotExists(QPDFObjGen const& og);
QPDFObjectHandle reserveStream(QPDFObjGen const& og);
+ QPDFObjectHandle
+ newIndirect(QPDFObjGen const&, std::shared_ptr<QPDFObject> const&);
+ bool isCached(QPDFObjGen const& og);
+ bool isUnresolved(QPDFObjGen const& og);
+ void updateCache(
+ QPDFObjGen const& og,
+ std::shared_ptr<QPDFObject> const& object,
+ qpdf_offset_t end_before_space,
+ qpdf_offset_t end_after_space);
// Calls finish() on the pipeline when done but does not delete it
bool pipeStreamData(
@@ -1727,7 +1729,6 @@ class QPDF
bool in_parse;
bool parsed;
std::set<int> resolved_object_streams;
- bool ever_replaced_objects;
// Linearization data
qpdf_offset_t first_xref_item_offset; // actual value from file
diff --git a/include/qpdf/QPDFObject.hh b/include/qpdf/QPDFObject.hh
index eb7c4b90..e6d1d18b 100644
--- a/include/qpdf/QPDFObject.hh
+++ b/include/qpdf/QPDFObject.hh
@@ -25,6 +25,7 @@
#include <qpdf/Constants.h>
#include <qpdf/DLL.h>
#include <qpdf/JSON.hh>
+#include <qpdf/QPDFValue.hh>
#include <qpdf/Types.h>
#include <string>
@@ -34,9 +35,9 @@ class QPDFObjectHandle;
class QPDFObject
{
- public:
- QPDFObject();
+ friend class QPDFValue;
+ public:
// Objects derived from QPDFObject are accessible through
// QPDFObjectHandle. Each object returns a unique type code that
// has one of the valid qpdf_object_type_e values. As new object
@@ -61,18 +62,128 @@ class QPDFObject
static constexpr object_type_e ot_stream = ::ot_stream;
static constexpr object_type_e ot_operator = ::ot_operator;
static constexpr object_type_e ot_inlineimage = ::ot_inlineimage;
+ static constexpr object_type_e ot_unresolved = ::ot_unresolved;
+ QPDFObject() = default;
virtual ~QPDFObject() = default;
- virtual std::shared_ptr<QPDFObject> shallowCopy() = 0;
- virtual std::string unparse() = 0;
- virtual JSON getJSON(int json_version) = 0;
+
+ std::shared_ptr<QPDFObject>
+ shallowCopy()
+ {
+ return value->shallowCopy();
+ }
+ std::string
+ unparse()
+ {
+ return value->unparse();
+ }
+ JSON
+ getJSON(int json_version)
+ {
+ return value->getJSON(json_version);
+ }
// Return a unique type code for the object
- virtual object_type_e getTypeCode() const = 0;
+ object_type_e
+ getTypeCode() const
+ {
+ return value->type_code;
+ }
// Return a string literal that describes the type, useful for
// debugging and testing
- virtual char const* getTypeName() const = 0;
+ char const*
+ getTypeName() const
+ {
+ return value->type_name;
+ }
+ // Returns nullptr for direct objects
+ QPDF*
+ getQPDF() const
+ {
+ return value->qpdf;
+ }
+ QPDFObjGen
+ getObjGen() const
+ {
+ return value->og;
+ }
+
+ void
+ setDescription(QPDF* qpdf, std::string const& description)
+ {
+ return value->setDescription(qpdf, description);
+ }
+ bool
+ getDescription(QPDF*& qpdf, std::string& description)
+ {
+ return value->getDescription(qpdf, description);
+ }
+ bool
+ hasDescription()
+ {
+ return value->hasDescription();
+ }
+ void
+ setParsedOffset(qpdf_offset_t offset)
+ {
+ value->setParsedOffset(offset);
+ }
+ qpdf_offset_t
+ getParsedOffset()
+ {
+ return value->getParsedOffset();
+ }
+ void
+ assign(std::shared_ptr<QPDFObject> o)
+ {
+ value = o->value;
+ }
+ void
+ swapWith(std::shared_ptr<QPDFObject> o)
+ {
+ auto v = value;
+ value = o->value;
+ o->value = v;
+ auto og = value->og;
+ value->og = o->value->og;
+ o->value->og = og;
+ }
+
+ // The following two methods are for use by class QPDF only
+ void
+ setObjGen(QPDF* qpdf, QPDFObjGen const& og)
+ {
+ value->qpdf = qpdf;
+ value->og = og;
+ }
+ void
+ resetObjGen()
+ {
+ value->qpdf = nullptr;
+ value->og = QPDFObjGen();
+ }
+
+ bool
+ isUnresolved() const
+ {
+ return value->type_code == ::ot_unresolved;
+ }
+ void
+ resolve()
+ {
+ if (isUnresolved()) {
+ doResolve();
+ }
+ }
+ void doResolve();
+
+ template <typename T>
+ T*
+ as()
+ {
+ return dynamic_cast<T*>(value.get());
+ }
// Accessor to give specific access to non-public methods
class ObjAccessor
@@ -89,29 +200,20 @@ class QPDFObject
}
}
};
- friend class ObjAccessor;
- virtual void setDescription(QPDF*, std::string const&);
- bool getDescription(QPDF*&, std::string&);
- bool hasDescription();
-
- void setParsedOffset(qpdf_offset_t offset);
- qpdf_offset_t getParsedOffset();
+ friend class ObjAccessor;
protected:
virtual void
releaseResolved()
{
+ value->releaseResolved();
}
- static std::shared_ptr<QPDFObject> do_create(QPDFObject*);
private:
QPDFObject(QPDFObject const&) = delete;
QPDFObject& operator=(QPDFObject const&) = delete;
-
- QPDF* owning_qpdf;
- std::string object_description;
- qpdf_offset_t parsed_offset;
+ std::shared_ptr<QPDFValue> value;
};
#endif // QPDFOBJECT_HH
diff --git a/include/qpdf/QPDFObjectHandle.hh b/include/qpdf/QPDFObjectHandle.hh
index c1bed81f..16e8dc8b 100644
--- a/include/qpdf/QPDFObjectHandle.hh
+++ b/include/qpdf/QPDFObjectHandle.hh
@@ -43,8 +43,18 @@
class Pipeline;
class QPDF;
-class QPDF_Dictionary;
class QPDF_Array;
+class QPDF_Bool;
+class QPDF_Dictionary;
+class QPDF_InlineImage;
+class QPDF_Integer;
+class QPDF_Name;
+class QPDF_Null;
+class QPDF_Operator;
+class QPDF_Real;
+class QPDF_Reserved;
+class QPDF_Stream;
+class QPDF_String;
class QPDFTokenizer;
class QPDFExc;
class Pl_QPDFTokenizer;
@@ -316,7 +326,7 @@ class QPDFObjectHandle
};
QPDF_DLL
- QPDFObjectHandle();
+ QPDFObjectHandle() = default;
QPDF_DLL
QPDFObjectHandle(QPDFObjectHandle const&) = default;
QPDF_DLL
@@ -963,8 +973,8 @@ class QPDFObjectHandle
// null for a direct object if allow_nullptr is set to true or
// throws a runtime error otherwise.
QPDF_DLL
- inline QPDF*
- getOwningQPDF(bool allow_nullptr = true, std::string const& error_msg = "");
+ inline QPDF* getOwningQPDF(
+ bool allow_nullptr = true, std::string const& error_msg = "") const;
// Create a shallow copy of an object as a direct object, but do not
// traverse across indirect object boundaries. That means that,
@@ -1443,9 +1453,9 @@ class QPDFObjectHandle
private:
static QPDFObjectHandle
- newIndirect(QPDF* qpdf, QPDFObjGen const& og)
+ newIndirect(std::shared_ptr<QPDFObject> const& obj)
{
- return QPDFObjectHandle::newIndirect(qpdf, og);
+ return QPDFObjectHandle(obj);
}
static QPDFObjectHandle
newStream(
@@ -1458,12 +1468,6 @@ class QPDFObjectHandle
return QPDFObjectHandle::newStream(
qpdf, og, stream_dict, offset, length);
}
- // Reserve an object with a specific ID
- static QPDFObjectHandle
- makeReserved()
- {
- return QPDFObjectHandle::makeReserved();
- }
};
friend class Factory;
@@ -1483,6 +1487,16 @@ class QPDFObjectHandle
};
return o.obj;
}
+ static QPDF_Array*
+ asArray(QPDFObjectHandle& oh)
+ {
+ return oh.asArray();
+ }
+ static QPDF_Stream*
+ asStream(QPDFObjectHandle& oh)
+ {
+ return oh.asStream();
+ }
};
friend class ObjAccessor;
@@ -1563,18 +1577,32 @@ class QPDFObjectHandle
bool isImage(bool exclude_imagemask = true);
private:
- QPDFObjectHandle(QPDF*, QPDFObjGen const& og);
- QPDFObjectHandle(std::shared_ptr<QPDFObject> const&);
+ QPDFObjectHandle(std::shared_ptr<QPDFObject> const& obj) :
+ obj(obj)
+ {
+ }
// Private object factory methods
- static QPDFObjectHandle newIndirect(QPDF*, QPDFObjGen const& og);
static QPDFObjectHandle newStream(
QPDF* qpdf,
QPDFObjGen const& og,
QPDFObjectHandle stream_dict,
qpdf_offset_t offset,
size_t length);
- static QPDFObjectHandle makeReserved();
+
+ QPDF_Array* asArray();
+ QPDF_Bool* asBool();
+ QPDF_Dictionary* asDictionary();
+ QPDF_InlineImage* asInlineImage();
+ QPDF_Integer* asInteger();
+ QPDF_Name* asName();
+ QPDF_Null* asNull();
+ QPDF_Operator* asOperator();
+ QPDF_Real* asReal();
+ QPDF_Reserved* asReserved();
+ QPDF_Stream* asStream();
+ QPDF_Stream* asStreamWithAssert();
+ QPDF_String* asString();
void typeWarning(char const* expected_type, std::string const& warning);
void objectWarning(std::string const& warning);
@@ -1601,15 +1629,10 @@ class QPDFObjectHandle
static void warn(QPDF*, QPDFExc const&);
void checkOwnership(QPDFObjectHandle const&) const;
- bool initialized;
-
// Moving members of QPDFObjectHandle into a smart pointer incurs
// a substantial performance penalty since QPDFObjectHandle
// objects are copied around so frequently.
- QPDF* qpdf;
- QPDFObjGen og;
std::shared_ptr<QPDFObject> obj;
- bool reserved;
};
#ifndef QPDF_NO_QPDF_STRING
@@ -1832,44 +1855,45 @@ class QPDFObjectHandle::QPDFArrayItems
inline QPDFObjGen
QPDFObjectHandle::getObjGen() const
{
- return og;
+ return isInitialized() ? obj->getObjGen() : QPDFObjGen();
}
inline int
QPDFObjectHandle::getObjectID() const
{
- return og.getObj();
+ return getObjGen().getObj();
}
inline int
QPDFObjectHandle::getGeneration() const
{
- return og.getGen();
+ return getObjGen().getGen();
}
inline bool
QPDFObjectHandle::isIndirect() const
{
- return initialized && (getObjectID() != 0);
+ return (obj != nullptr) && (getObjectID() != 0);
}
inline bool
QPDFObjectHandle::isInitialized() const
{
- return initialized;
+ return obj != nullptr;
}
// Indirect object accessors
inline QPDF*
QPDFObjectHandle::getOwningQPDF(
- bool allow_nullptr, std::string const& error_msg)
+ bool allow_nullptr, std::string const& error_msg) const
{
// Will be null for direct objects
- if (!allow_nullptr && (this->qpdf == nullptr)) {
+ auto result = isInitialized() ? this->obj->getQPDF() : nullptr;
+ if (!allow_nullptr && (result == nullptr)) {
throw std::runtime_error(
error_msg == "" ? "attempt to use a null qpdf object" : error_msg);
}
- return this->qpdf;
+ return result;
}
inline void
@@ -1877,7 +1901,7 @@ 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()) {
+ if (isInitialized()) {
this->obj->setParsedOffset(offset);
}
}
diff --git a/include/qpdf/QPDFValue.hh b/include/qpdf/QPDFValue.hh
new file mode 100644
index 00000000..8b4f53b5
--- /dev/null
+++ b/include/qpdf/QPDFValue.hh
@@ -0,0 +1,130 @@
+// Copyright (c) 2005-2022 Jay Berkenbilt
+//
+// This file is part of qpdf.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Versions of qpdf prior to version 7 were released under the terms
+// of version 2.0 of the Artistic License. At your option, you may
+// continue to consider qpdf to be licensed under those terms. Please
+// see the manual for additional information.
+
+#ifndef QPDFVALUE_HH
+#define QPDFVALUE_HH
+
+#include <qpdf/Constants.h>
+#include <qpdf/DLL.h>
+#include <qpdf/JSON.hh>
+#include <qpdf/QPDFObjGen.hh>
+#include <qpdf/Types.h>
+
+#include <string>
+
+class QPDF;
+class QPDFObjectHandle;
+class QPDFObject;
+
+class QPDFValue
+{
+ friend class QPDFObject;
+
+ public:
+ virtual ~QPDFValue() = default;
+
+ virtual std::shared_ptr<QPDFObject> shallowCopy() = 0;
+ virtual std::string unparse() = 0;
+ virtual JSON getJSON(int json_version) = 0;
+ virtual void
+ setDescription(QPDF* qpdf, std::string const& description)
+ {
+ owning_qpdf = qpdf;
+ object_description = description;
+ }
+ bool
+ getDescription(QPDF*& qpdf, std::string& description)
+ {
+ qpdf = owning_qpdf;
+ description = object_description;
+ return owning_qpdf != nullptr;
+ }
+ bool
+ hasDescription()
+ {
+ return owning_qpdf != nullptr;
+ }
+ void
+ setParsedOffset(qpdf_offset_t offset)
+ {
+ if (parsed_offset < 0) {
+ parsed_offset = offset;
+ }
+ }
+ qpdf_offset_t
+ getParsedOffset()
+ {
+ return parsed_offset;
+ }
+ QPDF*
+ getQPDF()
+ {
+ return qpdf;
+ }
+ QPDFObjGen
+ getObjGen()
+ {
+ return og;
+ }
+
+ protected:
+ QPDFValue() :
+ type_code(::ot_uninitialized),
+ type_name("uninitialized")
+ {
+ }
+ QPDFValue(qpdf_object_type_e type_code, char const* type_name) :
+ type_code(type_code),
+ type_name(type_name)
+ {
+ }
+ QPDFValue(
+ qpdf_object_type_e type_code,
+ char const* type_name,
+ QPDF* qpdf,
+ QPDFObjGen const& og) :
+ type_code(type_code),
+ type_name(type_name),
+ qpdf(qpdf),
+ og(og)
+ {
+ }
+ virtual void
+ releaseResolved()
+ {
+ }
+ static std::shared_ptr<QPDFObject> do_create(QPDFValue*);
+
+ private:
+ QPDFValue(QPDFValue const&) = delete;
+ QPDFValue& operator=(QPDFValue const&) = delete;
+ QPDF* owning_qpdf{nullptr};
+ std::string object_description;
+ qpdf_offset_t parsed_offset{-1};
+ const qpdf_object_type_e type_code;
+ char const* type_name;
+
+ protected:
+ QPDF* qpdf{nullptr};
+ QPDFObjGen og;
+};
+
+#endif // QPDFVALUE_HH
diff --git a/libqpdf/CMakeLists.txt b/libqpdf/CMakeLists.txt
index 51f7476d..686ea04a 100644
--- a/libqpdf/CMakeLists.txt
+++ b/libqpdf/CMakeLists.txt
@@ -85,6 +85,7 @@ set(libqpdf_SOURCES
QPDFSystemError.cc
QPDFTokenizer.cc
QPDFUsage.cc
+ QPDFValue.cc
QPDFWriter.cc
QPDFXRefEntry.cc
QPDF_Array.cc
@@ -99,6 +100,7 @@ set(libqpdf_SOURCES
QPDF_Reserved.cc
QPDF_Stream.cc
QPDF_String.cc
+ QPDF_Unresolved.cc
QPDF_encryption.cc
QPDF_json.cc
QPDF_linearization.cc
diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc
index 6ae74b25..9593c44f 100644
--- a/libqpdf/QPDF.cc
+++ b/libqpdf/QPDF.cc
@@ -24,7 +24,9 @@
#include <qpdf/QPDF_Array.hh>
#include <qpdf/QPDF_Dictionary.hh>
#include <qpdf/QPDF_Null.hh>
+#include <qpdf/QPDF_Reserved.hh>
#include <qpdf/QPDF_Stream.hh>
+#include <qpdf/QPDF_Unresolved.hh>
#include <qpdf/QTC.hh>
#include <qpdf/QUtil.hh>
@@ -222,7 +224,6 @@ QPDF::Members::Members() :
immediate_copy_from(false),
in_parse(false),
parsed(false),
- ever_replaced_objects(false),
first_xref_item_offset(0),
uncompressed_after_compressed(false)
{
@@ -258,6 +259,7 @@ QPDF::~QPDF()
this->m->xref_table.clear();
for (auto const& iter: this->m->obj_cache) {
QPDFObject::ObjAccessor::releaseResolved(iter.second.object.get());
+ iter.second.object->resetObjGen();
}
}
@@ -1397,7 +1399,7 @@ QPDF::fixDanglingReferences(bool force)
std::list<QPDFObjectHandle> queue;
queue.push_back(this->m->trailer);
for (auto const& og: to_process) {
- QPDFObjectHandle obj = QPDFObjectHandle::Factory::newIndirect(this, og);
+ auto obj = getObject(og);
if (obj.isDictionary() || obj.isArray()) {
queue.push_back(obj);
} else if (obj.isStream()) {
@@ -1419,18 +1421,15 @@ QPDF::fixDanglingReferences(bool force)
to_check.push_back(iter.second);
}
} else if (obj.isArray()) {
- QPDF_Array* arr = dynamic_cast<QPDF_Array*>(
- QPDFObjectHandle::ObjAccessor::getObject(obj).get());
+ auto arr = QPDFObjectHandle::ObjAccessor::asArray(obj);
arr->addExplicitElementsToList(to_check);
}
for (auto sub: to_check) {
if (sub.isIndirect()) {
- if (sub.getOwningQPDF() == this) {
- QPDFObjGen og(sub.getObjGen());
- if (this->m->obj_cache.count(og) == 0) {
- QTC::TC("qpdf", "QPDF detected dangling ref");
- queue.push_back(sub);
- }
+ if ((sub.getOwningQPDF() == this) &&
+ isUnresolved(sub.getObjGen())) {
+ QTC::TC("qpdf", "QPDF detected dangling ref");
+ queue.push_back(sub);
}
} else {
queue.push_back(sub);
@@ -1462,8 +1461,7 @@ QPDF::getAllObjects()
fixDanglingReferences(true);
std::vector<QPDFObjectHandle> result;
for (auto const& iter: this->m->obj_cache) {
- QPDFObjGen const& og = iter.first;
- result.push_back(QPDFObjectHandle::Factory::newIndirect(this, og));
+ result.push_back(newIndirect(iter.first, iter.second.object));
}
return result;
}
@@ -1888,7 +1886,7 @@ QPDF::readObjectAtOffset(
"expected endobj");
}
- if (!this->m->obj_cache.count(og)) {
+ if (isUnresolved(og)) {
// Store the object in the cache here so it gets cached
// whether we first know the offset or whether we first know
// the object ID and generation (in which we case we would get
@@ -1919,8 +1917,8 @@ QPDF::readObjectAtOffset(
}
}
qpdf_offset_t end_after_space = this->m->file->tell();
-
- this->m->obj_cache[og] = ObjCache(
+ updateCache(
+ og,
QPDFObjectHandle::ObjAccessor::getObject(oh),
end_before_space,
end_after_space);
@@ -1929,31 +1927,14 @@ QPDF::readObjectAtOffset(
return oh;
}
-bool
-QPDF::objectChanged(QPDFObjGen const& og, std::shared_ptr<QPDFObject>& oph)
-{
- // See if the object cached at og, if any, is the one passed in.
- // QPDFObjectHandle uses this to detect outdated handles to
- // replaced or swapped objects. This is a somewhat expensive check
- // because it happens with every dereference of a
- // QPDFObjectHandle. To reduce the hit somewhat, short-circuit the
- // check if we never called a function that replaces an object
- // already in cache. It is important for functions that do this to
- // set ever_replaced_objects = true.
-
- if (!this->m->ever_replaced_objects) {
- return false;
- }
- auto c = this->m->obj_cache.find(og);
- if (c == this->m->obj_cache.end()) {
- return true;
- }
- return (c->second.object.get() != oph.get());
-}
-
-std::shared_ptr<QPDFObject>
+void
QPDF::resolve(QPDFObjGen const& og)
{
+ if (isCached(og) && !isUnresolved(og)) {
+ // We only need to resolve unresolved objects
+ return;
+ }
+
// Check object cache before checking xref table. This allows us
// to insert things into the object cache that don't actually
// exist in the file.
@@ -1967,11 +1948,12 @@ QPDF::resolve(QPDFObjGen const& og)
"",
this->m->file->getLastOffset(),
("loop detected resolving object " + og.unparse(' ')));
- return QPDF_Null::create();
+ updateCache(og, QPDF_Null::create(), -1, -1);
+ return;
}
ResolveRecorder rr(this, og);
- if ((!this->m->obj_cache.count(og)) && this->m->xref_table.count(og)) {
+ if (m->xref_table.count(og) != 0) {
QPDFXRefEntry const& entry = this->m->xref_table[og];
try {
switch (entry.getType()) {
@@ -2009,19 +1991,17 @@ QPDF::resolve(QPDFObjGen const& og)
": error reading object: " + e.what()));
}
}
- if (this->m->obj_cache.count(og) == 0) {
+
+ if (isUnresolved(og)) {
// PDF spec says unknown objects resolve to the null object.
QTC::TC("qpdf", "QPDF resolve failure to null");
- QPDFObjectHandle oh = QPDFObjectHandle::newNull();
- this->m->obj_cache[og] =
- ObjCache(QPDFObjectHandle::ObjAccessor::getObject(oh), -1, -1);
+ updateCache(og, QPDF_Null::create(), -1, -1);
}
- std::shared_ptr<QPDFObject> result(this->m->obj_cache[og].object);
+ auto result(this->m->obj_cache[og].object);
if (!result->hasDescription()) {
result->setDescription(this, ("object " + og.unparse(' ')));
}
- return result;
}
void
@@ -2109,15 +2089,15 @@ QPDF::resolveObjectsInStream(int obj_stream_number)
// objects appended to the file, so it is necessary to recheck the
// xref table and only cache what would actually be resolved here.
for (auto const& iter: offsets) {
- int obj = iter.first;
- QPDFObjGen og(obj, 0);
+ QPDFObjGen og(iter.first, 0);
QPDFXRefEntry const& entry = this->m->xref_table[og];
if ((entry.getType() == 2) &&
(entry.getObjStreamNumber() == obj_stream_number)) {
int offset = iter.second;
input->seek(offset, SEEK_SET);
QPDFObjectHandle oh = readObject(input, "", og, true);
- this->m->obj_cache[og] = ObjCache(
+ updateCache(
+ og,
QPDFObjectHandle::ObjAccessor::getObject(oh),
end_before_space,
end_after_space);
@@ -2128,6 +2108,47 @@ QPDF::resolveObjectsInStream(int obj_stream_number)
}
QPDFObjectHandle
+QPDF::newIndirect(QPDFObjGen const& og, std::shared_ptr<QPDFObject> const& obj)
+{
+ obj->setObjGen(this, og);
+ if (!obj->hasDescription()) {
+ obj->setDescription(this, "object " + og.unparse(' '));
+ }
+ return QPDFObjectHandle::Factory::newIndirect(obj);
+}
+
+void
+QPDF::updateCache(
+ QPDFObjGen const& og,
+ std::shared_ptr<QPDFObject> const& object,
+ qpdf_offset_t end_before_space,
+ qpdf_offset_t end_after_space)
+{
+ object->setObjGen(this, og);
+ if (isCached(og)) {
+ auto& cache = m->obj_cache[og];
+ cache.object->resetObjGen();
+ cache.object->assign(object);
+ cache.end_before_space = end_before_space;
+ cache.end_after_space = end_after_space;
+ } else {
+ m->obj_cache[og] = ObjCache(object, end_before_space, end_after_space);
+ }
+}
+
+bool
+QPDF::isCached(QPDFObjGen const& og)
+{
+ return m->obj_cache.count(og) != 0;
+}
+
+bool
+QPDF::isUnresolved(QPDFObjGen const& og)
+{
+ return !isCached(og) || m->obj_cache[og].object->isUnresolved();
+}
+
+QPDFObjectHandle
QPDF::makeIndirectObject(QPDFObjectHandle oh)
{
int max_objid = toI(getObjectCount());
@@ -2136,19 +2157,21 @@ QPDF::makeIndirectObject(QPDFObjectHandle oh)
"max object id is too high to create new objects");
}
QPDFObjGen next(max_objid + 1, 0);
- this->m->obj_cache[next] =
+ m->obj_cache[next] =
ObjCache(QPDFObjectHandle::ObjAccessor::getObject(oh), -1, -1);
- return QPDFObjectHandle::Factory::newIndirect(this, next);
+ return newIndirect(next, m->obj_cache[next].object);
}
QPDFObjectHandle
QPDF::reserveObjectIfNotExists(QPDFObjGen const& og)
{
- if ((!this->m->obj_cache.count(og)) && (!this->m->xref_table.count(og))) {
+ if (!isCached(og) && !m->xref_table.count(og)) {
resolve(og);
- replaceObject(og, QPDFObjectHandle::Factory::makeReserved());
+ m->obj_cache[og].object = QPDF_Reserved::create();
+ return newIndirect(og, m->obj_cache[og].object);
+ } else {
+ return getObject(og);
}
- return getObject(og);
}
QPDFObjectHandle
@@ -2161,7 +2184,13 @@ QPDF::reserveStream(QPDFObjGen const& og)
QPDFObjectHandle
QPDF::getObject(QPDFObjGen const& og)
{
- return QPDFObjectHandle::Factory::newIndirect(this, og);
+ if (!og.isIndirect()) {
+ return QPDFObjectHandle::newNull();
+ }
+ if (!isCached(og)) {
+ m->obj_cache[og] = ObjCache(QPDF_Unresolved::create(this, og), -1, -1);
+ }
+ return newIndirect(og, m->obj_cache[og].object);
}
QPDFObjectHandle
@@ -2196,14 +2225,11 @@ QPDF::replaceObject(QPDFObjGen const& og, QPDFObjectHandle oh)
throw std::logic_error(
"QPDF::replaceObject called with indirect object handle");
}
-
// Force new object to appear in the cache
resolve(og);
// Replace the object in the object cache
- this->m->ever_replaced_objects = true;
- this->m->obj_cache[og] =
- ObjCache(QPDFObjectHandle::ObjAccessor::getObject(oh), -1, -1);
+ updateCache(og, QPDFObjectHandle::ObjAccessor::getObject(oh), -1, -1);
}
void
@@ -2456,12 +2482,12 @@ QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign)
QPDFObjGen local_og(result.getObjGen());
// Copy information from the foreign stream so we can pipe its
// data later without keeping the original QPDF object around.
+
QPDF* foreign_stream_qpdf = foreign.getOwningQPDF(
false, "unable to retrieve owning qpdf from foreign stream");
- QPDF_Stream* stream = dynamic_cast<QPDF_Stream*>(
- QPDFObjectHandle::ObjAccessor::getObject(foreign).get());
- if (!stream) {
+ auto stream = QPDFObjectHandle::ObjAccessor::asStream(foreign);
+ if (stream == nullptr) {
throw std::logic_error("unable to retrieve underlying"
" stream object from foreign stream");
}
@@ -2525,10 +2551,7 @@ QPDF::swapObjects(QPDFObjGen const& og1, QPDFObjGen const& og2)
// cache.
resolve(og1);
resolve(og2);
- ObjCache t = this->m->obj_cache[og1];
- this->m->ever_replaced_objects = true;
- this->m->obj_cache[og1] = this->m->obj_cache[og2];
- this->m->obj_cache[og2] = t;
+ m->obj_cache[og1].object->swapWith(m->obj_cache[og2].object);
}
unsigned long long
diff --git a/libqpdf/QPDFObject.cc b/libqpdf/QPDFObject.cc
index 382dd6c6..8b538021 100644
--- a/libqpdf/QPDFObject.cc
+++ b/libqpdf/QPDFObject.cc
@@ -1,47 +1,10 @@
#include <qpdf/QPDFObject.hh>
-QPDFObject::QPDFObject() :
- owning_qpdf(nullptr),
- parsed_offset(-1)
-{
-}
-
-std::shared_ptr<QPDFObject>
-QPDFObject::do_create(QPDFObject* object)
-{
- std::shared_ptr<QPDFObject> obj(object);
- return obj;
-}
-
-void
-QPDFObject::setDescription(QPDF* qpdf, std::string const& description)
-{
- this->owning_qpdf = qpdf;
- this->object_description = description;
-}
-
-bool
-QPDFObject::getDescription(QPDF*& qpdf, std::string& description)
-{
- qpdf = this->owning_qpdf;
- description = this->object_description;
- return this->owning_qpdf != nullptr;
-}
-
-bool
-QPDFObject::hasDescription()
-{
- return this->owning_qpdf != nullptr;
-}
+#include <qpdf/QPDF.hh>
void
-QPDFObject::setParsedOffset(qpdf_offset_t offset)
-{
- this->parsed_offset = offset;
-}
-
-qpdf_offset_t
-QPDFObject::getParsedOffset()
+QPDFObject::doResolve()
{
- return this->parsed_offset;
+ auto og = value->og;
+ QPDF::Resolver::resolve(value->qpdf, og);
}
diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc
index 2227a77b..19a85034 100644
--- a/libqpdf/QPDFObjectHandle.cc
+++ b/libqpdf/QPDFObjectHandle.cc
@@ -21,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>
@@ -234,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()
{
@@ -286,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
@@ -312,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
@@ -368,51 +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;
+ return dereference() && (obj->getTypeCode() == QPDFObject::ot_reserved);
}
bool
@@ -450,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");
@@ -462,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;
}
@@ -474,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");
@@ -486,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;
}
@@ -585,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");
@@ -597,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;
}
@@ -609,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");
@@ -621,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;
}
@@ -633,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");
@@ -645,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");
@@ -667,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;
}
@@ -679,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");
@@ -691,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");
@@ -713,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;
}
@@ -731,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");
@@ -744,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 {
@@ -757,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");
@@ -769,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;
}
}
@@ -786,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;
}
}
@@ -805,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),
@@ -826,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;
}
@@ -841,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");
@@ -855,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");
@@ -867,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");
@@ -881,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");
@@ -899,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");
@@ -918,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 {
@@ -935,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;
@@ -953,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");
@@ -967,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 +
@@ -995,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");
@@ -1008,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");
@@ -1200,9 +1269,10 @@ 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");
@@ -1229,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");
@@ -1241,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;
@@ -1259,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
@@ -1314,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,
@@ -1332,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,
@@ -1368,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
@@ -1379,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
@@ -1395,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
@@ -1446,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
@@ -1459,11 +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);
+ asStreamWithAssert()->replaceStreamData(sdp, filter, decode_parms);
}
std::map<std::string, QPDFObjectHandle>
@@ -1478,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 {
@@ -1648,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();
}
@@ -1675,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);
}
}
@@ -1696,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);
}
@@ -1917,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
@@ -1945,21 +1992,6 @@ QPDFObjectHandle::getParsedOffset()
}
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)
{
return QPDFObjectHandle(QPDF_Bool::create(value));
@@ -2128,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;
}
@@ -2155,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
@@ -2212,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);
@@ -2258,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() ||
@@ -2268,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(
@@ -2280,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(
@@ -2329,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");
}
@@ -2544,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."
@@ -2564,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 == nullptr) {
- std::shared_ptr<QPDFObject> obj =
- QPDF::Resolver::resolve(this->qpdf, getObjGen());
- if (obj == 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;
}
diff --git a/libqpdf/QPDFParser.cc b/libqpdf/QPDFParser.cc
index ccdd9db0..9aa1f426 100644
--- a/libqpdf/QPDFParser.cc
+++ b/libqpdf/QPDFParser.cc
@@ -1,8 +1,8 @@
#include <qpdf/QPDFParser.hh>
#include <qpdf/QPDF.hh>
+#include <qpdf/QPDFObjGen.hh>
#include <qpdf/QPDFObjectHandle.hh>
-#include <qpdf/QPDF_Array.hh>
#include <qpdf/QTC.hh>
#include <qpdf/QUtil.hh>
@@ -55,6 +55,7 @@ QPDFParser::parse(bool& empty, bool content_stream)
while (!done) {
bool bad = false;
+ bool indirect_ref = false;
is_null = false;
auto& frame = stack.back();
auto& olist = frame.olist;
@@ -185,12 +186,16 @@ QPDFParser::parse(bool& empty, bool content_stream)
"QPDFObjectHandle::parse called without context"
" on an object with indirect references");
}
- // Try to resolve indirect objects
- object = QPDFObjectHandle::newIndirect(
- context,
- QPDFObjGen(
- olist.at(size - 2).getIntValueAsInt(),
- olist.back().getIntValueAsInt()));
+ auto ref_og = QPDFObjGen(
+ olist.at(size - 2).getIntValueAsInt(),
+ olist.back().getIntValueAsInt());
+ if (ref_og.isIndirect()) {
+ object = context->getObject(ref_og);
+ indirect_ref = true;
+ } else {
+ QTC::TC("qpdf", "QPDFParser indirect with 0 objid");
+ is_null = true;
+ }
olist.pop_back();
olist.pop_back();
} else if ((value == "endobj") && (state == st_top)) {
@@ -274,8 +279,8 @@ QPDFParser::parse(bool& empty, bool content_stream)
case st_dictionary:
case st_array:
- if (!object.isDirectNull()) {
- // No need to set description for direct nulls- they will
+ if (!indirect_ref && !object.isDirectNull()) {
+ // No need to set description for direct nulls - they will
// become implicit.
setDescriptionFromInput(object, input->getLastOffset());
object.setParsedOffset(input->getLastOffset());
diff --git a/libqpdf/QPDFValue.cc b/libqpdf/QPDFValue.cc
new file mode 100644
index 00000000..8a6222d2
--- /dev/null
+++ b/libqpdf/QPDFValue.cc
@@ -0,0 +1,11 @@
+#include <qpdf/QPDFValue.hh>
+
+#include <qpdf/QPDFObject.hh>
+
+std::shared_ptr<QPDFObject>
+QPDFValue::do_create(QPDFValue* object)
+{
+ std::shared_ptr<QPDFObject> obj(new QPDFObject());
+ obj->value = std::shared_ptr<QPDFValue>(object);
+ return obj;
+}
diff --git a/libqpdf/QPDF_Array.cc b/libqpdf/QPDF_Array.cc
index 55e4d20a..63fe98d4 100644
--- a/libqpdf/QPDF_Array.cc
+++ b/libqpdf/QPDF_Array.cc
@@ -4,12 +4,14 @@
#include <qpdf/QUtil.hh>
#include <stdexcept>
-QPDF_Array::QPDF_Array(std::vector<QPDFObjectHandle> const& v)
+QPDF_Array::QPDF_Array(std::vector<QPDFObjectHandle> const& v) :
+ QPDFValue(::ot_array, "array")
{
setFromVector(v);
}
QPDF_Array::QPDF_Array(SparseOHArray const& items) :
+ QPDFValue(::ot_array, "array"),
elements(items)
{
}
@@ -62,18 +64,6 @@ QPDF_Array::getJSON(int json_version)
return j;
}
-QPDFObject::object_type_e
-QPDF_Array::getTypeCode() const
-{
- return QPDFObject::ot_array;
-}
-
-char const*
-QPDF_Array::getTypeName() const
-{
- return "array";
-}
-
int
QPDF_Array::getNItems() const
{
diff --git a/libqpdf/QPDF_Bool.cc b/libqpdf/QPDF_Bool.cc
index f26325c3..efbfd6c9 100644
--- a/libqpdf/QPDF_Bool.cc
+++ b/libqpdf/QPDF_Bool.cc
@@ -1,6 +1,7 @@
#include <qpdf/QPDF_Bool.hh>
QPDF_Bool::QPDF_Bool(bool val) :
+ QPDFValue(::ot_boolean, "boolean"),
val(val)
{
}
@@ -29,18 +30,6 @@ QPDF_Bool::getJSON(int json_version)
return JSON::makeBool(this->val);
}
-QPDFObject::object_type_e
-QPDF_Bool::getTypeCode() const
-{
- return QPDFObject::ot_boolean;
-}
-
-char const*
-QPDF_Bool::getTypeName() const
-{
- return "boolean";
-}
-
bool
QPDF_Bool::getVal() const
{
diff --git a/libqpdf/QPDF_Dictionary.cc b/libqpdf/QPDF_Dictionary.cc
index 60b2339f..845bcad8 100644
--- a/libqpdf/QPDF_Dictionary.cc
+++ b/libqpdf/QPDF_Dictionary.cc
@@ -1,10 +1,10 @@
#include <qpdf/QPDF_Dictionary.hh>
#include <qpdf/QPDF_Name.hh>
-#include <qpdf/QPDF_Null.hh>
QPDF_Dictionary::QPDF_Dictionary(
std::map<std::string, QPDFObjectHandle> const& items) :
+ QPDFValue(::ot_dictionary, "dictionary"),
items(items)
{
}
@@ -58,18 +58,6 @@ QPDF_Dictionary::getJSON(int json_version)
return j;
}
-QPDFObject::object_type_e
-QPDF_Dictionary::getTypeCode() const
-{
- return QPDFObject::ot_dictionary;
-}
-
-char const*
-QPDF_Dictionary::getTypeName() const
-{
- return "dictionary";
-}
-
bool
QPDF_Dictionary::hasKey(std::string const& key)
{
diff --git a/libqpdf/QPDF_InlineImage.cc b/libqpdf/QPDF_InlineImage.cc
index c3c656e0..76318196 100644
--- a/libqpdf/QPDF_InlineImage.cc
+++ b/libqpdf/QPDF_InlineImage.cc
@@ -1,6 +1,7 @@
#include <qpdf/QPDF_InlineImage.hh>
QPDF_InlineImage::QPDF_InlineImage(std::string const& val) :
+ QPDFValue(::ot_inlineimage, "inline-image"),
val(val)
{
}
@@ -29,18 +30,6 @@ QPDF_InlineImage::getJSON(int json_version)
return JSON::makeNull();
}
-QPDFObject::object_type_e
-QPDF_InlineImage::getTypeCode() const
-{
- return QPDFObject::ot_inlineimage;
-}
-
-char const*
-QPDF_InlineImage::getTypeName() const
-{
- return "inline-image";
-}
-
std::string
QPDF_InlineImage::getVal() const
{
diff --git a/libqpdf/QPDF_Integer.cc b/libqpdf/QPDF_Integer.cc
index e8d23e4a..24812573 100644
--- a/libqpdf/QPDF_Integer.cc
+++ b/libqpdf/QPDF_Integer.cc
@@ -3,6 +3,7 @@
#include <qpdf/QUtil.hh>
QPDF_Integer::QPDF_Integer(long long val) :
+ QPDFValue(::ot_integer, "integer"),
val(val)
{
}
@@ -31,18 +32,6 @@ QPDF_Integer::getJSON(int json_version)
return JSON::makeInt(this->val);
}
-QPDFObject::object_type_e
-QPDF_Integer::getTypeCode() const
-{
- return QPDFObject::ot_integer;
-}
-
-char const*
-QPDF_Integer::getTypeName() const
-{
- return "integer";
-}
-
long long
QPDF_Integer::getVal() const
{
diff --git a/libqpdf/QPDF_Name.cc b/libqpdf/QPDF_Name.cc
index 73990775..c86d34b4 100644
--- a/libqpdf/QPDF_Name.cc
+++ b/libqpdf/QPDF_Name.cc
@@ -5,6 +5,7 @@
#include <string.h>
QPDF_Name::QPDF_Name(std::string const& name) :
+ QPDFValue(::ot_name, "name"),
name(name)
{
}
@@ -61,18 +62,6 @@ QPDF_Name::getJSON(int json_version)
}
}
-QPDFObject::object_type_e
-QPDF_Name::getTypeCode() const
-{
- return QPDFObject::ot_name;
-}
-
-char const*
-QPDF_Name::getTypeName() const
-{
- return "name";
-}
-
std::string
QPDF_Name::getName() const
{
diff --git a/libqpdf/QPDF_Null.cc b/libqpdf/QPDF_Null.cc
index b015ed8b..f60dda1f 100644
--- a/libqpdf/QPDF_Null.cc
+++ b/libqpdf/QPDF_Null.cc
@@ -1,5 +1,10 @@
#include <qpdf/QPDF_Null.hh>
+QPDF_Null::QPDF_Null() :
+ QPDFValue(::ot_null, "null")
+{
+}
+
std::shared_ptr<QPDFObject>
QPDF_Null::create()
{
@@ -23,15 +28,3 @@ QPDF_Null::getJSON(int json_version)
{
return JSON::makeNull();
}
-
-QPDFObject::object_type_e
-QPDF_Null::getTypeCode() const
-{
- return QPDFObject::ot_null;
-}
-
-char const*
-QPDF_Null::getTypeName() const
-{
- return "null";
-}
diff --git a/libqpdf/QPDF_Operator.cc b/libqpdf/QPDF_Operator.cc
index cd5009ae..547ff40a 100644
--- a/libqpdf/QPDF_Operator.cc
+++ b/libqpdf/QPDF_Operator.cc
@@ -1,6 +1,7 @@
#include <qpdf/QPDF_Operator.hh>
QPDF_Operator::QPDF_Operator(std::string const& val) :
+ QPDFValue(::ot_operator, "operator"),
val(val)
{
}
@@ -20,7 +21,7 @@ QPDF_Operator::shallowCopy()
std::string
QPDF_Operator::unparse()
{
- return this->val;
+ return val;
}
JSON
@@ -29,18 +30,6 @@ QPDF_Operator::getJSON(int json_version)
return JSON::makeNull();
}
-QPDFObject::object_type_e
-QPDF_Operator::getTypeCode() const
-{
- return QPDFObject::ot_operator;
-}
-
-char const*
-QPDF_Operator::getTypeName() const
-{
- return "operator";
-}
-
std::string
QPDF_Operator::getVal() const
{
diff --git a/libqpdf/QPDF_Real.cc b/libqpdf/QPDF_Real.cc
index 138bbb3c..85c9ceeb 100644
--- a/libqpdf/QPDF_Real.cc
+++ b/libqpdf/QPDF_Real.cc
@@ -3,12 +3,14 @@
#include <qpdf/QUtil.hh>
QPDF_Real::QPDF_Real(std::string const& val) :
+ QPDFValue(::ot_real, "real"),
val(val)
{
}
QPDF_Real::QPDF_Real(
double value, int decimal_places, bool trim_trailing_zeroes) :
+ QPDFValue(::ot_real, "real"),
val(QUtil::double_to_string(value, decimal_places, trim_trailing_zeroes))
{
}
@@ -60,18 +62,6 @@ QPDF_Real::getJSON(int json_version)
return JSON::makeNumber(result);
}
-QPDFObject::object_type_e
-QPDF_Real::getTypeCode() const
-{
- return QPDFObject::ot_real;
-}
-
-char const*
-QPDF_Real::getTypeName() const
-{
- return "real";
-}
-
std::string
QPDF_Real::getVal()
{
diff --git a/libqpdf/QPDF_Reserved.cc b/libqpdf/QPDF_Reserved.cc
index 5808a369..f5af4688 100644
--- a/libqpdf/QPDF_Reserved.cc
+++ b/libqpdf/QPDF_Reserved.cc
@@ -2,6 +2,11 @@
#include <stdexcept>
+QPDF_Reserved::QPDF_Reserved() :
+ QPDFValue(::ot_reserved, "reserved")
+{
+}
+
std::shared_ptr<QPDFObject>
QPDF_Reserved::create()
{
@@ -17,25 +22,15 @@ QPDF_Reserved::shallowCopy()
std::string
QPDF_Reserved::unparse()
{
- throw std::logic_error("attempt to unparse QPDF_Reserved");
+ throw std::logic_error(
+ "QPDFObjectHandle: attempting to unparse a reserved object");
return "";
}
JSON
QPDF_Reserved::getJSON(int json_version)
{
- throw std::logic_error("attempt to generate JSON from QPDF_Reserved");
+ throw std::logic_error(
+ "QPDFObjectHandle: attempting to unparse a reserved object");
return JSON::makeNull();
}
-
-QPDFObject::object_type_e
-QPDF_Reserved::getTypeCode() const
-{
- return QPDFObject::ot_reserved;
-}
-
-char const*
-QPDF_Reserved::getTypeName() const
-{
- return "reserved";
-}
diff --git a/libqpdf/QPDF_Stream.cc b/libqpdf/QPDF_Stream.cc
index 1b7f9461..9932c15d 100644
--- a/libqpdf/QPDF_Stream.cc
+++ b/libqpdf/QPDF_Stream.cc
@@ -114,6 +114,7 @@ QPDF_Stream::QPDF_Stream(
QPDFObjectHandle stream_dict,
qpdf_offset_t offset,
size_t length) :
+ QPDFValue(::ot_stream, "stream"),
qpdf(qpdf),
og(og),
filter_on_write(true),
@@ -291,22 +292,10 @@ QPDF_Stream::getStreamJSON(
return result;
}
-QPDFObject::object_type_e
-QPDF_Stream::getTypeCode() const
-{
- return QPDFObject::ot_stream;
-}
-
-char const*
-QPDF_Stream::getTypeName() const
-{
- return "stream";
-}
-
void
QPDF_Stream::setDescription(QPDF* qpdf, std::string const& description)
{
- this->QPDFObject::setDescription(qpdf, description);
+ this->QPDFValue::setDescription(qpdf, description);
setDictDescription();
}
diff --git a/libqpdf/QPDF_String.cc b/libqpdf/QPDF_String.cc
index b038366b..c6cb6c41 100644
--- a/libqpdf/QPDF_String.cc
+++ b/libqpdf/QPDF_String.cc
@@ -21,6 +21,7 @@ is_iso_latin1_printable(char ch)
}
QPDF_String::QPDF_String(std::string const& val) :
+ QPDFValue(::ot_string, "string"),
val(val)
{
}
@@ -84,18 +85,6 @@ QPDF_String::getJSON(int json_version)
return JSON::makeString(result);
}
-QPDFObject::object_type_e
-QPDF_String::getTypeCode() const
-{
- return QPDFObject::ot_string;
-}
-
-char const*
-QPDF_String::getTypeName() const
-{
- return "string";
-}
-
bool
QPDF_String::useHexString() const
{
diff --git a/libqpdf/QPDF_Unresolved.cc b/libqpdf/QPDF_Unresolved.cc
new file mode 100644
index 00000000..f824a9a6
--- /dev/null
+++ b/libqpdf/QPDF_Unresolved.cc
@@ -0,0 +1,36 @@
+#include <qpdf/QPDF_Unresolved.hh>
+
+#include <stdexcept>
+
+QPDF_Unresolved::QPDF_Unresolved(QPDF* qpdf, QPDFObjGen const& og) :
+ QPDFValue(::ot_unresolved, "unresolved", qpdf, og)
+{
+}
+
+std::shared_ptr<QPDFObject>
+QPDF_Unresolved::create(QPDF* qpdf, QPDFObjGen const& og)
+{
+ return do_create(new QPDF_Unresolved(qpdf, og));
+}
+
+std::shared_ptr<QPDFObject>
+QPDF_Unresolved::shallowCopy()
+{
+ throw std::logic_error(
+ "attempted to shallow copy unresolved QPDFObjectHandle");
+ return create(qpdf, og);
+}
+
+std::string
+QPDF_Unresolved::unparse()
+{
+ throw std::logic_error(
+ "attempted to unparse an unresolved QPDFObjectHandle");
+ return "";
+}
+
+JSON
+QPDF_Unresolved::getJSON(int json_version)
+{
+ return JSON::makeNull();
+}
diff --git a/libqpdf/QPDF_linearization.cc b/libqpdf/QPDF_linearization.cc
index e988092e..e09f7b68 100644
--- a/libqpdf/QPDF_linearization.cc
+++ b/libqpdf/QPDF_linearization.cc
@@ -137,8 +137,7 @@ QPDF::isLinearized()
return false;
}
- QPDFObjectHandle candidate = QPDFObjectHandle::Factory::newIndirect(
- this, QPDFObjGen(lindict_obj, 0));
+ auto candidate = getObjectByID(lindict_obj, 0);
if (!candidate.isDictionary()) {
return false;
}
diff --git a/libqpdf/qpdf/QPDF_Array.hh b/libqpdf/qpdf/QPDF_Array.hh
index 3e095637..426efe36 100644
--- a/libqpdf/qpdf/QPDF_Array.hh
+++ b/libqpdf/qpdf/QPDF_Array.hh
@@ -1,13 +1,13 @@
#ifndef QPDF_ARRAY_HH
#define QPDF_ARRAY_HH
-#include <qpdf/QPDFObject.hh>
+#include <qpdf/QPDFValue.hh>
#include <qpdf/SparseOHArray.hh>
#include <list>
#include <vector>
-class QPDF_Array: public QPDFObject
+class QPDF_Array: public QPDFValue
{
public:
virtual ~QPDF_Array() = default;
@@ -17,8 +17,6 @@ class QPDF_Array: public QPDFObject
virtual std::shared_ptr<QPDFObject> shallowCopy();
virtual std::string unparse();
virtual JSON getJSON(int json_version);
- virtual QPDFObject::object_type_e getTypeCode() const;
- virtual char const* getTypeName() const;
int getNItems() const;
QPDFObjectHandle getItem(int n) const;
diff --git a/libqpdf/qpdf/QPDF_Bool.hh b/libqpdf/qpdf/QPDF_Bool.hh
index dbedc70a..3e45cd8e 100644
--- a/libqpdf/qpdf/QPDF_Bool.hh
+++ b/libqpdf/qpdf/QPDF_Bool.hh
@@ -1,9 +1,9 @@
#ifndef QPDF_BOOL_HH
#define QPDF_BOOL_HH
-#include <qpdf/QPDFObject.hh>
+#include <qpdf/QPDFValue.hh>
-class QPDF_Bool: public QPDFObject
+class QPDF_Bool: public QPDFValue
{
public:
virtual ~QPDF_Bool() = default;
@@ -11,8 +11,6 @@ class QPDF_Bool: public QPDFObject
virtual std::shared_ptr<QPDFObject> shallowCopy();
virtual std::string unparse();
virtual JSON getJSON(int json_version);
- virtual QPDFObject::object_type_e getTypeCode() const;
- virtual char const* getTypeName() const;
bool getVal() const;
private:
diff --git a/libqpdf/qpdf/QPDF_Dictionary.hh b/libqpdf/qpdf/QPDF_Dictionary.hh
index cacc8961..19ab8d9b 100644
--- a/libqpdf/qpdf/QPDF_Dictionary.hh
+++ b/libqpdf/qpdf/QPDF_Dictionary.hh
@@ -1,14 +1,14 @@
#ifndef QPDF_DICTIONARY_HH
#define QPDF_DICTIONARY_HH
-#include <qpdf/QPDFObject.hh>
+#include <qpdf/QPDFValue.hh>
#include <map>
#include <set>
#include <qpdf/QPDFObjectHandle.hh>
-class QPDF_Dictionary: public QPDFObject
+class QPDF_Dictionary: public QPDFValue
{
public:
virtual ~QPDF_Dictionary() = default;
@@ -17,8 +17,6 @@ class QPDF_Dictionary: public QPDFObject
virtual std::shared_ptr<QPDFObject> shallowCopy();
virtual std::string unparse();
virtual JSON getJSON(int json_version);
- virtual QPDFObject::object_type_e getTypeCode() const;
- virtual char const* getTypeName() const;
// hasKey() and getKeys() treat keys with null values as if they
// aren't there. getKey() returns null for the value of a
diff --git a/libqpdf/qpdf/QPDF_InlineImage.hh b/libqpdf/qpdf/QPDF_InlineImage.hh
index caaeaf87..b7bea9c7 100644
--- a/libqpdf/qpdf/QPDF_InlineImage.hh
+++ b/libqpdf/qpdf/QPDF_InlineImage.hh
@@ -1,9 +1,9 @@
#ifndef QPDF_INLINEIMAGE_HH
#define QPDF_INLINEIMAGE_HH
-#include <qpdf/QPDFObject.hh>
+#include <qpdf/QPDFValue.hh>
-class QPDF_InlineImage: public QPDFObject
+class QPDF_InlineImage: public QPDFValue
{
public:
virtual ~QPDF_InlineImage() = default;
@@ -11,8 +11,6 @@ class QPDF_InlineImage: public QPDFObject
virtual std::shared_ptr<QPDFObject> shallowCopy();
virtual std::string unparse();
virtual JSON getJSON(int json_version);
- virtual QPDFObject::object_type_e getTypeCode() const;
- virtual char const* getTypeName() const;
std::string getVal() const;
private:
diff --git a/libqpdf/qpdf/QPDF_Integer.hh b/libqpdf/qpdf/QPDF_Integer.hh
index 2c17daf0..7e09673c 100644
--- a/libqpdf/qpdf/QPDF_Integer.hh
+++ b/libqpdf/qpdf/QPDF_Integer.hh
@@ -1,9 +1,9 @@
#ifndef QPDF_INTEGER_HH
#define QPDF_INTEGER_HH
-#include <qpdf/QPDFObject.hh>
+#include <qpdf/QPDFValue.hh>
-class QPDF_Integer: public QPDFObject
+class QPDF_Integer: public QPDFValue
{
public:
virtual ~QPDF_Integer() = default;
@@ -11,8 +11,6 @@ class QPDF_Integer: public QPDFObject
virtual std::shared_ptr<QPDFObject> shallowCopy();
virtual std::string unparse();
virtual JSON getJSON(int json_version);
- virtual QPDFObject::object_type_e getTypeCode() const;
- virtual char const* getTypeName() const;
long long getVal() const;
private:
diff --git a/libqpdf/qpdf/QPDF_Name.hh b/libqpdf/qpdf/QPDF_Name.hh
index cf653b2e..74fc7e44 100644
--- a/libqpdf/qpdf/QPDF_Name.hh
+++ b/libqpdf/qpdf/QPDF_Name.hh
@@ -1,9 +1,9 @@
#ifndef QPDF_NAME_HH
#define QPDF_NAME_HH
-#include <qpdf/QPDFObject.hh>
+#include <qpdf/QPDFValue.hh>
-class QPDF_Name: public QPDFObject
+class QPDF_Name: public QPDFValue
{
public:
virtual ~QPDF_Name() = default;
@@ -11,8 +11,6 @@ class QPDF_Name: public QPDFObject
virtual std::shared_ptr<QPDFObject> shallowCopy();
virtual std::string unparse();
virtual JSON getJSON(int json_version);
- virtual QPDFObject::object_type_e getTypeCode() const;
- virtual char const* getTypeName() const;
std::string getName() const;
// Put # into strings with characters unsuitable for name token
diff --git a/libqpdf/qpdf/QPDF_Null.hh b/libqpdf/qpdf/QPDF_Null.hh
index 16833424..68973de9 100644
--- a/libqpdf/qpdf/QPDF_Null.hh
+++ b/libqpdf/qpdf/QPDF_Null.hh
@@ -1,9 +1,9 @@
#ifndef QPDF_NULL_HH
#define QPDF_NULL_HH
-#include <qpdf/QPDFObject.hh>
+#include <qpdf/QPDFValue.hh>
-class QPDF_Null: public QPDFObject
+class QPDF_Null: public QPDFValue
{
public:
virtual ~QPDF_Null() = default;
@@ -11,11 +11,9 @@ class QPDF_Null: public QPDFObject
virtual std::shared_ptr<QPDFObject> shallowCopy();
virtual std::string unparse();
virtual JSON getJSON(int json_version);
- virtual QPDFObject::object_type_e getTypeCode() const;
- virtual char const* getTypeName() const;
private:
- QPDF_Null() = default;
+ QPDF_Null();
};
#endif // QPDF_NULL_HH
diff --git a/libqpdf/qpdf/QPDF_Operator.hh b/libqpdf/qpdf/QPDF_Operator.hh
index 1da43d72..767c0ba0 100644
--- a/libqpdf/qpdf/QPDF_Operator.hh
+++ b/libqpdf/qpdf/QPDF_Operator.hh
@@ -1,9 +1,9 @@
#ifndef QPDF_OPERATOR_HH
#define QPDF_OPERATOR_HH
-#include <qpdf/QPDFObject.hh>
+#include <qpdf/QPDFValue.hh>
-class QPDF_Operator: public QPDFObject
+class QPDF_Operator: public QPDFValue
{
public:
virtual ~QPDF_Operator() = default;
@@ -11,8 +11,6 @@ class QPDF_Operator: public QPDFObject
virtual std::shared_ptr<QPDFObject> shallowCopy();
virtual std::string unparse();
virtual JSON getJSON(int json_version);
- virtual QPDFObject::object_type_e getTypeCode() const;
- virtual char const* getTypeName() const;
std::string getVal() const;
private:
diff --git a/libqpdf/qpdf/QPDF_Real.hh b/libqpdf/qpdf/QPDF_Real.hh
index f5ab4bd6..dc0f3ff8 100644
--- a/libqpdf/qpdf/QPDF_Real.hh
+++ b/libqpdf/qpdf/QPDF_Real.hh
@@ -1,9 +1,9 @@
#ifndef QPDF_REAL_HH
#define QPDF_REAL_HH
-#include <qpdf/QPDFObject.hh>
+#include <qpdf/QPDFValue.hh>
-class QPDF_Real: public QPDFObject
+class QPDF_Real: public QPDFValue
{
public:
virtual ~QPDF_Real() = default;
@@ -13,8 +13,6 @@ class QPDF_Real: public QPDFObject
virtual std::shared_ptr<QPDFObject> shallowCopy();
virtual std::string unparse();
virtual JSON getJSON(int json_version);
- virtual QPDFObject::object_type_e getTypeCode() const;
- virtual char const* getTypeName() const;
std::string getVal();
private:
diff --git a/libqpdf/qpdf/QPDF_Reserved.hh b/libqpdf/qpdf/QPDF_Reserved.hh
index 243a1728..f90242a9 100644
--- a/libqpdf/qpdf/QPDF_Reserved.hh
+++ b/libqpdf/qpdf/QPDF_Reserved.hh
@@ -1,9 +1,9 @@
#ifndef QPDF_RESERVED_HH
#define QPDF_RESERVED_HH
-#include <qpdf/QPDFObject.hh>
+#include <qpdf/QPDFValue.hh>
-class QPDF_Reserved: public QPDFObject
+class QPDF_Reserved: public QPDFValue
{
public:
virtual ~QPDF_Reserved() = default;
@@ -11,11 +11,9 @@ class QPDF_Reserved: public QPDFObject
virtual std::shared_ptr<QPDFObject> shallowCopy();
virtual std::string unparse();
virtual JSON getJSON(int json_version);
- virtual QPDFObject::object_type_e getTypeCode() const;
- virtual char const* getTypeName() const;
private:
- QPDF_Reserved() = default;
+ QPDF_Reserved();
};
#endif // QPDF_RESERVED_HH
diff --git a/libqpdf/qpdf/QPDF_Stream.hh b/libqpdf/qpdf/QPDF_Stream.hh
index 8980c751..3a16160e 100644
--- a/libqpdf/qpdf/QPDF_Stream.hh
+++ b/libqpdf/qpdf/QPDF_Stream.hh
@@ -3,9 +3,9 @@
#include <qpdf/Types.h>
-#include <qpdf/QPDFObject.hh>
#include <qpdf/QPDFObjectHandle.hh>
#include <qpdf/QPDFStreamFilter.hh>
+#include <qpdf/QPDFValue.hh>
#include <functional>
#include <memory>
@@ -13,7 +13,7 @@
class Pipeline;
class QPDF;
-class QPDF_Stream: public QPDFObject
+class QPDF_Stream: public QPDFValue
{
public:
virtual ~QPDF_Stream() = default;
@@ -26,8 +26,6 @@ class QPDF_Stream: public QPDFObject
virtual std::shared_ptr<QPDFObject> shallowCopy();
virtual std::string unparse();
virtual JSON getJSON(int json_version);
- virtual QPDFObject::object_type_e getTypeCode() const;
- virtual char const* getTypeName() const;
virtual void setDescription(QPDF*, std::string const&);
QPDFObjectHandle getDict() const;
bool isDataModified() const;
diff --git a/libqpdf/qpdf/QPDF_String.hh b/libqpdf/qpdf/QPDF_String.hh
index b6d77637..a92427e3 100644
--- a/libqpdf/qpdf/QPDF_String.hh
+++ b/libqpdf/qpdf/QPDF_String.hh
@@ -1,11 +1,11 @@
#ifndef QPDF_STRING_HH
#define QPDF_STRING_HH
-#include <qpdf/QPDFObject.hh>
+#include <qpdf/QPDFValue.hh>
// QPDF_Strings may included embedded null characters.
-class QPDF_String: public QPDFObject
+class QPDF_String: public QPDFValue
{
friend class QPDFWriter;
@@ -16,8 +16,6 @@ class QPDF_String: public QPDFObject
create_utf16(std::string const& utf8_val);
virtual std::shared_ptr<QPDFObject> shallowCopy();
virtual std::string unparse();
- virtual QPDFObject::object_type_e getTypeCode() const;
- virtual char const* getTypeName() const;
std::string unparse(bool force_binary);
virtual JSON getJSON(int json_version);
std::string getVal() const;
diff --git a/libqpdf/qpdf/QPDF_Unresolved.hh b/libqpdf/qpdf/QPDF_Unresolved.hh
new file mode 100644
index 00000000..efcf4e3d
--- /dev/null
+++ b/libqpdf/qpdf/QPDF_Unresolved.hh
@@ -0,0 +1,19 @@
+#ifndef QPDF_UNRESOLVED_HH
+#define QPDF_UNRESOLVED_HH
+
+#include <qpdf/QPDFValue.hh>
+
+class QPDF_Unresolved: public QPDFValue
+{
+ public:
+ virtual ~QPDF_Unresolved() = default;
+ static std::shared_ptr<QPDFObject> create(QPDF* qpdf, QPDFObjGen const& og);
+ virtual std::shared_ptr<QPDFObject> shallowCopy();
+ virtual std::string unparse();
+ virtual JSON getJSON(int json_version);
+
+ private:
+ QPDF_Unresolved(QPDF* qpdf, QPDFObjGen const& og);
+};
+
+#endif // QPDF_UNRESOLVED_HH
diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov
index f13385e4..c3ab0a07 100644
--- a/qpdf/qpdf.testcov
+++ b/qpdf/qpdf.testcov
@@ -254,7 +254,7 @@ QPDFWriter standard deterministic ID 1
QPDFWriter linearized deterministic ID 1
QPDFWriter deterministic with no data 0
qpdf-c called qpdf_set_deterministic_ID 0
-QPDFObjectHandle indirect with 0 objid 0
+QPDFParser indirect with 0 objid 0
QPDF object id 0 0
QPDF recursion loop in resolve 0
QPDFParser treat word as string 0
diff --git a/qpdf/qtest/qpdf/issue-51.out b/qpdf/qtest/qpdf/issue-51.out
index b4bd165c..feffea44 100644
--- a/qpdf/qtest/qpdf/issue-51.out
+++ b/qpdf/qtest/qpdf/issue-51.out
@@ -9,7 +9,6 @@ WARNING: issue-51.pdf (object 2 0, offset 26): /Length key in stream dictionary
WARNING: issue-51.pdf (object 2 0, offset 71): attempting to recover stream length
WARNING: issue-51.pdf (object 2 0, offset 71): unable to recover stream data; treating stream as empty
WARNING: issue-51.pdf (object 2 0, offset 977): expected endobj
-WARNING: issue-51.pdf (object 2 0, offset 977): EOF after endobj
WARNING: issue-51.pdf (object 3 0): object has offset 0
WARNING: issue-51.pdf (object 4 0): object has offset 0
WARNING: issue-51.pdf (object 5 0): object has offset 0
diff --git a/qpdf/qtest/type-checks.test b/qpdf/qtest/type-checks.test
index 03d75a6c..17b3c994 100644
--- a/qpdf/qtest/type-checks.test
+++ b/qpdf/qtest/type-checks.test
@@ -14,7 +14,7 @@ cleanup();
my $td = new TestDriver('type-checks');
-my $n_tests = 5;
+my $n_tests = 6;
# Whenever object-types.pdf is edited, object-types-os.pdf should be
# regenerated.
@@ -43,6 +43,10 @@ $td->runtest("compound type checks",
{$td->COMMAND => "test_driver 82 object-types-os.pdf"},
{$td->STRING => "test 82 done\n", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
+$td->runtest("indirect objects belonging to destroyed QPDF",
+ {$td->COMMAND => "test_driver 92 -"},
+ {$td->STRING => "test 92 done\n", $td->EXIT_STATUS => 0},
+ $td->NORMALIZE_NEWLINES);
cleanup();
$td->report($n_tests);
diff --git a/qpdf/test_driver.cc b/qpdf/test_driver.cc
index aa4f9ce5..5572e824 100644
--- a/qpdf/test_driver.cc
+++ b/qpdf/test_driver.cc
@@ -3258,6 +3258,20 @@ test_91(QPDF& pdf, char const* arg2)
2, &p, qpdf_dl_none, qpdf_sj_inline, "", std::set<std::string>());
}
+static void
+test_92(QPDF& pdf, char const* arg2)
+{
+ // Exercise indirect objects owned by destroyed QPDF object.
+ QPDF* qpdf = new QPDF();
+ qpdf->emptyPDF();
+ auto root = qpdf->getRoot();
+ assert(root.getOwningQPDF() != nullptr);
+ assert(root.isIndirect());
+ delete qpdf;
+ assert(root.getOwningQPDF() == nullptr);
+ assert(!root.isIndirect());
+}
+
void
runtest(int n, char const* filename1, char const* arg2)
{
@@ -3265,7 +3279,7 @@ runtest(int n, char const* filename1, char const* arg2)
// the test suite to see how the test is invoked to find the file
// that the test is supposed to operate on.
- std::set<int> ignore_filename = {61, 81, 83, 84, 85, 86, 87};
+ std::set<int> ignore_filename = {61, 81, 83, 84, 85, 86, 87, 92};
if (n == 0) {
// Throw in some random test cases that don't fit anywhere
@@ -3362,7 +3376,8 @@ runtest(int n, char const* filename1, char const* arg2)
{76, test_76}, {77, test_77}, {78, test_78}, {79, test_79},
{80, test_80}, {81, test_81}, {82, test_82}, {83, test_83},
{84, test_84}, {85, test_85}, {86, test_86}, {87, test_87},
- {88, test_88}, {89, test_89}, {90, test_90}, {91, test_91}};
+ {88, test_88}, {89, test_89}, {90, test_90}, {91, test_91},
+ {92, test_92}};
auto fn = test_functions.find(n);
if (fn == test_functions.end()) {