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,7 +177,7 @@ main(int argc, char* argv[])
177 QPDF qpdf; 177 QPDF qpdf;
178 qpdf.processFile(filename, password); 178 qpdf.processFile(filename, password);
179 179
180 - QPDFOutlineDocumentHelper odh(qpdf); 180 + auto& odh = QPDFOutlineDocumentHelper::get(qpdf);
181 if (odh.hasOutlines()) { 181 if (odh.hasOutlines()) {
182 std::vector<int> numbers; 182 std::vector<int> numbers;
183 if (show_targets) { 183 if (show_targets) {
fuzz/qpdf_outlines_fuzzer.cc
@@ -49,7 +49,7 @@ FuzzHelper::testOutlines() @@ -49,7 +49,7 @@ FuzzHelper::testOutlines()
49 { 49 {
50 std::shared_ptr<QPDF> q = getQpdf(); 50 std::shared_ptr<QPDF> q = getQpdf();
51 std::list<std::vector<QPDFOutlineObjectHelper>> queue; 51 std::list<std::vector<QPDFOutlineObjectHelper>> queue;
52 - QPDFOutlineDocumentHelper odh(*q); 52 + auto& odh = QPDFOutlineDocumentHelper::get(*q);
53 queue.push_back(odh.getTopLevelOutlines()); 53 queue.push_back(odh.getTopLevelOutlines());
54 while (!queue.empty()) { 54 while (!queue.empty()) {
55 for (auto& ol: *(queue.begin())) { 55 for (auto& ol: *(queue.begin())) {
include/qpdf/QPDF.hh
@@ -64,6 +64,7 @@ class QPDFLogger; @@ -64,6 +64,7 @@ class QPDFLogger;
64 class QPDFParser; 64 class QPDFParser;
65 class QPDFAcroFormDocumentHelper; 65 class QPDFAcroFormDocumentHelper;
66 class QPDFEmbeddedFileDocumentHelper; 66 class QPDFEmbeddedFileDocumentHelper;
  67 +class QPDFOutlineDocumentHelper;
67 class QPDFPageLabelDocumentHelper; 68 class QPDFPageLabelDocumentHelper;
68 69
69 class QPDF 70 class QPDF
@@ -802,6 +803,7 @@ class QPDF @@ -802,6 +803,7 @@ class QPDF
802 inline bool reconstructed_xref() const; 803 inline bool reconstructed_xref() const;
803 inline QPDFAcroFormDocumentHelper& acroform(); 804 inline QPDFAcroFormDocumentHelper& acroform();
804 inline QPDFEmbeddedFileDocumentHelper& embedded_files(); 805 inline QPDFEmbeddedFileDocumentHelper& embedded_files();
  806 + inline QPDFOutlineDocumentHelper& outlines();
805 inline QPDFPageLabelDocumentHelper& page_labels(); 807 inline QPDFPageLabelDocumentHelper& page_labels();
806 808
807 // For testing only -- do not add to DLL 809 // For testing only -- do not add to DLL
include/qpdf/QPDFOutlineDocumentHelper.hh
@@ -38,6 +38,21 @@ @@ -38,6 +38,21 @@
38 class QPDFOutlineDocumentHelper: public QPDFDocumentHelper 38 class QPDFOutlineDocumentHelper: public QPDFDocumentHelper
39 { 39 {
40 public: 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 QPDF_DLL 56 QPDF_DLL
42 QPDFOutlineDocumentHelper(QPDF&); 57 QPDFOutlineDocumentHelper(QPDF&);
43 58
libqpdf/QPDFJob.cc
@@ -17,7 +17,6 @@ @@ -17,7 +17,6 @@
17 #include <qpdf/QPDFExc.hh> 17 #include <qpdf/QPDFExc.hh>
18 #include <qpdf/QPDFLogger.hh> 18 #include <qpdf/QPDFLogger.hh>
19 #include <qpdf/QPDFObjectHandle_private.hh> 19 #include <qpdf/QPDFObjectHandle_private.hh>
20 -#include <qpdf/QPDFOutlineDocumentHelper.hh>  
21 #include <qpdf/QPDFPageDocumentHelper.hh> 20 #include <qpdf/QPDFPageDocumentHelper.hh>
22 #include <qpdf/QPDFPageObjectHelper.hh> 21 #include <qpdf/QPDFPageObjectHelper.hh>
23 #include <qpdf/QPDFSystemError.hh> 22 #include <qpdf/QPDFSystemError.hh>
@@ -1051,7 +1050,7 @@ QPDFJob::doJSONPages(Pipeline* p, bool&amp; first, QPDF&amp; pdf) @@ -1051,7 +1050,7 @@ QPDFJob::doJSONPages(Pipeline* p, bool&amp; first, QPDF&amp; pdf)
1051 bool first_page = true; 1050 bool first_page = true;
1052 JSON::writeArrayOpen(p, first_page, 2); 1051 JSON::writeArrayOpen(p, first_page, 2);
1053 auto& pldh = pdf.page_labels(); 1052 auto& pldh = pdf.page_labels();
1054 - QPDFOutlineDocumentHelper odh(pdf); 1053 + auto& odh = pdf.outlines();
1055 int pageno = -1; 1054 int pageno = -1;
1056 for (auto& ph: QPDFPageDocumentHelper(pdf).getAllPages()) { 1055 for (auto& ph: QPDFPageDocumentHelper(pdf).getAllPages()) {
1057 ++pageno; 1056 ++pageno;
@@ -1168,8 +1167,7 @@ QPDFJob::doJSONOutlines(Pipeline* p, bool&amp; first, QPDF&amp; pdf) @@ -1168,8 +1167,7 @@ QPDFJob::doJSONOutlines(Pipeline* p, bool&amp; first, QPDF&amp; pdf)
1168 } 1167 }
1169 1168
1170 JSON j_outlines = JSON::makeArray(); 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 JSON::writeDictionaryItem(p, first, "outlines", j_outlines, 1); 1171 JSON::writeDictionaryItem(p, first, "outlines", j_outlines, 1);
1174 } 1172 }
1175 1173
libqpdf/QPDFOutlineDocumentHelper.cc
1 #include <qpdf/QPDFOutlineDocumentHelper.hh> 1 #include <qpdf/QPDFOutlineDocumentHelper.hh>
2 2
3 #include <qpdf/QPDFObjectHandle_private.hh> 3 #include <qpdf/QPDFObjectHandle_private.hh>
  4 +#include <qpdf/QPDF_private.hh>
4 #include <qpdf/QTC.hh> 5 #include <qpdf/QTC.hh>
5 6
6 class QPDFOutlineDocumentHelper::Members 7 class QPDFOutlineDocumentHelper::Members
@@ -27,6 +28,21 @@ QPDFOutlineDocumentHelper::QPDFOutlineDocumentHelper(QPDF&amp; qpdf) : @@ -27,6 +28,21 @@ QPDFOutlineDocumentHelper::QPDFOutlineDocumentHelper(QPDF&amp; qpdf) :
27 QPDFDocumentHelper(qpdf), 28 QPDFDocumentHelper(qpdf),
28 m(std::make_shared<Members>()) 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 QPDFObjectHandle root = qpdf.getRoot(); 46 QPDFObjectHandle root = qpdf.getRoot();
31 if (!root.hasKey("/Outlines")) { 47 if (!root.hasKey("/Outlines")) {
32 return; 48 return;
libqpdf/qpdf/QPDF_private.hh
@@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
6 #include <qpdf/QPDFAcroFormDocumentHelper.hh> 6 #include <qpdf/QPDFAcroFormDocumentHelper.hh>
7 #include <qpdf/QPDFEmbeddedFileDocumentHelper.hh> 7 #include <qpdf/QPDFEmbeddedFileDocumentHelper.hh>
8 #include <qpdf/QPDFObject_private.hh> 8 #include <qpdf/QPDFObject_private.hh>
  9 +#include <qpdf/QPDFOutlineDocumentHelper.hh>
9 #include <qpdf/QPDFPageLabelDocumentHelper.hh> 10 #include <qpdf/QPDFPageLabelDocumentHelper.hh>
10 #include <qpdf/QPDFTokenizer_private.hh> 11 #include <qpdf/QPDFTokenizer_private.hh>
11 12
@@ -556,6 +557,7 @@ class QPDF::Members @@ -556,6 +557,7 @@ class QPDF::Members
556 // Document Helpers; 557 // Document Helpers;
557 std::unique_ptr<QPDFAcroFormDocumentHelper> acroform; 558 std::unique_ptr<QPDFAcroFormDocumentHelper> acroform;
558 std::unique_ptr<QPDFEmbeddedFileDocumentHelper> embedded_files; 559 std::unique_ptr<QPDFEmbeddedFileDocumentHelper> embedded_files;
  560 + std::unique_ptr<QPDFOutlineDocumentHelper> outlines;
559 std::unique_ptr<QPDFPageLabelDocumentHelper> page_labels; 561 std::unique_ptr<QPDFPageLabelDocumentHelper> page_labels;
560 }; 562 };
561 563
@@ -597,6 +599,15 @@ QPDF::embedded_files() @@ -597,6 +599,15 @@ QPDF::embedded_files()
597 return *m->embedded_files; 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 inline QPDFPageLabelDocumentHelper& 611 inline QPDFPageLabelDocumentHelper&
601 QPDF::page_labels() 612 QPDF::page_labels()
602 { 613 {