Commit 1111240a2e9780fc012471c07bce4569963228b8

Authored by m-holger
1 parent c5b728f8

Refactor document helper access through `QPDF::Doc`

Replace direct access to document helpers (`acroform()`, `pages()`, `embedded_files()`, etc.) with calls through `QPDF::doc()` for better encapsulation. Adjust related methods, constructors, and memory management accordingly.
include/qpdf/QPDF.hh
... ... @@ -62,11 +62,6 @@ class BitWriter;
62 62 class BufferInputSource;
63 63 class QPDFLogger;
64 64 class QPDFParser;
65   -class QPDFAcroFormDocumentHelper;
66   -class QPDFEmbeddedFileDocumentHelper;
67   -class QPDFOutlineDocumentHelper;
68   -class QPDFPageDocumentHelper;
69   -class QPDFPageLabelDocumentHelper;
70 65  
71 66 class QPDF
72 67 {
... ... @@ -803,11 +798,6 @@ class QPDF
803 798 class JobSetter;
804 799  
805 800 inline bool reconstructed_xref() const;
806   - inline QPDFAcroFormDocumentHelper& acroform();
807   - inline QPDFEmbeddedFileDocumentHelper& embedded_files();
808   - inline QPDFOutlineDocumentHelper& outlines();
809   - inline QPDFPageDocumentHelper& pages();
810   - inline QPDFPageLabelDocumentHelper& page_labels();
811 801 inline Doc& doc();
812 802  
813 803 // For testing only -- do not add to DLL
... ...
libqpdf/QPDFAcroFormDocumentHelper.cc
... ... @@ -45,7 +45,7 @@ QPDFAcroFormDocumentHelper::QPDFAcroFormDocumentHelper(QPDF& qpdf) :
45 45 QPDFAcroFormDocumentHelper&
46 46 QPDFAcroFormDocumentHelper::get(QPDF& qpdf)
47 47 {
48   - return qpdf.acroform();
  48 + return qpdf.doc().acroform();
49 49 }
50 50  
51 51 void
... ...
libqpdf/QPDFEmbeddedFileDocumentHelper.cc
... ... @@ -53,7 +53,7 @@ QPDFEmbeddedFileDocumentHelper::QPDFEmbeddedFileDocumentHelper(QPDF& qpdf) :
53 53 QPDFEmbeddedFileDocumentHelper&
54 54 QPDFEmbeddedFileDocumentHelper::get(QPDF& qpdf)
55 55 {
56   - return qpdf.embedded_files();
  56 + return qpdf.doc().embedded_files();
57 57 }
58 58  
59 59 void
... ...
libqpdf/QPDFFormFieldObjectHelper.cc
... ... @@ -337,7 +337,7 @@ QPDFFormFieldObjectHelper::setV(QPDFObjectHandle value, bool need_appearances)
337 337 QPDF& qpdf = oh().getQPDF(
338 338 "QPDFFormFieldObjectHelper::setV called with need_appearances = "
339 339 "true on an object that is not associated with an owning QPDF");
340   - qpdf.acroform().setNeedAppearances(true);
  340 + qpdf.doc().acroform().setNeedAppearances(true);
341 341 }
342 342 }
343 343  
... ...
libqpdf/QPDFJob.cc
... ... @@ -751,12 +751,13 @@ QPDFJob::doCheck(QPDF& pdf)
751 751 }
752 752  
753 753 // Create all document helper to trigger any validations they carry out.
754   - auto& pages = pdf.pages();
755   - (void)pdf.acroform();
756   - (void)pdf.embedded_files();
757   - (void)pdf.page_labels();
758   - (void)pdf.outlines().resolveNamedDest(QPDFObjectHandle::newString("dummy"));
759   - (void)pdf.outlines().getOutlinesForPage(pages.getAllPages().at(0));
  754 + auto& doc = pdf.doc();
  755 + auto& pages = doc.pages();
  756 + (void)doc.acroform();
  757 + (void)doc.embedded_files();
  758 + (void)doc.page_labels();
  759 + (void)doc.outlines().resolveNamedDest(QPDFObjectHandle::newString("dummy"));
  760 + (void)doc.outlines().getOutlinesForPage(pages.getAllPages().at(0));
760 761  
761 762 // Write the file to nowhere, uncompressing streams. This causes full file traversal and
762 763 // decoding of all streams we can decode.
... ... @@ -839,8 +840,8 @@ QPDFJob::doShowPages(QPDF& pdf)
839 840 {
840 841 int pageno = 0;
841 842 auto& cout = *m->log->getInfo();
842   - for (auto& ph: pdf.pages().getAllPages()) {
843   - QPDFObjectHandle page = ph.getObjectHandle();
  843 + for (auto& page: pdf.getAllPages()) {
  844 + QPDFPageObjectHelper ph(page);
844 845 ++pageno;
845 846  
846 847 cout << "page " << pageno << ": " << page.getObjectID() << " " << page.getGeneration()
... ... @@ -871,7 +872,7 @@ QPDFJob::doShowPages(QPDF&amp; pdf)
871 872 void
872 873 QPDFJob::doListAttachments(QPDF& pdf)
873 874 {
874   - auto& efdh = pdf.embedded_files();
  875 + auto& efdh = pdf.doc().embedded_files();
875 876 if (efdh.hasEmbeddedFiles()) {
876 877 for (auto const& i: efdh.getEmbeddedFiles()) {
877 878 std::string const& key = i.first;
... ... @@ -911,7 +912,7 @@ QPDFJob::doListAttachments(QPDF&amp; pdf)
911 912 void
912 913 QPDFJob::doShowAttachment(QPDF& pdf)
913 914 {
914   - auto& efdh = pdf.embedded_files();
  915 + auto& efdh = pdf.doc().embedded_files();
915 916 auto fs = efdh.getEmbeddedFile(m->attachment_to_show);
916 917 if (!fs) {
917 918 throw std::runtime_error("attachment " + m->attachment_to_show + " not found");
... ... @@ -1030,13 +1031,13 @@ QPDFJob::doJSONPages(Pipeline* p, bool&amp; first, QPDF&amp; pdf)
1030 1031 JSON::writeDictionaryKey(p, first, "pages", 1);
1031 1032 bool first_page = true;
1032 1033 JSON::writeArrayOpen(p, first_page, 2);
1033   - auto& pldh = pdf.page_labels();
1034   - auto& odh = pdf.outlines();
  1034 + auto& pldh = pdf.doc().page_labels();
  1035 + auto& odh = pdf.doc().outlines();
1035 1036 int pageno = -1;
1036   - for (auto& ph: pdf.pages().getAllPages()) {
  1037 + for (auto& page: pdf.getAllPages()) {
1037 1038 ++pageno;
1038 1039 JSON j_page = JSON::makeDictionary();
1039   - QPDFObjectHandle page = ph.getObjectHandle();
  1040 + QPDFPageObjectHelper ph(page);
1040 1041 j_page.addDictionaryMember("object", page.getJSON(m->json_version));
1041 1042 JSON j_images = j_page.addDictionaryMember("images", JSON::makeArray());
1042 1043 for (auto const& iter2: ph.getImages()) {
... ... @@ -1093,8 +1094,8 @@ void
1093 1094 QPDFJob::doJSONPageLabels(Pipeline* p, bool& first, QPDF& pdf)
1094 1095 {
1095 1096 JSON j_labels = JSON::makeArray();
1096   - auto& pldh = pdf.page_labels();
1097   - long long npages = QIntC::to_longlong(pdf.pages().getAllPages().size());
  1097 + auto& pldh = pdf.doc().page_labels();
  1098 + long long npages = QIntC::to_longlong(pdf.getAllPages().size());
1098 1099 if (pldh.hasPageLabels()) {
1099 1100 std::vector<QPDFObjectHandle> labels;
1100 1101 pldh.getLabelsForPageRange(0, npages - 1, 0, labels);
... ... @@ -1142,13 +1143,12 @@ QPDFJob::doJSONOutlines(Pipeline* p, bool&amp; first, QPDF&amp; pdf)
1142 1143 {
1143 1144 std::map<QPDFObjGen, int> page_numbers;
1144 1145 int n = 0;
1145   - for (auto const& ph: pdf.pages().getAllPages()) {
1146   - QPDFObjectHandle oh = ph.getObjectHandle();
1147   - page_numbers[oh.getObjGen()] = ++n;
  1146 + for (auto const& oh: pdf.getAllPages()) {
  1147 + page_numbers[oh] = ++n;
1148 1148 }
1149 1149  
1150 1150 JSON j_outlines = JSON::makeArray();
1151   - addOutlinesToJson(pdf.outlines().getTopLevelOutlines(), j_outlines, page_numbers);
  1151 + addOutlinesToJson(pdf.doc().outlines().getTopLevelOutlines(), j_outlines, page_numbers);
1152 1152 JSON::writeDictionaryItem(p, first, "outlines", j_outlines, 1);
1153 1153 }
1154 1154  
... ... @@ -1156,14 +1156,14 @@ void
1156 1156 QPDFJob::doJSONAcroform(Pipeline* p, bool& first, QPDF& pdf)
1157 1157 {
1158 1158 JSON j_acroform = JSON::makeDictionary();
1159   - auto& afdh = pdf.acroform();
  1159 + auto& afdh = pdf.doc().acroform();
1160 1160 j_acroform.addDictionaryMember("hasacroform", JSON::makeBool(afdh.hasAcroForm()));
1161 1161 j_acroform.addDictionaryMember("needappearances", JSON::makeBool(afdh.getNeedAppearances()));
1162 1162 JSON j_fields = j_acroform.addDictionaryMember("fields", JSON::makeArray());
1163 1163 int pagepos1 = 0;
1164   - for (auto const& page: pdf.pages().getAllPages()) {
  1164 + for (auto const& page: pdf.getAllPages()) {
1165 1165 ++pagepos1;
1166   - for (auto& aoh: afdh.getWidgetAnnotationsForPage(page)) {
  1166 + for (auto& aoh: afdh.getWidgetAnnotationsForPage({page})) {
1167 1167 QPDFFormFieldObjectHelper ffh = afdh.getFieldForAnnotation(aoh);
1168 1168 if (!ffh.getObjectHandle().isDictionary()) {
1169 1169 continue;
... ... @@ -1297,7 +1297,7 @@ QPDFJob::doJSONAttachments(Pipeline* p, bool&amp; first, QPDF&amp; pdf)
1297 1297 };
1298 1298  
1299 1299 JSON j_attachments = JSON::makeDictionary();
1300   - auto& efdh = pdf.embedded_files();
  1300 + auto& efdh = pdf.doc().embedded_files();
1301 1301 for (auto const& iter: efdh.getEmbeddedFiles()) {
1302 1302 std::string const& key = iter.first;
1303 1303 auto fsoh = iter.second;
... ... @@ -1873,7 +1873,7 @@ QPDFJob::doUnderOverlayForPage(
1873 1873 if (!(uo.pdf && pagenos[pageno.idx].contains(uo_idx))) {
1874 1874 return "";
1875 1875 }
1876   - auto& dest_afdh = dest_page.qpdf()->acroform();
  1876 + auto& dest_afdh = dest_page.qpdf()->doc().acroform();
1877 1877  
1878 1878 auto const& pages = uo.pdf->getAllPages();
1879 1879 std::string content;
... ... @@ -1894,7 +1894,7 @@ QPDFJob::doUnderOverlayForPage(
1894 1894 QPDFMatrix cm;
1895 1895 std::string new_content = dest_page.placeFormXObject(
1896 1896 fo[from_no.no][uo_idx], name, dest_page.getTrimBox().getArrayAsRectangle(), cm);
1897   - dest_page.copyAnnotations(from_page, cm, &dest_afdh, &from_page.qpdf()->acroform());
  1897 + dest_page.copyAnnotations(from_page, cm, &dest_afdh, &from_page.qpdf()->doc().acroform());
1898 1898 if (!new_content.empty()) {
1899 1899 resources.mergeResources("<< /XObject << >> >>"_qpdf);
1900 1900 auto xobject = resources.getKey("/XObject");
... ... @@ -2019,7 +2019,7 @@ void
2019 2019 QPDFJob::addAttachments(QPDF& pdf)
2020 2020 {
2021 2021 maybe_set_pagemode(pdf, "/UseAttachments");
2022   - auto& efdh = pdf.embedded_files();
  2022 + auto& efdh = pdf.doc().embedded_files();
2023 2023 std::vector<std::string> duplicated_keys;
2024 2024 for (auto const& to_add: m->attachments_to_add) {
2025 2025 if ((!to_add.replace) && efdh.getEmbeddedFile(to_add.key)) {
... ... @@ -2063,7 +2063,7 @@ void
2063 2063 QPDFJob::copyAttachments(QPDF& pdf)
2064 2064 {
2065 2065 maybe_set_pagemode(pdf, "/UseAttachments");
2066   - auto& efdh = pdf.embedded_files();
  2066 + auto& efdh = pdf.doc().embedded_files();
2067 2067 std::vector<std::string> duplicates;
2068 2068 for (auto const& to_copy: m->attachments_to_copy) {
2069 2069 doIfVerbose([&](Pipeline& v, std::string const& prefix) {
... ... @@ -2071,7 +2071,7 @@ QPDFJob::copyAttachments(QPDF&amp; pdf)
2071 2071 });
2072 2072 std::unique_ptr<QPDF> other;
2073 2073 processFile(other, to_copy.path.c_str(), to_copy.password.c_str(), false, false);
2074   - auto& other_efdh = other->embedded_files();
  2074 + auto& other_efdh = other->doc().embedded_files();
2075 2075 auto other_attachments = other_efdh.getEmbeddedFiles();
2076 2076 for (auto const& iter: other_attachments) {
2077 2077 std::string new_key = to_copy.prefix + iter.first;
... ... @@ -2114,7 +2114,7 @@ QPDFJob::handleTransformations(QPDF&amp; pdf)
2114 2114 QPDFAcroFormDocumentHelper* afdh_ptr = nullptr;
2115 2115 auto afdh = [&]() -> QPDFAcroFormDocumentHelper& {
2116 2116 if (!afdh_ptr) {
2117   - afdh_ptr = &pdf.acroform();
  2117 + afdh_ptr = &pdf.doc().acroform();
2118 2118 }
2119 2119 return *afdh_ptr;
2120 2120 };
... ... @@ -2205,7 +2205,7 @@ QPDFJob::handleTransformations(QPDF&amp; pdf)
2205 2205 pdf.getRoot().replaceKey("/PageLabels", page_labels);
2206 2206 }
2207 2207 if (!m->attachments_to_remove.empty()) {
2208   - auto& efdh = pdf.embedded_files();
  2208 + auto& efdh = pdf.doc().embedded_files();
2209 2209 for (auto const& key: m->attachments_to_remove) {
2210 2210 if (efdh.removeEmbeddedFile(key)) {
2211 2211 doIfVerbose([&](Pipeline& v, std::string const& prefix) {
... ... @@ -2344,7 +2344,7 @@ QPDFJob::Input::initialize(Inputs&amp; in, QPDF* a_qpdf)
2344 2344 if (in.job.m->remove_unreferenced_page_resources != QPDFJob::re_no) {
2345 2345 remove_unreferenced = in.job.shouldRemoveUnreferencedResources(*qpdf);
2346 2346 }
2347   - if (qpdf->page_labels().hasPageLabels()) {
  2347 + if (qpdf->doc().page_labels().hasPageLabels()) {
2348 2348 in.any_page_labels = true;
2349 2349 }
2350 2350 }
... ... @@ -2574,15 +2574,15 @@ QPDFJob::handlePageSpecs(QPDF&amp; pdf)
2574 2574 // original file that we are selecting.
2575 2575 std::vector<QPDFObjectHandle> new_labels;
2576 2576 int out_pageno = 0;
2577   - auto& this_afdh = pdf.acroform();
  2577 + auto& this_afdh = pdf.doc().acroform();
2578 2578 std::set<QPDFObjGen> referenced_fields;
2579 2579 for (auto& selection: new_specs.empty() ? m->inputs.selections : new_specs) {
2580 2580 auto& input = selection.input();
2581 2581 if (input.cfis) {
2582 2582 input.cfis->stayOpen(true);
2583 2583 }
2584   - auto* pldh = m->inputs.any_page_labels ? &input.qpdf->page_labels() : nullptr;
2585   - auto& other_afdh = input.qpdf->acroform();
  2584 + auto* pldh = m->inputs.any_page_labels ? &input.qpdf->doc().page_labels() : nullptr;
  2585 + auto& other_afdh = input.qpdf->doc().acroform();
2586 2586 doIfVerbose([&](Pipeline& v, std::string const& prefix) {
2587 2587 v << prefix << ": adding pages from " << selection.filename() << "\n";
2588 2588 });
... ... @@ -3012,8 +3012,8 @@ QPDFJob::doSplitPages(QPDF&amp; pdf)
3012 3012 QPDFPageDocumentHelper dh(pdf);
3013 3013 dh.removeUnreferencedResources();
3014 3014 }
3015   - auto& pldh = pdf.page_labels();
3016   - auto& afdh = pdf.acroform();
  3015 + auto& pldh = pdf.doc().page_labels();
  3016 + auto& afdh = pdf.doc().acroform();
3017 3017 std::vector<QPDFObjectHandle> const& pages = pdf.getAllPages();
3018 3018 size_t pageno_len = std::to_string(pages.size()).length();
3019 3019 size_t num_pages = pages.size();
... ... @@ -3025,7 +3025,8 @@ QPDFJob::doSplitPages(QPDF&amp; pdf)
3025 3025 }
3026 3026 QPDF outpdf;
3027 3027 outpdf.emptyPDF();
3028   - QPDFAcroFormDocumentHelper* out_afdh = afdh.hasAcroForm() ? &outpdf.acroform() : nullptr;
  3028 + QPDFAcroFormDocumentHelper* out_afdh =
  3029 + afdh.hasAcroForm() ? &outpdf.doc().acroform() : nullptr;
3029 3030 if (m->suppress_warnings) {
3030 3031 outpdf.setSuppressWarnings(true);
3031 3032 }
... ...
libqpdf/QPDFOutlineDocumentHelper.cc
... ... @@ -34,7 +34,7 @@ QPDFOutlineDocumentHelper::QPDFOutlineDocumentHelper(QPDF&amp; qpdf) :
34 34 QPDFOutlineDocumentHelper&
35 35 QPDFOutlineDocumentHelper::get(QPDF& qpdf)
36 36 {
37   - return qpdf.outlines();
  37 + return qpdf.doc().outlines();
38 38 }
39 39  
40 40 void
... ...
libqpdf/QPDFPageDocumentHelper.cc
... ... @@ -18,7 +18,7 @@ QPDFPageDocumentHelper::QPDFPageDocumentHelper(QPDF&amp; qpdf) :
18 18 QPDFPageDocumentHelper&
19 19 QPDFPageDocumentHelper::get(QPDF& qpdf)
20 20 {
21   - return qpdf.pages();
  21 + return qpdf.doc().pages();
22 22 }
23 23  
24 24 void
... ... @@ -72,7 +72,7 @@ QPDFPageDocumentHelper::removePage(QPDFPageObjectHelper page)
72 72 void
73 73 QPDFPageDocumentHelper::flattenAnnotations(int required_flags, int forbidden_flags)
74 74 {
75   - auto& afdh = qpdf.acroform();
  75 + auto& afdh = qpdf.doc().acroform();
76 76 if (afdh.getNeedAppearances()) {
77 77 qpdf.getRoot()
78 78 .getKey("/AcroForm")
... ...
libqpdf/QPDFPageLabelDocumentHelper.cc
... ... @@ -26,7 +26,7 @@ QPDFPageLabelDocumentHelper::QPDFPageLabelDocumentHelper(QPDF&amp; qpdf) :
26 26 QPDFPageLabelDocumentHelper&
27 27 QPDFPageLabelDocumentHelper::get(QPDF& qpdf)
28 28 {
29   - return qpdf.page_labels();
  29 + return qpdf.doc().page_labels();
30 30 }
31 31  
32 32 void
... ...
libqpdf/qpdf/QPDF_private.hh
... ... @@ -425,9 +425,61 @@ class QPDF::Doc
425 425 {
426 426 }
427 427  
  428 + QPDFAcroFormDocumentHelper&
  429 + acroform()
  430 + {
  431 + if (!acroform_) {
  432 + acroform_ = std::make_unique<QPDFAcroFormDocumentHelper>(qpdf);
  433 + }
  434 + return *acroform_;
  435 + }
  436 +
  437 + QPDFEmbeddedFileDocumentHelper&
  438 + embedded_files()
  439 + {
  440 + if (!embedded_files_) {
  441 + embedded_files_ = std::make_unique<QPDFEmbeddedFileDocumentHelper>(qpdf);
  442 + }
  443 + return *embedded_files_;
  444 + }
  445 +
  446 + QPDFOutlineDocumentHelper&
  447 + outlines()
  448 + {
  449 + if (!outlines_) {
  450 + outlines_ = std::make_unique<QPDFOutlineDocumentHelper>(qpdf);
  451 + }
  452 + return *outlines_;
  453 + }
  454 +
  455 + QPDFPageDocumentHelper&
  456 + pages()
  457 + {
  458 + if (!pages_) {
  459 + pages_ = std::make_unique<QPDFPageDocumentHelper>(qpdf);
  460 + }
  461 + return *pages_;
  462 + }
  463 +
  464 + QPDFPageLabelDocumentHelper&
  465 + page_labels()
  466 + {
  467 + if (!page_labels_) {
  468 + page_labels_ = std::make_unique<QPDFPageLabelDocumentHelper>(qpdf);
  469 + }
  470 + return *page_labels_;
  471 + }
  472 +
428 473 private:
429 474 QPDF& qpdf;
430 475 QPDF::Members& m;
  476 +
  477 + // Document Helpers;
  478 + std::unique_ptr<QPDFAcroFormDocumentHelper> acroform_;
  479 + std::unique_ptr<QPDFEmbeddedFileDocumentHelper> embedded_files_;
  480 + std::unique_ptr<QPDFOutlineDocumentHelper> outlines_;
  481 + std::unique_ptr<QPDFPageDocumentHelper> pages_;
  482 + std::unique_ptr<QPDFPageLabelDocumentHelper> page_labels_;
431 483 };
432 484  
433 485 class QPDF::Members
... ... @@ -514,13 +566,6 @@ class QPDF::Members
514 566 // Optimization data
515 567 std::map<ObjUser, std::set<QPDFObjGen>> obj_user_to_objects;
516 568 std::map<QPDFObjGen, std::set<ObjUser>> object_to_obj_users;
517   -
518   - // Document Helpers;
519   - std::unique_ptr<QPDFAcroFormDocumentHelper> acroform;
520   - std::unique_ptr<QPDFEmbeddedFileDocumentHelper> embedded_files;
521   - std::unique_ptr<QPDFOutlineDocumentHelper> outlines;
522   - std::unique_ptr<QPDFPageDocumentHelper> pages;
523   - std::unique_ptr<QPDFPageLabelDocumentHelper> page_labels;
524 569 };
525 570  
526 571 // JobSetter class is restricted to QPDFJob.
... ... @@ -543,51 +588,6 @@ QPDF::reconstructed_xref() const
543 588 return m->reconstructed_xref;
544 589 }
545 590  
546   -inline QPDFAcroFormDocumentHelper&
547   -QPDF::acroform()
548   -{
549   - if (!m->acroform) {
550   - m->acroform = std::make_unique<QPDFAcroFormDocumentHelper>(*this);
551   - }
552   - return *m->acroform;
553   -}
554   -
555   -inline QPDFEmbeddedFileDocumentHelper&
556   -QPDF::embedded_files()
557   -{
558   - if (!m->embedded_files) {
559   - m->embedded_files = std::make_unique<QPDFEmbeddedFileDocumentHelper>(*this);
560   - }
561   - return *m->embedded_files;
562   -}
563   -
564   -inline QPDFOutlineDocumentHelper&
565   -QPDF::outlines()
566   -{
567   - if (!m->outlines) {
568   - m->outlines = std::make_unique<QPDFOutlineDocumentHelper>(*this);
569   - }
570   - return *m->outlines;
571   -}
572   -
573   -inline QPDFPageDocumentHelper&
574   -QPDF::pages()
575   -{
576   - if (!m->pages) {
577   - m->pages = std::make_unique<QPDFPageDocumentHelper>(*this);
578   - }
579   - return *m->pages;
580   -}
581   -
582   -inline QPDFPageLabelDocumentHelper&
583   -QPDF::page_labels()
584   -{
585   - if (!m->page_labels) {
586   - m->page_labels = std::make_unique<QPDFPageLabelDocumentHelper>(*this);
587   - }
588   - return *m->page_labels;
589   -}
590   -
591 591 inline QPDF::Doc&
592 592 QPDF::doc()
593 593 {
... ...