In FUTURE, treat uninitialized object handles as null

This commit is contained in:
m-holger 2024-03-17 12:53:30 +00:00
parent 7a7a8c4471
commit bddb168dbf
19 changed files with 312 additions and 70 deletions

View File

@ -55,6 +55,9 @@ class QPDF_DLL_CLASS QPDFObjectHelper
}
protected:
#ifdef QPDF_FUTURE
QPDFObjectHelper() = default;
#endif
QPDFObjectHandle oh;
};

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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")) {

View File

@ -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
}
}

View File

@ -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,

View File

@ -90,8 +90,10 @@ QPDFOutlineDocumentHelper::resolveNamedDest(QPDFObjectHandle name)
}
}
}
#ifndef QPDF_FUTURE
if (!result.isInitialized()) {
result = QPDFObjectHandle::newNull();
}
#endif
return result;
}

View File

@ -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

View File

@ -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());
}
}

View File

@ -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";
}
}
}

View File

@ -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

View File

@ -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 {

View File

@ -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},

View File

@ -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"},

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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);