Commit 847f02462e2f949573c0a83962d5766e90d86baa

Authored by m-holger
1 parent e6555a36

Integrate `QPDFOutlineDocumentHelper` with `QPDF` for improved outline managemen…

…t. Add shared helper retrieval, validation methods, and update usages across the codebase.
examples/pdf-bookmarks.cc
... ... @@ -177,7 +177,7 @@ main(int argc, char* argv[])
177 177 QPDF qpdf;
178 178 qpdf.processFile(filename, password);
179 179  
180   - QPDFOutlineDocumentHelper odh(qpdf);
  180 + auto& odh = QPDFOutlineDocumentHelper::get(qpdf);
181 181 if (odh.hasOutlines()) {
182 182 std::vector<int> numbers;
183 183 if (show_targets) {
... ...
fuzz/qpdf_outlines_fuzzer.cc
... ... @@ -49,7 +49,7 @@ FuzzHelper::testOutlines()
49 49 {
50 50 std::shared_ptr<QPDF> q = getQpdf();
51 51 std::list<std::vector<QPDFOutlineObjectHelper>> queue;
52   - QPDFOutlineDocumentHelper odh(*q);
  52 + auto& odh = QPDFOutlineDocumentHelper::get(*q);
53 53 queue.push_back(odh.getTopLevelOutlines());
54 54 while (!queue.empty()) {
55 55 for (auto& ol: *(queue.begin())) {
... ...
include/qpdf/QPDF.hh
... ... @@ -64,6 +64,7 @@ class QPDFLogger;
64 64 class QPDFParser;
65 65 class QPDFAcroFormDocumentHelper;
66 66 class QPDFEmbeddedFileDocumentHelper;
  67 +class QPDFOutlineDocumentHelper;
67 68 class QPDFPageLabelDocumentHelper;
68 69  
69 70 class QPDF
... ... @@ -802,6 +803,7 @@ class QPDF
802 803 inline bool reconstructed_xref() const;
803 804 inline QPDFAcroFormDocumentHelper& acroform();
804 805 inline QPDFEmbeddedFileDocumentHelper& embedded_files();
  806 + inline QPDFOutlineDocumentHelper& outlines();
805 807 inline QPDFPageLabelDocumentHelper& page_labels();
806 808  
807 809 // For testing only -- do not add to DLL
... ...
include/qpdf/QPDFOutlineDocumentHelper.hh
... ... @@ -38,6 +38,21 @@
38 38 class QPDFOutlineDocumentHelper: public QPDFDocumentHelper
39 39 {
40 40 public:
  41 + // Get a shared document helper for a given QPDF object.
  42 + //
  43 + // Retrieving a document helper for a QPDF object rather than creating a new one avoids repeated
  44 + // validation of the Acroform structure, which can be expensive.
  45 + QPDF_DLL
  46 + static QPDFOutlineDocumentHelper& get(QPDF& qpdf);
  47 +
  48 + // Re-validate the Outlines structure. This is useful if you have modified the structure of the
  49 + // Outlines dictionary in a way that would invalidate the cache.
  50 + //
  51 + // If repair is true, the document will be repaired if possible if the validation encounters
  52 + // errors.
  53 + QPDF_DLL
  54 + void validate(bool repair = true);
  55 +
41 56 QPDF_DLL
42 57 QPDFOutlineDocumentHelper(QPDF&);
43 58  
... ...
libqpdf/QPDFJob.cc
... ... @@ -17,7 +17,6 @@
17 17 #include <qpdf/QPDFExc.hh>
18 18 #include <qpdf/QPDFLogger.hh>
19 19 #include <qpdf/QPDFObjectHandle_private.hh>
20   -#include <qpdf/QPDFOutlineDocumentHelper.hh>
21 20 #include <qpdf/QPDFPageDocumentHelper.hh>
22 21 #include <qpdf/QPDFPageObjectHelper.hh>
23 22 #include <qpdf/QPDFSystemError.hh>
... ... @@ -1051,7 +1050,7 @@ QPDFJob::doJSONPages(Pipeline* p, bool&amp; first, QPDF&amp; pdf)
1051 1050 bool first_page = true;
1052 1051 JSON::writeArrayOpen(p, first_page, 2);
1053 1052 auto& pldh = pdf.page_labels();
1054   - QPDFOutlineDocumentHelper odh(pdf);
  1053 + auto& odh = pdf.outlines();
1055 1054 int pageno = -1;
1056 1055 for (auto& ph: QPDFPageDocumentHelper(pdf).getAllPages()) {
1057 1056 ++pageno;
... ... @@ -1168,8 +1167,7 @@ QPDFJob::doJSONOutlines(Pipeline* p, bool&amp; first, QPDF&amp; pdf)
1168 1167 }
1169 1168  
1170 1169 JSON j_outlines = JSON::makeArray();
1171   - QPDFOutlineDocumentHelper odh(pdf);
1172   - addOutlinesToJson(odh.getTopLevelOutlines(), j_outlines, page_numbers);
  1170 + addOutlinesToJson(pdf.outlines().getTopLevelOutlines(), j_outlines, page_numbers);
1173 1171 JSON::writeDictionaryItem(p, first, "outlines", j_outlines, 1);
1174 1172 }
1175 1173  
... ...
libqpdf/QPDFOutlineDocumentHelper.cc
1 1 #include <qpdf/QPDFOutlineDocumentHelper.hh>
2 2  
3 3 #include <qpdf/QPDFObjectHandle_private.hh>
  4 +#include <qpdf/QPDF_private.hh>
4 5 #include <qpdf/QTC.hh>
5 6  
6 7 class QPDFOutlineDocumentHelper::Members
... ... @@ -27,6 +28,21 @@ QPDFOutlineDocumentHelper::QPDFOutlineDocumentHelper(QPDF&amp; qpdf) :
27 28 QPDFDocumentHelper(qpdf),
28 29 m(std::make_shared<Members>())
29 30 {
  31 + validate();
  32 +}
  33 +
  34 +QPDFOutlineDocumentHelper&
  35 +QPDFOutlineDocumentHelper::get(QPDF& qpdf)
  36 +{
  37 + return qpdf.outlines();
  38 +}
  39 +
  40 +void
  41 +QPDFOutlineDocumentHelper::validate(bool repair)
  42 +{
  43 + m->outlines.clear();
  44 + m->names_dest = nullptr;
  45 +
30 46 QPDFObjectHandle root = qpdf.getRoot();
31 47 if (!root.hasKey("/Outlines")) {
32 48 return;
... ...
libqpdf/qpdf/QPDF_private.hh
... ... @@ -6,6 +6,7 @@
6 6 #include <qpdf/QPDFAcroFormDocumentHelper.hh>
7 7 #include <qpdf/QPDFEmbeddedFileDocumentHelper.hh>
8 8 #include <qpdf/QPDFObject_private.hh>
  9 +#include <qpdf/QPDFOutlineDocumentHelper.hh>
9 10 #include <qpdf/QPDFPageLabelDocumentHelper.hh>
10 11 #include <qpdf/QPDFTokenizer_private.hh>
11 12  
... ... @@ -556,6 +557,7 @@ class QPDF::Members
556 557 // Document Helpers;
557 558 std::unique_ptr<QPDFAcroFormDocumentHelper> acroform;
558 559 std::unique_ptr<QPDFEmbeddedFileDocumentHelper> embedded_files;
  560 + std::unique_ptr<QPDFOutlineDocumentHelper> outlines;
559 561 std::unique_ptr<QPDFPageLabelDocumentHelper> page_labels;
560 562 };
561 563  
... ... @@ -597,6 +599,15 @@ QPDF::embedded_files()
597 599 return *m->embedded_files;
598 600 }
599 601  
  602 +inline QPDFOutlineDocumentHelper&
  603 +QPDF::outlines()
  604 +{
  605 + if (!m->outlines) {
  606 + m->outlines = std::make_unique<QPDFOutlineDocumentHelper>(*this);
  607 + }
  608 + return *m->outlines;
  609 +}
  610 +
600 611 inline QPDFPageLabelDocumentHelper&
601 612 QPDF::page_labels()
602 613 {
... ...