Commit c53d54b13dc6ad369646a09c64d392549effac38
1 parent
cef6425b
Add optional parameter allow_nullptr to QPDFObjectHandle::getOwningQPDF
Also, inline method and add optional parameter error_msg.
Showing
8 changed files
with
59 additions
and
64 deletions
include/qpdf/QPDFObjectHandle.hh
| ... | ... | @@ -957,9 +957,11 @@ class QPDFObjectHandle |
| 957 | 957 | std::set<std::string>* resource_names = nullptr); |
| 958 | 958 | |
| 959 | 959 | // Return the QPDF object that owns an indirect object. Returns |
| 960 | - // null for a direct object. | |
| 960 | + // null for a direct object if allow_nullptr is set to true or | |
| 961 | + // throws a runtime error otherwise. | |
| 961 | 962 | QPDF_DLL |
| 962 | - QPDF* getOwningQPDF(); | |
| 963 | + inline QPDF* | |
| 964 | + getOwningQPDF(bool allow_nullptr = true, std::string const& error_msg = ""); | |
| 963 | 965 | |
| 964 | 966 | // Create a shallow copy of an object as a direct object, but do not |
| 965 | 967 | // traverse across indirect object boundaries. That means that, |
| ... | ... | @@ -1876,4 +1878,17 @@ QPDFObjectHandle::isInitialized() const |
| 1876 | 1878 | return initialized; |
| 1877 | 1879 | } |
| 1878 | 1880 | |
| 1881 | +// Indirect object accessors | |
| 1882 | +inline QPDF* | |
| 1883 | +QPDFObjectHandle::getOwningQPDF( | |
| 1884 | + bool allow_nullptr, std::string const& error_msg) | |
| 1885 | +{ | |
| 1886 | + // Will be null for direct objects | |
| 1887 | + if (!allow_nullptr && (this->qpdf == nullptr)) { | |
| 1888 | + throw std::runtime_error( | |
| 1889 | + error_msg == "" ? "attempt to use a null qpdf object" : error_msg); | |
| 1890 | + } | |
| 1891 | + return this->qpdf; | |
| 1892 | +} | |
| 1893 | + | |
| 1879 | 1894 | #endif // QPDFOBJECTHANDLE_HH | ... | ... |
libqpdf/QPDF.cc
| ... | ... | @@ -2266,7 +2266,7 @@ QPDF::copyForeignObject(QPDFObjectHandle foreign) |
| 2266 | 2266 | throw std::logic_error( |
| 2267 | 2267 | "QPDF::copyForeign called with direct object handle"); |
| 2268 | 2268 | } |
| 2269 | - QPDF* other = foreign.getOwningQPDF(); | |
| 2269 | + QPDF* other = foreign.getOwningQPDF(false); | |
| 2270 | 2270 | if (other == this) { |
| 2271 | 2271 | QTC::TC("qpdf", "QPDF copyForeign not foreign"); |
| 2272 | 2272 | throw std::logic_error( |
| ... | ... | @@ -2456,11 +2456,9 @@ QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign) |
| 2456 | 2456 | QPDFObjGen local_og(result.getObjGen()); |
| 2457 | 2457 | // Copy information from the foreign stream so we can pipe its |
| 2458 | 2458 | // data later without keeping the original QPDF object around. |
| 2459 | - QPDF* foreign_stream_qpdf = foreign.getOwningQPDF(); | |
| 2460 | - if (!foreign_stream_qpdf) { | |
| 2461 | - throw std::logic_error("unable to retrieve owning qpdf" | |
| 2462 | - " from foreign stream"); | |
| 2463 | - } | |
| 2459 | + QPDF* foreign_stream_qpdf = foreign.getOwningQPDF( | |
| 2460 | + false, "unable to retrieve owning qpdf from foreign stream"); | |
| 2461 | + | |
| 2464 | 2462 | QPDF_Stream* stream = dynamic_cast<QPDF_Stream*>( |
| 2465 | 2463 | QPDFObjectHandle::ObjAccessor::getObject(foreign).get()); |
| 2466 | 2464 | if (!stream) { | ... | ... |
libqpdf/QPDFFormFieldObjectHelper.cc
| ... | ... | @@ -362,13 +362,11 @@ QPDFFormFieldObjectHelper::setV(QPDFObjectHandle value, bool need_appearances) |
| 362 | 362 | setFieldAttribute("/V", value); |
| 363 | 363 | } |
| 364 | 364 | if (need_appearances) { |
| 365 | - QPDF* qpdf = this->oh.getOwningQPDF(); | |
| 366 | - if (!qpdf) { | |
| 367 | - throw std::logic_error( | |
| 368 | - "QPDFFormFieldObjectHelper::setV called with" | |
| 369 | - " need_appearances = true on an object that is" | |
| 370 | - " not associated with an owning QPDF"); | |
| 371 | - } | |
| 365 | + QPDF* qpdf = this->oh.getOwningQPDF( | |
| 366 | + false, | |
| 367 | + "QPDFFormFieldObjectHelper::setV called with need_appearances = " | |
| 368 | + "true on an object that is not associated with an owning QPDF"); | |
| 369 | + | |
| 372 | 370 | QPDFAcroFormDocumentHelper(*qpdf).setNeedAppearances(true); |
| 373 | 371 | } |
| 374 | 372 | } |
| ... | ... | @@ -883,7 +881,7 @@ QPDFFormFieldObjectHelper::generateTextAppearance( |
| 883 | 881 | if (found_font_in_dr && resources.isDictionary()) { |
| 884 | 882 | QTC::TC("qpdf", "QPDFFormFieldObjectHelper get font from /DR"); |
| 885 | 883 | if (resources.isIndirect()) { |
| 886 | - resources = resources.getOwningQPDF()->makeIndirectObject( | |
| 884 | + resources = resources.getOwningQPDF(false)->makeIndirectObject( | |
| 887 | 885 | resources.shallowCopy()); |
| 888 | 886 | AS.getDict().replaceKey("/Resources", resources); |
| 889 | 887 | } | ... | ... |
libqpdf/QPDFJob.cc
| ... | ... | @@ -2161,7 +2161,7 @@ QPDFJob::doUnderOverlayForPage( |
| 2161 | 2161 | std::map<unsigned long long, std::shared_ptr<QPDFAcroFormDocumentHelper>> |
| 2162 | 2162 | afdh; |
| 2163 | 2163 | auto make_afdh = [&](QPDFPageObjectHelper& ph) { |
| 2164 | - QPDF* q = ph.getObjectHandle().getOwningQPDF(); | |
| 2164 | + QPDF* q = ph.getObjectHandle().getOwningQPDF(false); | |
| 2165 | 2165 | return get_afdh_for_qpdf(afdh, q); |
| 2166 | 2166 | }; |
| 2167 | 2167 | auto dest_afdh = make_afdh(dest_page); |
| ... | ... | @@ -2597,7 +2597,7 @@ static QPDFObjectHandle |
| 2597 | 2597 | added_page(QPDF& pdf, QPDFObjectHandle page) |
| 2598 | 2598 | { |
| 2599 | 2599 | QPDFObjectHandle result = page; |
| 2600 | - if (page.getOwningQPDF() != &pdf) { | |
| 2600 | + if (page.getOwningQPDF(false) != &pdf) { | |
| 2601 | 2601 | // Calling copyForeignObject on an object we already copied |
| 2602 | 2602 | // will give us the already existing copy. |
| 2603 | 2603 | result = pdf.copyForeignObject(page); | ... | ... |
libqpdf/QPDFObjectHandle.cc
| ... | ... | @@ -1207,14 +1207,6 @@ QPDFObjectHandle::getUniqueResourceName( |
| 1207 | 1207 | " QPDFObjectHandle::getUniqueResourceName"); |
| 1208 | 1208 | } |
| 1209 | 1209 | |
| 1210 | -// Indirect object accessors | |
| 1211 | -QPDF* | |
| 1212 | -QPDFObjectHandle::getOwningQPDF() | |
| 1213 | -{ | |
| 1214 | - // Will be null for direct objects | |
| 1215 | - return this->qpdf; | |
| 1216 | -} | |
| 1217 | - | |
| 1218 | 1210 | // Dictionary mutators |
| 1219 | 1211 | |
| 1220 | 1212 | void |
| ... | ... | @@ -1634,16 +1626,15 @@ QPDFObjectHandle::coalesceContentStreams() |
| 1634 | 1626 | // files may have pages that are invalid in other ways. |
| 1635 | 1627 | return; |
| 1636 | 1628 | } |
| 1637 | - QPDF* qpdf = getOwningQPDF(); | |
| 1638 | - if (qpdf == nullptr) { | |
| 1639 | - // Should not be possible for a page object to not have an | |
| 1640 | - // owning PDF unless it was manually constructed in some | |
| 1641 | - // incorrect way. However, it can happen in a PDF file whose | |
| 1642 | - // page structure is direct, which is against spec but still | |
| 1643 | - // possible to hand construct, as in fuzz issue 27393. | |
| 1644 | - throw std::runtime_error("coalesceContentStreams called on object" | |
| 1645 | - " with no associated PDF file"); | |
| 1646 | - } | |
| 1629 | + // Should not be possible for a page object to not have an | |
| 1630 | + // owning PDF unless it was manually constructed in some | |
| 1631 | + // incorrect way. However, it can happen in a PDF file whose | |
| 1632 | + // page structure is direct, which is against spec but still | |
| 1633 | + // possible to hand construct, as in fuzz issue 27393. | |
| 1634 | + QPDF* qpdf = getOwningQPDF( | |
| 1635 | + false, | |
| 1636 | + "coalesceContentStreams called on object with no associated PDF file"); | |
| 1637 | + | |
| 1647 | 1638 | QPDFObjectHandle new_contents = newStream(qpdf); |
| 1648 | 1639 | this->replaceKey("/Contents", new_contents); |
| 1649 | 1640 | ... | ... |
libqpdf/QPDFPageObjectHelper.cc
| ... | ... | @@ -432,7 +432,8 @@ QPDFPageObjectHelper::externalizeInlineImages(size_t min_size, bool shallow) |
| 432 | 432 | this->oh.replaceKey( |
| 433 | 433 | "/Contents", |
| 434 | 434 | QPDFObjectHandle::newStream( |
| 435 | - this->oh.getOwningQPDF(), b.getBufferSharedPointer())); | |
| 435 | + this->oh.getOwningQPDF(false), | |
| 436 | + b.getBufferSharedPointer())); | |
| 436 | 437 | } |
| 437 | 438 | } |
| 438 | 439 | } else { |
| ... | ... | @@ -683,11 +684,10 @@ QPDFPageObjectHelper::removeUnreferencedResources() |
| 683 | 684 | QPDFPageObjectHelper |
| 684 | 685 | QPDFPageObjectHelper::shallowCopyPage() |
| 685 | 686 | { |
| 686 | - QPDF* qpdf = this->oh.getOwningQPDF(); | |
| 687 | - if (!qpdf) { | |
| 688 | - throw std::runtime_error("QPDFPageObjectHelper::shallowCopyPage" | |
| 689 | - " called with a direct object"); | |
| 690 | - } | |
| 687 | + QPDF* qpdf = this->oh.getOwningQPDF( | |
| 688 | + false, | |
| 689 | + "QPDFPageObjectHelper::shallowCopyPage called with a direct object"); | |
| 690 | + | |
| 691 | 691 | QPDFObjectHandle new_page = this->oh.shallowCopy(); |
| 692 | 692 | return QPDFPageObjectHelper(qpdf->makeIndirectObject(new_page)); |
| 693 | 693 | } |
| ... | ... | @@ -743,11 +743,10 @@ QPDFPageObjectHelper::getMatrixForTransformations(bool invert) |
| 743 | 743 | QPDFObjectHandle |
| 744 | 744 | QPDFPageObjectHelper::getFormXObjectForPage(bool handle_transformations) |
| 745 | 745 | { |
| 746 | - QPDF* qpdf = this->oh.getOwningQPDF(); | |
| 747 | - if (!qpdf) { | |
| 748 | - throw std::runtime_error("QPDFPageObjectHelper::getFormXObjectForPage" | |
| 749 | - " called with a direct object"); | |
| 750 | - } | |
| 746 | + QPDF* qpdf = this->oh.getOwningQPDF( | |
| 747 | + false, | |
| 748 | + "QPDFPageObjectHelper::getFormXObjectForPage called with a direct " | |
| 749 | + "object"); | |
| 751 | 750 | QPDFObjectHandle result = QPDFObjectHandle::newStream(qpdf); |
| 752 | 751 | QPDFObjectHandle newdict = result.getDict(); |
| 753 | 752 | newdict.replaceKey("/Type", QPDFObjectHandle::newName("/XObject")); |
| ... | ... | @@ -917,11 +916,9 @@ QPDFPageObjectHelper::placeFormXObject( |
| 917 | 916 | void |
| 918 | 917 | QPDFPageObjectHelper::flattenRotation(QPDFAcroFormDocumentHelper* afdh) |
| 919 | 918 | { |
| 920 | - QPDF* qpdf = this->oh.getOwningQPDF(); | |
| 921 | - if (!qpdf) { | |
| 922 | - throw std::runtime_error("QPDFPageObjectHelper::flattenRotation" | |
| 923 | - " called with a direct object"); | |
| 924 | - } | |
| 919 | + QPDF* qpdf = this->oh.getOwningQPDF( | |
| 920 | + false, | |
| 921 | + "QPDFPageObjectHelper::flattenRotation called with a direct object"); | |
| 925 | 922 | |
| 926 | 923 | auto rotate_oh = this->oh.getKey("/Rotate"); |
| 927 | 924 | int rotate = 0; |
| ... | ... | @@ -1066,16 +1063,12 @@ QPDFPageObjectHelper::copyAnnotations( |
| 1066 | 1063 | return; |
| 1067 | 1064 | } |
| 1068 | 1065 | |
| 1069 | - QPDF* from_qpdf = from_page.getObjectHandle().getOwningQPDF(); | |
| 1070 | - if (!from_qpdf) { | |
| 1071 | - throw std::runtime_error("QPDFPageObjectHelper::copyAnnotations:" | |
| 1072 | - " from page is a direct object"); | |
| 1073 | - } | |
| 1074 | - QPDF* this_qpdf = this->oh.getOwningQPDF(); | |
| 1075 | - if (!this_qpdf) { | |
| 1076 | - throw std::runtime_error("QPDFPageObjectHelper::copyAnnotations:" | |
| 1077 | - " this page is a direct object"); | |
| 1078 | - } | |
| 1066 | + QPDF* from_qpdf = from_page.getObjectHandle().getOwningQPDF( | |
| 1067 | + false, | |
| 1068 | + "QPDFPageObjectHelper::copyAnnotations: from page is a direct object"); | |
| 1069 | + QPDF* this_qpdf = this->oh.getOwningQPDF( | |
| 1070 | + false, | |
| 1071 | + "QPDFPageObjectHelper::copyAnnotations: this page is a direct object"); | |
| 1079 | 1072 | |
| 1080 | 1073 | std::vector<QPDFObjectHandle> new_annots; |
| 1081 | 1074 | std::vector<QPDFObjectHandle> new_fields; | ... | ... |
libqpdf/QPDF_pages.cc
| ... | ... | @@ -234,7 +234,7 @@ QPDF::insertPage(QPDFObjectHandle newpage, int pos) |
| 234 | 234 | newpage = makeIndirectObject(newpage); |
| 235 | 235 | } else if (newpage.getOwningQPDF() != this) { |
| 236 | 236 | QTC::TC("qpdf", "QPDF insert foreign page"); |
| 237 | - newpage.getOwningQPDF()->pushInheritedAttributesToPage(); | |
| 237 | + newpage.getOwningQPDF(false)->pushInheritedAttributesToPage(); | |
| 238 | 238 | newpage = copyForeignObject(newpage); |
| 239 | 239 | } else { |
| 240 | 240 | QTC::TC("qpdf", "QPDF insert indirect page"); | ... | ... |