mirror of https://github.com/qpdf/qpdf.git
In FUTURE, treat uninitialized object handles as null
This commit is contained in:
parent
7a7a8c4471
commit
bddb168dbf
|
@ -55,6 +55,9 @@ class QPDF_DLL_CLASS QPDFObjectHelper
|
|||
}
|
||||
|
||||
protected:
|
||||
#ifdef QPDF_FUTURE
|
||||
QPDFObjectHelper() = default;
|
||||
#endif
|
||||
QPDFObjectHandle oh;
|
||||
};
|
||||
|
||||
|
|
|
@ -79,16 +79,14 @@ NNTreeIterator::PathElement::PathElement(QPDFObjectHandle const& node, int kid_n
|
|||
QPDFObjectHandle
|
||||
NNTreeIterator::getNextKid(PathElement& pe, bool backward)
|
||||
{
|
||||
QPDFObjectHandle result;
|
||||
bool found = false;
|
||||
while (!found) {
|
||||
while (true) {
|
||||
pe.kid_number += backward ? -1 : 1;
|
||||
auto kids = pe.node.getKey("/Kids");
|
||||
if ((pe.kid_number >= 0) && (pe.kid_number < kids.getArrayNItems())) {
|
||||
result = kids.getArrayItem(pe.kid_number);
|
||||
auto result = kids.getArrayItem(pe.kid_number);
|
||||
if (result.isDictionary() &&
|
||||
(result.hasKey("/Kids") || result.hasKey(impl.details.itemsKey()))) {
|
||||
found = true;
|
||||
return result;
|
||||
} else {
|
||||
QTC::TC("qpdf", "NNTree skip invalid kid");
|
||||
warn(
|
||||
|
@ -97,11 +95,12 @@ NNTreeIterator::getNextKid(PathElement& pe, bool backward)
|
|||
("skipping over invalid kid at index " + std::to_string(pe.kid_number)));
|
||||
}
|
||||
} else {
|
||||
result = QPDFObjectHandle::newNull();
|
||||
found = true;
|
||||
#ifndef QPDF_FUTURE
|
||||
return QPDFObjectHandle::newNull();
|
||||
#endif
|
||||
return {};
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -228,9 +228,15 @@ QPDF::~QPDF()
|
|||
// the xref table anyway just to prevent any possibility of resolve() succeeding.
|
||||
m->xref_table.clear();
|
||||
for (auto const& iter: m->obj_cache) {
|
||||
iter.second.object->disconnect();
|
||||
if (iter.second.object->getTypeCode() != ::ot_null) {
|
||||
if (iter.second.object) {
|
||||
iter.second.object->disconnect();
|
||||
#ifndef QPDF_FUTURE
|
||||
if (iter.second.object->getTypeCode() != ::ot_null) {
|
||||
iter.second.object->destroy();
|
||||
}
|
||||
#else
|
||||
iter.second.object->destroy();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1571,7 +1577,10 @@ QPDF::readObjectAtOffset(
|
|||
if (offset == 0) {
|
||||
QTC::TC("qpdf", "QPDF bogus 0 offset", 0);
|
||||
warn(damagedPDF(0, "object has offset 0"));
|
||||
#ifndef QPDF_FUTURE
|
||||
return QPDFObjectHandle::newNull();
|
||||
#endif
|
||||
return {};
|
||||
}
|
||||
|
||||
m->file->seek(offset, SEEK_SET);
|
||||
|
@ -1629,7 +1638,10 @@ QPDF::readObjectAtOffset(
|
|||
("object " + exp_og.unparse(' ') +
|
||||
" not found in file after regenerating cross reference "
|
||||
"table")));
|
||||
#ifndef QPDF_FUTURE
|
||||
return QPDFObjectHandle::newNull();
|
||||
#endif
|
||||
return {};
|
||||
}
|
||||
} else {
|
||||
throw;
|
||||
|
@ -1835,7 +1847,9 @@ QPDF::resolveObjectsInStream(int obj_stream_number)
|
|||
QPDFObjectHandle
|
||||
QPDF::newIndirect(QPDFObjGen const& og, std::shared_ptr<QPDFObject> const& obj)
|
||||
{
|
||||
obj->setDefaultDescription(this, og);
|
||||
if (obj) {
|
||||
obj->setDefaultDescription(this, og);
|
||||
}
|
||||
return {obj};
|
||||
}
|
||||
|
||||
|
@ -1890,9 +1904,11 @@ QPDF::makeIndirectFromQPDFObject(std::shared_ptr<QPDFObject> const& obj)
|
|||
QPDFObjectHandle
|
||||
QPDF::makeIndirectObject(QPDFObjectHandle oh)
|
||||
{
|
||||
#ifndef QPDF_FUTURE
|
||||
if (!oh.isInitialized()) {
|
||||
throw std::logic_error("attempted to make an uninitialized QPDFObjectHandle indirect");
|
||||
}
|
||||
#endif
|
||||
return makeIndirectFromQPDFObject(oh.getObj());
|
||||
}
|
||||
|
||||
|
@ -1985,11 +2001,19 @@ QPDF::replaceObject(int objid, int generation, QPDFObjectHandle oh)
|
|||
void
|
||||
QPDF::replaceObject(QPDFObjGen const& og, QPDFObjectHandle oh)
|
||||
{
|
||||
#ifndef QPDF_FUTURE
|
||||
if (oh.isIndirect() || !oh.isInitialized()) {
|
||||
#else
|
||||
if (oh.isIndirect()) {
|
||||
#endif
|
||||
QTC::TC("qpdf", "QPDF replaceObject called with indirect object");
|
||||
throw std::logic_error("QPDF::replaceObject called with indirect object handle");
|
||||
}
|
||||
updateCache(og, oh.getObj(), -1, -1);
|
||||
auto obj = oh.getObj();
|
||||
if (!obj) {
|
||||
obj = QPDF_Null::create();
|
||||
}
|
||||
updateCache(og, obj, -1, -1);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2092,7 +2116,10 @@ QPDF::copyForeignObject(QPDFObjectHandle foreign)
|
|||
if (!obj_copier.object_map.count(og)) {
|
||||
warn(damagedPDF("unexpected reference to /Pages object while copying foreign object; "
|
||||
"replacing with null"));
|
||||
#ifndef QPDF_FUTURE
|
||||
return QPDFObjectHandle::newNull();
|
||||
#endif
|
||||
return {};
|
||||
}
|
||||
return obj_copier.object_map[foreign.getObjGen()];
|
||||
}
|
||||
|
@ -2166,7 +2193,9 @@ QPDF::replaceForeignIndirectObjects(QPDFObjectHandle foreign, ObjCopier& obj_cop
|
|||
// This case would occur if this is a reference to a Pages object that we didn't
|
||||
// traverse into.
|
||||
QTC::TC("qpdf", "QPDF replace foreign indirect with null");
|
||||
#ifndef QPDF_FUTURE
|
||||
result = QPDFObjectHandle::newNull();
|
||||
#endif
|
||||
} else {
|
||||
result = mapping->second;
|
||||
}
|
||||
|
|
|
@ -55,7 +55,11 @@ QPDFAcroFormDocumentHelper::addFormField(QPDFFormFieldObjectHelper ff)
|
|||
}
|
||||
fields.appendItem(ff.getObjectHandle());
|
||||
QPDFObjGen::set visited;
|
||||
#ifndef QPDF_FUTURE
|
||||
traverseField(ff.getObjectHandle(), QPDFObjectHandle::newNull(), 0, visited);
|
||||
#else
|
||||
traverseField(ff.getObjectHandle(), {}, 0, visited);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -15,7 +15,9 @@ QPDFFormFieldObjectHelper::QPDFFormFieldObjectHelper(QPDFObjectHandle oh) :
|
|||
}
|
||||
|
||||
QPDFFormFieldObjectHelper::QPDFFormFieldObjectHelper() :
|
||||
#ifndef QPDF_FUTURE
|
||||
QPDFObjectHelper(QPDFObjectHandle::newNull()),
|
||||
#endif
|
||||
m(new Members())
|
||||
{
|
||||
}
|
||||
|
@ -51,15 +53,13 @@ QPDFFormFieldObjectHelper::getFieldFromAcroForm(std::string const& name)
|
|||
{
|
||||
QPDFObjectHandle result = QPDFObjectHandle::newNull();
|
||||
// Fields are supposed to be indirect, so this should work.
|
||||
QPDF* q = this->oh.getOwningQPDF();
|
||||
if (!q) {
|
||||
return result;
|
||||
if (QPDF* q = this->oh.getOwningQPDF()) {
|
||||
return q->getRoot().getKey("/AcroForm").getKeyIfDict(name);
|
||||
}
|
||||
auto acroform = q->getRoot().getKey("/AcroForm");
|
||||
if (!acroform.isDictionary()) {
|
||||
return result;
|
||||
}
|
||||
return acroform.getKey(name);
|
||||
#ifndef QPDF_FUTURE
|
||||
return QPDFObjectHandle::newNull();
|
||||
#endif
|
||||
return {};
|
||||
}
|
||||
|
||||
QPDFObjectHandle
|
||||
|
@ -67,9 +67,12 @@ QPDFFormFieldObjectHelper::getInheritableFieldValue(std::string const& name)
|
|||
{
|
||||
QPDFObjectHandle node = this->oh;
|
||||
if (!node.isDictionary()) {
|
||||
#ifndef QPDF_FUTURE
|
||||
return QPDFObjectHandle::newNull();
|
||||
#endif
|
||||
return {};
|
||||
}
|
||||
QPDFObjectHandle result(node.getKey(name));
|
||||
auto result(node.getKey(name));
|
||||
if (result.isNull()) {
|
||||
QPDFObjGen::set seen;
|
||||
while (seen.add(node) && node.hasKey("/Parent")) {
|
||||
|
|
|
@ -27,9 +27,11 @@ QPDFObjGen::set::add(QPDFObjectHandle const& oh)
|
|||
if (auto* ptr = oh.getObjectPtr()) {
|
||||
return add(ptr->getObjGen());
|
||||
} else {
|
||||
#ifndef QPDF_FUTURE
|
||||
throw std::logic_error(
|
||||
"attempt to retrieve QPDFObjGen from uninitialized QPDFObjectHandle");
|
||||
return false;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,9 +41,11 @@ QPDFObjGen::set::add(QPDFObjectHelper const& helper)
|
|||
if (auto* ptr = helper.getObjectHandle().getObjectPtr()) {
|
||||
return add(ptr->getObjGen());
|
||||
} else {
|
||||
#ifndef QPDF_FUTURE
|
||||
throw std::logic_error(
|
||||
"attempt to retrieve QPDFObjGen from uninitialized QPDFObjectHandle");
|
||||
return false;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,8 +55,10 @@ QPDFObjGen::set::erase(QPDFObjectHandle const& oh)
|
|||
if (auto* ptr = oh.getObjectPtr()) {
|
||||
erase(ptr->getObjGen());
|
||||
} else {
|
||||
#ifndef QPDF_FUTURE
|
||||
throw std::logic_error(
|
||||
"attempt to retrieve QPDFObjGen from uninitialized QPDFObjectHandle");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,7 +68,9 @@ QPDFObjGen::set::erase(QPDFObjectHelper const& helper)
|
|||
if (auto* ptr = helper.getObjectHandle().getObjectPtr()) {
|
||||
erase(ptr->getObjGen());
|
||||
} else {
|
||||
#ifndef QPDF_FUTURE
|
||||
throw std::logic_error(
|
||||
"attempt to retrieve QPDFObjGen from uninitialized QPDFObjectHandle");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
@ -240,13 +240,21 @@ QPDFObjectHandle::disconnect()
|
|||
qpdf_object_type_e
|
||||
QPDFObjectHandle::getTypeCode()
|
||||
{
|
||||
#ifndef QPDF_FUTURE
|
||||
return dereference() ? this->obj->getTypeCode() : ::ot_uninitialized;
|
||||
#else
|
||||
return dereference() ? this->obj->getTypeCode() : ::ot_null;
|
||||
#endif
|
||||
}
|
||||
|
||||
char const*
|
||||
QPDFObjectHandle::getTypeName()
|
||||
{
|
||||
#ifndef QPDF_FUTURE
|
||||
return dereference() ? this->obj->getTypeName() : "uninitialized";
|
||||
#else
|
||||
return dereference() ? this->obj->getTypeName() : "null";
|
||||
#endif
|
||||
}
|
||||
|
||||
QPDF_Array*
|
||||
|
@ -346,13 +354,21 @@ QPDFObjectHandle::isDirectNull() const
|
|||
{
|
||||
// Don't call dereference() -- this is a const method, and we know
|
||||
// objid == 0, so there's nothing to resolve.
|
||||
return (isInitialized() && (getObjectID() == 0) && (obj->getTypeCode() == ::ot_null));
|
||||
#ifdef QPDF_FUTURE
|
||||
return !obj || (getObjectID() == 0 && obj->getTypeCode() == ::ot_null);
|
||||
#else
|
||||
return isInitialized() && getObjectID() == 0 && obj->getTypeCode() == ::ot_null;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
QPDFObjectHandle::isNull()
|
||||
{
|
||||
return dereference() && (obj->getTypeCode() == ::ot_null);
|
||||
#ifdef QPDF_FUTURE
|
||||
return !obj || (dereference() && obj->getTypeCode() == ::ot_null);
|
||||
#else
|
||||
return dereference() && obj->getTypeCode() == ::ot_null;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -992,21 +1008,22 @@ QPDFObjectHandle::getKey(std::string const& key)
|
|||
QPDFObjectHandle
|
||||
QPDFObjectHandle::getKeyIfDict(std::string const& key)
|
||||
{
|
||||
#ifndef QPDF_FUTURE
|
||||
return isNull() ? newNull() : getKey(key);
|
||||
#endif
|
||||
return isNull() ? QPDFObjectHandle() : getKey(key);
|
||||
}
|
||||
|
||||
std::set<std::string>
|
||||
QPDFObjectHandle::getKeys()
|
||||
{
|
||||
std::set<std::string> result;
|
||||
auto dict = asDictionary();
|
||||
if (dict) {
|
||||
result = dict->getKeys();
|
||||
if (auto dict = asDictionary()) {
|
||||
return dict->getKeys();
|
||||
} else {
|
||||
typeWarning("dictionary", "treating as empty");
|
||||
QTC::TC("qpdf", "QPDFObjectHandle dictionary empty set for getKeys");
|
||||
}
|
||||
return result;
|
||||
return {};
|
||||
}
|
||||
|
||||
std::map<std::string, QPDFObjectHandle>
|
||||
|
@ -1015,12 +1032,12 @@ QPDFObjectHandle::getDictAsMap()
|
|||
std::map<std::string, QPDFObjectHandle> result;
|
||||
auto dict = asDictionary();
|
||||
if (dict) {
|
||||
result = dict->getAsMap();
|
||||
return dict->getAsMap();
|
||||
} else {
|
||||
typeWarning("dictionary", "treating as empty");
|
||||
QTC::TC("qpdf", "QPDFObjectHandle dictionary empty map for asMap");
|
||||
}
|
||||
return result;
|
||||
return {};
|
||||
}
|
||||
|
||||
// Array and Name accessors
|
||||
|
@ -1240,13 +1257,15 @@ QPDFObjectHandle::removeKey(std::string const& key)
|
|||
QPDFObjectHandle
|
||||
QPDFObjectHandle::removeKeyAndGetOld(std::string const& key)
|
||||
{
|
||||
auto result = QPDFObjectHandle::newNull();
|
||||
auto dict = asDictionary();
|
||||
if (dict) {
|
||||
result = dict->getKey(key);
|
||||
if (auto dict = asDictionary()) {
|
||||
auto result = dict->getKey(key);
|
||||
removeKey(key);
|
||||
return result;
|
||||
}
|
||||
removeKey(key);
|
||||
return result;
|
||||
#ifndef QPDF_FUTURE
|
||||
return QPDFObjectHandle::newNull();
|
||||
#endif
|
||||
return {};
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1588,7 +1607,11 @@ std::string
|
|||
QPDFObjectHandle::unparseResolved()
|
||||
{
|
||||
if (!dereference()) {
|
||||
#ifndef QPDF_FUTURE
|
||||
throw std::logic_error("attempted to dereference an uninitialized QPDFObjectHandle");
|
||||
#else
|
||||
return "null";
|
||||
#endif
|
||||
}
|
||||
return obj->unparse();
|
||||
}
|
||||
|
@ -1617,7 +1640,11 @@ QPDFObjectHandle::getJSON(int json_version, bool dereference_indirect)
|
|||
if ((!dereference_indirect) && isIndirect()) {
|
||||
return JSON::makeString(unparse());
|
||||
} else if (!dereference()) {
|
||||
#ifndef QPDF_FUTURE
|
||||
throw std::logic_error("attempted to dereference an uninitialized QPDFObjectHandle");
|
||||
#else
|
||||
return JSON::makeNull();
|
||||
#endif
|
||||
} else {
|
||||
Pl_Buffer p{"json"};
|
||||
JSON::Writer jw{&p, 0};
|
||||
|
@ -1633,7 +1660,11 @@ QPDFObjectHandle::writeJSON(int json_version, JSON::Writer& p, bool dereference_
|
|||
if (!dereference_indirect && isIndirect()) {
|
||||
p << "\"" << getObjGen().unparse(' ') << " R\"";
|
||||
} else if (!dereference()) {
|
||||
#ifndef QPDF_FUTURE
|
||||
throw std::logic_error("attempted to dereference an uninitialized QPDFObjectHandle");
|
||||
#else
|
||||
p << "null";
|
||||
#endif
|
||||
} else {
|
||||
obj->writeJSON(json_version, p);
|
||||
}
|
||||
|
@ -2074,7 +2105,11 @@ QPDFObjectHandle
|
|||
QPDFObjectHandle::shallowCopy()
|
||||
{
|
||||
if (!dereference()) {
|
||||
#ifndef QPDF_FUTURE
|
||||
throw std::logic_error("operation attempted on uninitialized QPDFObjectHandle");
|
||||
#else
|
||||
return {};
|
||||
#endif
|
||||
}
|
||||
return {obj->copy()};
|
||||
}
|
||||
|
@ -2083,7 +2118,11 @@ QPDFObjectHandle
|
|||
QPDFObjectHandle::unsafeShallowCopy()
|
||||
{
|
||||
if (!dereference()) {
|
||||
#ifndef QPDF_FUTURE
|
||||
throw std::logic_error("operation attempted on uninitialized QPDFObjectHandle");
|
||||
#else
|
||||
return {};
|
||||
#endif
|
||||
}
|
||||
return {obj->copy(true)};
|
||||
}
|
||||
|
@ -2092,6 +2131,9 @@ void
|
|||
QPDFObjectHandle::makeDirect(QPDFObjGen::set& visited, bool stop_at_streams)
|
||||
{
|
||||
assertInitialized();
|
||||
if (!obj) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto cur_og = getObjGen();
|
||||
if (!visited.add(cur_og)) {
|
||||
|
@ -2161,9 +2203,11 @@ QPDFObjectHandle::makeDirect(bool allow_streams)
|
|||
void
|
||||
QPDFObjectHandle::assertInitialized() const
|
||||
{
|
||||
#ifndef QPDF_FUTURE
|
||||
if (!isInitialized()) {
|
||||
throw std::logic_error("operation attempted on uninitialized QPDFObjectHandle");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2173,10 +2217,16 @@ QPDFObjectHandle::typeWarning(char const* expected_type, std::string const& warn
|
|||
std::string description;
|
||||
// Type checks above guarantee that the object has been dereferenced. Nevertheless, dereference
|
||||
// throws exceptions in the test suite
|
||||
#ifdef QPDF_FUTURE
|
||||
if (dereference()) {
|
||||
obj->getDescription(context, description);
|
||||
}
|
||||
#else
|
||||
if (!dereference()) {
|
||||
throw std::logic_error("attempted to dereference an uninitialized QPDFObjectHandle");
|
||||
}
|
||||
this->obj->getDescription(context, description);
|
||||
obj->getDescription(context, description);
|
||||
#endif
|
||||
// Null context handled by warn
|
||||
warn(
|
||||
context,
|
||||
|
|
|
@ -90,8 +90,10 @@ QPDFOutlineDocumentHelper::resolveNamedDest(QPDFObjectHandle name)
|
|||
}
|
||||
}
|
||||
}
|
||||
#ifndef QPDF_FUTURE
|
||||
if (!result.isInitialized()) {
|
||||
result = QPDFObjectHandle::newNull();
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -58,9 +58,11 @@ QPDFOutlineObjectHelper::getDest()
|
|||
QTC::TC("qpdf", "QPDFOutlineObjectHelper action dest");
|
||||
dest = A.getKey("/D");
|
||||
}
|
||||
#ifndef QPDF_FUTURE
|
||||
if (!dest.isInitialized()) {
|
||||
dest = QPDFObjectHandle::newNull();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (dest.isName() || dest.isString()) {
|
||||
QTC::TC("qpdf", "QPDFOutlineObjectHelper named dest");
|
||||
|
@ -77,7 +79,10 @@ QPDFOutlineObjectHelper::getDestPage()
|
|||
if ((dest.isArray()) && (dest.getArrayNItems() > 0)) {
|
||||
return dest.getArrayItem(0);
|
||||
}
|
||||
#ifndef QPDF_FUTURE
|
||||
return QPDFObjectHandle::newNull();
|
||||
#endif
|
||||
return {};
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -394,7 +394,11 @@ QPDFParser::add(std::shared_ptr<QPDFObject>&& obj)
|
|||
void
|
||||
QPDFParser::addNull()
|
||||
{
|
||||
#ifndef QPDF_FUTURE
|
||||
const static ObjectPtr null_obj = QPDF_Null::create();
|
||||
#else
|
||||
const static ObjectPtr null_obj;
|
||||
#endif
|
||||
|
||||
if (frame->state != st_dictionary_value) {
|
||||
// If state is st_dictionary_key then there is a missing key. Push onto olist for
|
||||
|
@ -448,7 +452,7 @@ QPDFParser::fixMissingKeys()
|
|||
{
|
||||
std::set<std::string> names;
|
||||
for (auto& obj: frame->olist) {
|
||||
if (obj->getTypeCode() == ::ot_name) {
|
||||
if (obj && obj->getTypeCode() == ::ot_name) {
|
||||
names.insert(obj->getStringValue());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,11 @@
|
|||
#include <qpdf/QPDFObject_private.hh>
|
||||
#include <qpdf/QTC.hh>
|
||||
|
||||
#ifndef QPDF_FUTURE
|
||||
static const QPDFObjectHandle null_oh = QPDFObjectHandle::newNull();
|
||||
|
||||
#else
|
||||
static const QPDFObjectHandle null_oh;
|
||||
#endif
|
||||
inline void
|
||||
QPDF_Array::checkOwnership(QPDFObjectHandle const& item) const
|
||||
{
|
||||
|
@ -21,7 +24,9 @@ QPDF_Array::checkOwnership(QPDFObjectHandle const& item) const
|
|||
}
|
||||
}
|
||||
} else {
|
||||
#ifndef QPDF_FUTURE
|
||||
throw std::logic_error("Attempting to add an uninitialized object to a QPDF_Array.");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,7 +53,7 @@ QPDF_Array::QPDF_Array(std::vector<std::shared_ptr<QPDFObject>>&& v, bool sparse
|
|||
if (sparse) {
|
||||
sp = std::make_unique<Sparse>();
|
||||
for (auto&& item: v) {
|
||||
if (item->getTypeCode() != ::ot_null || item->getObjGen().isIndirect()) {
|
||||
if (item && (item->getTypeCode() != ::ot_null || item->getObjGen().isIndirect())) {
|
||||
sp->elements[sp->size] = std::move(item);
|
||||
}
|
||||
++sp->size;
|
||||
|
@ -84,7 +89,7 @@ QPDF_Array::copy(bool shallow)
|
|||
for (auto const& element: sp->elements) {
|
||||
auto const& obj = element.second;
|
||||
result->sp->elements[element.first] =
|
||||
obj->getObjGen().isIndirect() ? obj : obj->copy();
|
||||
!obj || obj->getObjGen().isIndirect() ? obj : obj->copy();
|
||||
}
|
||||
return do_create(result);
|
||||
} else {
|
||||
|
@ -106,13 +111,13 @@ QPDF_Array::disconnect()
|
|||
if (sp) {
|
||||
for (auto& item: sp->elements) {
|
||||
auto& obj = item.second;
|
||||
if (!obj->getObjGen().isIndirect()) {
|
||||
if (obj && !obj->getObjGen().isIndirect()) {
|
||||
obj->disconnect();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (auto& obj: elements) {
|
||||
if (!obj->getObjGen().isIndirect()) {
|
||||
if (obj && !obj->getObjGen().isIndirect()) {
|
||||
obj->disconnect();
|
||||
}
|
||||
}
|
||||
|
@ -130,9 +135,13 @@ QPDF_Array::unparse()
|
|||
for (int j = next; j < key; ++j) {
|
||||
result += "null ";
|
||||
}
|
||||
item.second->resolve();
|
||||
auto og = item.second->getObjGen();
|
||||
result += og.isIndirect() ? og.unparse(' ') + " R " : item.second->unparse() + " ";
|
||||
if (item.second) {
|
||||
item.second->resolve();
|
||||
auto og = item.second->getObjGen();
|
||||
result += og.isIndirect() ? og.unparse(' ') + " R " : item.second->unparse() + " ";
|
||||
} else {
|
||||
result += "null ";
|
||||
}
|
||||
next = ++key;
|
||||
}
|
||||
for (int j = next; j < sp->size; ++j) {
|
||||
|
@ -140,9 +149,13 @@ QPDF_Array::unparse()
|
|||
}
|
||||
} else {
|
||||
for (auto const& item: elements) {
|
||||
item->resolve();
|
||||
auto og = item->getObjGen();
|
||||
result += og.isIndirect() ? og.unparse(' ') + " R " : item->unparse() + " ";
|
||||
if (item) {
|
||||
item->resolve();
|
||||
auto og = item->getObjGen();
|
||||
result += og.isIndirect() ? og.unparse(' ') + " R " : item->unparse() + " ";
|
||||
} else {
|
||||
result += "null ";
|
||||
}
|
||||
}
|
||||
}
|
||||
result += "]";
|
||||
|
@ -161,11 +174,15 @@ QPDF_Array::writeJSON(int json_version, JSON::Writer& p)
|
|||
p.writeNext() << "null";
|
||||
}
|
||||
p.writeNext();
|
||||
auto og = item.second->getObjGen();
|
||||
if (og.isIndirect()) {
|
||||
p << "\"" << og.unparse(' ') << " R\"";
|
||||
if (item.second) {
|
||||
auto og = item.second->getObjGen();
|
||||
if (og.isIndirect()) {
|
||||
p << "\"" << og.unparse(' ') << " R\"";
|
||||
} else {
|
||||
item.second->writeJSON(json_version, p);
|
||||
}
|
||||
} else {
|
||||
item.second->writeJSON(json_version, p);
|
||||
p << "null";
|
||||
}
|
||||
next = ++key;
|
||||
}
|
||||
|
@ -175,11 +192,15 @@ QPDF_Array::writeJSON(int json_version, JSON::Writer& p)
|
|||
} else {
|
||||
for (auto const& item: elements) {
|
||||
p.writeNext();
|
||||
auto og = item->getObjGen();
|
||||
if (og.isIndirect()) {
|
||||
p << "\"" << og.unparse(' ') << " R\"";
|
||||
if (item) {
|
||||
auto og = item->getObjGen();
|
||||
if (og.isIndirect()) {
|
||||
p << "\"" << og.unparse(' ') << " R\"";
|
||||
} else {
|
||||
item->writeJSON(json_version, p);
|
||||
}
|
||||
} else {
|
||||
item->writeJSON(json_version, p);
|
||||
p << "null";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,10 @@ QPDF_Null::create(
|
|||
std::shared_ptr<QPDFObject>
|
||||
QPDF_Null::copy(bool shallow)
|
||||
{
|
||||
#ifndef QPDF_FUTURE
|
||||
return create();
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string
|
||||
|
|
|
@ -102,11 +102,14 @@ main()
|
|||
assert(c->unparse() == "[ null null null null null 5 0 R null [ 0 1 42 3 ] null null ]");
|
||||
assert(d->unparse() == "[ null null null null null 5 0 R null [ 0 1 2 3 ] null null ]");
|
||||
|
||||
#ifndef QPDF_FUTURE
|
||||
|
||||
try {
|
||||
b.setAt(3, {});
|
||||
std::cout << "inserted uninitialized object\n";
|
||||
} catch (std::logic_error&) {
|
||||
}
|
||||
#endif
|
||||
QPDF pdf2;
|
||||
pdf2.emptyPDF();
|
||||
try {
|
||||
|
|
|
@ -12,6 +12,8 @@ require TestDriver;
|
|||
|
||||
cleanup();
|
||||
|
||||
my $future = check_future();
|
||||
|
||||
my $td = new TestDriver('c-api-object-handle');
|
||||
|
||||
my $n_tests = 13;
|
||||
|
@ -54,10 +56,20 @@ $td->runtest("C wrap and clone objects",
|
|||
{$td->COMMAND => "qpdf-ctest 28 minimal.pdf '' ''"},
|
||||
{$td->STRING => "C test 28 done\n", $td->EXIT_STATUS => 0},
|
||||
$td->NORMALIZE_NEWLINES);
|
||||
$td->runtest("C object handle errors",
|
||||
{$td->COMMAND => "qpdf-ctest 29 minimal.pdf '' ''"},
|
||||
{$td->FILE => "c-oh-errors.out", $td->EXIT_STATUS => 0},
|
||||
$td->NORMALIZE_NEWLINES);
|
||||
if ($future)
|
||||
{
|
||||
$td->runtest("C object handle errors",
|
||||
{$td->COMMAND => "qpdf-ctest 29 minimal.pdf '' ''"},
|
||||
{$td->FILE => "c-oh-errors-future.out", $td->EXIT_STATUS => 0},
|
||||
$td->NORMALIZE_NEWLINES);
|
||||
}
|
||||
else
|
||||
{
|
||||
$td->runtest("C object handle errors",
|
||||
{$td->COMMAND => "qpdf-ctest 29 minimal.pdf '' ''"},
|
||||
{$td->FILE => "c-oh-errors.out", $td->EXIT_STATUS => 0},
|
||||
$td->NORMALIZE_NEWLINES);
|
||||
}
|
||||
$td->runtest("C unhandled error warning",
|
||||
{$td->COMMAND => "qpdf-ctest 30 bad1.pdf '' ''"},
|
||||
{$td->FILE => "c-unhandled-error.out", $td->EXIT_STATUS => 0},
|
||||
|
|
|
@ -12,15 +12,28 @@ require TestDriver;
|
|||
|
||||
cleanup();
|
||||
|
||||
my $future = check_future();
|
||||
|
||||
my $td = new TestDriver('invalid-objects');
|
||||
|
||||
my $n_tests = 4;
|
||||
|
||||
$td->runtest("closed input source",
|
||||
{$td->COMMAND => "test_driver 73 minimal.pdf"},
|
||||
{$td->FILE => "test73.out",
|
||||
$td->EXIT_STATUS => 2},
|
||||
$td->NORMALIZE_NEWLINES);
|
||||
if ($future)
|
||||
{
|
||||
$td->runtest("closed input source",
|
||||
{$td->COMMAND => "test_driver 73 minimal.pdf"},
|
||||
{$td->FILE => "test73_future.out",
|
||||
$td->EXIT_STATUS => 2},
|
||||
$td->NORMALIZE_NEWLINES);
|
||||
}
|
||||
else
|
||||
{
|
||||
$td->runtest("closed input source",
|
||||
{$td->COMMAND => "test_driver 73 minimal.pdf"},
|
||||
{$td->FILE => "test73.out",
|
||||
$td->EXIT_STATUS => 2},
|
||||
$td->NORMALIZE_NEWLINES);
|
||||
}
|
||||
|
||||
$td->runtest("empty object",
|
||||
{$td->COMMAND => "qpdf -show-object=7,0 empty-object.pdf"},
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
get root: operation for dictionary attempted on object of type null: returning null for attempted key retrieval
|
||||
code: 7
|
||||
file:
|
||||
pos: 0
|
||||
text: operation for dictionary attempted on object of type null: returning null for attempted key retrieval
|
||||
bad parse: parsed object (offset 1): unknown token while reading object; treating as string
|
||||
code: 5
|
||||
file: parsed object
|
||||
pos: 1
|
||||
text: unknown token while reading object; treating as string
|
||||
type mismatch (int operation on string): operation for integer attempted on object of type string: returning 0
|
||||
code: 7
|
||||
file:
|
||||
pos: 0
|
||||
text: operation for integer attempted on object of type string: returning 0
|
||||
type mismatch (string operation on int): operation for string attempted on object of type integer: returning empty string
|
||||
code: 7
|
||||
file:
|
||||
pos: 0
|
||||
text: operation for string attempted on object of type integer: returning empty string
|
||||
array type mismatch - n_items: operation for array attempted on object of type integer: treating as empty
|
||||
code: 7
|
||||
file:
|
||||
pos: 0
|
||||
text: operation for array attempted on object of type integer: treating as empty
|
||||
array type mismatch - item: operation for array attempted on object of type integer: returning null
|
||||
code: 7
|
||||
file:
|
||||
pos: 0
|
||||
text: operation for array attempted on object of type integer: returning null
|
||||
append to non-array: operation for array attempted on object of type integer: ignoring attempt to append item
|
||||
code: 7
|
||||
file:
|
||||
pos: 0
|
||||
text: operation for array attempted on object of type integer: ignoring attempt to append item
|
||||
array bounds: returning null for out of bounds array access
|
||||
code: 7
|
||||
file:
|
||||
pos: 0
|
||||
text: returning null for out of bounds array access
|
||||
dictionary iter type mismatch: operation for dictionary attempted on object of type integer: treating as empty
|
||||
code: 7
|
||||
file:
|
||||
pos: 0
|
||||
text: operation for dictionary attempted on object of type integer: treating as empty
|
||||
dictionary type mismatch: operation for dictionary attempted on object of type integer: returning null for attempted key retrieval
|
||||
code: 7
|
||||
file:
|
||||
pos: 0
|
||||
text: operation for dictionary attempted on object of type integer: returning null for attempted key retrieval
|
||||
dictionary type mismatch: operation for dictionary attempted on object of type integer: returning false for a key containment request
|
||||
code: 7
|
||||
file:
|
||||
pos: 0
|
||||
text: operation for dictionary attempted on object of type integer: returning false for a key containment request
|
||||
C test 29 done
|
|
@ -0,0 +1,3 @@
|
|||
getRoot: operation for dictionary attempted on object of type null: returning null for attempted key retrieval
|
||||
WARNING: closed input source: object 1/0: error reading object: QPDF operation attempted on a QPDF object with no input source. QPDF operations are invalid before processFile (or another process method) or after closeInputSource
|
||||
closed input source: unable to find /Root dictionary
|
|
@ -158,4 +158,15 @@ sub cleanup
|
|||
system("rm -rf *split-out* ???-kfo.pdf *.tmpout \@file.pdf auto-*");
|
||||
}
|
||||
|
||||
sub check_future
|
||||
{
|
||||
my $future = 0;
|
||||
chomp($_ = `qpdf --version`);
|
||||
if (m/future/)
|
||||
{
|
||||
$future = 1;
|
||||
}
|
||||
$future;
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
|
@ -214,8 +214,10 @@ test_0_1(QPDF& pdf, char const* arg2)
|
|||
}
|
||||
|
||||
QTC::TC("qpdf", "main QTest indirect", qtest.isIndirect() ? 1 : 0);
|
||||
std::cout << "/QTest is " << (qtest.isIndirect() ? "in" : "") << "direct and has type "
|
||||
<< qtest.getTypeName() << " (" << qtest.getTypeCode() << ")" << std::endl;
|
||||
auto tn = qtest.getTypeName();
|
||||
auto tc = qtest.getTypeCode();
|
||||
std::cout << "/QTest is " << (qtest.isIndirect() ? "in" : "") << "direct and has type " << tn
|
||||
<< " (" << tc << ")" << std::endl;
|
||||
|
||||
if (qtest.isNull()) {
|
||||
QTC::TC("qpdf", "main QTest null");
|
||||
|
@ -1545,7 +1547,13 @@ test_42(QPDF& pdf, char const* arg2)
|
|||
assert(!uninitialized.isInitialized());
|
||||
assert(!uninitialized.isInteger());
|
||||
assert(!uninitialized.isDictionary());
|
||||
#ifdef QPDF_FUTURE
|
||||
assert(uninitialized.isNull());
|
||||
assert(uninitialized.isScalar());
|
||||
#else
|
||||
assert(!uninitialized.isNull());
|
||||
assert(!uninitialized.isScalar());
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -3477,8 +3485,13 @@ runtest(int n, char const* filename1, char const* arg2)
|
|||
assert(password == "1234567890123456789012(45678");
|
||||
|
||||
QPDFObjectHandle uninitialized;
|
||||
#ifndef QPDF_FUTURE
|
||||
assert(uninitialized.getTypeCode() == ::ot_uninitialized);
|
||||
assert(strcmp(uninitialized.getTypeName(), "uninitialized") == 0);
|
||||
#else
|
||||
assert(uninitialized.getTypeCode() == ::ot_null);
|
||||
assert(strcmp(uninitialized.getTypeName(), "null") == 0);
|
||||
#endif
|
||||
|
||||
// ABI: until QPDF 12, spot check deprecated constants
|
||||
assert(QPDFObject::ot_dictionary == ::ot_dictionary);
|
||||
|
|
Loading…
Reference in New Issue