2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-06-09 05:32:43 +00:00

Add private methods QPDFObjectHandle::asArray etc

Centralise casting of QPDFObjects and reduce repeated dereferencing.
This commit is contained in:
m-holger 2022-08-02 19:13:29 +01:00
parent 2a2eebcaea
commit 114bffa089
4 changed files with 287 additions and 177 deletions

View File

@ -43,8 +43,18 @@
class Pipeline; class Pipeline;
class QPDF; class QPDF;
class QPDF_Dictionary;
class QPDF_Array; 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 QPDFTokenizer;
class QPDFExc; class QPDFExc;
class Pl_QPDFTokenizer; class Pl_QPDFTokenizer;
@ -1480,6 +1490,16 @@ class QPDFObjectHandle
}; };
return o.obj; return o.obj;
} }
static QPDF_Array*
asArray(QPDFObjectHandle& oh)
{
return oh.asArray();
}
static QPDF_Stream*
asStream(QPDFObjectHandle& oh)
{
return oh.asStream();
}
}; };
friend class ObjAccessor; friend class ObjAccessor;
@ -1581,6 +1601,20 @@ class QPDFObjectHandle
qpdf_offset_t offset, qpdf_offset_t offset,
size_t length); size_t length);
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 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);
@ -1881,7 +1915,7 @@ QPDFObjectHandle::setParsedOffset(qpdf_offset_t offset)
{ {
// This is called during parsing on newly created direct objects, // This is called during parsing on newly created direct objects,
// so we can't call dereference() here. // so we can't call dereference() here.
if (this->obj.get()) { if (initialized) {
this->obj->setParsedOffset(offset); this->obj->setParsedOffset(offset);
} }
} }

View File

@ -1420,8 +1420,7 @@ QPDF::fixDanglingReferences(bool force)
to_check.push_back(iter.second); to_check.push_back(iter.second);
} }
} else if (obj.isArray()) { } else if (obj.isArray()) {
QPDF_Array* arr = dynamic_cast<QPDF_Array*>( auto arr = QPDFObjectHandle::ObjAccessor::asArray(obj);
QPDFObjectHandle::ObjAccessor::getObject(obj).get());
arr->addExplicitElementsToList(to_check); arr->addExplicitElementsToList(to_check);
} }
for (auto sub: to_check) { for (auto sub: to_check) {
@ -2468,12 +2467,12 @@ QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign)
QPDFObjGen local_og(result.getObjGen()); QPDFObjGen local_og(result.getObjGen());
// Copy information from the foreign stream so we can pipe its // Copy information from the foreign stream so we can pipe its
// data later without keeping the original QPDF object around. // data later without keeping the original QPDF object around.
QPDF* foreign_stream_qpdf = foreign.getOwningQPDF( QPDF* foreign_stream_qpdf = foreign.getOwningQPDF(
false, "unable to retrieve owning qpdf from foreign stream"); false, "unable to retrieve owning qpdf from foreign stream");
QPDF_Stream* stream = dynamic_cast<QPDF_Stream*>( auto stream = QPDFObjectHandle::ObjAccessor::asStream(foreign);
QPDFObjectHandle::ObjAccessor::getObject(foreign).get()); if (stream == nullptr) {
if (!stream) {
throw std::logic_error("unable to retrieve underlying" throw std::logic_error("unable to retrieve underlying"
" stream object from foreign stream"); " stream object from foreign stream");
} }

View File

@ -277,24 +277,91 @@ QPDFObjectHandle::getTypeName()
return dereference() ? this->obj->getTypeName() : "uninitialized"; return dereference() ? this->obj->getTypeName() : "uninitialized";
} }
namespace QPDF_Array*
QPDFObjectHandle::asArray()
{ {
template <class T> return isArray() ? dynamic_cast<QPDF_Array*>(obj.get()) : nullptr;
class QPDFObjectTypeAccessor }
{
public: QPDF_Bool*
static bool QPDFObjectHandle::asBool()
check(std::shared_ptr<QPDFObject> const& o) {
{ return isBool() ? dynamic_cast<QPDF_Bool*>(obj.get()) : nullptr;
return (o && dynamic_cast<T const*>(o.get())); }
}
}; QPDF_Dictionary*
} // namespace QPDFObjectHandle::asDictionary()
{
return isDictionary() ? dynamic_cast<QPDF_Dictionary*>(obj.get()) : nullptr;
}
QPDF_InlineImage*
QPDFObjectHandle::asInlineImage()
{
return isInlineImage() ? dynamic_cast<QPDF_InlineImage*>(obj.get())
: nullptr;
}
QPDF_Integer*
QPDFObjectHandle::asInteger()
{
return isInteger() ? dynamic_cast<QPDF_Integer*>(obj.get()) : nullptr;
}
QPDF_Name*
QPDFObjectHandle::asName()
{
return isName() ? dynamic_cast<QPDF_Name*>(obj.get()) : nullptr;
}
QPDF_Null*
QPDFObjectHandle::asNull()
{
return isNull() ? dynamic_cast<QPDF_Null*>(obj.get()) : nullptr;
}
QPDF_Operator*
QPDFObjectHandle::asOperator()
{
return isOperator() ? dynamic_cast<QPDF_Operator*>(obj.get()) : nullptr;
}
QPDF_Real*
QPDFObjectHandle::asReal()
{
return isReal() ? dynamic_cast<QPDF_Real*>(obj.get()) : nullptr;
}
QPDF_Reserved*
QPDFObjectHandle::asReserved()
{
return isReserved() ? dynamic_cast<QPDF_Reserved*>(obj.get()) : nullptr;
}
QPDF_Stream*
QPDFObjectHandle::asStream()
{
return isStream() ? dynamic_cast<QPDF_Stream*>(obj.get()) : nullptr;
}
QPDF_Stream*
QPDFObjectHandle::asStreamWithAssert()
{
auto stream = asStream();
assertType("stream", stream);
return stream;
}
QPDF_String*
QPDFObjectHandle::asString()
{
return isString() ? dynamic_cast<QPDF_String*>(obj.get()) : nullptr;
}
bool bool
QPDFObjectHandle::isBool() QPDFObjectHandle::isBool()
{ {
return dereference() && QPDFObjectTypeAccessor<QPDF_Bool>::check(obj); return dereference() && (obj->getTypeCode() == QPDFObject::ot_boolean);
} }
bool bool
@ -303,26 +370,26 @@ QPDFObjectHandle::isDirectNull() const
// Don't call dereference() -- this is a const method, and we know // Don't call dereference() -- this is a const method, and we know
// objid == 0, so there's nothing to resolve. // objid == 0, so there's nothing to resolve.
return ( return (
this->initialized && (getObjectID() == 0) && initialized && (getObjectID() == 0) &&
QPDFObjectTypeAccessor<QPDF_Null>::check(obj)); (obj->getTypeCode() == QPDFObject::ot_null));
} }
bool bool
QPDFObjectHandle::isNull() QPDFObjectHandle::isNull()
{ {
return dereference() && QPDFObjectTypeAccessor<QPDF_Null>::check(obj); return dereference() && (obj->getTypeCode() == QPDFObject::ot_null);
} }
bool bool
QPDFObjectHandle::isInteger() QPDFObjectHandle::isInteger()
{ {
return dereference() && QPDFObjectTypeAccessor<QPDF_Integer>::check(obj); return dereference() && (obj->getTypeCode() == QPDFObject::ot_integer);
} }
bool bool
QPDFObjectHandle::isReal() QPDFObjectHandle::isReal()
{ {
return dereference() && QPDFObjectTypeAccessor<QPDF_Real>::check(obj); return dereference() && (obj->getTypeCode() == QPDFObject::ot_real);
} }
bool bool
@ -359,51 +426,49 @@ QPDFObjectHandle::getValueAsNumber(double& value)
bool bool
QPDFObjectHandle::isName() QPDFObjectHandle::isName()
{ {
return dereference() && QPDFObjectTypeAccessor<QPDF_Name>::check(obj); return dereference() && (obj->getTypeCode() == QPDFObject::ot_name);
} }
bool bool
QPDFObjectHandle::isString() QPDFObjectHandle::isString()
{ {
return dereference() && QPDFObjectTypeAccessor<QPDF_String>::check(obj); return dereference() && (obj->getTypeCode() == QPDFObject::ot_string);
} }
bool bool
QPDFObjectHandle::isOperator() QPDFObjectHandle::isOperator()
{ {
return dereference() && QPDFObjectTypeAccessor<QPDF_Operator>::check(obj); return dereference() && (obj->getTypeCode() == QPDFObject::ot_operator);
} }
bool bool
QPDFObjectHandle::isInlineImage() QPDFObjectHandle::isInlineImage()
{ {
return dereference() && return dereference() && (obj->getTypeCode() == QPDFObject::ot_inlineimage);
QPDFObjectTypeAccessor<QPDF_InlineImage>::check(obj);
} }
bool bool
QPDFObjectHandle::isArray() QPDFObjectHandle::isArray()
{ {
return dereference() && QPDFObjectTypeAccessor<QPDF_Array>::check(obj); return dereference() && (obj->getTypeCode() == QPDFObject::ot_array);
} }
bool bool
QPDFObjectHandle::isDictionary() QPDFObjectHandle::isDictionary()
{ {
return dereference() && QPDFObjectTypeAccessor<QPDF_Dictionary>::check(obj); return dereference() && (obj->getTypeCode() == QPDFObject::ot_dictionary);
} }
bool bool
QPDFObjectHandle::isStream() QPDFObjectHandle::isStream()
{ {
return dereference() && QPDFObjectTypeAccessor<QPDF_Stream>::check(obj); return dereference() && (obj->getTypeCode() == QPDFObject::ot_stream);
} }
bool bool
QPDFObjectHandle::isReserved() QPDFObjectHandle::isReserved()
{ {
// dereference will clear reserved if this has been replaced return dereference() && (obj->getTypeCode() == QPDFObject::ot_reserved);
return dereference() && QPDFObjectTypeAccessor<QPDF_Reserved>::check(obj);
} }
bool bool
@ -441,8 +506,9 @@ QPDFObjectHandle::isStreamOfType(
bool bool
QPDFObjectHandle::getBoolValue() QPDFObjectHandle::getBoolValue()
{ {
if (isBool()) { auto boolean = asBool();
return dynamic_cast<QPDF_Bool*>(obj.get())->getVal(); if (boolean) {
return boolean->getVal();
} else { } else {
typeWarning("boolean", "returning false"); typeWarning("boolean", "returning false");
QTC::TC("qpdf", "QPDFObjectHandle boolean returning false"); QTC::TC("qpdf", "QPDFObjectHandle boolean returning false");
@ -453,10 +519,11 @@ QPDFObjectHandle::getBoolValue()
bool bool
QPDFObjectHandle::getValueAsBool(bool& value) QPDFObjectHandle::getValueAsBool(bool& value)
{ {
if (!isBool()) { auto boolean = asBool();
if (boolean == nullptr) {
return false; return false;
} }
value = dynamic_cast<QPDF_Bool*>(obj.get())->getVal(); value = boolean->getVal();
return true; return true;
} }
@ -465,8 +532,9 @@ QPDFObjectHandle::getValueAsBool(bool& value)
long long long long
QPDFObjectHandle::getIntValue() QPDFObjectHandle::getIntValue()
{ {
if (isInteger()) { auto integer = asInteger();
return dynamic_cast<QPDF_Integer*>(obj.get())->getVal(); if (integer) {
return integer->getVal();
} else { } else {
typeWarning("integer", "returning 0"); typeWarning("integer", "returning 0");
QTC::TC("qpdf", "QPDFObjectHandle integer returning 0"); QTC::TC("qpdf", "QPDFObjectHandle integer returning 0");
@ -477,10 +545,11 @@ QPDFObjectHandle::getIntValue()
bool bool
QPDFObjectHandle::getValueAsInt(long long& value) QPDFObjectHandle::getValueAsInt(long long& value)
{ {
if (!isInteger()) { auto integer = asInteger();
if (integer == nullptr) {
return false; return false;
} }
value = dynamic_cast<QPDF_Integer*>(obj.get())->getVal(); value = integer->getVal();
return true; return true;
} }
@ -576,8 +645,9 @@ QPDFObjectHandle::getValueAsUInt(unsigned int& value)
std::string std::string
QPDFObjectHandle::getRealValue() QPDFObjectHandle::getRealValue()
{ {
if (isReal()) { auto real = asReal();
return dynamic_cast<QPDF_Real*>(obj.get())->getVal(); if (real) {
return real->getVal();
} else { } else {
typeWarning("real", "returning 0.0"); typeWarning("real", "returning 0.0");
QTC::TC("qpdf", "QPDFObjectHandle real returning 0.0"); QTC::TC("qpdf", "QPDFObjectHandle real returning 0.0");
@ -588,10 +658,11 @@ QPDFObjectHandle::getRealValue()
bool bool
QPDFObjectHandle::getValueAsReal(std::string& value) QPDFObjectHandle::getValueAsReal(std::string& value)
{ {
if (!isReal()) { auto real = asReal();
if (real == nullptr) {
return false; return false;
} }
value = dynamic_cast<QPDF_Real*>(obj.get())->getVal(); value = real->getVal();
return true; return true;
} }
@ -600,8 +671,9 @@ QPDFObjectHandle::getValueAsReal(std::string& value)
std::string std::string
QPDFObjectHandle::getName() QPDFObjectHandle::getName()
{ {
if (isName()) { auto name = asName();
return dynamic_cast<QPDF_Name*>(obj.get())->getName(); if (name) {
return name->getName();
} else { } else {
typeWarning("name", "returning dummy name"); typeWarning("name", "returning dummy name");
QTC::TC("qpdf", "QPDFObjectHandle name returning dummy name"); QTC::TC("qpdf", "QPDFObjectHandle name returning dummy name");
@ -612,10 +684,11 @@ QPDFObjectHandle::getName()
bool bool
QPDFObjectHandle::getValueAsName(std::string& value) QPDFObjectHandle::getValueAsName(std::string& value)
{ {
if (!isName()) { auto name = asName();
if (name == nullptr) {
return false; return false;
} }
value = dynamic_cast<QPDF_Name*>(obj.get())->getName(); value = name->getName();
return true; return true;
} }
@ -624,8 +697,9 @@ QPDFObjectHandle::getValueAsName(std::string& value)
std::string std::string
QPDFObjectHandle::getStringValue() QPDFObjectHandle::getStringValue()
{ {
if (isString()) { auto str = asString();
return dynamic_cast<QPDF_String*>(obj.get())->getVal(); if (str) {
return str->getVal();
} else { } else {
typeWarning("string", "returning empty string"); typeWarning("string", "returning empty string");
QTC::TC("qpdf", "QPDFObjectHandle string returning empty string"); QTC::TC("qpdf", "QPDFObjectHandle string returning empty string");
@ -636,18 +710,20 @@ QPDFObjectHandle::getStringValue()
bool bool
QPDFObjectHandle::getValueAsString(std::string& value) QPDFObjectHandle::getValueAsString(std::string& value)
{ {
if (!isString()) { auto str = asString();
if (str == nullptr) {
return false; return false;
} }
value = dynamic_cast<QPDF_String*>(obj.get())->getVal(); value = str->getVal();
return true; return true;
} }
std::string std::string
QPDFObjectHandle::getUTF8Value() QPDFObjectHandle::getUTF8Value()
{ {
if (isString()) { auto str = asString();
return dynamic_cast<QPDF_String*>(obj.get())->getUTF8Val(); if (str) {
return str->getUTF8Val();
} else { } else {
typeWarning("string", "returning empty string"); typeWarning("string", "returning empty string");
QTC::TC("qpdf", "QPDFObjectHandle string returning empty utf8"); QTC::TC("qpdf", "QPDFObjectHandle string returning empty utf8");
@ -658,10 +734,11 @@ QPDFObjectHandle::getUTF8Value()
bool bool
QPDFObjectHandle::getValueAsUTF8(std::string& value) QPDFObjectHandle::getValueAsUTF8(std::string& value)
{ {
if (!isString()) { auto str = asString();
if (str == nullptr) {
return false; return false;
} }
value = dynamic_cast<QPDF_String*>(obj.get())->getUTF8Val(); value = str->getUTF8Val();
return true; return true;
} }
@ -670,8 +747,9 @@ QPDFObjectHandle::getValueAsUTF8(std::string& value)
std::string std::string
QPDFObjectHandle::getOperatorValue() QPDFObjectHandle::getOperatorValue()
{ {
if (isOperator()) { auto op = asOperator();
return dynamic_cast<QPDF_Operator*>(obj.get())->getVal(); if (op) {
return op->getVal();
} else { } else {
typeWarning("operator", "returning fake value"); typeWarning("operator", "returning fake value");
QTC::TC("qpdf", "QPDFObjectHandle operator returning fake value"); QTC::TC("qpdf", "QPDFObjectHandle operator returning fake value");
@ -682,18 +760,20 @@ QPDFObjectHandle::getOperatorValue()
bool bool
QPDFObjectHandle::getValueAsOperator(std::string& value) QPDFObjectHandle::getValueAsOperator(std::string& value)
{ {
if (!isOperator()) { auto op = asOperator();
if (op == nullptr) {
return false; return false;
} }
value = dynamic_cast<QPDF_Operator*>(obj.get())->getVal(); value = op->getVal();
return true; return true;
} }
std::string std::string
QPDFObjectHandle::getInlineImageValue() QPDFObjectHandle::getInlineImageValue()
{ {
if (isInlineImage()) { auto image = asInlineImage();
return dynamic_cast<QPDF_InlineImage*>(obj.get())->getVal(); if (image) {
return image->getVal();
} else { } else {
typeWarning("inlineimage", "returning empty data"); typeWarning("inlineimage", "returning empty data");
QTC::TC("qpdf", "QPDFObjectHandle inlineimage returning empty data"); QTC::TC("qpdf", "QPDFObjectHandle inlineimage returning empty data");
@ -704,10 +784,11 @@ QPDFObjectHandle::getInlineImageValue()
bool bool
QPDFObjectHandle::getValueAsInlineImage(std::string& value) QPDFObjectHandle::getValueAsInlineImage(std::string& value)
{ {
if (!isInlineImage()) { auto image = asInlineImage();
if (image == nullptr) {
return false; return false;
} }
value = dynamic_cast<QPDF_InlineImage*>(obj.get())->getVal(); value = image->getVal();
return true; return true;
} }
@ -722,8 +803,9 @@ QPDFObjectHandle::aitems()
int int
QPDFObjectHandle::getArrayNItems() QPDFObjectHandle::getArrayNItems()
{ {
if (isArray()) { auto array = asArray();
return dynamic_cast<QPDF_Array*>(obj.get())->getNItems(); if (array) {
return array->getNItems();
} else { } else {
typeWarning("array", "treating as empty"); typeWarning("array", "treating as empty");
QTC::TC("qpdf", "QPDFObjectHandle array treating as empty"); QTC::TC("qpdf", "QPDFObjectHandle array treating as empty");
@ -735,11 +817,12 @@ QPDFObjectHandle
QPDFObjectHandle::getArrayItem(int n) QPDFObjectHandle::getArrayItem(int n)
{ {
QPDFObjectHandle result; QPDFObjectHandle result;
if (isArray() && (n < getArrayNItems()) && (n >= 0)) { auto array = asArray();
result = dynamic_cast<QPDF_Array*>(obj.get())->getItem(n); if (array && (n < array->getNItems()) && (n >= 0)) {
result = array->getItem(n);
} else { } else {
result = newNull(); result = newNull();
if (isArray()) { if (array) {
objectWarning("returning null for out of bounds array access"); objectWarning("returning null for out of bounds array access");
QTC::TC("qpdf", "QPDFObjectHandle array bounds"); QTC::TC("qpdf", "QPDFObjectHandle array bounds");
} else { } else {
@ -748,7 +831,7 @@ QPDFObjectHandle::getArrayItem(int n)
} }
QPDF* context = nullptr; QPDF* context = nullptr;
std::string description; std::string description;
if (this->obj->getDescription(context, description)) { if (obj->getDescription(context, description)) {
result.setObjectDescription( result.setObjectDescription(
context, context,
description + " -> null returned from invalid array access"); description + " -> null returned from invalid array access");
@ -760,14 +843,12 @@ QPDFObjectHandle::getArrayItem(int n)
bool bool
QPDFObjectHandle::isRectangle() QPDFObjectHandle::isRectangle()
{ {
if (!isArray()) { auto array = asArray();
return false; if ((array == nullptr) || (array->getNItems() != 4)) {
}
if (getArrayNItems() != 4) {
return false; return false;
} }
for (int i = 0; i < 4; ++i) { for (int i = 0; i < 4; ++i) {
if (!getArrayItem(i).isNumber()) { if (!array->getItem(i).isNumber()) {
return false; return false;
} }
} }
@ -777,14 +858,12 @@ QPDFObjectHandle::isRectangle()
bool bool
QPDFObjectHandle::isMatrix() QPDFObjectHandle::isMatrix()
{ {
if (!isArray()) { auto array = asArray();
return false; if ((array == nullptr) || (array->getNItems() != 6)) {
}
if (getArrayNItems() != 6) {
return false; return false;
} }
for (int i = 0; i < 6; ++i) { for (int i = 0; i < 6; ++i) {
if (!getArrayItem(i).isNumber()) { if (!array->getItem(i).isNumber()) {
return false; return false;
} }
} }
@ -796,13 +875,14 @@ QPDFObjectHandle::getArrayAsRectangle()
{ {
Rectangle result; Rectangle result;
if (isRectangle()) { if (isRectangle()) {
auto array = asArray();
// Rectangle coordinates are always supposed to be llx, lly, // Rectangle coordinates are always supposed to be llx, lly,
// urx, ury, but files have been found in the wild where // urx, ury, but files have been found in the wild where
// llx > urx or lly > ury. // llx > urx or lly > ury.
double i0 = getArrayItem(0).getNumericValue(); double i0 = array->getItem(0).getNumericValue();
double i1 = getArrayItem(1).getNumericValue(); double i1 = array->getItem(1).getNumericValue();
double i2 = getArrayItem(2).getNumericValue(); double i2 = array->getItem(2).getNumericValue();
double i3 = getArrayItem(3).getNumericValue(); double i3 = array->getItem(3).getNumericValue();
result = Rectangle( result = Rectangle(
std::min(i0, i2), std::min(i0, i2),
std::min(i1, i3), std::min(i1, i3),
@ -817,13 +897,14 @@ QPDFObjectHandle::getArrayAsMatrix()
{ {
Matrix result; Matrix result;
if (isMatrix()) { if (isMatrix()) {
auto array = asArray();
result = Matrix( result = Matrix(
getArrayItem(0).getNumericValue(), array->getItem(0).getNumericValue(),
getArrayItem(1).getNumericValue(), array->getItem(1).getNumericValue(),
getArrayItem(2).getNumericValue(), array->getItem(2).getNumericValue(),
getArrayItem(3).getNumericValue(), array->getItem(3).getNumericValue(),
getArrayItem(4).getNumericValue(), array->getItem(4).getNumericValue(),
getArrayItem(5).getNumericValue()); array->getItem(5).getNumericValue());
} }
return result; return result;
} }
@ -832,8 +913,9 @@ std::vector<QPDFObjectHandle>
QPDFObjectHandle::getArrayAsVector() QPDFObjectHandle::getArrayAsVector()
{ {
std::vector<QPDFObjectHandle> result; std::vector<QPDFObjectHandle> result;
if (isArray()) { auto array = asArray();
dynamic_cast<QPDF_Array*>(obj.get())->getAsVector(result); if (array) {
array->getAsVector(result);
} else { } else {
typeWarning("array", "treating as empty"); typeWarning("array", "treating as empty");
QTC::TC("qpdf", "QPDFObjectHandle array treating as empty vector"); QTC::TC("qpdf", "QPDFObjectHandle array treating as empty vector");
@ -846,9 +928,10 @@ QPDFObjectHandle::getArrayAsVector()
void void
QPDFObjectHandle::setArrayItem(int n, QPDFObjectHandle const& item) QPDFObjectHandle::setArrayItem(int n, QPDFObjectHandle const& item)
{ {
if (isArray()) { auto array = asArray();
if (array) {
checkOwnership(item); checkOwnership(item);
dynamic_cast<QPDF_Array*>(obj.get())->setItem(n, item); array->setItem(n, item);
} else { } else {
typeWarning("array", "ignoring attempt to set item"); typeWarning("array", "ignoring attempt to set item");
QTC::TC("qpdf", "QPDFObjectHandle array ignoring set item"); QTC::TC("qpdf", "QPDFObjectHandle array ignoring set item");
@ -858,11 +941,12 @@ QPDFObjectHandle::setArrayItem(int n, QPDFObjectHandle const& item)
void void
QPDFObjectHandle::setArrayFromVector(std::vector<QPDFObjectHandle> const& items) QPDFObjectHandle::setArrayFromVector(std::vector<QPDFObjectHandle> const& items)
{ {
if (isArray()) { auto array = asArray();
if (array) {
for (auto const& item: items) { for (auto const& item: items) {
checkOwnership(item); checkOwnership(item);
} }
dynamic_cast<QPDF_Array*>(obj.get())->setFromVector(items); array->setFromVector(items);
} else { } else {
typeWarning("array", "ignoring attempt to replace items"); typeWarning("array", "ignoring attempt to replace items");
QTC::TC("qpdf", "QPDFObjectHandle array ignoring replace items"); QTC::TC("qpdf", "QPDFObjectHandle array ignoring replace items");
@ -872,8 +956,9 @@ QPDFObjectHandle::setArrayFromVector(std::vector<QPDFObjectHandle> const& items)
void void
QPDFObjectHandle::insertItem(int at, QPDFObjectHandle const& item) QPDFObjectHandle::insertItem(int at, QPDFObjectHandle const& item)
{ {
if (isArray()) { auto array = asArray();
dynamic_cast<QPDF_Array*>(obj.get())->insertItem(at, item); if (array) {
array->insertItem(at, item);
} else { } else {
typeWarning("array", "ignoring attempt to insert item"); typeWarning("array", "ignoring attempt to insert item");
QTC::TC("qpdf", "QPDFObjectHandle array ignoring insert item"); QTC::TC("qpdf", "QPDFObjectHandle array ignoring insert item");
@ -890,9 +975,10 @@ QPDFObjectHandle::insertItemAndGetNew(int at, QPDFObjectHandle const& item)
void void
QPDFObjectHandle::appendItem(QPDFObjectHandle const& item) QPDFObjectHandle::appendItem(QPDFObjectHandle const& item)
{ {
if (isArray()) { auto array = asArray();
if (array) {
checkOwnership(item); checkOwnership(item);
dynamic_cast<QPDF_Array*>(obj.get())->appendItem(item); array->appendItem(item);
} else { } else {
typeWarning("array", "ignoring attempt to append item"); typeWarning("array", "ignoring attempt to append item");
QTC::TC("qpdf", "QPDFObjectHandle array ignoring append item"); QTC::TC("qpdf", "QPDFObjectHandle array ignoring append item");
@ -909,10 +995,11 @@ QPDFObjectHandle::appendItemAndGetNew(QPDFObjectHandle const& item)
void void
QPDFObjectHandle::eraseItem(int at) QPDFObjectHandle::eraseItem(int at)
{ {
if (isArray() && (at < getArrayNItems()) && (at >= 0)) { auto array = asArray();
dynamic_cast<QPDF_Array*>(obj.get())->eraseItem(at); if (array && (at < array->getNItems()) && (at >= 0)) {
array->eraseItem(at);
} else { } else {
if (isArray()) { if (array) {
objectWarning("ignoring attempt to erase out of bounds array item"); objectWarning("ignoring attempt to erase out of bounds array item");
QTC::TC("qpdf", "QPDFObjectHandle erase array bounds"); QTC::TC("qpdf", "QPDFObjectHandle erase array bounds");
} else { } else {
@ -926,8 +1013,9 @@ QPDFObjectHandle
QPDFObjectHandle::eraseItemAndGetOld(int at) QPDFObjectHandle::eraseItemAndGetOld(int at)
{ {
auto result = QPDFObjectHandle::newNull(); auto result = QPDFObjectHandle::newNull();
if (isArray() && (at < getArrayNItems()) && (at >= 0)) { auto array = asArray();
result = getArrayItem(at); if (array && (at < array->getNItems()) && (at >= 0)) {
result = array->getItem(at);
} }
eraseItem(at); eraseItem(at);
return result; return result;
@ -944,8 +1032,9 @@ QPDFObjectHandle::ditems()
bool bool
QPDFObjectHandle::hasKey(std::string const& key) QPDFObjectHandle::hasKey(std::string const& key)
{ {
if (isDictionary()) { auto dict = asDictionary();
return dynamic_cast<QPDF_Dictionary*>(obj.get())->hasKey(key); if (dict) {
return dict->hasKey(key);
} else { } else {
typeWarning( typeWarning(
"dictionary", "returning false for a key containment request"); "dictionary", "returning false for a key containment request");
@ -958,15 +1047,16 @@ QPDFObjectHandle
QPDFObjectHandle::getKey(std::string const& key) QPDFObjectHandle::getKey(std::string const& key)
{ {
QPDFObjectHandle result; QPDFObjectHandle result;
if (isDictionary()) { auto dict = asDictionary();
result = dynamic_cast<QPDF_Dictionary*>(obj.get())->getKey(key); if (dict) {
result = dict->getKey(key);
} else { } else {
typeWarning("dictionary", "returning null for attempted key retrieval"); typeWarning("dictionary", "returning null for attempted key retrieval");
QTC::TC("qpdf", "QPDFObjectHandle dictionary null for getKey"); QTC::TC("qpdf", "QPDFObjectHandle dictionary null for getKey");
result = newNull(); result = newNull();
QPDF* qpdf = nullptr; QPDF* qpdf = nullptr;
std::string description; std::string description;
if (this->obj->getDescription(qpdf, description)) { if (obj->getDescription(qpdf, description)) {
result.setObjectDescription( result.setObjectDescription(
qpdf, qpdf,
(description + " -> null returned from getting key " + key + (description + " -> null returned from getting key " + key +
@ -986,8 +1076,9 @@ std::set<std::string>
QPDFObjectHandle::getKeys() QPDFObjectHandle::getKeys()
{ {
std::set<std::string> result; std::set<std::string> result;
if (isDictionary()) { auto dict = asDictionary();
result = dynamic_cast<QPDF_Dictionary*>(obj.get())->getKeys(); if (dict) {
result = dict->getKeys();
} else { } else {
typeWarning("dictionary", "treating as empty"); typeWarning("dictionary", "treating as empty");
QTC::TC("qpdf", "QPDFObjectHandle dictionary empty set for getKeys"); QTC::TC("qpdf", "QPDFObjectHandle dictionary empty set for getKeys");
@ -999,8 +1090,9 @@ std::map<std::string, QPDFObjectHandle>
QPDFObjectHandle::getDictAsMap() QPDFObjectHandle::getDictAsMap()
{ {
std::map<std::string, QPDFObjectHandle> result; std::map<std::string, QPDFObjectHandle> result;
if (isDictionary()) { auto dict = asDictionary();
result = dynamic_cast<QPDF_Dictionary*>(obj.get())->getAsMap(); if (dict) {
result = dict->getAsMap();
} else { } else {
typeWarning("dictionary", "treating as empty"); typeWarning("dictionary", "treating as empty");
QTC::TC("qpdf", "QPDFObjectHandle dictionary empty map for asMap"); QTC::TC("qpdf", "QPDFObjectHandle dictionary empty map for asMap");
@ -1191,9 +1283,10 @@ void
QPDFObjectHandle::replaceKey( QPDFObjectHandle::replaceKey(
std::string const& key, QPDFObjectHandle const& value) std::string const& key, QPDFObjectHandle const& value)
{ {
if (isDictionary()) { auto dict = asDictionary();
if (dict) {
checkOwnership(value); checkOwnership(value);
dynamic_cast<QPDF_Dictionary*>(obj.get())->replaceKey(key, value); dict->replaceKey(key, value);
} else { } else {
typeWarning("dictionary", "ignoring key replacement request"); typeWarning("dictionary", "ignoring key replacement request");
QTC::TC("qpdf", "QPDFObjectHandle dictionary ignoring replaceKey"); QTC::TC("qpdf", "QPDFObjectHandle dictionary ignoring replaceKey");
@ -1220,8 +1313,9 @@ QPDFObjectHandle::replaceKeyAndGetOld(
void void
QPDFObjectHandle::removeKey(std::string const& key) QPDFObjectHandle::removeKey(std::string const& key)
{ {
if (isDictionary()) { auto dict = asDictionary();
dynamic_cast<QPDF_Dictionary*>(obj.get())->removeKey(key); if (dict) {
dict->removeKey(key);
} else { } else {
typeWarning("dictionary", "ignoring key removal request"); typeWarning("dictionary", "ignoring key removal request");
QTC::TC("qpdf", "QPDFObjectHandle dictionary ignoring removeKey"); QTC::TC("qpdf", "QPDFObjectHandle dictionary ignoring removeKey");
@ -1232,8 +1326,9 @@ QPDFObjectHandle
QPDFObjectHandle::removeKeyAndGetOld(std::string const& key) QPDFObjectHandle::removeKeyAndGetOld(std::string const& key)
{ {
auto result = QPDFObjectHandle::newNull(); auto result = QPDFObjectHandle::newNull();
if (isDictionary()) { auto dict = asDictionary();
result = getKey(key); if (dict) {
result = dict->getKey(key);
} }
removeKey(key); removeKey(key);
return result; return result;
@ -1250,50 +1345,43 @@ QPDFObjectHandle::replaceOrRemoveKey(
QPDFObjectHandle QPDFObjectHandle
QPDFObjectHandle::getDict() QPDFObjectHandle::getDict()
{ {
assertStream(); return asStreamWithAssert()->getDict();
return dynamic_cast<QPDF_Stream*>(obj.get())->getDict();
} }
void void
QPDFObjectHandle::setFilterOnWrite(bool val) QPDFObjectHandle::setFilterOnWrite(bool val)
{ {
assertStream(); asStreamWithAssert()->setFilterOnWrite(val);
dynamic_cast<QPDF_Stream*>(obj.get())->setFilterOnWrite(val);
} }
bool bool
QPDFObjectHandle::getFilterOnWrite() QPDFObjectHandle::getFilterOnWrite()
{ {
assertStream(); return asStreamWithAssert()->getFilterOnWrite();
return dynamic_cast<QPDF_Stream*>(obj.get())->getFilterOnWrite();
} }
bool bool
QPDFObjectHandle::isDataModified() QPDFObjectHandle::isDataModified()
{ {
assertStream(); return asStreamWithAssert()->isDataModified();
return dynamic_cast<QPDF_Stream*>(obj.get())->isDataModified();
} }
void void
QPDFObjectHandle::replaceDict(QPDFObjectHandle const& new_dict) QPDFObjectHandle::replaceDict(QPDFObjectHandle const& new_dict)
{ {
assertStream(); asStreamWithAssert()->replaceDict(new_dict);
dynamic_cast<QPDF_Stream*>(obj.get())->replaceDict(new_dict);
} }
std::shared_ptr<Buffer> std::shared_ptr<Buffer>
QPDFObjectHandle::getStreamData(qpdf_stream_decode_level_e level) QPDFObjectHandle::getStreamData(qpdf_stream_decode_level_e level)
{ {
assertStream(); return asStreamWithAssert()->getStreamData(level);
return dynamic_cast<QPDF_Stream*>(obj.get())->getStreamData(level);
} }
std::shared_ptr<Buffer> std::shared_ptr<Buffer>
QPDFObjectHandle::getRawStreamData() QPDFObjectHandle::getRawStreamData()
{ {
assertStream(); return asStreamWithAssert()->getRawStreamData();
return dynamic_cast<QPDF_Stream*>(obj.get())->getRawStreamData();
} }
bool bool
@ -1305,8 +1393,7 @@ QPDFObjectHandle::pipeStreamData(
bool suppress_warnings, bool suppress_warnings,
bool will_retry) bool will_retry)
{ {
assertStream(); return asStreamWithAssert()->pipeStreamData(
return dynamic_cast<QPDF_Stream*>(obj.get())->pipeStreamData(
p, p,
filtering_attempted, filtering_attempted,
encode_flags, encode_flags,
@ -1323,9 +1410,8 @@ QPDFObjectHandle::pipeStreamData(
bool suppress_warnings, bool suppress_warnings,
bool will_retry) bool will_retry)
{ {
assertStream();
bool filtering_attempted; bool filtering_attempted;
dynamic_cast<QPDF_Stream*>(obj.get())->pipeStreamData( asStreamWithAssert()->pipeStreamData(
p, p,
&filtering_attempted, &filtering_attempted,
encode_flags, encode_flags,
@ -1359,9 +1445,7 @@ QPDFObjectHandle::replaceStreamData(
QPDFObjectHandle const& filter, QPDFObjectHandle const& filter,
QPDFObjectHandle const& decode_parms) QPDFObjectHandle const& decode_parms)
{ {
assertStream(); asStreamWithAssert()->replaceStreamData(data, filter, decode_parms);
dynamic_cast<QPDF_Stream*>(obj.get())->replaceStreamData(
data, filter, decode_parms);
} }
void void
@ -1370,14 +1454,12 @@ QPDFObjectHandle::replaceStreamData(
QPDFObjectHandle const& filter, QPDFObjectHandle const& filter,
QPDFObjectHandle const& decode_parms) QPDFObjectHandle const& decode_parms)
{ {
assertStream();
auto b = std::make_shared<Buffer>(data.length()); auto b = std::make_shared<Buffer>(data.length());
unsigned char* bp = b->getBuffer(); unsigned char* bp = b->getBuffer();
if (bp) { if (bp) {
memcpy(bp, data.c_str(), data.length()); memcpy(bp, data.c_str(), data.length());
} }
dynamic_cast<QPDF_Stream*>(obj.get())->replaceStreamData( asStreamWithAssert()->replaceStreamData(b, filter, decode_parms);
b, filter, decode_parms);
} }
void void
@ -1386,9 +1468,7 @@ QPDFObjectHandle::replaceStreamData(
QPDFObjectHandle const& filter, QPDFObjectHandle const& filter,
QPDFObjectHandle const& decode_parms) QPDFObjectHandle const& decode_parms)
{ {
assertStream(); asStreamWithAssert()->replaceStreamData(provider, filter, decode_parms);
dynamic_cast<QPDF_Stream*>(obj.get())->replaceStreamData(
provider, filter, decode_parms);
} }
namespace namespace
@ -1437,11 +1517,9 @@ QPDFObjectHandle::replaceStreamData(
QPDFObjectHandle const& filter, QPDFObjectHandle const& filter,
QPDFObjectHandle const& decode_parms) QPDFObjectHandle const& decode_parms)
{ {
assertStream();
auto sdp = auto sdp =
std::shared_ptr<StreamDataProvider>(new FunctionProvider(provider)); std::shared_ptr<StreamDataProvider>(new FunctionProvider(provider));
dynamic_cast<QPDF_Stream*>(obj.get())->replaceStreamData( asStreamWithAssert()->replaceStreamData(sdp, filter, decode_parms);
sdp, filter, decode_parms);
} }
void void
@ -1450,11 +1528,9 @@ QPDFObjectHandle::replaceStreamData(
QPDFObjectHandle const& filter, QPDFObjectHandle const& filter,
QPDFObjectHandle const& decode_parms) QPDFObjectHandle const& decode_parms)
{ {
assertStream();
auto sdp = auto sdp =
std::shared_ptr<StreamDataProvider>(new FunctionProvider(provider)); std::shared_ptr<StreamDataProvider>(new FunctionProvider(provider));
dynamic_cast<QPDF_Stream*>(obj.get())->replaceStreamData( asStreamWithAssert()->replaceStreamData(sdp, filter, decode_parms);
sdp, filter, decode_parms);
} }
std::map<std::string, QPDFObjectHandle> std::map<std::string, QPDFObjectHandle>
@ -1469,10 +1545,11 @@ QPDFObjectHandle::arrayOrStreamToStreamArray(
{ {
all_description = description; all_description = description;
std::vector<QPDFObjectHandle> result; std::vector<QPDFObjectHandle> result;
if (isArray()) { auto array = asArray();
int n_items = getArrayNItems(); if (array) {
int n_items = array->getNItems();
for (int i = 0; i < n_items; ++i) { for (int i = 0; i < n_items; ++i) {
QPDFObjectHandle item = getArrayItem(i); QPDFObjectHandle item = array->getItem(i);
if (item.isStream()) { if (item.isStream()) {
result.push_back(item); result.push_back(item);
} else { } else {
@ -1649,8 +1726,9 @@ QPDFObjectHandle::unparseResolved()
std::string std::string
QPDFObjectHandle::unparseBinary() QPDFObjectHandle::unparseBinary()
{ {
if (this->isString()) { auto str = asString();
return dynamic_cast<QPDF_String*>(this->obj.get())->unparse(true); if (str) {
return str->unparse(true);
} else { } else {
return unparse(); return unparse();
} }
@ -1666,7 +1744,7 @@ QPDFObjectHandle::getJSON(bool dereference_indirect)
JSON JSON
QPDFObjectHandle::getJSON(int json_version, bool dereference_indirect) QPDFObjectHandle::getJSON(int json_version, bool dereference_indirect)
{ {
if ((!dereference_indirect) && this->isIndirect()) { if ((!dereference_indirect) && isIndirect()) {
return JSON::makeString(unparse()); return JSON::makeString(unparse());
} else if (!dereference()) { } else if (!dereference()) {
throw std::logic_error( throw std::logic_error(
@ -1675,7 +1753,7 @@ QPDFObjectHandle::getJSON(int json_version, bool dereference_indirect)
throw std::logic_error( throw std::logic_error(
"QPDFObjectHandle: attempting to unparse a reserved object"); "QPDFObjectHandle: attempting to unparse a reserved object");
} else { } else {
return this->obj->getJSON(json_version); return obj->getJSON(json_version);
} }
} }
@ -1687,8 +1765,7 @@ QPDFObjectHandle::getStreamJSON(
Pipeline* p, Pipeline* p,
std::string const& data_filename) std::string const& data_filename)
{ {
assertStream(); return asStreamWithAssert()->getStreamJSON(
return dynamic_cast<QPDF_Stream*>(obj.get())->getStreamJSON(
json_version, json_data, decode_level, p, data_filename); json_version, json_data, decode_level, p, data_filename);
} }
@ -1908,8 +1985,7 @@ QPDFObjectHandle::addContentTokenFilter(std::shared_ptr<TokenFilter> filter)
void void
QPDFObjectHandle::addTokenFilter(std::shared_ptr<TokenFilter> filter) QPDFObjectHandle::addTokenFilter(std::shared_ptr<TokenFilter> filter)
{ {
assertStream(); return asStreamWithAssert()->addTokenFilter(filter);
return dynamic_cast<QPDF_Stream*>(obj.get())->addTokenFilter(filter);
} }
QPDFObjectHandle QPDFObjectHandle
@ -1946,7 +2022,6 @@ QPDFObjectHandle::newIndirect(QPDF* qpdf, QPDFObjGen const& og)
QTC::TC("qpdf", "QPDFObjectHandle indirect with 0 objid"); QTC::TC("qpdf", "QPDFObjectHandle indirect with 0 objid");
return newNull(); return newNull();
} }
return QPDFObjectHandle(qpdf, og, QPDF_Unresolved::create()); return QPDFObjectHandle(qpdf, og, QPDF_Unresolved::create());
} }
@ -2119,8 +2194,7 @@ QPDFObjectHandle::newStream(QPDF* qpdf)
QPDFObjectHandle stream_dict = newDictionary(); QPDFObjectHandle stream_dict = newDictionary();
QPDFObjectHandle result = qpdf->makeIndirectObject(QPDFObjectHandle( QPDFObjectHandle result = qpdf->makeIndirectObject(QPDFObjectHandle(
QPDF_Stream::create(qpdf, QPDFObjGen(), stream_dict, 0, 0))); QPDF_Stream::create(qpdf, QPDFObjGen(), stream_dict, 0, 0)));
result.dereference(); auto stream = result.asStream();
QPDF_Stream* stream = dynamic_cast<QPDF_Stream*>(result.obj.get());
stream->setObjGen(result.getObjGen()); stream->setObjGen(result.getObjGen());
return result; return result;
} }
@ -2248,9 +2322,10 @@ QPDFObjectHandle::copyObject(
new_obj = obj->shallowCopy(); new_obj = obj->shallowCopy();
} else if (isArray()) { } else if (isArray()) {
std::vector<QPDFObjectHandle> items; std::vector<QPDFObjectHandle> items;
int n = getArrayNItems(); auto array = asArray();
int n = array->getNItems();
for (int i = 0; i < n; ++i) { for (int i = 0; i < n; ++i) {
items.push_back(getArrayItem(i)); items.push_back(array->getItem(i));
if ((!first_level_only) && if ((!first_level_only) &&
(cross_indirect || (!items.back().isIndirect()))) { (cross_indirect || (!items.back().isIndirect()))) {
items.back().copyObject( items.back().copyObject(
@ -2260,8 +2335,9 @@ QPDFObjectHandle::copyObject(
new_obj = QPDF_Array::create(items); new_obj = QPDF_Array::create(items);
} else if (isDictionary()) { } else if (isDictionary()) {
std::map<std::string, QPDFObjectHandle> items; std::map<std::string, QPDFObjectHandle> items;
auto dict = asDictionary();
for (auto const& key: getKeys()) { for (auto const& key: getKeys()) {
items[key] = getKey(key); items[key] = dict->getKey(key);
if ((!first_level_only) && if ((!first_level_only) &&
(cross_indirect || (!items[key].isIndirect()))) { (cross_indirect || (!items[key].isIndirect()))) {
items[key].copyObject( items[key].copyObject(
@ -2309,7 +2385,7 @@ QPDFObjectHandle::makeDirect(bool allow_streams)
void void
QPDFObjectHandle::assertInitialized() const QPDFObjectHandle::assertInitialized() const
{ {
if (!this->initialized) { if (!initialized) {
throw std::logic_error("operation attempted on uninitialized " throw std::logic_error("operation attempted on uninitialized "
"QPDFObjectHandle"); "QPDFObjectHandle");
} }
@ -2551,7 +2627,6 @@ QPDFObjectHandle::dereference()
(getObjectID() && (getObjectID() &&
QPDF::Resolver::objectChanged(this->qpdf, getObjGen(), this->obj))) { QPDF::Resolver::objectChanged(this->qpdf, getObjGen(), this->obj))) {
this->obj = QPDF::Resolver::resolve(this->qpdf, getObjGen()); this->obj = QPDF::Resolver::resolve(this->qpdf, getObjGen());
} }
return true; return true;
} }

View File

@ -17,14 +17,16 @@ QPDF_Reserved::shallowCopy()
std::string std::string
QPDF_Reserved::unparse() QPDF_Reserved::unparse()
{ {
throw std::logic_error("attempt to unparse QPDF_Reserved"); throw std::logic_error(
"QPDFObjectHandle: attempting to unparse a reserved object");
return ""; return "";
} }
JSON JSON
QPDF_Reserved::getJSON(int json_version) 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(); return JSON::makeNull();
} }