Commit 0adfd74f8b5dc96091cd0b4251b08401f54df2ed
Committed by
GitHub
Merge pull request #747 from m-holger/new_stream
Add optional parameter allow_nullptr to QPDFObjectHandle::getOwningQPDF
Showing
7 changed files
with
58 additions
and
63 deletions
include/qpdf/QPDFObjectHandle.hh
| @@ -957,9 +957,11 @@ class QPDFObjectHandle | @@ -957,9 +957,11 @@ class QPDFObjectHandle | ||
| 957 | std::set<std::string>* resource_names = nullptr); | 957 | std::set<std::string>* resource_names = nullptr); |
| 958 | 958 | ||
| 959 | // Return the QPDF object that owns an indirect object. Returns | 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 | QPDF_DLL | 962 | QPDF_DLL |
| 962 | - QPDF* getOwningQPDF(); | 963 | + inline QPDF* |
| 964 | + getOwningQPDF(bool allow_nullptr = true, std::string const& error_msg = ""); | ||
| 963 | 965 | ||
| 964 | // Create a shallow copy of an object as a direct object, but do not | 966 | // Create a shallow copy of an object as a direct object, but do not |
| 965 | // traverse across indirect object boundaries. That means that, | 967 | // traverse across indirect object boundaries. That means that, |
| @@ -1876,4 +1878,17 @@ QPDFObjectHandle::isInitialized() const | @@ -1876,4 +1878,17 @@ QPDFObjectHandle::isInitialized() const | ||
| 1876 | return initialized; | 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 | #endif // QPDFOBJECTHANDLE_HH | 1894 | #endif // QPDFOBJECTHANDLE_HH |
libqpdf/QPDF.cc
| @@ -2266,7 +2266,7 @@ QPDF::copyForeignObject(QPDFObjectHandle foreign) | @@ -2266,7 +2266,7 @@ QPDF::copyForeignObject(QPDFObjectHandle foreign) | ||
| 2266 | throw std::logic_error( | 2266 | throw std::logic_error( |
| 2267 | "QPDF::copyForeign called with direct object handle"); | 2267 | "QPDF::copyForeign called with direct object handle"); |
| 2268 | } | 2268 | } |
| 2269 | - QPDF* other = foreign.getOwningQPDF(); | 2269 | + QPDF* other = foreign.getOwningQPDF(false); |
| 2270 | if (other == this) { | 2270 | if (other == this) { |
| 2271 | QTC::TC("qpdf", "QPDF copyForeign not foreign"); | 2271 | QTC::TC("qpdf", "QPDF copyForeign not foreign"); |
| 2272 | throw std::logic_error( | 2272 | throw std::logic_error( |
| @@ -2456,11 +2456,9 @@ QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign) | @@ -2456,11 +2456,9 @@ QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign) | ||
| 2456 | QPDFObjGen local_og(result.getObjGen()); | 2456 | QPDFObjGen local_og(result.getObjGen()); |
| 2457 | // Copy information from the foreign stream so we can pipe its | 2457 | // Copy information from the foreign stream so we can pipe its |
| 2458 | // data later without keeping the original QPDF object around. | 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 | QPDF_Stream* stream = dynamic_cast<QPDF_Stream*>( | 2462 | QPDF_Stream* stream = dynamic_cast<QPDF_Stream*>( |
| 2465 | QPDFObjectHandle::ObjAccessor::getObject(foreign).get()); | 2463 | QPDFObjectHandle::ObjAccessor::getObject(foreign).get()); |
| 2466 | if (!stream) { | 2464 | if (!stream) { |
libqpdf/QPDFFormFieldObjectHelper.cc
| @@ -362,13 +362,11 @@ QPDFFormFieldObjectHelper::setV(QPDFObjectHandle value, bool need_appearances) | @@ -362,13 +362,11 @@ QPDFFormFieldObjectHelper::setV(QPDFObjectHandle value, bool need_appearances) | ||
| 362 | setFieldAttribute("/V", value); | 362 | setFieldAttribute("/V", value); |
| 363 | } | 363 | } |
| 364 | if (need_appearances) { | 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 | QPDFAcroFormDocumentHelper(*qpdf).setNeedAppearances(true); | 370 | QPDFAcroFormDocumentHelper(*qpdf).setNeedAppearances(true); |
| 373 | } | 371 | } |
| 374 | } | 372 | } |
| @@ -883,7 +881,7 @@ QPDFFormFieldObjectHelper::generateTextAppearance( | @@ -883,7 +881,7 @@ QPDFFormFieldObjectHelper::generateTextAppearance( | ||
| 883 | if (found_font_in_dr && resources.isDictionary()) { | 881 | if (found_font_in_dr && resources.isDictionary()) { |
| 884 | QTC::TC("qpdf", "QPDFFormFieldObjectHelper get font from /DR"); | 882 | QTC::TC("qpdf", "QPDFFormFieldObjectHelper get font from /DR"); |
| 885 | if (resources.isIndirect()) { | 883 | if (resources.isIndirect()) { |
| 886 | - resources = resources.getOwningQPDF()->makeIndirectObject( | 884 | + resources = resources.getOwningQPDF(false)->makeIndirectObject( |
| 887 | resources.shallowCopy()); | 885 | resources.shallowCopy()); |
| 888 | AS.getDict().replaceKey("/Resources", resources); | 886 | AS.getDict().replaceKey("/Resources", resources); |
| 889 | } | 887 | } |
libqpdf/QPDFJob.cc
| @@ -2161,7 +2161,7 @@ QPDFJob::doUnderOverlayForPage( | @@ -2161,7 +2161,7 @@ QPDFJob::doUnderOverlayForPage( | ||
| 2161 | std::map<unsigned long long, std::shared_ptr<QPDFAcroFormDocumentHelper>> | 2161 | std::map<unsigned long long, std::shared_ptr<QPDFAcroFormDocumentHelper>> |
| 2162 | afdh; | 2162 | afdh; |
| 2163 | auto make_afdh = [&](QPDFPageObjectHelper& ph) { | 2163 | auto make_afdh = [&](QPDFPageObjectHelper& ph) { |
| 2164 | - QPDF* q = ph.getObjectHandle().getOwningQPDF(); | 2164 | + QPDF* q = ph.getObjectHandle().getOwningQPDF(false); |
| 2165 | return get_afdh_for_qpdf(afdh, q); | 2165 | return get_afdh_for_qpdf(afdh, q); |
| 2166 | }; | 2166 | }; |
| 2167 | auto dest_afdh = make_afdh(dest_page); | 2167 | auto dest_afdh = make_afdh(dest_page); |
| @@ -2597,7 +2597,7 @@ static QPDFObjectHandle | @@ -2597,7 +2597,7 @@ static QPDFObjectHandle | ||
| 2597 | added_page(QPDF& pdf, QPDFObjectHandle page) | 2597 | added_page(QPDF& pdf, QPDFObjectHandle page) |
| 2598 | { | 2598 | { |
| 2599 | QPDFObjectHandle result = page; | 2599 | QPDFObjectHandle result = page; |
| 2600 | - if (page.getOwningQPDF() != &pdf) { | 2600 | + if (page.getOwningQPDF(false) != &pdf) { |
| 2601 | // Calling copyForeignObject on an object we already copied | 2601 | // Calling copyForeignObject on an object we already copied |
| 2602 | // will give us the already existing copy. | 2602 | // will give us the already existing copy. |
| 2603 | result = pdf.copyForeignObject(page); | 2603 | result = pdf.copyForeignObject(page); |
libqpdf/QPDFObjectHandle.cc
| @@ -1207,14 +1207,6 @@ QPDFObjectHandle::getUniqueResourceName( | @@ -1207,14 +1207,6 @@ QPDFObjectHandle::getUniqueResourceName( | ||
| 1207 | " QPDFObjectHandle::getUniqueResourceName"); | 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 | // Dictionary mutators | 1210 | // Dictionary mutators |
| 1219 | 1211 | ||
| 1220 | void | 1212 | void |
| @@ -1634,16 +1626,15 @@ QPDFObjectHandle::coalesceContentStreams() | @@ -1634,16 +1626,15 @@ QPDFObjectHandle::coalesceContentStreams() | ||
| 1634 | // files may have pages that are invalid in other ways. | 1626 | // files may have pages that are invalid in other ways. |
| 1635 | return; | 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 | QPDFObjectHandle new_contents = newStream(qpdf); | 1638 | QPDFObjectHandle new_contents = newStream(qpdf); |
| 1648 | this->replaceKey("/Contents", new_contents); | 1639 | this->replaceKey("/Contents", new_contents); |
| 1649 | 1640 |
libqpdf/QPDFPageObjectHelper.cc
| @@ -432,7 +432,8 @@ QPDFPageObjectHelper::externalizeInlineImages(size_t min_size, bool shallow) | @@ -432,7 +432,8 @@ QPDFPageObjectHelper::externalizeInlineImages(size_t min_size, bool shallow) | ||
| 432 | this->oh.replaceKey( | 432 | this->oh.replaceKey( |
| 433 | "/Contents", | 433 | "/Contents", |
| 434 | QPDFObjectHandle::newStream( | 434 | QPDFObjectHandle::newStream( |
| 435 | - this->oh.getOwningQPDF(), b.getBufferSharedPointer())); | 435 | + this->oh.getOwningQPDF(false), |
| 436 | + b.getBufferSharedPointer())); | ||
| 436 | } | 437 | } |
| 437 | } | 438 | } |
| 438 | } else { | 439 | } else { |
| @@ -683,11 +684,10 @@ QPDFPageObjectHelper::removeUnreferencedResources() | @@ -683,11 +684,10 @@ QPDFPageObjectHelper::removeUnreferencedResources() | ||
| 683 | QPDFPageObjectHelper | 684 | QPDFPageObjectHelper |
| 684 | QPDFPageObjectHelper::shallowCopyPage() | 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 | QPDFObjectHandle new_page = this->oh.shallowCopy(); | 691 | QPDFObjectHandle new_page = this->oh.shallowCopy(); |
| 692 | return QPDFPageObjectHelper(qpdf->makeIndirectObject(new_page)); | 692 | return QPDFPageObjectHelper(qpdf->makeIndirectObject(new_page)); |
| 693 | } | 693 | } |
| @@ -743,11 +743,10 @@ QPDFPageObjectHelper::getMatrixForTransformations(bool invert) | @@ -743,11 +743,10 @@ QPDFPageObjectHelper::getMatrixForTransformations(bool invert) | ||
| 743 | QPDFObjectHandle | 743 | QPDFObjectHandle |
| 744 | QPDFPageObjectHelper::getFormXObjectForPage(bool handle_transformations) | 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 | QPDFObjectHandle result = QPDFObjectHandle::newStream(qpdf); | 750 | QPDFObjectHandle result = QPDFObjectHandle::newStream(qpdf); |
| 752 | QPDFObjectHandle newdict = result.getDict(); | 751 | QPDFObjectHandle newdict = result.getDict(); |
| 753 | newdict.replaceKey("/Type", QPDFObjectHandle::newName("/XObject")); | 752 | newdict.replaceKey("/Type", QPDFObjectHandle::newName("/XObject")); |
| @@ -917,11 +916,9 @@ QPDFPageObjectHelper::placeFormXObject( | @@ -917,11 +916,9 @@ QPDFPageObjectHelper::placeFormXObject( | ||
| 917 | void | 916 | void |
| 918 | QPDFPageObjectHelper::flattenRotation(QPDFAcroFormDocumentHelper* afdh) | 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 | auto rotate_oh = this->oh.getKey("/Rotate"); | 923 | auto rotate_oh = this->oh.getKey("/Rotate"); |
| 927 | int rotate = 0; | 924 | int rotate = 0; |
| @@ -1066,16 +1063,12 @@ QPDFPageObjectHelper::copyAnnotations( | @@ -1066,16 +1063,12 @@ QPDFPageObjectHelper::copyAnnotations( | ||
| 1066 | return; | 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 | std::vector<QPDFObjectHandle> new_annots; | 1073 | std::vector<QPDFObjectHandle> new_annots; |
| 1081 | std::vector<QPDFObjectHandle> new_fields; | 1074 | std::vector<QPDFObjectHandle> new_fields; |
libqpdf/QPDF_pages.cc
| @@ -234,7 +234,7 @@ QPDF::insertPage(QPDFObjectHandle newpage, int pos) | @@ -234,7 +234,7 @@ QPDF::insertPage(QPDFObjectHandle newpage, int pos) | ||
| 234 | newpage = makeIndirectObject(newpage); | 234 | newpage = makeIndirectObject(newpage); |
| 235 | } else if (newpage.getOwningQPDF() != this) { | 235 | } else if (newpage.getOwningQPDF() != this) { |
| 236 | QTC::TC("qpdf", "QPDF insert foreign page"); | 236 | QTC::TC("qpdf", "QPDF insert foreign page"); |
| 237 | - newpage.getOwningQPDF()->pushInheritedAttributesToPage(); | 237 | + newpage.getOwningQPDF(false)->pushInheritedAttributesToPage(); |
| 238 | newpage = copyForeignObject(newpage); | 238 | newpage = copyForeignObject(newpage); |
| 239 | } else { | 239 | } else { |
| 240 | QTC::TC("qpdf", "QPDF insert indirect page"); | 240 | QTC::TC("qpdf", "QPDF insert indirect page"); |