2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-06-02 10:20:52 +00:00

Refactor resolving of objects

This commit is contained in:
m-holger 2024-03-10 15:34:58 +00:00
parent e9166457fa
commit 1f3a6fa30c
6 changed files with 106 additions and 84 deletions

View File

@ -772,13 +772,20 @@ class QPDF
class Resolver class Resolver
{ {
friend class QPDFObject; friend class QPDFObject;
friend class QPDF_Unresolved;
private: private:
static void static void
resolve(QPDF* qpdf, QPDFObjGen const& og) resolve(QPDF* qpdf, QPDFObjGen og)
{ {
qpdf->resolve(og); qpdf->resolve(og);
} }
static QPDFObject*
getResolved(QPDF* qpdf, QPDFObjGen og)
{
qpdf->resolve(og);
return qpdf->m->obj_cache[og].object.get();
}
}; };
// StreamCopier class is restricted to QPDFObjectHandle so it can copy stream data. // StreamCopier class is restricted to QPDFObjectHandle so it can copy stream data.

View File

@ -1363,24 +1363,23 @@ class QPDFObjectHandle
void writeJSON(int json_version, JSON::Writer& p, bool dereference_indirect = false); void writeJSON(int json_version, JSON::Writer& p, bool dereference_indirect = false);
private: private:
QPDF_Array* asArray(); QPDF_Array* asArray() const;
QPDF_Bool* asBool(); QPDF_Bool* asBool() const;
QPDF_Dictionary* asDictionary(); QPDF_Dictionary* asDictionary() const;
QPDF_InlineImage* asInlineImage(); QPDF_InlineImage* asInlineImage() const;
QPDF_Integer* asInteger(); QPDF_Integer* asInteger() const;
QPDF_Name* asName(); QPDF_Name* asName() const;
QPDF_Null* asNull(); QPDF_Null* asNull() const;
QPDF_Operator* asOperator(); QPDF_Operator* asOperator() const;
QPDF_Real* asReal(); QPDF_Real* asReal() const;
QPDF_Reserved* asReserved(); QPDF_Reserved* asReserved() const;
QPDF_Stream* asStream(); QPDF_Stream* asStream() const;
QPDF_Stream* asStreamWithAssert(); QPDF_Stream* asStreamWithAssert();
QPDF_String* asString(); QPDF_String* asString() const;
void typeWarning(char const* expected_type, std::string const& warning); void typeWarning(char const* expected_type, std::string const& warning);
void objectWarning(std::string const& warning); void objectWarning(std::string const& warning);
void assertType(char const* type_name, bool istype); void assertType(char const* type_name, bool istype);
inline bool dereference();
void makeDirect(QPDFObjGen::set& visited, bool stop_at_streams); void makeDirect(QPDFObjGen::set& visited, bool stop_at_streams);
void disconnect(); void disconnect();
void setParsedOffset(qpdf_offset_t offset); void setParsedOffset(qpdf_offset_t offset);

View File

@ -240,79 +240,79 @@ QPDFObjectHandle::disconnect()
qpdf_object_type_e qpdf_object_type_e
QPDFObjectHandle::getTypeCode() QPDFObjectHandle::getTypeCode()
{ {
return dereference() ? this->obj->getTypeCode() : ::ot_uninitialized; return isInitialized() ? obj->getResolvedTypeCode() : ::ot_uninitialized;
} }
char const* char const*
QPDFObjectHandle::getTypeName() QPDFObjectHandle::getTypeName()
{ {
return dereference() ? this->obj->getTypeName() : "uninitialized"; return isInitialized() ? this->obj->getTypeName() : "uninitialized";
} }
QPDF_Array* QPDF_Array*
QPDFObjectHandle::asArray() QPDFObjectHandle::asArray() const
{ {
return dereference() ? obj->as<QPDF_Array>() : nullptr; return isInitialized() ? obj->as<QPDF_Array>() : nullptr;
} }
QPDF_Bool* QPDF_Bool*
QPDFObjectHandle::asBool() QPDFObjectHandle::asBool() const
{ {
return dereference() ? obj->as<QPDF_Bool>() : nullptr; return isInitialized() ? obj->as<QPDF_Bool>() : nullptr;
} }
QPDF_Dictionary* QPDF_Dictionary*
QPDFObjectHandle::asDictionary() QPDFObjectHandle::asDictionary() const
{ {
return dereference() ? obj->as<QPDF_Dictionary>() : nullptr; return isInitialized() ? obj->as<QPDF_Dictionary>() : nullptr;
} }
QPDF_InlineImage* QPDF_InlineImage*
QPDFObjectHandle::asInlineImage() QPDFObjectHandle::asInlineImage() const
{ {
return dereference() ? obj->as<QPDF_InlineImage>() : nullptr; return isInitialized() ? obj->as<QPDF_InlineImage>() : nullptr;
} }
QPDF_Integer* QPDF_Integer*
QPDFObjectHandle::asInteger() QPDFObjectHandle::asInteger() const
{ {
return dereference() ? obj->as<QPDF_Integer>() : nullptr; return isInitialized() ? obj->as<QPDF_Integer>() : nullptr;
} }
QPDF_Name* QPDF_Name*
QPDFObjectHandle::asName() QPDFObjectHandle::asName() const
{ {
return dereference() ? obj->as<QPDF_Name>() : nullptr; return isInitialized() ? obj->as<QPDF_Name>() : nullptr;
} }
QPDF_Null* QPDF_Null*
QPDFObjectHandle::asNull() QPDFObjectHandle::asNull() const
{ {
return dereference() ? obj->as<QPDF_Null>() : nullptr; return isInitialized() ? obj->as<QPDF_Null>() : nullptr;
} }
QPDF_Operator* QPDF_Operator*
QPDFObjectHandle::asOperator() QPDFObjectHandle::asOperator() const
{ {
return dereference() ? obj->as<QPDF_Operator>() : nullptr; return isInitialized() ? obj->as<QPDF_Operator>() : nullptr;
} }
QPDF_Real* QPDF_Real*
QPDFObjectHandle::asReal() QPDFObjectHandle::asReal() const
{ {
return dereference() ? obj->as<QPDF_Real>() : nullptr; return isInitialized() ? obj->as<QPDF_Real>() : nullptr;
} }
QPDF_Reserved* QPDF_Reserved*
QPDFObjectHandle::asReserved() QPDFObjectHandle::asReserved() const
{ {
return dereference() ? obj->as<QPDF_Reserved>() : nullptr; return isInitialized() ? obj->as<QPDF_Reserved>() : nullptr;
} }
QPDF_Stream* QPDF_Stream*
QPDFObjectHandle::asStream() QPDFObjectHandle::asStream() const
{ {
return dereference() ? obj->as<QPDF_Stream>() : nullptr; return isInitialized() ? obj->as<QPDF_Stream>() : nullptr;
} }
QPDF_Stream* QPDF_Stream*
@ -324,21 +324,21 @@ QPDFObjectHandle::asStreamWithAssert()
} }
QPDF_String* QPDF_String*
QPDFObjectHandle::asString() QPDFObjectHandle::asString() const
{ {
return dereference() ? obj->as<QPDF_String>() : nullptr; return isInitialized() ? obj->as<QPDF_String>() : nullptr;
} }
bool bool
QPDFObjectHandle::isDestroyed() QPDFObjectHandle::isDestroyed()
{ {
return dereference() && (obj->getTypeCode() == ::ot_destroyed); return isInitialized() && (obj->getResolvedTypeCode() == ::ot_destroyed);
} }
bool bool
QPDFObjectHandle::isBool() QPDFObjectHandle::isBool()
{ {
return dereference() && (obj->getTypeCode() == ::ot_boolean); return isInitialized() && (obj->getResolvedTypeCode() == ::ot_boolean);
} }
bool bool
@ -352,19 +352,19 @@ QPDFObjectHandle::isDirectNull() const
bool bool
QPDFObjectHandle::isNull() QPDFObjectHandle::isNull()
{ {
return dereference() && (obj->getTypeCode() == ::ot_null); return isInitialized() && (obj->getResolvedTypeCode() == ::ot_null);
} }
bool bool
QPDFObjectHandle::isInteger() QPDFObjectHandle::isInteger()
{ {
return dereference() && (obj->getTypeCode() == ::ot_integer); return isInitialized() && (obj->getResolvedTypeCode() == ::ot_integer);
} }
bool bool
QPDFObjectHandle::isReal() QPDFObjectHandle::isReal()
{ {
return dereference() && (obj->getTypeCode() == ::ot_real); return isInitialized() && (obj->getResolvedTypeCode() == ::ot_real);
} }
bool bool
@ -401,49 +401,49 @@ QPDFObjectHandle::getValueAsNumber(double& value)
bool bool
QPDFObjectHandle::isName() QPDFObjectHandle::isName()
{ {
return dereference() && (obj->getTypeCode() == ::ot_name); return isInitialized() && (obj->getResolvedTypeCode() == ::ot_name);
} }
bool bool
QPDFObjectHandle::isString() QPDFObjectHandle::isString()
{ {
return dereference() && (obj->getTypeCode() == ::ot_string); return isInitialized() && (obj->getResolvedTypeCode() == ::ot_string);
} }
bool bool
QPDFObjectHandle::isOperator() QPDFObjectHandle::isOperator()
{ {
return dereference() && (obj->getTypeCode() == ::ot_operator); return isInitialized() && (obj->getResolvedTypeCode() == ::ot_operator);
} }
bool bool
QPDFObjectHandle::isInlineImage() QPDFObjectHandle::isInlineImage()
{ {
return dereference() && (obj->getTypeCode() == ::ot_inlineimage); return isInitialized() && (obj->getResolvedTypeCode() == ::ot_inlineimage);
} }
bool bool
QPDFObjectHandle::isArray() QPDFObjectHandle::isArray()
{ {
return dereference() && (obj->getTypeCode() == ::ot_array); return isInitialized() && (obj->getResolvedTypeCode() == ::ot_array);
} }
bool bool
QPDFObjectHandle::isDictionary() QPDFObjectHandle::isDictionary()
{ {
return dereference() && (obj->getTypeCode() == ::ot_dictionary); return isInitialized() && (obj->getResolvedTypeCode() == ::ot_dictionary);
} }
bool bool
QPDFObjectHandle::isStream() QPDFObjectHandle::isStream()
{ {
return dereference() && (obj->getTypeCode() == ::ot_stream); return isInitialized() && (obj->getResolvedTypeCode() == ::ot_stream);
} }
bool bool
QPDFObjectHandle::isReserved() QPDFObjectHandle::isReserved()
{ {
return dereference() && (obj->getTypeCode() == ::ot_reserved); return isInitialized() && (obj->getResolvedTypeCode() == ::ot_reserved);
} }
bool bool
@ -1586,7 +1586,7 @@ QPDFObjectHandle::unparse()
std::string std::string
QPDFObjectHandle::unparseResolved() QPDFObjectHandle::unparseResolved()
{ {
if (!dereference()) { if (!isInitialized()) {
throw std::logic_error("attempted to dereference an uninitialized QPDFObjectHandle"); throw std::logic_error("attempted to dereference an uninitialized QPDFObjectHandle");
} }
return obj->unparse(); return obj->unparse();
@ -1615,7 +1615,7 @@ QPDFObjectHandle::getJSON(int json_version, bool dereference_indirect)
{ {
if ((!dereference_indirect) && isIndirect()) { if ((!dereference_indirect) && isIndirect()) {
return JSON::makeString(unparse()); return JSON::makeString(unparse());
} else if (!dereference()) { } else if (!isInitialized()) {
throw std::logic_error("attempted to dereference an uninitialized QPDFObjectHandle"); throw std::logic_error("attempted to dereference an uninitialized QPDFObjectHandle");
} else { } else {
Pl_Buffer p{"json"}; Pl_Buffer p{"json"};
@ -1631,7 +1631,7 @@ QPDFObjectHandle::writeJSON(int json_version, JSON::Writer& p, bool dereference_
{ {
if (!dereference_indirect && isIndirect()) { if (!dereference_indirect && isIndirect()) {
p << "\"" << getObjGen().unparse(' ') << " R\""; p << "\"" << getObjGen().unparse(' ') << " R\"";
} else if (!dereference()) { } else if (!isInitialized()) {
throw std::logic_error("attempted to dereference an uninitialized QPDFObjectHandle"); throw std::logic_error("attempted to dereference an uninitialized QPDFObjectHandle");
} else { } else {
obj->writeJSON(json_version, p); obj->writeJSON(json_version, p);
@ -1874,7 +1874,7 @@ QPDFObjectHandle::parse(
qpdf_offset_t qpdf_offset_t
QPDFObjectHandle::getParsedOffset() QPDFObjectHandle::getParsedOffset()
{ {
if (dereference()) { if (isInitialized()) {
return this->obj->getParsedOffset(); return this->obj->getParsedOffset();
} else { } else {
return -1; return -1;
@ -2066,13 +2066,13 @@ QPDFObjectHandle::setObjectDescription(QPDF* owning_qpdf, std::string const& obj
bool bool
QPDFObjectHandle::hasObjectDescription() QPDFObjectHandle::hasObjectDescription()
{ {
return dereference() && obj.get() && obj->hasDescription(); return isInitialized() && obj->hasDescription();
} }
QPDFObjectHandle QPDFObjectHandle
QPDFObjectHandle::shallowCopy() QPDFObjectHandle::shallowCopy()
{ {
if (!dereference()) { if (!isInitialized()) {
throw std::logic_error("operation attempted on uninitialized QPDFObjectHandle"); throw std::logic_error("operation attempted on uninitialized QPDFObjectHandle");
} }
return {obj->copy()}; return {obj->copy()};
@ -2081,7 +2081,7 @@ QPDFObjectHandle::shallowCopy()
QPDFObjectHandle QPDFObjectHandle
QPDFObjectHandle::unsafeShallowCopy() QPDFObjectHandle::unsafeShallowCopy()
{ {
if (!dereference()) { if (!isInitialized()) {
throw std::logic_error("operation attempted on uninitialized QPDFObjectHandle"); throw std::logic_error("operation attempted on uninitialized QPDFObjectHandle");
} }
return {obj->copy(true)}; return {obj->copy(true)};
@ -2172,7 +2172,7 @@ QPDFObjectHandle::typeWarning(char const* expected_type, std::string const& warn
std::string description; std::string description;
// Type checks above guarantee that the object has been dereferenced. Nevertheless, dereference // Type checks above guarantee that the object has been dereferenced. Nevertheless, dereference
// throws exceptions in the test suite // throws exceptions in the test suite
if (!dereference()) { if (!isInitialized()) {
throw std::logic_error("attempted to dereference an uninitialized QPDFObjectHandle"); throw std::logic_error("attempted to dereference an uninitialized QPDFObjectHandle");
} }
this->obj->getDescription(context, description); this->obj->getDescription(context, description);
@ -2193,7 +2193,7 @@ QPDFObjectHandle::warnIfPossible(std::string const& warning)
{ {
QPDF* context = nullptr; QPDF* context = nullptr;
std::string description; std::string description;
if (dereference() && obj->getDescription(context, description)) { if (isInitialized() && obj->getDescription(context, description)) {
warn(context, QPDFExc(qpdf_e_damaged_pdf, "", description, 0, warning)); warn(context, QPDFExc(qpdf_e_damaged_pdf, "", description, 0, warning));
} else { } else {
*QPDFLogger::defaultLogger()->getError() << warning << "\n"; *QPDFLogger::defaultLogger()->getError() << warning << "\n";
@ -2372,16 +2372,6 @@ QPDFObjectHandle::assertPageObject()
} }
} }
inline bool
QPDFObjectHandle::dereference()
{
if (!isInitialized()) {
return false;
}
this->obj->resolve();
return true;
}
void void
QPDFObjectHandle::warn(QPDF* qpdf, QPDFExc const& e) QPDFObjectHandle::warn(QPDF* qpdf, QPDFExc const& e)
{ {

View File

@ -1,6 +1,7 @@
#include <qpdf/QPDF_Unresolved.hh> #include <qpdf/QPDF_Unresolved.hh>
#include <stdexcept> #include <qpdf/QPDF.hh>
#include <qpdf/QPDFObject_private.hh>
QPDF_Unresolved::QPDF_Unresolved(QPDF* qpdf, QPDFObjGen const& og) : QPDF_Unresolved::QPDF_Unresolved(QPDF* qpdf, QPDFObjGen const& og) :
QPDFValue(::ot_unresolved, "unresolved", qpdf, og) QPDFValue(::ot_unresolved, "unresolved", qpdf, og)
@ -16,19 +17,23 @@ QPDF_Unresolved::create(QPDF* qpdf, QPDFObjGen const& og)
std::shared_ptr<QPDFObject> std::shared_ptr<QPDFObject>
QPDF_Unresolved::copy(bool shallow) QPDF_Unresolved::copy(bool shallow)
{ {
throw std::logic_error("attempted to shallow copy an unresolved QPDFObjectHandle"); return QPDF::Resolver::getResolved(qpdf, og)->copy(shallow);
return nullptr;
} }
std::string std::string
QPDF_Unresolved::unparse() QPDF_Unresolved::unparse()
{ {
throw std::logic_error("attempted to unparse an unresolved QPDFObjectHandle"); return QPDF::Resolver::getResolved(qpdf, og)->unparse();
return "";
} }
void void
QPDF_Unresolved::writeJSON(int json_version, JSON::Writer& p) QPDF_Unresolved::writeJSON(int json_version, JSON::Writer& p)
{ {
throw std::logic_error("attempted to get JSON from an unresolved QPDFObjectHandle"); QPDF::Resolver::getResolved(qpdf, og)->writeJSON(json_version, p);
} }
std::string
QPDF_Unresolved::getStringValue() const
{
return QPDF::Resolver::getResolved(qpdf, og)->getStringValue();
}

View File

@ -5,8 +5,8 @@
// include/qpdf/QPDFObject.hh. See comments there for an explanation. // include/qpdf/QPDFObject.hh. See comments there for an explanation.
#include <qpdf/Constants.h> #include <qpdf/Constants.h>
#include <qpdf/DLL.h>
#include <qpdf/JSON.hh> #include <qpdf/JSON.hh>
#include <qpdf/QPDF.hh>
#include <qpdf/QPDFValue.hh> #include <qpdf/QPDFValue.hh>
#include <qpdf/Types.h> #include <qpdf/Types.h>
@ -43,18 +43,26 @@ class QPDFObject
{ {
return value->getStringValue(); return value->getStringValue();
} }
// Return a unique type code for the resolved object
qpdf_object_type_e
getResolvedTypeCode() const
{
auto tc = value->type_code;
return tc == ::ot_unresolved
? QPDF::Resolver::getResolved(value->qpdf, value->og)->value->type_code
: tc;
}
// Return a unique type code for the object // Return a unique type code for the object
qpdf_object_type_e qpdf_object_type_e
getTypeCode() const getTypeCode() const noexcept
{ {
return value->type_code; return value->type_code;
} }
// Return a string literal that describes the type, useful for debugging and testing // Return a string literal that describes the type, useful for debugging and testing
char const* char const*
getTypeName() const getTypeName() const
{ {
return value->type_name; return resolved_object()->value->type_name;
} }
QPDF* QPDF*
@ -164,13 +172,25 @@ class QPDFObject
doResolve(); doResolve();
} }
} }
const QPDFObject*
resolved_object() const
{
return isUnresolved() ? QPDF::Resolver::getResolved(value->qpdf, value->og) : this;
}
void doResolve(); void doResolve();
template <typename T> template <typename T>
T* T*
as() as() const
{ {
return dynamic_cast<T*>(value.get()); if (auto result = dynamic_cast<T*>(value.get())) {
return result;
} else {
return isUnresolved()
? dynamic_cast<T*>(QPDF::Resolver::getResolved(value->qpdf, value->og)->value.get())
: nullptr;
}
} }
private: private:

View File

@ -11,6 +11,7 @@ class QPDF_Unresolved: public QPDFValue
std::shared_ptr<QPDFObject> copy(bool shallow = false) override; std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
std::string unparse() override; std::string unparse() override;
void writeJSON(int json_version, JSON::Writer& p) override; void writeJSON(int json_version, JSON::Writer& p) override;
std::string getStringValue() const override;
private: private:
QPDF_Unresolved(QPDF* qpdf, QPDFObjGen const& og); QPDF_Unresolved(QPDF* qpdf, QPDFObjGen const& og);