Commit d90b400687b46b9e90083c3e22e9393b58e232d0

Authored by m-holger
1 parent 2c6a3e97

Refactor `QPDFJob::Selection` and `Inputs`: replace `Selection::filename` with `…

…input_entry`, centralize input file handling in `infile_name`, update `new_selection` logic, and simplify page range and input processing.
include/qpdf/QPDFJob.hh
... ... @@ -463,8 +463,6 @@ class QPDFJob
463 463 void setQPDFOptions(QPDF& pdf);
464 464 void handlePageSpecs(QPDF& pdf);
465 465 bool shouldRemoveUnreferencedResources(QPDF& pdf);
466   - void new_selection(
467   - std::string const& filename, std::string const& password, std::string const& range);
468 466 void handleRotations(QPDF& pdf);
469 467 void getUOPagenos(
470 468 std::vector<UnderOverlay>& uo, std::vector<std::map<size_t, std::vector<int>>>& pagenos);
... ...
libqpdf/QPDFJob.cc
... ... @@ -2347,10 +2347,25 @@ QPDFJob::Input::initialize(Inputs&amp; in, QPDF* a_qpdf)
2347 2347 }
2348 2348  
2349 2349 void
2350   -QPDFJob::Inputs::new_selection(
2351   - std::string const& filename, std::string const& password, std::string const& range)
  2350 +QPDFJob::Inputs::infile_name(std::string const& name)
2352 2351 {
2353   - selections.emplace_back(filename, password, range);
  2352 + if (!infile_name_.empty()) {
  2353 + usage("input file has already been given");
  2354 + }
  2355 + infile_name_ = name;
  2356 +
  2357 + auto& in_entry = *files.insert({name, Input()}).first;
  2358 + auto it = files.find("");
  2359 + if (it != files.end()) {
  2360 + // We allready have selection entries for the main input file. We need to fix them to point
  2361 + // to the correct files entry.
  2362 + for (auto& selection: selections) {
  2363 + if (selection.in_entry == &*it) {
  2364 + selection.in_entry = &in_entry;
  2365 + }
  2366 + }
  2367 + files.erase(it);
  2368 + }
2354 2369 }
2355 2370  
2356 2371 void
... ... @@ -2394,6 +2409,9 @@ QPDFJob::Inputs::process_all()
2394 2409 selection.process(*this);
2395 2410 }
2396 2411  
  2412 + if (!infile_name().empty()) {
  2413 + files.erase("");
  2414 + }
2397 2415 if (!keep_files_open_set) {
2398 2416 // Count the number of distinct files to determine whether we should keep files open or not.
2399 2417 // Rather than trying to code some portable heuristic based on OS limits, just hard-code
... ... @@ -2415,20 +2433,20 @@ QPDFJob::Inputs::process_all()
2415 2433 for (auto& selection: selections) {
2416 2434 // Read original pages from the PDF, and parse the page range associated with this
2417 2435 // occurrence of the file.
2418   - auto const& file_spec = files[selection.filename];
  2436 + auto const& input = selection.input();
2419 2437 if (selection.range.empty()) {
2420   - selection.selected_pages.reserve(static_cast<size_t>(file_spec.n_pages));
2421   - for (int i = 1; i <= file_spec.n_pages; ++i) {
  2438 + selection.selected_pages.reserve(static_cast<size_t>(input.n_pages));
  2439 + for (int i = 1; i <= input.n_pages; ++i) {
2422 2440 selection.selected_pages.push_back(i);
2423 2441 }
2424 2442 continue;
2425 2443 }
2426 2444 try {
2427 2445 selection.selected_pages =
2428   - QUtil::parse_numrange(selection.range.data(), files[selection.filename].n_pages);
  2446 + QUtil::parse_numrange(selection.range.data(), selection.input().n_pages);
2429 2447 } catch (std::runtime_error& e) {
2430 2448 throw std::runtime_error(
2431   - "parsing numeric range for " + selection.filename + ": " + e.what());
  2449 + "parsing numeric range for " + selection.filename() + ": " + e.what());
2432 2450 }
2433 2451 }
2434 2452 }
... ... @@ -2446,16 +2464,47 @@ QPDFJob::Inputs::clear()
2446 2464 return any_warnings;
2447 2465 }
2448 2466  
  2467 +QPDFJob::Selection&
  2468 +QPDFJob::Inputs::new_selection(std::string const& filename)
  2469 +{
  2470 + // Handle "." as a shortcut for the input file. Note that infile_name may not be known yet, in
  2471 + // which case we are wrongly entering an empty name. This will be corrected in the infile_name
  2472 + // setter.
  2473 + return selections.emplace_back(
  2474 + *files.insert({(filename == "." ? infile_name() : filename), Input()}).first);
  2475 +}
  2476 +
  2477 +void
  2478 +QPDFJob::Inputs::new_selection(
  2479 + std::string const& filename, std::string const& password, std::string const& range)
  2480 +{
  2481 + auto& selection = new_selection(filename);
  2482 + selection.password = password;
  2483 + selection.range = range;
  2484 +}
  2485 +
  2486 +QPDFJob::Selection::Selection(std::pair<const std::string, QPDFJob::Input>& entry) :
  2487 + in_entry(&entry)
  2488 +{
  2489 +}
  2490 +
  2491 +QPDFJob::Input&
  2492 +QPDFJob::Selection::input()
  2493 +{
  2494 + return in_entry->second;
  2495 +}
  2496 +
  2497 +std::string const&
  2498 +QPDFJob::Selection::filename()
  2499 +{
  2500 + return in_entry->first;
  2501 +}
  2502 +
2449 2503 void
2450 2504 QPDFJob::Selection::process(QPDFJob::Inputs& in)
2451 2505 {
2452   - // Handle "." as a shortcut for the input file.
2453   - if (filename == ".") {
2454   - filename = in.infile_name();
2455   - }
2456   - auto& input = in.files[filename];
2457 2506 if (!password.empty()) {
2458   - input.password = password;
  2507 + input().password = password;
2459 2508 }
2460 2509 }
2461 2510  
... ... @@ -2528,7 +2577,7 @@ QPDFJob::handlePageSpecs(QPDF&amp; pdf)
2528 2577 auto& this_afdh = pdf.acroform();
2529 2578 std::set<QPDFObjGen> referenced_fields;
2530 2579 for (auto& selection: new_specs.empty() ? m->inputs.selections : new_specs) {
2531   - auto& input = m->inputs.files[selection.filename];
  2580 + auto& input = selection.input();
2532 2581 if (input.cfis) {
2533 2582 input.cfis->stayOpen(true);
2534 2583 }
... ... @@ -2538,7 +2587,7 @@ QPDFJob::handlePageSpecs(QPDF&amp; pdf)
2538 2587 any_page_labels = true;
2539 2588 }
2540 2589 doIfVerbose([&](Pipeline& v, std::string const& prefix) {
2541   - v << prefix << ": adding pages from " << selection.filename << "\n";
  2590 + v << prefix << ": adding pages from " << selection.filename() << "\n";
2542 2591 });
2543 2592 for (auto pageno_iter: selection.selected_pages) {
2544 2593 // Pages are specified from 1 but numbered from 0 in the vector
... ...
libqpdf/QPDFJob_config.cc
... ... @@ -1001,7 +1001,7 @@ QPDFJob::PagesConfig::pageSpec(
1001 1001 QPDFJob::PagesConfig*
1002 1002 QPDFJob::PagesConfig::file(std::string const& arg)
1003 1003 {
1004   - config->o.m->inputs.new_selection(arg, {}, {});
  1004 + (void)config->o.m->inputs.new_selection(arg);
1005 1005 return this;
1006 1006 }
1007 1007  
... ...
libqpdf/qpdf/QPDFJob_private.hh
... ... @@ -10,25 +10,24 @@
10 10 // single clause in the --pages option.
11 11 struct QPDFJob::Selection
12 12 {
13   - Selection(std::string const& filename, std::string const& password, std::string const& range) :
14   - filename(filename),
15   - password(password),
16   - range(range)
17   - {
18   - }
  13 + Selection() = delete;
  14 +
  15 + Selection(std::pair<const std::string, QPDFJob::Input>& entry);
19 16  
20 17 Selection(QPDFJob::Selection const& other, int page) :
21   - filename(other.filename),
22   - // range and password are no longer required when this constructor is called.
  18 + in_entry(other.in_entry),
23 19 selected_pages({page})
24 20 {
25 21 }
26 22  
  23 + QPDFJob::Input& input();
  24 + std::string const& filename();
  25 +
27 26 void process(Inputs& in);
28 27  
29   - std::string filename;
  28 + std::pair<const std::string, QPDFJob::Input>* in_entry{nullptr};
30 29 std::string password;
31   - std::string range;
  30 + std::string range; // An empty range means all pages.
32 31 std::vector<int> selected_pages;
33 32 };
34 33  
... ... @@ -66,6 +65,8 @@ struct QPDFJob::Inputs
66 65 // Destroy all owned QPDF objects. Return false if any of the QPDF objects recorded warnings.
67 66 bool clear();
68 67  
  68 + Selection& new_selection(std::string const& filename);
  69 +
69 70 void new_selection(
70 71 std::string const& filename, std::string const& password, std::string const& range);
71 72  
... ... @@ -75,14 +76,7 @@ struct QPDFJob::Inputs
75 76 return infile_name_;
76 77 }
77 78  
78   - void
79   - infile_name(std::string const& name)
80   - {
81   - if (!infile_name_.empty()) {
82   - usage("input file has already been given");
83   - }
84   - infile_name_ = name;
85   - }
  79 + void infile_name(std::string const& name);
86 80  
87 81 std::string infile_name_;
88 82 std::string encryption_file;
... ...