Commit 0adfd74f8b5dc96091cd0b4251b08401f54df2ed

Authored by Jay Berkenbilt
Committed by GitHub
2 parents 2b01a79e c53d54b1

Merge pull request #747 from m-holger/new_stream

Add optional parameter allow_nullptr to QPDFObjectHandle::getOwningQPDF
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");