diff --git a/libqpdf/NNTree.cc b/libqpdf/NNTree.cc index 51c0cc5..42a5cdb 100644 --- a/libqpdf/NNTree.cc +++ b/libqpdf/NNTree.cc @@ -872,7 +872,7 @@ QPDFNameTreeObjectHelper::QPDFNameTreeObjectHelper( QPDFNameTreeObjectHelper QPDFNameTreeObjectHelper::newEmpty(QPDF& qpdf, bool auto_repair) { - return {qpdf.makeIndirectObject("<< /Names [] >>"_qpdf), qpdf, auto_repair}; + return {qpdf.makeIndirectObject(Dictionary({{"/Names", Array::empty()}})), qpdf, auto_repair}; } QPDFNameTreeObjectHelper::iterator::iterator(std::shared_ptr const& i) : @@ -1068,7 +1068,7 @@ QPDFNumberTreeObjectHelper::QPDFNumberTreeObjectHelper( QPDFNumberTreeObjectHelper QPDFNumberTreeObjectHelper::newEmpty(QPDF& qpdf, bool auto_repair) { - return {qpdf.makeIndirectObject("<< /Nums [] >>"_qpdf), qpdf, auto_repair}; + return {qpdf.makeIndirectObject(Dictionary({{"/Nums", Array::empty()}})), qpdf, auto_repair}; } QPDFNumberTreeObjectHelper::iterator::iterator(std::shared_ptr const& i) : diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index 5c7338b..890a6d2 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -635,21 +635,11 @@ QPDF::getPDFVersion() const int QPDF::getExtensionLevel() { - int result = 0; - QPDFObjectHandle obj = getRoot(); - if (obj.hasKey("/Extensions")) { - obj = obj.getKey("/Extensions"); - if (obj.isDictionary() && obj.hasKey("/ADBE")) { - obj = obj.getKey("/ADBE"); - if (obj.isDictionary() && obj.hasKey("/ExtensionLevel")) { - obj = obj.getKey("/ExtensionLevel"); - if (obj.isInteger()) { - result = obj.getIntValueAsInt(); - } - } - } + if (Integer ExtensionLevel = getRoot()["/Extensions"]["/ADBE"]["/ExtensionLevel"]) { + int result = ExtensionLevel; + return result; } - return result; + return 0; } QPDFObjectHandle @@ -661,17 +651,17 @@ QPDF::getTrailer() QPDFObjectHandle QPDF::getRoot() { - QPDFObjectHandle root = m->trailer.getKey("/Root"); - if (!root.isDictionary()) { + Dictionary Root = m->trailer["/Root"]; + if (!Root) { throw m->c.damagedPDF("", -1, "unable to find /Root dictionary"); - } else if ( - // Check_mode is an interim solution to request #810 pending a more comprehensive review of - // the approach to more extensive checks and warning levels. - m->cf.check_mode() && !root.getKey("/Type").isNameAndEquals("/Catalog")) { + } + // Check_mode is an interim solution to request #810 pending a more comprehensive review of the + // approach to more extensive checks and warning levels. + if (m->cf.check_mode() && Name(Root["/Type"]) != "/Catalog") { warn(m->c.damagedPDF("", -1, "catalog /Type entry missing or invalid")); - root.replaceKey("/Type", "/Catalog"_qpdf); + Root.replaceKey("/Type", Name("/Catalog")); } - return root; + return Root.oh(); } std::map diff --git a/libqpdf/QPDFJob.cc b/libqpdf/QPDFJob.cc index 30c0bf2..b9663c2 100644 --- a/libqpdf/QPDFJob.cc +++ b/libqpdf/QPDFJob.cc @@ -1883,7 +1883,7 @@ QPDFJob::doUnderOverlayForPage( fo[from_no.no][uo_idx], name, dest_page.getTrimBox().getArrayAsRectangle(), cm); dest_page.copyAnnotations(from_page, cm, &dest_afdh, &from_page.qpdf()->doc().acroform()); if (!new_content.empty()) { - resources.mergeResources("<< /XObject << >> >>"_qpdf); + resources.mergeResources(Dictionary({{"/XObject", Dictionary::empty()}})); auto xobject = resources.getKey("/XObject"); if (xobject.isDictionary()) { xobject.replaceKey(name, fo[from_no.no][uo_idx]); diff --git a/libqpdf/QPDFPageLabelDocumentHelper.cc b/libqpdf/QPDFPageLabelDocumentHelper.cc index 48847fb..a1c56ce 100644 --- a/libqpdf/QPDFPageLabelDocumentHelper.cc +++ b/libqpdf/QPDFPageLabelDocumentHelper.cc @@ -131,19 +131,19 @@ QPDFPageLabelDocumentHelper::pageLabelDict( case pl_none: break; case pl_digits: - num.replaceKey("/S", "/D"_qpdf); + num.replaceKey("/S", Name("/D")); break; case pl_alpha_lower: - num.replaceKey("/S", "/a"_qpdf); + num.replaceKey("/S", Name("/a")); break; case pl_alpha_upper: - num.replaceKey("/S", "/A"_qpdf); + num.replaceKey("/S", Name("/A")); break; case pl_roman_lower: - num.replaceKey("/S", "/r"_qpdf); + num.replaceKey("/S", Name("/r")); break; case pl_roman_upper: - num.replaceKey("/S", "/R"_qpdf); + num.replaceKey("/S", Name("/R")); break; } if (!prefix.empty()) { diff --git a/libqpdf/QPDFPageObjectHelper.cc b/libqpdf/QPDFPageObjectHelper.cc index 530247f..25c5bad 100644 --- a/libqpdf/QPDFPageObjectHelper.cc +++ b/libqpdf/QPDFPageObjectHelper.cc @@ -406,7 +406,7 @@ QPDFPageObjectHelper::externalizeInlineImages(size_t min_size, bool shallow) QPDFObjectHandle resources = getAttribute("/Resources", true); // Calling mergeResources also ensures that /XObject becomes direct and is not shared with // other pages. - resources.mergeResources("<< /XObject << >> >>"_qpdf); + resources.mergeResources(Dictionary({{"/XObject", Dictionary::empty()}})); InlineImageTracker iit(oh().getOwningQPDF(), min_size, resources); Pl_Buffer b("new page content"); bool filtered = false; diff --git a/libqpdf/QPDF_pages.cc b/libqpdf/QPDF_pages.cc index a954a5d..021c42b 100644 --- a/libqpdf/QPDF_pages.cc +++ b/libqpdf/QPDF_pages.cc @@ -121,7 +121,7 @@ Pages::getAllPagesInternal( // Unconditionally setting the /Type to /Pages could cause problems, but trying to // accommodate the possibility may be excessive. cur_node.warn("/Type key should be /Pages but is not; overriding"); - cur_node.replaceKey("/Type", "/Pages"_qpdf); + cur_node.replaceKey("/Type", Name("/Pages")); } if (!media_box) { media_box = cur_node.getKey("/MediaBox").isRectangle(); @@ -226,7 +226,7 @@ Pages::getAllPagesInternal( } if (!kid.isDictionaryOfType("/Page")) { kid.warn("/Type key should be /Page but is not; overriding"); - kid.replaceKey("/Type", "/Page"_qpdf); + kid.replaceKey("/Type", Name("/Page")); ++errors; } if (m->reconstructed_xref && errors > 2) { @@ -698,7 +698,7 @@ Pages::flatten_annotations_for_page( std::string content = aoh.getPageContentForAppearance(name, rotate, required_flags, forbidden_flags); if (!content.empty()) { - resources.mergeResources("<< /XObject << >> >>"_qpdf); + resources.mergeResources(Dictionary({{"/XObject", Dictionary({{name, as}})}})); resources.getKey("/XObject").replaceKey(name, as); ++next_fx; } diff --git a/manual/release-notes.rst b/manual/release-notes.rst index 72c8e93..db330b8 100644 --- a/manual/release-notes.rst +++ b/manual/release-notes.rst @@ -65,6 +65,10 @@ more detail. - Other changes + - Calling ``QPDF::getRoot`` on a file with invalid trailer now throws a + ``damaged_pdf`` error with message "unable to find /Root dictionary" + rather than an internal error. + .. _r12-3-0-deprecate: - The following are believed to be not in use and have been deprecated. diff --git a/qpdf/qtest/qpdf/c-oh-errors.out b/qpdf/qtest/qpdf/c-oh-errors.out index aaeedef..c79544e 100644 --- a/qpdf/qtest/qpdf/c-oh-errors.out +++ b/qpdf/qtest/qpdf/c-oh-errors.out @@ -1,8 +1,8 @@ -get root: attempted to dereference an uninitialized QPDFObjectHandle - code: 1 - file: +get root: closed input source: unable to find /Root dictionary + code: 5 + file: closed input source pos: 0 - text: attempted to dereference an uninitialized QPDFObjectHandle + text: unable to find /Root dictionary bad parse: parsed object (offset 1): unknown token while reading object; treating as string code: 5 file: parsed object diff --git a/qpdf/qtest/qpdf/test73.out b/qpdf/qtest/qpdf/test73.out index ad6fb78..54e241a 100644 --- a/qpdf/qtest/qpdf/test73.out +++ b/qpdf/qtest/qpdf/test73.out @@ -1,3 +1,3 @@ -getRoot: attempted to dereference an uninitialized QPDFObjectHandle +getRoot: closed input source: unable to find /Root dictionary WARNING: closed input source: object 4/0: error reading object: QPDF operation attempted on a QPDF object with no input source. QPDF operations are invalid before processFile (or another process method) or after closeInputSource test 73 done