diff options
Diffstat (limited to 'libqpdf/QPDFObjectHandle.cc')
-rw-r--r-- | libqpdf/QPDFObjectHandle.cc | 484 |
1 files changed, 404 insertions, 80 deletions
diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc index d48461bf..2e9cc996 100644 --- a/libqpdf/QPDFObjectHandle.cc +++ b/libqpdf/QPDFObjectHandle.cc @@ -190,6 +190,18 @@ QPDFObjectHandle::releaseResolved() } } +void +QPDFObjectHandle::setObjectDescriptionFromInput( + QPDFObjectHandle object, QPDF* context, + std::string const& description, PointerHolder<InputSource> input, + qpdf_offset_t offset) +{ + object.setObjectDescription( + context, + input->getName() + ", " + description + + " at offset " + QUtil::int_to_string(offset)); +} + bool QPDFObjectHandle::isInitialized() const { @@ -282,7 +294,8 @@ QPDFObjectHandle::getNumericValue() } else { - throw std::logic_error("getNumericValue called for non-numeric object"); + typeWarning("number", "returning 0"); + QTC::TC("qpdf", "QPDFObjectHandle numeric non-numeric"); } return result; } @@ -363,8 +376,16 @@ QPDFObjectHandle::isScalar() bool QPDFObjectHandle::getBoolValue() { - assertBool(); - return dynamic_cast<QPDF_Bool*>(m->obj.getPointer())->getVal(); + if (isBool()) + { + return dynamic_cast<QPDF_Bool*>(m->obj.getPointer())->getVal(); + } + else + { + typeWarning("boolean", "returning false"); + QTC::TC("qpdf", "QPDFObjectHandle boolean returning false"); + return false; + } } // Integer accessors @@ -372,8 +393,16 @@ QPDFObjectHandle::getBoolValue() long long QPDFObjectHandle::getIntValue() { - assertInteger(); - return dynamic_cast<QPDF_Integer*>(m->obj.getPointer())->getVal(); + if (isInteger()) + { + return dynamic_cast<QPDF_Integer*>(m->obj.getPointer())->getVal(); + } + else + { + typeWarning("integer", "returning 0"); + QTC::TC("qpdf", "QPDFObjectHandle integer returning 0"); + return 0; + } } // Real accessors @@ -381,8 +410,16 @@ QPDFObjectHandle::getIntValue() std::string QPDFObjectHandle::getRealValue() { - assertReal(); - return dynamic_cast<QPDF_Real*>(m->obj.getPointer())->getVal(); + if (isReal()) + { + return dynamic_cast<QPDF_Real*>(m->obj.getPointer())->getVal(); + } + else + { + typeWarning("real", "returning 0.0"); + QTC::TC("qpdf", "QPDFObjectHandle real returning 0.0"); + return "0.0"; + } } // Name accessors @@ -390,8 +427,16 @@ QPDFObjectHandle::getRealValue() std::string QPDFObjectHandle::getName() { - assertName(); - return dynamic_cast<QPDF_Name*>(m->obj.getPointer())->getName(); + if (isName()) + { + return dynamic_cast<QPDF_Name*>(m->obj.getPointer())->getName(); + } + else + { + typeWarning("name", "returning dummy name"); + QTC::TC("qpdf", "QPDFObjectHandle name returning dummy name"); + return "/QPDFFakeName"; + } } // String accessors @@ -399,15 +444,31 @@ QPDFObjectHandle::getName() std::string QPDFObjectHandle::getStringValue() { - assertString(); - return dynamic_cast<QPDF_String*>(m->obj.getPointer())->getVal(); + if (isString()) + { + return dynamic_cast<QPDF_String*>(m->obj.getPointer())->getVal(); + } + else + { + typeWarning("string", "returning empty string"); + QTC::TC("qpdf", "QPDFObjectHandle string returning empty string"); + return ""; + } } std::string QPDFObjectHandle::getUTF8Value() { - assertString(); - return dynamic_cast<QPDF_String*>(m->obj.getPointer())->getUTF8Val(); + if (isString()) + { + return dynamic_cast<QPDF_String*>(m->obj.getPointer())->getUTF8Val(); + } + else + { + typeWarning("string", "returning empty string"); + QTC::TC("qpdf", "QPDFObjectHandle string returning empty utf8"); + return ""; + } } // Operator and Inline Image accessors @@ -415,15 +476,31 @@ QPDFObjectHandle::getUTF8Value() std::string QPDFObjectHandle::getOperatorValue() { - assertOperator(); - return dynamic_cast<QPDF_Operator*>(m->obj.getPointer())->getVal(); + if (isOperator()) + { + return dynamic_cast<QPDF_Operator*>(m->obj.getPointer())->getVal(); + } + else + { + typeWarning("operator", "returning fake value"); + QTC::TC("qpdf", "QPDFObjectHandle operator returning fake value"); + return "QPDFFAKE"; + } } std::string QPDFObjectHandle::getInlineImageValue() { - assertInlineImage(); - return dynamic_cast<QPDF_InlineImage*>(m->obj.getPointer())->getVal(); + if (isInlineImage()) + { + return dynamic_cast<QPDF_InlineImage*>(m->obj.getPointer())->getVal(); + } + else + { + typeWarning("inlineimage", "returning empty data"); + QTC::TC("qpdf", "QPDFObjectHandle inlineimage returning empty data"); + return ""; + } } // Array accessors @@ -431,22 +508,66 @@ QPDFObjectHandle::getInlineImageValue() int QPDFObjectHandle::getArrayNItems() { - assertArray(); - return dynamic_cast<QPDF_Array*>(m->obj.getPointer())->getNItems(); + if (isArray()) + { + return dynamic_cast<QPDF_Array*>(m->obj.getPointer())->getNItems(); + } + else + { + typeWarning("array", "treating as empty"); + QTC::TC("qpdf", "QPDFObjectHandle array treating as empty"); + return 0; + } } QPDFObjectHandle QPDFObjectHandle::getArrayItem(int n) { - assertArray(); - return dynamic_cast<QPDF_Array*>(m->obj.getPointer())->getItem(n); + QPDFObjectHandle result; + if (isArray() && (n < getArrayNItems()) && (n >= 0)) + { + result = dynamic_cast<QPDF_Array*>(m->obj.getPointer())->getItem(n); + } + else + { + result = newNull(); + if (isArray()) + { + objectWarning("returning null for out of bounds array access"); + QTC::TC("qpdf", "QPDFObjectHandle array bounds"); + } + else + { + typeWarning("array", "returning null"); + QTC::TC("qpdf", "QPDFObjectHandle array null for non-array"); + } + QPDF* context = 0; + std::string description; + if (this->m->obj->getDescription(context, description)) + { + result.setObjectDescription( + context, + description + + " -> null returned from invalid array access"); + } + } + return result; } std::vector<QPDFObjectHandle> QPDFObjectHandle::getArrayAsVector() { - assertArray(); - return dynamic_cast<QPDF_Array*>(m->obj.getPointer())->getAsVector(); + std::vector<QPDFObjectHandle> result; + if (isArray()) + { + result = dynamic_cast<QPDF_Array*>(m->obj.getPointer())->getAsVector(); + } + else + { + typeWarning("array", "treating as empty"); + QTC::TC("qpdf", "QPDFObjectHandle array treating as empty vector"); + } + return result; } // Array mutators @@ -454,36 +575,79 @@ QPDFObjectHandle::getArrayAsVector() void QPDFObjectHandle::setArrayItem(int n, QPDFObjectHandle const& item) { - assertArray(); - return dynamic_cast<QPDF_Array*>(m->obj.getPointer())->setItem(n, item); + if (isArray()) + { + dynamic_cast<QPDF_Array*>(m->obj.getPointer())->setItem(n, item); + } + else + { + typeWarning("array", "ignoring attempt to set item"); + QTC::TC("qpdf", "QPDFObjectHandle array ignoring set item"); + } } void QPDFObjectHandle::setArrayFromVector(std::vector<QPDFObjectHandle> const& items) { - assertArray(); - return dynamic_cast<QPDF_Array*>(m->obj.getPointer())->setFromVector(items); + if (isArray()) + { + dynamic_cast<QPDF_Array*>(m->obj.getPointer())->setFromVector(items); + } + else + { + typeWarning("array", "ignoring attempt to replace items"); + QTC::TC("qpdf", "QPDFObjectHandle array ignoring replace items"); + } } void QPDFObjectHandle::insertItem(int at, QPDFObjectHandle const& item) { - assertArray(); - return dynamic_cast<QPDF_Array*>(m->obj.getPointer())->insertItem(at, item); + if (isArray()) + { + dynamic_cast<QPDF_Array*>(m->obj.getPointer())->insertItem(at, item); + } + else + { + typeWarning("array", "ignoring attempt to insert item"); + QTC::TC("qpdf", "QPDFObjectHandle array ignoring insert item"); + } } void QPDFObjectHandle::appendItem(QPDFObjectHandle const& item) { - assertArray(); - return dynamic_cast<QPDF_Array*>(m->obj.getPointer())->appendItem(item); + if (isArray()) + { + dynamic_cast<QPDF_Array*>(m->obj.getPointer())->appendItem(item); + } + else + { + typeWarning("array", "ignoring attempt to append item"); + QTC::TC("qpdf", "QPDFObjectHandle array ignoring append item"); + } } void QPDFObjectHandle::eraseItem(int at) { - assertArray(); - return dynamic_cast<QPDF_Array*>(m->obj.getPointer())->eraseItem(at); + if (isArray() && (at < getArrayNItems()) && (at >= 0)) + { + dynamic_cast<QPDF_Array*>(m->obj.getPointer())->eraseItem(at); + } + else + { + if (isArray()) + { + objectWarning("ignoring attempt to erase out of bounds array item"); + QTC::TC("qpdf", "QPDFObjectHandle erase array bounds"); + } + else + { + typeWarning("array", "ignoring attempt to erase item"); + QTC::TC("qpdf", "QPDFObjectHandle array ignoring erase item"); + } + } } // Dictionary accessors @@ -491,29 +655,79 @@ QPDFObjectHandle::eraseItem(int at) bool QPDFObjectHandle::hasKey(std::string const& key) { - assertDictionary(); - return dynamic_cast<QPDF_Dictionary*>(m->obj.getPointer())->hasKey(key); + if (isDictionary()) + { + return dynamic_cast<QPDF_Dictionary*>(m->obj.getPointer())->hasKey(key); + } + else + { + typeWarning("dictionary", + "returning false for a key containment request"); + QTC::TC("qpdf", "QPDFObjectHandle dictionary false for hasKey"); + return false; + } } QPDFObjectHandle QPDFObjectHandle::getKey(std::string const& key) { - assertDictionary(); - return dynamic_cast<QPDF_Dictionary*>(m->obj.getPointer())->getKey(key); + QPDFObjectHandle result; + if (isDictionary()) + { + result = dynamic_cast<QPDF_Dictionary*>( + m->obj.getPointer())->getKey(key); + } + else + { + typeWarning( + "dictionary", "returning null for attempted key retrieval"); + QTC::TC("qpdf", "QPDFObjectHandle dictionary null for getKey"); + result = newNull(); + QPDF* qpdf = 0; + std::string description; + if (this->m->obj->getDescription(qpdf, description)) + { + result.setObjectDescription( + qpdf, + description + + " -> null returned from getting key " + + key + " from non-Dictionary"); + } + } + return result; } std::set<std::string> QPDFObjectHandle::getKeys() { - assertDictionary(); - return dynamic_cast<QPDF_Dictionary*>(m->obj.getPointer())->getKeys(); + std::set<std::string> result; + if (isDictionary()) + { + result = dynamic_cast<QPDF_Dictionary*>(m->obj.getPointer())->getKeys(); + } + else + { + typeWarning("dictionary", "treating as empty"); + QTC::TC("qpdf", "QPDFObjectHandle dictionary empty set for getKeys"); + } + return result; } std::map<std::string, QPDFObjectHandle> QPDFObjectHandle::getDictAsMap() { - assertDictionary(); - return dynamic_cast<QPDF_Dictionary*>(m->obj.getPointer())->getAsMap(); + std::map<std::string, QPDFObjectHandle> result; + if (isDictionary()) + { + result = dynamic_cast<QPDF_Dictionary*>( + m->obj.getPointer())->getAsMap(); + } + else + { + typeWarning("dictionary", "treating as empty"); + QTC::TC("qpdf", "QPDFObjectHandle dictionary empty map for asMap"); + } + return result; } // Array and Name accessors @@ -551,27 +765,48 @@ QPDFObjectHandle::getOwningQPDF() void QPDFObjectHandle::replaceKey(std::string const& key, - QPDFObjectHandle const& value) + QPDFObjectHandle value) { - assertDictionary(); - return dynamic_cast<QPDF_Dictionary*>( - m->obj.getPointer())->replaceKey(key, value); + if (isDictionary()) + { + dynamic_cast<QPDF_Dictionary*>( + m->obj.getPointer())->replaceKey(key, value); + } + else + { + typeWarning("dictionary", "ignoring key replacement request"); + QTC::TC("qpdf", "QPDFObjectHandle dictionary ignoring replaceKey"); + } } void QPDFObjectHandle::removeKey(std::string const& key) { - assertDictionary(); - return dynamic_cast<QPDF_Dictionary*>(m->obj.getPointer())->removeKey(key); + if (isDictionary()) + { + dynamic_cast<QPDF_Dictionary*>(m->obj.getPointer())->removeKey(key); + } + else + { + typeWarning("dictionary", "ignoring key removal request"); + QTC::TC("qpdf", "QPDFObjectHandle dictionary ignoring removeKey"); + } } void QPDFObjectHandle::replaceOrRemoveKey(std::string const& key, QPDFObjectHandle value) { - assertDictionary(); - return dynamic_cast<QPDF_Dictionary*>( - m->obj.getPointer())->replaceOrRemoveKey(key, value); + if (isDictionary()) + { + dynamic_cast<QPDF_Dictionary*>( + m->obj.getPointer())->replaceOrRemoveKey(key, value); + } + else + { + typeWarning("dictionary", "ignoring key removal/replacement request"); + QTC::TC("qpdf", "QPDFObjectHandle dictionary ignoring removereplace"); + } } // Stream accessors @@ -1173,35 +1408,45 @@ QPDFObjectHandle::parseInternal(PointerHolder<InputSource> input, std::vector<parser_state_e> state_stack; state_stack.push_back(st_top); std::vector<qpdf_offset_t> offset_stack; - offset_stack.push_back(input->tell()); + qpdf_offset_t offset = input->tell(); + offset_stack.push_back(offset); bool done = false; while (! done) { std::vector<QPDFObjectHandle>& olist = olist_stack.back(); parser_state_e state = state_stack.back(); - qpdf_offset_t offset = offset_stack.back(); + offset = offset_stack.back(); object = QPDFObjectHandle(); QPDFTokenizer::Token token = - tokenizer.readToken(input, object_description); + tokenizer.readToken(input, object_description, true); switch (token.getType()) { case QPDFTokenizer::tt_eof: - if (content_stream) + if (! content_stream) { - state = st_eof; - } - else - { - // When not in content stream mode, EOF is tt_bad and - // throws an exception before we get here. - throw std::logic_error( - "EOF received while not in content stream mode"); + QTC::TC("qpdf", "QPDFObjectHandle eof in parseInternal"); + warn(context, + QPDFExc(qpdf_e_damaged_pdf, input->getName(), + object_description, + input->getLastOffset(), + "unexpected EOF")); } + state = st_eof; break; + case QPDFTokenizer::tt_bad: + QTC::TC("qpdf", "QPDFObjectHandle bad token in parse"); + warn(context, + QPDFExc(qpdf_e_damaged_pdf, input->getName(), + object_description, + input->getLastOffset(), + token.getErrorMessage())); + object = newNull(); + break; + case QPDFTokenizer::tt_brace_open: case QPDFTokenizer::tt_brace_close: QTC::TC("qpdf", "QPDFObjectHandle bad brace"); @@ -1375,11 +1620,19 @@ QPDFObjectHandle::parseInternal(PointerHolder<InputSource> input, "parse error while reading object")); } done = true; - // Leave object uninitialized to indicate EOF + // In content stream mode, leave object uninitialized to + // indicate EOF + if (! content_stream) + { + object = newNull(); + } break; case st_dictionary: case st_array: + setObjectDescriptionFromInput( + object, context, object_description, input, + input->getLastOffset()); olist.push_back(object); break; @@ -1402,6 +1655,8 @@ QPDFObjectHandle::parseInternal(PointerHolder<InputSource> input, if (old_state == st_array) { object = newArray(olist); + setObjectDescriptionFromInput( + object, context, object_description, input, offset); } else if (old_state == st_dictionary) { @@ -1458,6 +1713,8 @@ QPDFObjectHandle::parseInternal(PointerHolder<InputSource> input, "dictionary ended prematurely; " "using null as value for last key")); val = newNull(); + setObjectDescriptionFromInput( + val, context, object_description, input, offset); } else { @@ -1466,6 +1723,8 @@ QPDFObjectHandle::parseInternal(PointerHolder<InputSource> input, dict[key_obj.getName()] = val; } object = newDictionary(dict); + setObjectDescriptionFromInput( + object, context, object_description, input, offset); } olist_stack.pop_back(); offset_stack.pop_back(); @@ -1480,6 +1739,8 @@ QPDFObjectHandle::parseInternal(PointerHolder<InputSource> input, } } + setObjectDescriptionFromInput( + object, context, object_description, input, offset); return object; } @@ -1635,6 +1896,26 @@ QPDFObjectHandle::newReserved(QPDF* qpdf) return result; } +void +QPDFObjectHandle::setObjectDescription(QPDF* owning_qpdf, + std::string const& object_description) +{ + if (isInitialized() && this->m->obj.getPointer()) + { + this->m->obj->setDescription(owning_qpdf, object_description); + } +} + +bool +QPDFObjectHandle::hasObjectDescription() +{ + if (isInitialized() && this->m->obj.getPointer()) + { + return this->m->obj->hasDescription(); + } + return false; +} + QPDFObjectHandle QPDFObjectHandle::shallowCopy() { @@ -1793,85 +2074,127 @@ QPDFObjectHandle::assertInitialized() const } void -QPDFObjectHandle::assertType(char const* type_name, bool istype) const +QPDFObjectHandle::typeWarning(char const* expected_type, + std::string const& warning) +{ + QPDF* context = 0; + std::string description; + if (this->m->obj->getDescription(context, description)) + { + warn(context, + QPDFExc( + qpdf_e_damaged_pdf, + "", description, 0, + std::string("operation for ") + expected_type + + " attempted on object of type " + + getTypeName() + ": " + warning)); + } + else + { + assertType(expected_type, false); + } +} + +void +QPDFObjectHandle::objectWarning(std::string const& warning) +{ + QPDF* context = 0; + std::string description; + if (this->m->obj->getDescription(context, description)) + { + warn(context, + QPDFExc( + qpdf_e_damaged_pdf, + "", description, 0, + warning)); + } + else + { + throw std::logic_error(warning); + } +} + +void +QPDFObjectHandle::assertType(char const* type_name, bool istype) { if (! istype) { throw std::logic_error(std::string("operation for ") + type_name + - " object attempted on object of wrong type"); + " attempted on object of type " + + getTypeName()); } } void QPDFObjectHandle::assertNull() { - assertType("Null", isNull()); + assertType("null", isNull()); } void QPDFObjectHandle::assertBool() { - assertType("Boolean", isBool()); + assertType("boolean", isBool()); } void QPDFObjectHandle::assertInteger() { - assertType("Integer", isInteger()); + assertType("integer", isInteger()); } void QPDFObjectHandle::assertReal() { - assertType("Real", isReal()); + assertType("real", isReal()); } void QPDFObjectHandle::assertName() { - assertType("Name", isName()); + assertType("name", isName()); } void QPDFObjectHandle::assertString() { - assertType("String", isString()); + assertType("string", isString()); } void QPDFObjectHandle::assertOperator() { - assertType("Operator", isOperator()); + assertType("operator", isOperator()); } void QPDFObjectHandle::assertInlineImage() { - assertType("InlineImage", isInlineImage()); + assertType("inlineimage", isInlineImage()); } void QPDFObjectHandle::assertArray() { - assertType("Array", isArray()); + assertType("array", isArray()); } void QPDFObjectHandle::assertDictionary() { - assertType("Dictionary", isDictionary()); + assertType("dictionary", isDictionary()); } void QPDFObjectHandle::assertStream() { - assertType("Stream", isStream()); + assertType("stream", isStream()); } void QPDFObjectHandle::assertReserved() { - assertType("Reserved", isReserved()); + assertType("reserved", isReserved()); } void @@ -1887,13 +2210,13 @@ QPDFObjectHandle::assertIndirect() void QPDFObjectHandle::assertScalar() { - assertType("Scalar", isScalar()); + assertType("scalar", isScalar()); } void QPDFObjectHandle::assertNumber() { - assertType("Number", isNumber()); + assertType("number", isNumber()); } bool @@ -1928,7 +2251,8 @@ QPDFObjectHandle::dereference() this->m->qpdf, this->m->objid, this->m->generation); if (obj.getPointer() == 0) { - QTC::TC("qpdf", "QPDFObjectHandle indirect to unknown"); + // QPDF::resolve never returns an uninitialized object, but + // check just in case. this->m->obj = new QPDF_Null(); } else if (dynamic_cast<QPDF_Reserved*>(obj.getPointer())) |