This commit is contained in:
m-holger 2024-04-15 16:17:37 +01:00 committed by GitHub
commit ee4cb1da76
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 3649 additions and 1733 deletions

View File

@ -772,12 +772,13 @@ class QPDF
class Resolver
{
friend class QPDFObject;
friend class QPDF_Unresolved;
private:
static void
resolve(QPDF* qpdf, QPDFObjGen const& og)
static QPDFObject*
resolved(QPDF* qpdf, QPDFObjGen og)
{
qpdf->resolve(og);
return qpdf->resolve(og);
}
};
@ -1028,7 +1029,7 @@ class QPDF
QPDFObjGen exp_og,
QPDFObjGen& og,
bool skip_cache_if_in_xref);
void resolve(QPDFObjGen og);
QPDFObject* resolve(QPDFObjGen og);
void resolveObjectsInStream(int obj_stream_number);
void stopOnError(std::string const& message);
QPDFObjectHandle reserveObjectIfNotExists(QPDFObjGen const& og);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,245 @@
// Copyright (c) 2005-2024 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 QPDFOBJECTHANDLE_INLINE_HH
#define QPDFOBJECTHANDLE_INLINE_HH
class QPDFObjectHandle::QPDFDictItems
{
// This class allows C++-style iteration, including range-for iteration, around dictionaries.
// You can write
// for (auto iter: QPDFDictItems(dictionary_obj))
// {
// // iter.first is a string
// // iter.second is a QPDFObjectHandle
// }
// See examples/pdf-name-number-tree.cc for a demonstration of using this API.
public:
QPDF_DLL
QPDFDictItems(QPDFObjectHandle const& oh);
class iterator
{
friend class QPDFDictItems;
public:
typedef std::pair<std::string, QPDFObjectHandle> T;
using iterator_category = std::bidirectional_iterator_tag;
using value_type = T;
using difference_type = long;
using pointer = T*;
using reference = T&;
QPDF_DLL
virtual ~iterator() = default;
QPDF_DLL
iterator& operator++();
QPDF_DLL
iterator
operator++(int)
{
iterator t = *this;
++(*this);
return t;
}
QPDF_DLL
iterator& operator--();
QPDF_DLL
iterator
operator--(int)
{
iterator t = *this;
--(*this);
return t;
}
QPDF_DLL
reference operator*();
QPDF_DLL
pointer operator->();
QPDF_DLL
bool operator==(iterator const& other) const;
QPDF_DLL
bool
operator!=(iterator const& other) const
{
return !operator==(other);
}
private:
iterator(QPDFObjectHandle& oh, bool for_begin);
void updateIValue();
class Members
{
friend class QPDFDictItems::iterator;
public:
QPDF_DLL
~Members() = default;
private:
Members(QPDFObjectHandle& oh, bool for_begin);
Members() = delete;
Members(Members const&) = delete;
QPDFObjectHandle& oh;
std::set<std::string> keys;
std::set<std::string>::iterator iter;
bool is_end;
};
std::shared_ptr<Members> m;
value_type ivalue;
};
QPDF_DLL
iterator begin();
QPDF_DLL
iterator end();
private:
QPDFObjectHandle oh;
};
class QPDFObjectHandle::QPDFArrayItems
{
// This class allows C++-style iteration, including range-for iteration, around arrays. You can
// write
// for (auto iter: QPDFArrayItems(array_obj))
// {
// // iter is a QPDFObjectHandle
// }
// See examples/pdf-name-number-tree.cc for a demonstration of using this API.
public:
QPDF_DLL
QPDFArrayItems(QPDFObjectHandle const& oh);
class iterator
{
friend class QPDFArrayItems;
public:
typedef QPDFObjectHandle T;
using iterator_category = std::bidirectional_iterator_tag;
using value_type = T;
using difference_type = long;
using pointer = T*;
using reference = T&;
QPDF_DLL
virtual ~iterator() = default;
QPDF_DLL
iterator& operator++();
QPDF_DLL
iterator
operator++(int)
{
iterator t = *this;
++(*this);
return t;
}
QPDF_DLL
iterator& operator--();
QPDF_DLL
iterator
operator--(int)
{
iterator t = *this;
--(*this);
return t;
}
QPDF_DLL
reference operator*();
QPDF_DLL
pointer operator->();
QPDF_DLL
bool operator==(iterator const& other) const;
QPDF_DLL
bool
operator!=(iterator const& other) const
{
return !operator==(other);
}
private:
iterator(QPDFObjectHandle& oh, bool for_begin);
void updateIValue();
class Members
{
friend class QPDFArrayItems::iterator;
public:
QPDF_DLL
~Members() = default;
private:
Members(QPDFObjectHandle& oh, bool for_begin);
Members() = delete;
Members(Members const&) = delete;
QPDFObjectHandle& oh;
int item_number;
bool is_end;
};
std::shared_ptr<Members> m;
value_type ivalue;
};
QPDF_DLL
iterator begin();
QPDF_DLL
iterator end();
private:
QPDFObjectHandle oh;
};
inline int
QPDFObjectHandle::getObjectID() const
{
return getObjGen().getObj();
}
inline int
QPDFObjectHandle::getGeneration() const
{
return getObjGen().getGen();
}
inline bool
QPDFObjectHandle::isIndirect() const
{
return (obj != nullptr) && (getObjectID() != 0);
}
inline bool
QPDFObjectHandle::isInitialized() const
{
return obj != nullptr;
}
#endif // QPDFOBJECTHANDLE_INLINE_HH

View File

@ -1696,11 +1696,11 @@ QPDF::readObjectAtOffset(
return oh;
}
void
QPDFObject*
QPDF::resolve(QPDFObjGen og)
{
if (!isUnresolved(og)) {
return;
return m->obj_cache[og].object.get();
}
if (m->resolving.count(og)) {
@ -1709,7 +1709,7 @@ QPDF::resolve(QPDFObjGen og)
QTC::TC("qpdf", "QPDF recursion loop in resolve");
warn(damagedPDF("", "loop detected resolving object " + og.unparse(' ')));
updateCache(og, QPDF_Null::create(), -1, -1);
return;
return m->obj_cache[og].object.get();
}
ResolveRecorder rr(this, og);
@ -1750,6 +1750,7 @@ QPDF::resolve(QPDFObjGen og)
auto result(m->obj_cache[og].object);
result->setDefaultDescription(this, og);
return result.get();
}
void

View File

@ -3,13 +3,6 @@
#include <qpdf/QPDF.hh>
#include <qpdf/QPDF_Destroyed.hh>
void
QPDFObject::doResolve()
{
auto og = value->og;
QPDF::Resolver::resolve(value->qpdf, og);
}
void
QPDFObject::destroy()
{

File diff suppressed because it is too large Load Diff

View File

@ -130,8 +130,7 @@ QPDF_Array::unparse()
for (int j = next; j < key; ++j) {
result += "null ";
}
item.second->resolve();
auto og = item.second->getObjGen();
auto og = item.second->resolved_object()->getObjGen();
result += og.isIndirect() ? og.unparse(' ') + " R " : item.second->unparse() + " ";
next = ++key;
}
@ -140,8 +139,7 @@ QPDF_Array::unparse()
}
} else {
for (auto const& item: elements) {
item->resolve();
auto og = item->getObjGen();
auto og = item->resolved_object()->getObjGen();
result += og.isIndirect() ? og.unparse(' ') + " R " : item->unparse() + " ";
}
}

View File

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

View File

@ -5,8 +5,8 @@
// include/qpdf/QPDFObject.hh. See comments there for an explanation.
#include <qpdf/Constants.h>
#include <qpdf/DLL.h>
#include <qpdf/JSON.hh>
#include <qpdf/QPDF.hh>
#include <qpdf/QPDFValue.hh>
#include <qpdf/Types.h>
@ -43,18 +43,26 @@ class QPDFObject
{
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::resolved(value->qpdf, value->og)->value->type_code
: tc;
}
// Return a unique type code for the object
qpdf_object_type_e
getTypeCode() const
getTypeCode() const noexcept
{
return value->type_code;
}
// Return a string literal that describes the type, useful for debugging and testing
char const*
getTypeName() const
{
return value->type_name;
return resolved_object()->value->type_name;
}
QPDF*
@ -157,20 +165,23 @@ class QPDFObject
{
return value->type_code == ::ot_unresolved;
}
void
resolve()
const QPDFObject*
resolved_object() const
{
if (isUnresolved()) {
doResolve();
}
return isUnresolved() ? QPDF::Resolver::resolved(value->qpdf, value->og) : this;
}
void doResolve();
template <typename 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::resolved(value->qpdf, value->og)->value.get())
: nullptr;
}
}
private:

View File

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