Commit 847f02462e2f949573c0a83962d5766e90d86baa
1 parent
e6555a36
Integrate `QPDFOutlineDocumentHelper` with `QPDF` for improved outline managemen…
…t. Add shared helper retrieval, validation methods, and update usages across the codebase.
Showing
7 changed files
with
48 additions
and
6 deletions
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& first, QPDF& 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& first, QPDF& 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& 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 | { | ... | ... |