Commit 980df238438bb616e9ab04eb76b96fc9117a2e04

Authored by m-holger
1 parent a000488d

Refactor `QPDFJob`: consolidate `QPDFPageData` into `Selection`, simplify page r…

…ange handling, and cleanup obsolete logic.
libqpdf/QPDFJob.cc
@@ -58,17 +58,6 @@ namespace @@ -58,17 +58,6 @@ namespace
58 std::shared_ptr<Pl_DCT::CompressConfig> config; 58 std::shared_ptr<Pl_DCT::CompressConfig> config;
59 }; 59 };
60 60
61 - struct QPDFPageData  
62 - {  
63 - QPDFPageData(std::string const& filename, QPDF* qpdf, std::string const& range);  
64 - QPDFPageData(QPDFPageData const& other, int page);  
65 -  
66 - std::string filename;  
67 - QPDF* qpdf;  
68 - std::vector<QPDFObjectHandle> orig_pages;  
69 - std::vector<int> selected_pages;  
70 - };  
71 -  
72 class ProgressReporter final: public QPDFWriter::ProgressReporter 61 class ProgressReporter final: public QPDFWriter::ProgressReporter
73 { 62 {
74 public: 63 public:
@@ -267,26 +256,6 @@ struct QPDFJob::PageNo @@ -267,26 +256,6 @@ struct QPDFJob::PageNo
267 int no{1}; 256 int no{1};
268 }; 257 };
269 258
270 -QPDFPageData::QPDFPageData(std::string const& filename, QPDF* qpdf, std::string const& range) :  
271 - filename(filename),  
272 - qpdf(qpdf),  
273 - orig_pages(qpdf->getAllPages())  
274 -{  
275 - try {  
276 - selected_pages = QUtil::parse_numrange(range.c_str(), QIntC::to_int(orig_pages.size()));  
277 - } catch (std::runtime_error& e) {  
278 - throw std::runtime_error("parsing numeric range for " + filename + ": " + e.what());  
279 - }  
280 -}  
281 -  
282 -QPDFPageData::QPDFPageData(QPDFPageData const& other, int page) :  
283 - filename(other.filename),  
284 - qpdf(other.qpdf),  
285 - orig_pages(other.orig_pages)  
286 -{  
287 - selected_pages.push_back(page);  
288 -}  
289 -  
290 QPDFJob::QPDFJob() : 259 QPDFJob::QPDFJob() :
291 m(std::make_shared<Members>()) 260 m(std::make_shared<Members>())
292 { 261 {
@@ -2411,7 +2380,6 @@ QPDFJob::handlePageSpecs(QPDF&amp; pdf) @@ -2411,7 +2380,6 @@ QPDFJob::handlePageSpecs(QPDF&amp; pdf)
2411 std::map<std::string, QPDF*> page_spec_qpdfs; 2380 std::map<std::string, QPDF*> page_spec_qpdfs;
2412 std::map<std::string, ClosedFileInputSource*> page_spec_cfis; 2381 std::map<std::string, ClosedFileInputSource*> page_spec_cfis;
2413 page_spec_qpdfs[m->infilename] = &pdf; 2382 page_spec_qpdfs[m->infilename] = &pdf;
2414 - std::vector<QPDFPageData> parsed_specs;  
2415 std::map<unsigned long long, std::set<QPDFObjGen>> copied_pages; 2383 std::map<unsigned long long, std::set<QPDFObjGen>> copied_pages;
2416 for (auto& selection: m->selections) { 2384 for (auto& selection: m->selections) {
2417 if (!page_spec_qpdfs.contains(selection.filename)) { 2385 if (!page_spec_qpdfs.contains(selection.filename)) {
@@ -2425,7 +2393,6 @@ QPDFJob::handlePageSpecs(QPDF&amp; pdf) @@ -2425,7 +2393,6 @@ QPDFJob::handlePageSpecs(QPDF&amp; pdf)
2425 auto password = selection.password; 2393 auto password = selection.password;
2426 if (!m->encryption_file.empty() && password.empty() && 2394 if (!m->encryption_file.empty() && password.empty() &&
2427 selection.filename == m->encryption_file) { 2395 selection.filename == m->encryption_file) {
2428 - QTC::TC("qpdf", "QPDFJob pages encryption password");  
2429 password = m->encryption_file_password; 2396 password = m->encryption_file_password;
2430 } 2397 }
2431 doIfVerbose([&](Pipeline& v, std::string const& prefix) { 2398 doIfVerbose([&](Pipeline& v, std::string const& prefix) {
@@ -2434,13 +2401,11 @@ QPDFJob::handlePageSpecs(QPDF&amp; pdf) @@ -2434,13 +2401,11 @@ QPDFJob::handlePageSpecs(QPDF&amp; pdf)
2434 std::shared_ptr<InputSource> is; 2401 std::shared_ptr<InputSource> is;
2435 ClosedFileInputSource* cis = nullptr; 2402 ClosedFileInputSource* cis = nullptr;
2436 if (!m->keep_files_open) { 2403 if (!m->keep_files_open) {
2437 - QTC::TC("qpdf", "QPDFJob keep files open n");  
2438 - cis = new ClosedFileInputSource(selection.filename.c_str()); 2404 + cis = new ClosedFileInputSource(selection.filename.data());
2439 is = std::shared_ptr<InputSource>(cis); 2405 is = std::shared_ptr<InputSource>(cis);
2440 cis->stayOpen(true); 2406 cis->stayOpen(true);
2441 } else { 2407 } else {
2442 - QTC::TC("qpdf", "QPDFJob keep files open y");  
2443 - FileInputSource* fis = new FileInputSource(selection.filename.c_str()); 2408 + FileInputSource* fis = new FileInputSource(selection.filename.data());
2444 is = std::shared_ptr<InputSource>(fis); 2409 is = std::shared_ptr<InputSource>(fis);
2445 } 2410 }
2446 std::unique_ptr<QPDF> qpdf_sp; 2411 std::unique_ptr<QPDF> qpdf_sp;
@@ -2455,8 +2420,15 @@ QPDFJob::handlePageSpecs(QPDF&amp; pdf) @@ -2455,8 +2420,15 @@ QPDFJob::handlePageSpecs(QPDF&amp; pdf)
2455 2420
2456 // Read original pages from the PDF, and parse the page range associated with this 2421 // Read original pages from the PDF, and parse the page range associated with this
2457 // occurrence of the file. 2422 // occurrence of the file.
2458 - parsed_specs.emplace_back(  
2459 - selection.filename, page_spec_qpdfs[selection.filename], selection.range); 2423 + selection.qpdf = page_spec_qpdfs[selection.filename];
  2424 + selection.orig_pages = selection.qpdf->getAllPages();
  2425 + try {
  2426 + selection.selected_pages = QUtil::parse_numrange(
  2427 + selection.range.data(), static_cast<int>(selection.orig_pages.size()));
  2428 + } catch (std::runtime_error& e) {
  2429 + throw std::runtime_error(
  2430 + "parsing numeric range for " + selection.filename + ": " + e.what());
  2431 + }
2460 } 2432 }
2461 2433
2462 std::map<unsigned long long, bool> remove_unreferenced; 2434 std::map<unsigned long long, bool> remove_unreferenced;
@@ -2491,16 +2463,17 @@ QPDFJob::handlePageSpecs(QPDF&amp; pdf) @@ -2491,16 +2463,17 @@ QPDFJob::handlePageSpecs(QPDF&amp; pdf)
2491 } 2463 }
2492 2464
2493 auto n_collate = m->collate.size(); 2465 auto n_collate = m->collate.size();
2494 - auto n_specs = parsed_specs.size(); 2466 + auto n_specs = m->selections.size();
2495 if (!(n_collate == 0 || n_collate == 1 || n_collate == n_specs)) { 2467 if (!(n_collate == 0 || n_collate == 1 || n_collate == n_specs)) {
2496 usage( 2468 usage(
2497 "--pages: if --collate has more than one value, it must have one value per page " 2469 "--pages: if --collate has more than one value, it must have one value per page "
2498 "specification"); 2470 "specification");
2499 } 2471 }
  2472 +
  2473 + std::vector<Selection> new_specs;
2500 if (n_collate > 0 && n_specs > 1) { 2474 if (n_collate > 0 && n_specs > 1) {
2501 // Collate the pages by selecting one page from each spec in order. When a spec runs out of 2475 // Collate the pages by selecting one page from each spec in order. When a spec runs out of
2502 // pages, stop selecting from it. 2476 // pages, stop selecting from it.
2503 - std::vector<QPDFPageData> new_parsed_specs;  
2504 // Make sure we have a collate value for each spec. We have already checked that a non-empty 2477 // Make sure we have a collate value for each spec. We have already checked that a non-empty
2505 // collate has either one value or one value per spec. 2478 // collate has either one value or one value per spec.
2506 for (auto i = n_collate; i < n_specs; ++i) { 2479 for (auto i = n_collate; i < n_specs; ++i) {
@@ -2511,20 +2484,20 @@ QPDFJob::handlePageSpecs(QPDF&amp; pdf) @@ -2511,20 +2484,20 @@ QPDFJob::handlePageSpecs(QPDF&amp; pdf)
2511 while (got_pages) { 2484 while (got_pages) {
2512 got_pages = false; 2485 got_pages = false;
2513 for (size_t i = 0; i < n_specs; ++i) { 2486 for (size_t i = 0; i < n_specs; ++i) {
2514 - QPDFPageData& page_data = parsed_specs.at(i); 2487 + auto& page_data = m->selections.at(i);
2515 for (size_t j = 0; j < m->collate.at(i); ++j) { 2488 for (size_t j = 0; j < m->collate.at(i); ++j) {
2516 if (cur_page.at(i) + j < page_data.selected_pages.size()) { 2489 if (cur_page.at(i) + j < page_data.selected_pages.size()) {
2517 got_pages = true; 2490 got_pages = true;
2518 - new_parsed_specs.emplace_back( 2491 + new_specs.emplace_back(
2519 page_data, page_data.selected_pages.at(cur_page.at(i) + j)); 2492 page_data, page_data.selected_pages.at(cur_page.at(i) + j));
2520 } 2493 }
2521 } 2494 }
2522 cur_page.at(i) += m->collate.at(i); 2495 cur_page.at(i) += m->collate.at(i);
2523 } 2496 }
2524 } 2497 }
2525 - parsed_specs = new_parsed_specs;  
2526 } 2498 }
2527 2499
  2500 + std::vector<Selection>& page_specs = new_specs.empty() ? m->selections : new_specs;
2528 // Add all the pages from all the files in the order specified. Keep track of any pages from the 2501 // Add all the pages from all the files in the order specified. Keep track of any pages from the
2529 // original file that we are selecting. 2502 // original file that we are selecting.
2530 std::set<int> selected_from_orig; 2503 std::set<int> selected_from_orig;
@@ -2533,7 +2506,7 @@ QPDFJob::handlePageSpecs(QPDF&amp; pdf) @@ -2533,7 +2506,7 @@ QPDFJob::handlePageSpecs(QPDF&amp; pdf)
2533 int out_pageno = 0; 2506 int out_pageno = 0;
2534 auto& this_afdh = pdf.acroform(); 2507 auto& this_afdh = pdf.acroform();
2535 std::set<QPDFObjGen> referenced_fields; 2508 std::set<QPDFObjGen> referenced_fields;
2536 - for (auto& page_data: parsed_specs) { 2509 + for (auto& page_data: page_specs) {
2537 ClosedFileInputSource* cis = nullptr; 2510 ClosedFileInputSource* cis = nullptr;
2538 if (page_spec_cfis.contains(page_data.filename)) { 2511 if (page_spec_cfis.contains(page_data.filename)) {
2539 cis = page_spec_cfis[page_data.filename]; 2512 cis = page_spec_cfis[page_data.filename];
libqpdf/qpdf/QPDFJob_private.hh
@@ -17,9 +17,21 @@ struct QPDFJob::Selection @@ -17,9 +17,21 @@ struct QPDFJob::Selection
17 { 17 {
18 } 18 }
19 19
  20 + Selection(QPDFJob::Selection const& other, int page) :
  21 + filename(other.filename),
  22 + // range and password are no longer required when this constructor is called.
  23 + qpdf(other.qpdf),
  24 + orig_pages(other.orig_pages),
  25 + selected_pages({page})
  26 + {
  27 + }
  28 +
20 std::string filename; 29 std::string filename;
21 std::string password; 30 std::string password;
22 std::string range; 31 std::string range;
  32 + QPDF* qpdf;
  33 + std::vector<QPDFObjectHandle> orig_pages;
  34 + std::vector<int> selected_pages;
23 }; 35 };
24 36
25 struct QPDFJob::RotationSpec 37 struct QPDFJob::RotationSpec
qpdf/qpdf.testcov
@@ -188,7 +188,6 @@ QPDF insert foreign page 0 @@ -188,7 +188,6 @@ QPDF insert foreign page 0
188 QPDFWriter copy use_aes 1 188 QPDFWriter copy use_aes 1
189 QPDFParser indirect without context 0 189 QPDFParser indirect without context 0
190 QPDFObjectHandle trailing data in parse 0 190 QPDFObjectHandle trailing data in parse 0
191 -QPDFJob pages encryption password 0  
192 QPDFTokenizer EOF reading token 0 191 QPDFTokenizer EOF reading token 0
193 QPDFTokenizer EOF reading appendable token 0 192 QPDFTokenizer EOF reading appendable token 0
194 QPDFWriter extra header text no newline 0 193 QPDFWriter extra header text no newline 0
@@ -286,8 +285,6 @@ QPDFAcroFormDocumentHelper non-dictionary field 0 @@ -286,8 +285,6 @@ QPDFAcroFormDocumentHelper non-dictionary field 0
286 QPDFAcroFormDocumentHelper loop 0 285 QPDFAcroFormDocumentHelper loop 0
287 QPDFAcroFormDocumentHelper field found 1 286 QPDFAcroFormDocumentHelper field found 1
288 QPDFAcroFormDocumentHelper annotation found 1 287 QPDFAcroFormDocumentHelper annotation found 1
289 -QPDFJob keep files open n 0  
290 -QPDFJob keep files open y 0  
291 QPDFJob automatically set keep files open 1 288 QPDFJob automatically set keep files open 1
292 QPDFOutlineDocumentHelper string named dest 0 289 QPDFOutlineDocumentHelper string named dest 0
293 QPDFObjectHandle merge top type mismatch 0 290 QPDFObjectHandle merge top type mismatch 0