Commit 980df238438bb616e9ab04eb76b96fc9117a2e04
1 parent
a000488d
Refactor `QPDFJob`: consolidate `QPDFPageData` into `Selection`, simplify page r…
…ange handling, and cleanup obsolete logic.
Showing
3 changed files
with
30 additions
and
48 deletions
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& pdf) | @@ -2411,7 +2380,6 @@ QPDFJob::handlePageSpecs(QPDF& 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& pdf) | @@ -2425,7 +2393,6 @@ QPDFJob::handlePageSpecs(QPDF& 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& pdf) | @@ -2434,13 +2401,11 @@ QPDFJob::handlePageSpecs(QPDF& 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& pdf) | @@ -2455,8 +2420,15 @@ QPDFJob::handlePageSpecs(QPDF& 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& pdf) | @@ -2491,16 +2463,17 @@ QPDFJob::handlePageSpecs(QPDF& 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& pdf) | @@ -2511,20 +2484,20 @@ QPDFJob::handlePageSpecs(QPDF& 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& pdf) | @@ -2533,7 +2506,7 @@ QPDFJob::handlePageSpecs(QPDF& 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 |