Commit c53d54b13dc6ad369646a09c64d392549effac38

Authored by m-holger
1 parent cef6425b

Add optional parameter allow_nullptr to QPDFObjectHandle::getOwningQPDF

Also, inline method and add optional parameter error_msg.
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");
... ...
libqpdf/QTC.cc
1 1 #include <qpdf/QTC.hh>
2 2  
3 3 #include <qpdf/QUtil.hh>
4   -#include <set>
5 4 #include <map>
  5 +#include <set>
6 6 #include <stdio.h>
7 7  
8 8 static bool
... ...