Commit 61879f9a09073e1e18e29676b95ba1b11003d375
1 parent
8486b9de
Refactor `QPDFWriter`: replace `pdf` with `qpdf`, streamline `Writer` class, and…
… improve encapsulation.
Showing
1 changed file
with
29 additions
and
28 deletions
libqpdf/QPDFWriter.cc
| @@ -27,7 +27,8 @@ | @@ -27,7 +27,8 @@ | ||
| 27 | using namespace std::literals; | 27 | using namespace std::literals; |
| 28 | using namespace qpdf; | 28 | using namespace qpdf; |
| 29 | 29 | ||
| 30 | -using Encryption = QPDF::Doc::Encryption; | 30 | +using Doc = QPDF::Doc; |
| 31 | +using Encryption = Doc::Encryption; | ||
| 31 | 32 | ||
| 32 | QPDFWriter::ProgressReporter::~ProgressReporter() // NOLINT (modernize-use-equals-default) | 33 | QPDFWriter::ProgressReporter::~ProgressReporter() // NOLINT (modernize-use-equals-default) |
| 33 | { | 34 | { |
| @@ -262,13 +263,13 @@ Pl_stack::Popper::pop() | @@ -262,13 +263,13 @@ Pl_stack::Popper::pop() | ||
| 262 | } | 263 | } |
| 263 | 264 | ||
| 264 | // Writer class is restricted to QPDFWriter so that only it can call certain methods. | 265 | // Writer class is restricted to QPDFWriter so that only it can call certain methods. |
| 265 | -class QPDF::Doc::Writer | 266 | +class Doc::Writer: Doc::Common |
| 266 | { | 267 | { |
| 267 | friend class QPDFWriter; | 268 | friend class QPDFWriter; |
| 268 | - Writer(QPDF& pdf) : | ||
| 269 | - pdf(pdf), | ||
| 270 | - lin(pdf.m->lin), | ||
| 271 | - objects(pdf.m->objects) | 269 | + Writer(QPDF& qpdf) : |
| 270 | + Common(qpdf, qpdf.doc().m), | ||
| 271 | + lin(m->lin), | ||
| 272 | + objects(m->objects) | ||
| 272 | { | 273 | { |
| 273 | } | 274 | } |
| 274 | 275 | ||
| @@ -326,10 +327,9 @@ class QPDF::Doc::Writer | @@ -326,10 +327,9 @@ class QPDF::Doc::Writer | ||
| 326 | size_t | 327 | size_t |
| 327 | tableSize() | 328 | tableSize() |
| 328 | { | 329 | { |
| 329 | - return pdf.m->objects.tableSize(); | 330 | + return qpdf.m->objects.tableSize(); |
| 330 | } | 331 | } |
| 331 | 332 | ||
| 332 | - QPDF& pdf; | ||
| 333 | QPDF::Doc::Linearization& lin; | 333 | QPDF::Doc::Linearization& lin; |
| 334 | QPDF::Doc::Objects& objects; | 334 | QPDF::Doc::Objects& objects; |
| 335 | }; | 335 | }; |
| @@ -352,7 +352,8 @@ class QPDFWriter::Members: QPDF::Doc::Writer | @@ -352,7 +352,8 @@ class QPDFWriter::Members: QPDF::Doc::Writer | ||
| 352 | QPDF::Doc::Writer(pdf), | 352 | QPDF::Doc::Writer(pdf), |
| 353 | w(w), | 353 | w(w), |
| 354 | root_og( | 354 | root_og( |
| 355 | - pdf.getRoot().getObjGen().isIndirect() ? pdf.getRoot().getObjGen() : QPDFObjGen(-1, 0)), | 355 | + qpdf.getRoot().getObjGen().isIndirect() ? qpdf.getRoot().getObjGen() |
| 356 | + : QPDFObjGen(-1, 0)), | ||
| 356 | pipeline_stack(pipeline) | 357 | pipeline_stack(pipeline) |
| 357 | { | 358 | { |
| 358 | } | 359 | } |
| @@ -1372,7 +1373,7 @@ QPDFWriter::Members::enqueueObject(QPDFObjectHandle object) | @@ -1372,7 +1373,7 @@ QPDFWriter::Members::enqueueObject(QPDFObjectHandle object) | ||
| 1372 | // object to have an owning QPDF that is from another file if a direct QPDFObjectHandle from | 1373 | // object to have an owning QPDF that is from another file if a direct QPDFObjectHandle from |
| 1373 | // one file was insert into another file without copying. Doing that is safe even if the | 1374 | // one file was insert into another file without copying. Doing that is safe even if the |
| 1374 | // original QPDF gets destroyed, which just disconnects the QPDFObjectHandle from its owner. | 1375 | // original QPDF gets destroyed, which just disconnects the QPDFObjectHandle from its owner. |
| 1375 | - if (object.getOwningQPDF() != &pdf) { | 1376 | + if (object.getOwningQPDF() != &qpdf) { |
| 1376 | throw std::logic_error( | 1377 | throw std::logic_error( |
| 1377 | "QPDFObjectHandle from different QPDF found while writing. Use " | 1378 | "QPDFObjectHandle from different QPDF found while writing. Use " |
| 1378 | "QPDF::copyForeignObject to add objects from another file."); | 1379 | "QPDF::copyForeignObject to add objects from another file."); |
| @@ -1396,7 +1397,7 @@ QPDFWriter::Members::enqueueObject(QPDFObjectHandle object) | @@ -1396,7 +1397,7 @@ QPDFWriter::Members::enqueueObject(QPDFObjectHandle object) | ||
| 1396 | // stream. Object streams always have generation 0. | 1397 | // stream. Object streams always have generation 0. |
| 1397 | // Detect loops by storing invalid object ID -1, which will get overwritten later. | 1398 | // Detect loops by storing invalid object ID -1, which will get overwritten later. |
| 1398 | o.renumber = -1; | 1399 | o.renumber = -1; |
| 1399 | - enqueueObject(pdf.getObject(o.object_stream, 0)); | 1400 | + enqueueObject(qpdf.getObject(o.object_stream, 0)); |
| 1400 | } else { | 1401 | } else { |
| 1401 | object_queue.emplace_back(object); | 1402 | object_queue.emplace_back(object); |
| 1402 | o.renumber = next_objid++; | 1403 | o.renumber = next_objid++; |
| @@ -1907,7 +1908,7 @@ QPDFWriter::Members::writeObjectStream(QPDFObjectHandle object) | @@ -1907,7 +1908,7 @@ QPDFWriter::Members::writeObjectStream(QPDFObjectHandle object) | ||
| 1907 | // reporting, decrement in pass 1. | 1908 | // reporting, decrement in pass 1. |
| 1908 | indicateProgress(true, false); | 1909 | indicateProgress(true, false); |
| 1909 | 1910 | ||
| 1910 | - QPDFObjectHandle obj_to_write = pdf.getObject(og); | 1911 | + QPDFObjectHandle obj_to_write = qpdf.getObject(og); |
| 1911 | if (obj_to_write.isStream()) { | 1912 | if (obj_to_write.isStream()) { |
| 1912 | // This condition occurred in a fuzz input. Ideally we should block it at parse | 1913 | // This condition occurred in a fuzz input. Ideally we should block it at parse |
| 1913 | // time, but it's not clear to me how to construct a case for this. | 1914 | // time, but it's not clear to me how to construct a case for this. |
| @@ -2024,7 +2025,7 @@ QPDFWriter::Members::writeObject(QPDFObjectHandle object, int object_stream_inde | @@ -2024,7 +2025,7 @@ QPDFWriter::Members::writeObject(QPDFObjectHandle object, int object_stream_inde | ||
| 2024 | std::string | 2025 | std::string |
| 2025 | QPDFWriter::Members::getOriginalID1() | 2026 | QPDFWriter::Members::getOriginalID1() |
| 2026 | { | 2027 | { |
| 2027 | - QPDFObjectHandle trailer = pdf.getTrailer(); | 2028 | + QPDFObjectHandle trailer = qpdf.getTrailer(); |
| 2028 | if (trailer.hasKey("/ID")) { | 2029 | if (trailer.hasKey("/ID")) { |
| 2029 | return trailer.getKey("/ID").getArrayItem(0).getStringValue(); | 2030 | return trailer.getKey("/ID").getArrayItem(0).getStringValue(); |
| 2030 | } else { | 2031 | } else { |
| @@ -2042,7 +2043,7 @@ QPDFWriter::Members::generateID(bool encrypted) | @@ -2042,7 +2043,7 @@ QPDFWriter::Members::generateID(bool encrypted) | ||
| 2042 | return; | 2043 | return; |
| 2043 | } | 2044 | } |
| 2044 | 2045 | ||
| 2045 | - QPDFObjectHandle trailer = pdf.getTrailer(); | 2046 | + QPDFObjectHandle trailer = qpdf.getTrailer(); |
| 2046 | 2047 | ||
| 2047 | std::string result; | 2048 | std::string result; |
| 2048 | 2049 | ||
| @@ -2126,7 +2127,7 @@ void | @@ -2126,7 +2127,7 @@ void | ||
| 2126 | QPDFWriter::Members::initializeSpecialStreams() | 2127 | QPDFWriter::Members::initializeSpecialStreams() |
| 2127 | { | 2128 | { |
| 2128 | // Mark all page content streams in case we are filtering or normalizing. | 2129 | // Mark all page content streams in case we are filtering or normalizing. |
| 2129 | - std::vector<QPDFObjectHandle> pages = pdf.getAllPages(); | 2130 | + std::vector<QPDFObjectHandle> pages = qpdf.getAllPages(); |
| 2130 | int num = 0; | 2131 | int num = 0; |
| 2131 | for (auto& page: pages) { | 2132 | for (auto& page: pages) { |
| 2132 | page_object_to_seq[page.getObjGen()] = ++num; | 2133 | page_object_to_seq[page.getObjGen()] = ++num; |
| @@ -2220,13 +2221,13 @@ QPDFWriter::Members::generateObjectStreams() | @@ -2220,13 +2221,13 @@ QPDFWriter::Members::generateObjectStreams() | ||
| 2220 | ++n_per; | 2221 | ++n_per; |
| 2221 | } | 2222 | } |
| 2222 | unsigned int n = 0; | 2223 | unsigned int n = 0; |
| 2223 | - int cur_ostream = pdf.newIndirectNull().getObjectID(); | 2224 | + int cur_ostream = qpdf.newIndirectNull().getObjectID(); |
| 2224 | for (auto const& item: eligible) { | 2225 | for (auto const& item: eligible) { |
| 2225 | if (n == n_per) { | 2226 | if (n == n_per) { |
| 2226 | n = 0; | 2227 | n = 0; |
| 2227 | // Construct a new null object as the "original" object stream. The rest of the code | 2228 | // Construct a new null object as the "original" object stream. The rest of the code |
| 2228 | // knows that this means we're creating the object stream from scratch. | 2229 | // knows that this means we're creating the object stream from scratch. |
| 2229 | - cur_ostream = pdf.newIndirectNull().getObjectID(); | 2230 | + cur_ostream = qpdf.newIndirectNull().getObjectID(); |
| 2230 | } | 2231 | } |
| 2231 | auto& o = obj[item]; | 2232 | auto& o = obj[item]; |
| 2232 | o.object_stream = cur_ostream; | 2233 | o.object_stream = cur_ostream; |
| @@ -2240,7 +2241,7 @@ QPDFWriter::Members::trimmed_trailer() | @@ -2240,7 +2241,7 @@ QPDFWriter::Members::trimmed_trailer() | ||
| 2240 | { | 2241 | { |
| 2241 | // Remove keys from the trailer that necessarily have to be replaced when writing the file. | 2242 | // Remove keys from the trailer that necessarily have to be replaced when writing the file. |
| 2242 | 2243 | ||
| 2243 | - Dictionary trailer = pdf.getTrailer().unsafeShallowCopy(); | 2244 | + Dictionary trailer = qpdf.getTrailer().unsafeShallowCopy(); |
| 2244 | 2245 | ||
| 2245 | // Remove encryption keys | 2246 | // Remove encryption keys |
| 2246 | trailer.erase("/ID"); | 2247 | trailer.erase("/ID"); |
| @@ -2265,8 +2266,8 @@ QPDFWriter::Members::trimmed_trailer() | @@ -2265,8 +2266,8 @@ QPDFWriter::Members::trimmed_trailer() | ||
| 2265 | void | 2266 | void |
| 2266 | QPDFWriter::Members::prepareFileForWrite() | 2267 | QPDFWriter::Members::prepareFileForWrite() |
| 2267 | { | 2268 | { |
| 2268 | - pdf.fixDanglingReferences(); | ||
| 2269 | - auto root = pdf.getRoot(); | 2269 | + qpdf.fixDanglingReferences(); |
| 2270 | + auto root = qpdf.getRoot(); | ||
| 2270 | auto oh = root.getKey("/Extensions"); | 2271 | auto oh = root.getKey("/Extensions"); |
| 2271 | if (oh.isDictionary()) { | 2272 | if (oh.isDictionary()) { |
| 2272 | const bool extensions_indirect = oh.isIndirect(); | 2273 | const bool extensions_indirect = oh.isIndirect(); |
| @@ -2335,7 +2336,7 @@ QPDFWriter::Members::doWriteSetup() | @@ -2335,7 +2336,7 @@ QPDFWriter::Members::doWriteSetup() | ||
| 2335 | } | 2336 | } |
| 2336 | 2337 | ||
| 2337 | if (preserve_encryption) { | 2338 | if (preserve_encryption) { |
| 2338 | - copyEncryptionParameters(pdf); | 2339 | + copyEncryptionParameters(qpdf); |
| 2339 | } | 2340 | } |
| 2340 | 2341 | ||
| 2341 | if (!forced_pdf_version.empty()) { | 2342 | if (!forced_pdf_version.empty()) { |
| @@ -2380,7 +2381,7 @@ QPDFWriter::Members::doWriteSetup() | @@ -2380,7 +2381,7 @@ QPDFWriter::Members::doWriteSetup() | ||
| 2380 | if (!obj.streams_empty) { | 2381 | if (!obj.streams_empty) { |
| 2381 | if (linearized) { | 2382 | if (linearized) { |
| 2382 | // Page dictionaries are not allowed to be compressed objects. | 2383 | // Page dictionaries are not allowed to be compressed objects. |
| 2383 | - for (auto& page: pdf.getAllPages()) { | 2384 | + for (auto& page: qpdf.getAllPages()) { |
| 2384 | if (obj[page].object_stream > 0) { | 2385 | if (obj[page].object_stream > 0) { |
| 2385 | obj[page].object_stream = 0; | 2386 | obj[page].object_stream = 0; |
| 2386 | } | 2387 | } |
| @@ -2416,7 +2417,7 @@ QPDFWriter::Members::doWriteSetup() | @@ -2416,7 +2417,7 @@ QPDFWriter::Members::doWriteSetup() | ||
| 2416 | } | 2417 | } |
| 2417 | } | 2418 | } |
| 2418 | 2419 | ||
| 2419 | - setMinimumPDFVersion(pdf.getPDFVersion(), pdf.getExtensionLevel()); | 2420 | + setMinimumPDFVersion(qpdf.getPDFVersion(), qpdf.getExtensionLevel()); |
| 2420 | final_pdf_version = min_pdf_version; | 2421 | final_pdf_version = min_pdf_version; |
| 2421 | final_extension_level = min_extension_level; | 2422 | final_extension_level = min_extension_level; |
| 2422 | if (!forced_pdf_version.empty()) { | 2423 | if (!forced_pdf_version.empty()) { |
| @@ -2438,7 +2439,7 @@ QPDFWriter::Members::write() | @@ -2438,7 +2439,7 @@ QPDFWriter::Members::write() | ||
| 2438 | 2439 | ||
| 2439 | // Set up progress reporting. For linearized files, we write two passes. events_expected is an | 2440 | // Set up progress reporting. For linearized files, we write two passes. events_expected is an |
| 2440 | // approximation, but it's good enough for progress reporting, which is mostly a guess anyway. | 2441 | // approximation, but it's good enough for progress reporting, which is mostly a guess anyway. |
| 2441 | - events_expected = QIntC::to_int(pdf.getObjectCount() * (linearized ? 2 : 1)); | 2442 | + events_expected = QIntC::to_int(qpdf.getObjectCount() * (linearized ? 2 : 1)); |
| 2442 | 2443 | ||
| 2443 | prepareFileForWrite(); | 2444 | prepareFileForWrite(); |
| 2444 | 2445 | ||
| @@ -2910,7 +2911,7 @@ QPDFWriter::Members::writeLinearized() | @@ -2910,7 +2911,7 @@ QPDFWriter::Members::writeLinearized() | ||
| 2910 | openObject(lindict_id); | 2911 | openObject(lindict_id); |
| 2911 | write("<<"); | 2912 | write("<<"); |
| 2912 | if (pass == 2) { | 2913 | if (pass == 2) { |
| 2913 | - std::vector<QPDFObjectHandle> const& pages = pdf.getAllPages(); | 2914 | + std::vector<QPDFObjectHandle> const& pages = qpdf.getAllPages(); |
| 2914 | int first_page_object = obj[pages.at(0)].renumber; | 2915 | int first_page_object = obj[pages.at(0)].renumber; |
| 2915 | 2916 | ||
| 2916 | write(" /Linearized 1 /L ").write(file_size + hint_length); | 2917 | write(" /Linearized 1 /L ").write(file_size + hint_length); |
| @@ -3110,7 +3111,7 @@ void | @@ -3110,7 +3111,7 @@ void | ||
| 3110 | QPDFWriter::Members::enqueueObjectsStandard() | 3111 | QPDFWriter::Members::enqueueObjectsStandard() |
| 3111 | { | 3112 | { |
| 3112 | if (preserve_unreferenced_objects) { | 3113 | if (preserve_unreferenced_objects) { |
| 3113 | - for (auto const& oh: pdf.getAllObjects()) { | 3114 | + for (auto const& oh: qpdf.getAllObjects()) { |
| 3114 | enqueueObject(oh); | 3115 | enqueueObject(oh); |
| 3115 | } | 3116 | } |
| 3116 | } | 3117 | } |
| @@ -3136,7 +3137,7 @@ QPDFWriter::Members::enqueueObjectsPCLm() | @@ -3136,7 +3137,7 @@ QPDFWriter::Members::enqueueObjectsPCLm() | ||
| 3136 | std::string image_transform_content = "q /image Do Q\n"; | 3137 | std::string image_transform_content = "q /image Do Q\n"; |
| 3137 | 3138 | ||
| 3138 | // enqueue all pages first | 3139 | // enqueue all pages first |
| 3139 | - std::vector<QPDFObjectHandle> all = pdf.getAllPages(); | 3140 | + std::vector<QPDFObjectHandle> all = qpdf.getAllPages(); |
| 3140 | for (auto& page: all) { | 3141 | for (auto& page: all) { |
| 3141 | // enqueue page | 3142 | // enqueue page |
| 3142 | enqueueObject(page); | 3143 | enqueueObject(page); |
| @@ -3149,7 +3150,7 @@ QPDFWriter::Members::enqueueObjectsPCLm() | @@ -3149,7 +3150,7 @@ QPDFWriter::Members::enqueueObjectsPCLm() | ||
| 3149 | for (auto& image: strips.as_dictionary()) { | 3150 | for (auto& image: strips.as_dictionary()) { |
| 3150 | if (!image.second.null()) { | 3151 | if (!image.second.null()) { |
| 3151 | enqueueObject(image.second); | 3152 | enqueueObject(image.second); |
| 3152 | - enqueueObject(QPDFObjectHandle::newStream(&pdf, image_transform_content)); | 3153 | + enqueueObject(QPDFObjectHandle::newStream(&qpdf, image_transform_content)); |
| 3153 | } | 3154 | } |
| 3154 | } | 3155 | } |
| 3155 | } | 3156 | } |