Commit 2f631997f2c21d13422f01f6fe1f2ec5ab1f7554

Authored by Jay Berkenbilt
1 parent 1ddf5b4b

QPDFJob increment: remove std::cout, std::cerr, whoami

Remove remaining temporary duplication of hard-coded values and direct
access to std::cout, std::cerr, and whoami in favor of parameters in
QPDFJob. This moves a few more static methods into QPDFJob member
functions.
include/qpdf/QPDFJob.hh
... ... @@ -50,7 +50,7 @@ class QPDFJob
50 50 void setMessagePrefix(std::string const&);
51 51  
52 52 // Override streams that errors and output go to. Defaults are
53   - // std::cout and std::cerr.
  53 + // std::cout and std::cerr. Pass nullptr to use the default.
54 54 QPDF_DLL
55 55 void setOutputStreams(std::ostream* out_stream, std::ostream* err_stream);
56 56  
... ... @@ -183,6 +183,11 @@ class QPDFJob
183 183 void doInspection(QPDF& pdf);
184 184 void showEncryption(QPDF& pdf);
185 185 void doCheck(QPDF& pdf);
  186 + void doShowObj(QPDF& pdf);
  187 + void doShowPages(QPDF& pdf);
  188 + void doListAttachments(QPDF& pdf);
  189 + void setEncryptionOptions(QPDF&, QPDFWriter&);
  190 + void maybeFixWritePassword(int R, std::string& password);
186 191  
187 192 enum remove_unref_e { re_auto, re_yes, re_no };
188 193  
... ... @@ -313,11 +318,11 @@ class QPDFJob
313 318 Members();
314 319 Members(Members const&) = delete;
315 320  
316   - std::string whoami;
  321 + std::string message_prefix;
317 322 bool warnings;
318 323 bool creates_output;
319   - std::ostream* out_stream;
320   - std::ostream* err_stream;
  324 + std::ostream* cout;
  325 + std::ostream* cerr;
321 326 unsigned long encryption_status;
322 327 };
323 328 PointerHolder<Members> m;
... ...
libqpdf/QPDFJob.cc
... ... @@ -34,10 +34,6 @@
34 34 #include <qpdf/QPDFWriter.hh>
35 35 #include <qpdf/QIntC.hh>
36 36  
37   -// QXXXQ temporary for compilation
38   -static char const* whoami = "qpdf";
39   -// /QXXXQ
40   -
41 37 namespace
42 38 {
43 39 class ImageOptimizer: public QPDFObjectHandle::StreamDataProvider
... ... @@ -68,7 +64,8 @@ namespace
68 64  
69 65 struct QPDFPageData
70 66 {
71   - QPDFPageData(std::string const& filename, QPDF* qpdf, char const* range);
  67 + QPDFPageData(std::string const& filename,
  68 + QPDF* qpdf, char const* range);
72 69 QPDFPageData(QPDFPageData const& other, int page);
73 70  
74 71 std::string filename;
... ... @@ -80,8 +77,11 @@ namespace
80 77 class ProgressReporter: public QPDFWriter::ProgressReporter
81 78 {
82 79 public:
83   - ProgressReporter(std::string const& whoami, char const* filename) :
84   - whoami(whoami),
  80 + ProgressReporter(std::ostream& cout,
  81 + std::string const& prefix,
  82 + char const* filename) :
  83 + cout(cout),
  84 + prefix(prefix),
85 85 filename(filename)
86 86 {
87 87 }
... ... @@ -91,7 +91,8 @@ namespace
91 91  
92 92 virtual void reportProgress(int);
93 93 private:
94   - std::string whoami;
  94 + std::ostream& cout;
  95 + std::string prefix;
95 96 std::string filename;
96 97 };
97 98 }
... ... @@ -127,17 +128,17 @@ QPDFPageData::QPDFPageData(QPDFPageData const&amp; other, int page) :
127 128 void
128 129 ProgressReporter::reportProgress(int percentage)
129 130 {
130   - std::cout << whoami << ": " << filename << ": write progress: "
131   - << percentage << "%" << std::endl;
  131 + this->cout << prefix << ": " << filename << ": write progress: "
  132 + << percentage << "%" << std::endl;
132 133 }
133 134  
134 135  
135 136 QPDFJob::Members::Members() :
136   - whoami("qpdf"),
  137 + message_prefix("qpdf"),
137 138 warnings(false),
138 139 creates_output(false),
139   - out_stream(&std::cout),
140   - err_stream(&std::cerr),
  140 + cout(&std::cout),
  141 + cerr(&std::cerr),
141 142 encryption_status(0)
142 143 {
143 144 }
... ... @@ -246,25 +247,25 @@ QPDFJob::QPDFJob() :
246 247 }
247 248  
248 249 void
249   -QPDFJob::setMessagePrefix(std::string const& whoami)
  250 +QPDFJob::setMessagePrefix(std::string const& message_prefix)
250 251 {
251   - this->m->whoami = whoami;
  252 + this->m->message_prefix = message_prefix;
252 253 }
253 254  
254 255 void
255 256 QPDFJob::setOutputStreams(std::ostream* out, std::ostream* err)
256 257 {
257   - this->m->out_stream = out ? out : &std::cout;
258   - this->m->err_stream = err ? err : &std::cerr;
  258 + this->m->cout = out ? out : &std::cout;
  259 + this->m->cerr = err ? err : &std::cerr;
259 260 }
260 261  
261 262 void
262 263 QPDFJob::doIfVerbose(
263 264 std::function<void(std::ostream&, std::string const& prefix)> fn)
264 265 {
265   - if (this->verbose && (this->m->out_stream != nullptr))
  266 + if (this->verbose && (this->m->cout != nullptr))
266 267 {
267   - fn(*(this->m->out_stream), this->m->whoami);
  268 + fn(*(this->m->cout), this->m->message_prefix);
268 269 }
269 270 }
270 271  
... ... @@ -344,57 +345,58 @@ QPDFJob::showEncryption(QPDF&amp; pdf)
344 345 QPDF::encryption_method_e stream_method = QPDF::e_unknown;
345 346 QPDF::encryption_method_e string_method = QPDF::e_unknown;
346 347 QPDF::encryption_method_e file_method = QPDF::e_unknown;
  348 + auto& cout = *this->m->cout;
347 349 if (! pdf.isEncrypted(R, P, V,
348 350 stream_method, string_method, file_method))
349 351 {
350   - std::cout << "File is not encrypted" << std::endl;
  352 + cout << "File is not encrypted" << std::endl;
351 353 }
352 354 else
353 355 {
354   - std::cout << "R = " << R << std::endl;
355   - std::cout << "P = " << P << std::endl;
  356 + cout << "R = " << R << std::endl;
  357 + cout << "P = " << P << std::endl;
356 358 std::string user_password = pdf.getTrimmedUserPassword();
357 359 std::string encryption_key = pdf.getEncryptionKey();
358   - std::cout << "User password = " << user_password << std::endl;
  360 + cout << "User password = " << user_password << std::endl;
359 361 if (o.show_encryption_key)
360 362 {
361   - std::cout << "Encryption key = "
362   - << QUtil::hex_encode(encryption_key) << std::endl;
  363 + cout << "Encryption key = "
  364 + << QUtil::hex_encode(encryption_key) << std::endl;
363 365 }
364 366 if (pdf.ownerPasswordMatched())
365 367 {
366   - std::cout << "Supplied password is owner password" << std::endl;
  368 + cout << "Supplied password is owner password" << std::endl;
367 369 }
368 370 if (pdf.userPasswordMatched())
369 371 {
370   - std::cout << "Supplied password is user password" << std::endl;
371   - }
372   - std::cout << "extract for accessibility: "
373   - << show_bool(pdf.allowAccessibility()) << std::endl
374   - << "extract for any purpose: "
375   - << show_bool(pdf.allowExtractAll()) << std::endl
376   - << "print low resolution: "
377   - << show_bool(pdf.allowPrintLowRes()) << std::endl
378   - << "print high resolution: "
379   - << show_bool(pdf.allowPrintHighRes()) << std::endl
380   - << "modify document assembly: "
381   - << show_bool(pdf.allowModifyAssembly()) << std::endl
382   - << "modify forms: "
383   - << show_bool(pdf.allowModifyForm()) << std::endl
384   - << "modify annotations: "
385   - << show_bool(pdf.allowModifyAnnotation()) << std::endl
386   - << "modify other: "
387   - << show_bool(pdf.allowModifyOther()) << std::endl
388   - << "modify anything: "
389   - << show_bool(pdf.allowModifyAll()) << std::endl;
  372 + cout << "Supplied password is user password" << std::endl;
  373 + }
  374 + cout << "extract for accessibility: "
  375 + << show_bool(pdf.allowAccessibility()) << std::endl
  376 + << "extract for any purpose: "
  377 + << show_bool(pdf.allowExtractAll()) << std::endl
  378 + << "print low resolution: "
  379 + << show_bool(pdf.allowPrintLowRes()) << std::endl
  380 + << "print high resolution: "
  381 + << show_bool(pdf.allowPrintHighRes()) << std::endl
  382 + << "modify document assembly: "
  383 + << show_bool(pdf.allowModifyAssembly()) << std::endl
  384 + << "modify forms: "
  385 + << show_bool(pdf.allowModifyForm()) << std::endl
  386 + << "modify annotations: "
  387 + << show_bool(pdf.allowModifyAnnotation()) << std::endl
  388 + << "modify other: "
  389 + << show_bool(pdf.allowModifyOther()) << std::endl
  390 + << "modify anything: "
  391 + << show_bool(pdf.allowModifyAll()) << std::endl;
390 392 if (V >= 4)
391 393 {
392   - std::cout << "stream encryption method: "
393   - << show_encryption_method(stream_method) << std::endl
394   - << "string encryption method: "
395   - << show_encryption_method(string_method) << std::endl
396   - << "file encryption method: "
397   - << show_encryption_method(file_method) << std::endl;
  394 + cout << "stream encryption method: "
  395 + << show_encryption_method(stream_method) << std::endl
  396 + << "string encryption method: "
  397 + << show_encryption_method(string_method) << std::endl
  398 + << "file encryption method: "
  399 + << show_encryption_method(file_method) << std::endl;
398 400 }
399 401 }
400 402 }
... ... @@ -409,21 +411,21 @@ QPDFJob::doCheck(QPDF&amp; pdf)
409 411 // errors.
410 412 bool okay = true;
411 413 bool warnings = false;
412   - std::cout << "checking " << o.infilename << std::endl;
  414 + auto& cout = *this->m->cout;
  415 + cout << "checking " << o.infilename << std::endl;
413 416 try
414 417 {
415 418 int extension_level = pdf.getExtensionLevel();
416   - std::cout << "PDF Version: " << pdf.getPDFVersion();
  419 + cout << "PDF Version: " << pdf.getPDFVersion();
417 420 if (extension_level > 0)
418 421 {
419   - std::cout << " extension level "
420   - << pdf.getExtensionLevel();
  422 + cout << " extension level " << pdf.getExtensionLevel();
421 423 }
422   - std::cout << std::endl;
  424 + cout << std::endl;
423 425 showEncryption(pdf);
424 426 if (pdf.isLinearized())
425 427 {
426   - std::cout << "File is linearized\n";
  428 + cout << "File is linearized\n";
427 429 // any errors or warnings are reported by
428 430 // checkLinearization(). We treat all issues reported here
429 431 // as warnings.
... ... @@ -434,7 +436,7 @@ QPDFJob::doCheck(QPDF&amp; pdf)
434 436 }
435 437 else
436 438 {
437   - std::cout << "File is not linearized\n";
  439 + cout << "File is not linearized\n";
438 440 }
439 441  
440 442 // Write the file no nowhere, uncompressing
... ... @@ -464,7 +466,7 @@ QPDFJob::doCheck(QPDF&amp; pdf)
464 466 catch (QPDFExc& e)
465 467 {
466 468 okay = false;
467   - *(this->m->err_stream)
  469 + *(this->m->cerr)
468 470 << "ERROR: page " << pageno << ": "
469 471 << e.what() << std::endl;
470 472 }
... ... @@ -472,7 +474,7 @@ QPDFJob::doCheck(QPDF&amp; pdf)
472 474 }
473 475 catch (std::exception& e)
474 476 {
475   - std::cerr << "ERROR: " << e.what() << std::endl;
  477 + (*this->m->cerr) << "ERROR: " << e.what() << std::endl;
476 478 okay = false;
477 479 }
478 480 if (! okay)
... ... @@ -486,7 +488,7 @@ QPDFJob::doCheck(QPDF&amp; pdf)
486 488 }
487 489 else
488 490 {
489   - *(this->m->out_stream)
  491 + *(this->m->cout)
490 492 << "No syntax or stream encoding errors"
491 493 << " found; the file may still contain"
492 494 << std::endl
... ... @@ -495,8 +497,10 @@ QPDFJob::doCheck(QPDF&amp; pdf)
495 497 }
496 498 }
497 499  
498   -static void do_show_obj(QPDF& pdf, QPDFJob& o)
  500 +void
  501 +QPDFJob::doShowObj(QPDF& pdf)
499 502 {
  503 + QPDFJob& o = *this; // QXXXQ
500 504 QPDFObjectHandle obj;
501 505 if (o.show_trailer)
502 506 {
... ... @@ -531,14 +535,14 @@ static void do_show_obj(QPDF&amp; pdf, QPDFJob&amp; o)
531 535 }
532 536 else
533 537 {
534   - std::cout
  538 + *(this->m->cout)
535 539 << "Object is stream. Dictionary:" << std::endl
536 540 << obj.getDict().unparseResolved() << std::endl;
537 541 }
538 542 }
539 543 else
540 544 {
541   - std::cout << obj.unparseResolved() << std::endl;
  545 + *(this->m->cout) << obj.unparseResolved() << std::endl;
542 546 }
543 547 if (error)
544 548 {
... ... @@ -547,11 +551,14 @@ static void do_show_obj(QPDF&amp; pdf, QPDFJob&amp; o)
547 551 }
548 552 }
549 553  
550   -static void do_show_pages(QPDF& pdf, QPDFJob& o)
  554 +void
  555 +QPDFJob::doShowPages(QPDF& pdf)
551 556 {
  557 + QPDFJob& o = *this; // QXXXQ
552 558 QPDFPageDocumentHelper dh(pdf);
553 559 std::vector<QPDFPageObjectHelper> pages = dh.getAllPages();
554 560 int pageno = 0;
  561 + auto& cout = *this->m->cout;
555 562 for (std::vector<QPDFPageObjectHelper>::iterator iter = pages.begin();
556 563 iter != pages.end(); ++iter)
557 564 {
... ... @@ -559,15 +566,15 @@ static void do_show_pages(QPDF&amp; pdf, QPDFJob&amp; o)
559 566 QPDFObjectHandle page = ph.getObjectHandle();
560 567 ++pageno;
561 568  
562   - std::cout << "page " << pageno << ": "
563   - << page.getObjectID() << " "
564   - << page.getGeneration() << " R" << std::endl;
  569 + cout << "page " << pageno << ": "
  570 + << page.getObjectID() << " "
  571 + << page.getGeneration() << " R" << std::endl;
565 572 if (o.show_page_images)
566 573 {
567 574 std::map<std::string, QPDFObjectHandle> images = ph.getImages();
568 575 if (! images.empty())
569 576 {
570   - std::cout << " images:" << std::endl;
  577 + cout << " images:" << std::endl;
571 578 for (auto const& iter2: images)
572 579 {
573 580 std::string const& name = iter2.first;
... ... @@ -577,26 +584,28 @@ static void do_show_pages(QPDF&amp; pdf, QPDFJob&amp; o)
577 584 dict.getKey("/Width").getIntValueAsInt();
578 585 int height =
579 586 dict.getKey("/Height").getIntValueAsInt();
580   - std::cout << " " << name << ": "
581   - << image.unparse()
582   - << ", " << width << " x " << height
583   - << std::endl;
  587 + cout << " " << name << ": "
  588 + << image.unparse()
  589 + << ", " << width << " x " << height
  590 + << std::endl;
584 591 }
585 592 }
586 593 }
587 594  
588   - std::cout << " content:" << std::endl;
  595 + cout << " content:" << std::endl;
589 596 std::vector<QPDFObjectHandle> content =
590 597 ph.getPageContents();
591 598 for (auto& iter2: content)
592 599 {
593   - std::cout << " " << iter2.unparse() << std::endl;
  600 + cout << " " << iter2.unparse() << std::endl;
594 601 }
595 602 }
596 603 }
597 604  
598   -static void do_list_attachments(QPDF& pdf, QPDFJob& o)
  605 +void
  606 +QPDFJob::doListAttachments(QPDF& pdf)
599 607 {
  608 + QPDFJob& o = *this; // QXXXQ
600 609 QPDFEmbeddedFileDocumentHelper efdh(pdf);
601 610 if (efdh.hasEmbeddedFiles())
602 611 {
... ... @@ -604,10 +613,11 @@ static void do_list_attachments(QPDF&amp; pdf, QPDFJob&amp; o)
604 613 {
605 614 std::string const& key = i.first;
606 615 auto efoh = i.second;
607   - std::cout << key << " -> "
608   - << efoh->getEmbeddedFileStream().getObjGen()
609   - << std::endl;
610   - o.doIfVerbose([&](std::ostream& cout, std::string const& whoami) {
  616 + *(this->m->cout)
  617 + << key << " -> "
  618 + << efoh->getEmbeddedFileStream().getObjGen()
  619 + << std::endl;
  620 + o.doIfVerbose([&](std::ostream& cout, std::string const& prefix) {
611 621 auto desc = efoh->getDescription();
612 622 if (! desc.empty())
613 623 {
... ... @@ -633,7 +643,8 @@ static void do_list_attachments(QPDF&amp; pdf, QPDFJob&amp; o)
633 643 }
634 644 else
635 645 {
636   - std::cout << o.infilename << " has no embedded files" << std::endl;
  646 + *(this->m->cout)
  647 + << o.infilename << " has no embedded files" << std::endl;
637 648 }
638 649 }
639 650  
... ... @@ -1554,7 +1565,7 @@ QPDFJob::doJSON(QPDF&amp; pdf)
1554 1565 std::list<std::string> errors;
1555 1566 if (! j.checkSchema(schema, errors))
1556 1567 {
1557   - *(this->m->err_stream)
  1568 + *(this->m->cerr)
1558 1569 << "QPDFJob didn't create JSON that complies with its own rules.\n\
1559 1570 Please report this as a bug at\n\
1560 1571 https://github.com/qpdf/qpdf/issues/new\n\
... ... @@ -1563,11 +1574,11 @@ ideally with the file that caused the error and the output below. Thanks!\n\
1563 1574 for (std::list<std::string>::iterator iter = errors.begin();
1564 1575 iter != errors.end(); ++iter)
1565 1576 {
1566   - std::cerr << (*iter) << std::endl;
  1577 + *(this->m->cerr) << (*iter) << std::endl;
1567 1578 }
1568 1579 }
1569 1580  
1570   - std::cout << j.unparse() << std::endl;
  1581 + *(this->m->cout) << j.unparse() << std::endl;
1571 1582 }
1572 1583  
1573 1584 void
... ... @@ -1585,7 +1596,7 @@ QPDFJob::doInspection(QPDF&amp; pdf)
1585 1596 if (o.show_npages)
1586 1597 {
1587 1598 QTC::TC("qpdf", "qpdf npages");
1588   - std::cout << pdf.getRoot().getKey("/Pages").
  1599 + *(this->m->cout) << pdf.getRoot().getKey("/Pages").
1589 1600 getKey("/Count").getIntValue() << std::endl;
1590 1601 }
1591 1602 if (o.show_encryption)
... ... @@ -1596,8 +1607,8 @@ QPDFJob::doInspection(QPDF&amp; pdf)
1596 1607 {
1597 1608 if (pdf.checkLinearization())
1598 1609 {
1599   - std::cout << o.infilename << ": no linearization errors"
1600   - << std::endl;
  1610 + *(this->m->cout)
  1611 + << o.infilename << ": no linearization errors" << std::endl;
1601 1612 }
1602 1613 else
1603 1614 {
... ... @@ -1612,8 +1623,8 @@ QPDFJob::doInspection(QPDF&amp; pdf)
1612 1623 }
1613 1624 else
1614 1625 {
1615   - std::cout << o.infilename << " is not linearized"
1616   - << std::endl;
  1626 + *(this->m->cout)
  1627 + << o.infilename << " is not linearized" << std::endl;
1617 1628 }
1618 1629 }
1619 1630 if (o.show_xref)
... ... @@ -1622,15 +1633,15 @@ QPDFJob::doInspection(QPDF&amp; pdf)
1622 1633 }
1623 1634 if ((o.show_obj > 0) || o.show_trailer)
1624 1635 {
1625   - do_show_obj(pdf, o);
  1636 + doShowObj(pdf);
1626 1637 }
1627 1638 if (o.show_pages)
1628 1639 {
1629   - do_show_pages(pdf, o);
  1640 + doShowPages(pdf);
1630 1641 }
1631 1642 if (o.list_attachments)
1632 1643 {
1633   - do_list_attachments(pdf, o);
  1644 + doListAttachments(pdf);
1634 1645 }
1635 1646 if (! o.attachment_to_show.empty())
1636 1647 {
... ... @@ -1661,8 +1672,8 @@ ImageOptimizer::makePipeline(std::string const&amp; description, Pipeline* next)
1661 1672 {
1662 1673 if (! description.empty())
1663 1674 {
1664   - o.doIfVerbose([&](std::ostream& cout, std::string const& whoami) {
1665   - cout << whoami << ": " << description
  1675 + o.doIfVerbose([&](std::ostream& cout, std::string const& prefix) {
  1676 + cout << prefix << ": " << description
1666 1677 << ": not optimizing because image dictionary"
1667 1678 << " is missing required keys" << std::endl;
1668 1679 });
... ... @@ -1675,8 +1686,8 @@ ImageOptimizer::makePipeline(std::string const&amp; description, Pipeline* next)
1675 1686 QTC::TC("qpdf", "qpdf image optimize bits per component");
1676 1687 if (! description.empty())
1677 1688 {
1678   - o.doIfVerbose([&](std::ostream& cout, std::string const& whoami) {
1679   - cout << whoami << ": " << description
  1689 + o.doIfVerbose([&](std::ostream& cout, std::string const& prefix) {
  1690 + cout << prefix << ": " << description
1680 1691 << ": not optimizing because image has other than"
1681 1692 << " 8 bits per component" << std::endl;
1682 1693 });
... ... @@ -1728,8 +1739,8 @@ ImageOptimizer::makePipeline(std::string const&amp; description, Pipeline* next)
1728 1739 QTC::TC("qpdf", "qpdf image optimize colorspace");
1729 1740 if (! description.empty())
1730 1741 {
1731   - o.doIfVerbose([&](std::ostream& cout, std::string const& whoami) {
1732   - cout << whoami << ": " << description
  1742 + o.doIfVerbose([&](std::ostream& cout, std::string const& prefix) {
  1743 + cout << prefix << ": " << description
1733 1744 << ": not optimizing because qpdf can't optimize"
1734 1745 << " images with this colorspace" << std::endl;
1735 1746 });
... ... @@ -1743,8 +1754,8 @@ ImageOptimizer::makePipeline(std::string const&amp; description, Pipeline* next)
1743 1754 QTC::TC("qpdf", "qpdf image optimize too small");
1744 1755 if (! description.empty())
1745 1756 {
1746   - o.doIfVerbose([&](std::ostream& cout, std::string const& whoami) {
1747   - cout << whoami << ": " << description
  1757 + o.doIfVerbose([&](std::ostream& cout, std::string const& prefix) {
  1758 + cout << prefix << ": " << description
1748 1759 << ": not optimizing because image"
1749 1760 << " is smaller than requested minimum dimensions"
1750 1761 << std::endl;
... ... @@ -1763,8 +1774,8 @@ ImageOptimizer::evaluate(std::string const&amp; description)
1763 1774 if (! image.pipeStreamData(0, 0, qpdf_dl_specialized, true))
1764 1775 {
1765 1776 QTC::TC("qpdf", "qpdf image optimize no pipeline");
1766   - o.doIfVerbose([&](std::ostream& cout, std::string const& whoami) {
1767   - cout << whoami << ": " << description
  1777 + o.doIfVerbose([&](std::ostream& cout, std::string const& prefix) {
  1778 + cout << prefix << ": " << description
1768 1779 << ": not optimizing because unable to decode data"
1769 1780 << " or data already uses DCT"
1770 1781 << std::endl;
... ... @@ -1787,15 +1798,15 @@ ImageOptimizer::evaluate(std::string const&amp; description)
1787 1798 if (c.getCount() >= orig_length)
1788 1799 {
1789 1800 QTC::TC("qpdf", "qpdf image optimize no shrink");
1790   - o.doIfVerbose([&](std::ostream& cout, std::string const& whoami) {
1791   - cout << whoami << ": " << description
  1801 + o.doIfVerbose([&](std::ostream& cout, std::string const& prefix) {
  1802 + cout << prefix << ": " << description
1792 1803 << ": not optimizing because DCT compression does not"
1793 1804 << " reduce image size" << std::endl;
1794 1805 });
1795 1806 return false;
1796 1807 }
1797   - o.doIfVerbose([&](std::ostream& cout, std::string const& whoami) {
1798   - cout << whoami << ": " << description
  1808 + o.doIfVerbose([&](std::ostream& cout, std::string const& prefix) {
  1809 + cout << prefix << ": " << description
1799 1810 << ": optimizing image reduces size from "
1800 1811 << orig_length << " to " << c.getCount()
1801 1812 << std::endl;
... ... @@ -1919,8 +1930,8 @@ static PointerHolder&lt;QPDF&gt; do_process(
1919 1930 if (! warned)
1920 1931 {
1921 1932 warned = true;
1922   - o.doIfVerbose([&](std::ostream& cout, std::string const& whoami) {
1923   - cout << whoami << ": supplied password didn't work;"
  1933 + o.doIfVerbose([&](std::ostream& cout, std::string const& prefix) {
  1934 + cout << prefix << ": supplied password didn't work;"
1924 1935 << " trying other passwords based on interpreting"
1925 1936 << " password with different string encodings"
1926 1937 << std::endl;
... ... @@ -2061,7 +2072,7 @@ static void do_under_overlay_for_page(
2061 2072 iter != pagenos[pageno].end(); ++iter)
2062 2073 {
2063 2074 int from_pageno = *iter;
2064   - o.doIfVerbose([&](std::ostream& cout, std::string const& whoami) {
  2075 + o.doIfVerbose([&](std::ostream& cout, std::string const& prefix) {
2065 2076 cout << " " << uo.which << " " << from_pageno << std::endl;
2066 2077 });
2067 2078 auto from_page = pages.at(QIntC::to_size(from_pageno - 1));
... ... @@ -2144,12 +2155,12 @@ QPDFJob::handleUnderOverlay(QPDF&amp; pdf)
2144 2155 QPDFPageDocumentHelper main_pdh(pdf);
2145 2156 std::vector<QPDFPageObjectHelper> main_pages = main_pdh.getAllPages();
2146 2157 size_t main_npages = main_pages.size();
2147   - o.doIfVerbose([&](std::ostream& cout, std::string const& whoami) {
2148   - cout << whoami << ": processing underlay/overlay" << std::endl;
  2158 + o.doIfVerbose([&](std::ostream& cout, std::string const& prefix) {
  2159 + cout << prefix << ": processing underlay/overlay" << std::endl;
2149 2160 });
2150 2161 for (size_t i = 0; i < main_npages; ++i)
2151 2162 {
2152   - o.doIfVerbose([&](std::ostream& cout, std::string const& whoami) {
  2163 + o.doIfVerbose([&](std::ostream& cout, std::string const& prefix) {
2153 2164 cout << " page " << 1+i << std::endl;
2154 2165 });
2155 2166 do_under_overlay_for_page(pdf, o, o.underlay, underlay_pagenos, i,
... ... @@ -2200,8 +2211,8 @@ QPDFJob::addAttachments(QPDF&amp; pdf)
2200 2211 }
2201 2212  
2202 2213 efdh.replaceEmbeddedFile(to_add.key, fs);
2203   - o.doIfVerbose([&](std::ostream& cout, std::string const& whoami) {
2204   - cout << whoami << ": attached " << to_add.path
  2214 + o.doIfVerbose([&](std::ostream& cout, std::string const& prefix) {
  2215 + cout << prefix << ": attached " << to_add.path
2205 2216 << " as " << to_add.filename
2206 2217 << " with key " << to_add.key << std::endl;
2207 2218 });
... ... @@ -2235,8 +2246,8 @@ QPDFJob::copyAttachments(QPDF&amp; pdf)
2235 2246 std::vector<std::string> duplicates;
2236 2247 for (auto const& to_copy: o.attachments_to_copy)
2237 2248 {
2238   - o.doIfVerbose([&](std::ostream& cout, std::string const& whoami) {
2239   - cout << whoami << ": copying attachments from "
  2249 + o.doIfVerbose([&](std::ostream& cout, std::string const& prefix) {
  2250 + cout << prefix << ": copying attachments from "
2240 2251 << to_copy.path << std::endl;
2241 2252 });
2242 2253 auto other = processFile(
... ... @@ -2258,7 +2269,7 @@ QPDFJob::copyAttachments(QPDF&amp; pdf)
2258 2269 efdh.replaceEmbeddedFile(
2259 2270 new_key, QPDFFileSpecObjectHelper(new_fs_oh));
2260 2271 o.doIfVerbose([&](std::ostream& cout,
2261   - std::string const& whoami) {
  2272 + std::string const& prefix) {
2262 2273 cout << " " << iter.first << " -> " << new_key
2263 2274 << std::endl;
2264 2275 });
... ... @@ -2386,8 +2397,8 @@ QPDFJob::handleTransformations(QPDF&amp; pdf)
2386 2397 if (efdh.removeEmbeddedFile(key))
2387 2398 {
2388 2399 o.doIfVerbose([&](std::ostream& cout,
2389   - std::string const& whoami) {
2390   - cout << whoami <<
  2400 + std::string const& prefix) {
  2401 + cout << prefix <<
2391 2402 ": removed attachment " << key << std::endl;
2392 2403 });
2393 2404 }
... ... @@ -2431,8 +2442,8 @@ static bool should_remove_unreferenced_resources(QPDF&amp; pdf, QPDFJob&amp; o)
2431 2442 std::set<QPDFObjGen> resources_seen; // shared resources detection
2432 2443 std::set<QPDFObjGen> nodes_seen; // loop detection
2433 2444  
2434   - o.doIfVerbose([&](std::ostream& cout, std::string const& whoami) {
2435   - cout << whoami << ": " << pdf.getFilename()
  2445 + o.doIfVerbose([&](std::ostream& cout, std::string const& prefix) {
  2446 + cout << prefix << ": " << pdf.getFilename()
2436 2447 << ": checking for shared resources" << std::endl;
2437 2448 });
2438 2449  
... ... @@ -2457,7 +2468,7 @@ static bool should_remove_unreferenced_resources(QPDF&amp; pdf, QPDFJob&amp; o)
2457 2468 {
2458 2469 QTC::TC("qpdf", "qpdf found resources in non-leaf");
2459 2470 o.doIfVerbose([&](std::ostream& cout,
2460   - std::string const& whoami) {
  2471 + std::string const& prefix) {
2461 2472 cout << " found resources in non-leaf page node "
2462 2473 << og.getObj() << " " << og.getGen()
2463 2474 << std::endl;
... ... @@ -2481,7 +2492,7 @@ static bool should_remove_unreferenced_resources(QPDF&amp; pdf, QPDFJob&amp; o)
2481 2492 {
2482 2493 QTC::TC("qpdf", "qpdf found shared resources in leaf");
2483 2494 o.doIfVerbose([&](std::ostream& cout,
2484   - std::string const& whoami) {
  2495 + std::string const& prefix) {
2485 2496 cout << " found shared resources in leaf node "
2486 2497 << og.getObj() << " " << og.getGen()
2487 2498 << ": "
... ... @@ -2503,7 +2514,7 @@ static bool should_remove_unreferenced_resources(QPDF&amp; pdf, QPDFJob&amp; o)
2503 2514 {
2504 2515 QTC::TC("qpdf", "qpdf found shared xobject in leaf");
2505 2516 o.doIfVerbose([&](std::ostream& cout,
2506   - std::string const& whoami) {
  2517 + std::string const& prefix) {
2507 2518 cout << " found shared xobject in leaf node "
2508 2519 << og.getObj() << " " << og.getGen()
2509 2520 << ": "
... ... @@ -2535,8 +2546,8 @@ static bool should_remove_unreferenced_resources(QPDF&amp; pdf, QPDFJob&amp; o)
2535 2546 }
2536 2547 }
2537 2548  
2538   - o.doIfVerbose([&](std::ostream& cout, std::string const& whoami) {
2539   - cout << whoami << ": no shared resources found" << std::endl;
  2549 + o.doIfVerbose([&](std::ostream& cout, std::string const& prefix) {
  2550 + cout << prefix << ": no shared resources found" << std::endl;
2540 2551 });
2541 2552 return false;
2542 2553 }
... ... @@ -2583,25 +2594,23 @@ static void handle_page_specs(
2583 2594 // some portable heuristic based on OS limits, just hard-code
2584 2595 // this at a given number and allow users to override.
2585 2596 std::set<std::string> filenames;
2586   - for (std::vector<QPDFJob::PageSpec>::iterator iter = o.page_specs.begin();
2587   - iter != o.page_specs.end(); ++iter)
  2597 + for (auto& page_spec: o.page_specs)
2588 2598 {
2589   - QPDFJob::PageSpec& page_spec = *iter;
2590 2599 filenames.insert(page_spec.filename);
2591 2600 }
2592 2601 if (filenames.size() > o.keep_files_open_threshold)
2593 2602 {
2594 2603 QTC::TC("qpdf", "qpdf disable keep files open");
2595   - o.doIfVerbose([&](std::ostream& cout, std::string const& whoami) {
2596   - cout << whoami << ": selecting --keep-open-files=n"
  2604 + o.doIfVerbose([&](std::ostream& cout, std::string const& prefix) {
  2605 + cout << prefix << ": selecting --keep-open-files=n"
2597 2606 << std::endl;
2598 2607 });
2599 2608 o.keep_files_open = false;
2600 2609 }
2601 2610 else
2602 2611 {
2603   - o.doIfVerbose([&](std::ostream& cout, std::string const& whoami) {
2604   - cout << whoami << ": selecting --keep-open-files=y"
  2612 + o.doIfVerbose([&](std::ostream& cout, std::string const& prefix) {
  2613 + cout << prefix << ": selecting --keep-open-files=y"
2605 2614 << std::endl;
2606 2615 });
2607 2616 o.keep_files_open = true;
... ... @@ -2638,8 +2647,8 @@ static void handle_page_specs(
2638 2647 QTC::TC("qpdf", "qpdf pages encryption password");
2639 2648 password = o.encryption_file_password;
2640 2649 }
2641   - o.doIfVerbose([&](std::ostream& cout, std::string const& whoami) {
2642   - cout << whoami << ": processing "
  2650 + o.doIfVerbose([&](std::ostream& cout, std::string const& prefix) {
  2651 + cout << prefix << ": processing "
2643 2652 << page_spec.filename << std::endl;
2644 2653 });
2645 2654 PointerHolder<InputSource> is;
... ... @@ -2709,8 +2718,8 @@ static void handle_page_specs(
2709 2718 // without changing their object numbers. This enables other
2710 2719 // things in the original file, such as outlines, to continue to
2711 2720 // work.
2712   - o.doIfVerbose([&](std::ostream& cout, std::string const& whoami) {
2713   - cout << whoami
  2721 + o.doIfVerbose([&](std::ostream& cout, std::string const& prefix) {
  2722 + cout << prefix
2714 2723 << ": removing unreferenced pages from primary input"
2715 2724 << std::endl;
2716 2725 });
... ... @@ -2783,8 +2792,8 @@ static void handle_page_specs(
2783 2792 {
2784 2793 any_page_labels = true;
2785 2794 }
2786   - o.doIfVerbose([&](std::ostream& cout, std::string const& whoami) {
2787   - cout << whoami << ": adding pages from "
  2795 + o.doIfVerbose([&](std::ostream& cout, std::string const& prefix) {
  2796 + cout << prefix << ": adding pages from "
2788 2797 << page_data.filename << std::endl;
2789 2798 });
2790 2799 for (std::vector<int>::iterator pageno_iter =
... ... @@ -2963,8 +2972,10 @@ static void handle_rotations(QPDF&amp; pdf, QPDFJob&amp; o)
2963 2972 }
2964 2973 }
2965 2974  
2966   -static void maybe_fix_write_password(int R, QPDFJob& o, std::string& password)
  2975 +void
  2976 +QPDFJob::maybeFixWritePassword(int R, std::string& password)
2967 2977 {
  2978 + QPDFJob& o = *this; // QXXXQ
2968 2979 switch (o.password_mode)
2969 2980 {
2970 2981 case QPDFJob::pm_bytes:
... ... @@ -3020,9 +3031,9 @@ static void maybe_fix_write_password(int R, QPDFJob&amp; o, std::string&amp; password)
3020 3031 {
3021 3032 QTC::TC("qpdf", "qpdf auto-encode password");
3022 3033 o.doIfVerbose([&](std::ostream& cout,
3023   - std::string const& whoami) {
  3034 + std::string const& prefix) {
3024 3035 cout
3025   - << whoami
  3036 + << prefix
3026 3037 << ": automatically converting Unicode"
3027 3038 << " password to single-byte encoding as"
3028 3039 << " required for 40-bit or 128-bit"
... ... @@ -3033,8 +3044,8 @@ static void maybe_fix_write_password(int R, QPDFJob&amp; o, std::string&amp; password)
3033 3044 else
3034 3045 {
3035 3046 QTC::TC("qpdf", "qpdf bytes fallback warning");
3036   - std::cerr
3037   - << whoami << ": WARNING: "
  3047 + *(this->m->cerr)
  3048 + << this->m->message_prefix << ": WARNING: "
3038 3049 << "supplied password looks like a Unicode"
3039 3050 << " password with characters not allowed in"
3040 3051 << " passwords for 40-bit and 128-bit encryption;"
... ... @@ -3060,8 +3071,10 @@ static void maybe_fix_write_password(int R, QPDFJob&amp; o, std::string&amp; password)
3060 3071 }
3061 3072 }
3062 3073  
3063   -static void set_encryption_options(QPDF& pdf, QPDFJob& o, QPDFWriter& w)
  3074 +void
  3075 +QPDFJob::setEncryptionOptions(QPDF& pdf, QPDFWriter& w)
3064 3076 {
  3077 + QPDFJob& o = *this; // QXXXQ
3065 3078 int R = 0;
3066 3079 if (o.keylen == 40)
3067 3080 {
... ... @@ -3095,12 +3108,13 @@ static void set_encryption_options(QPDF&amp; pdf, QPDFJob&amp; o, QPDFWriter&amp; w)
3095 3108 }
3096 3109 if ((R > 3) && (o.r3_accessibility == false))
3097 3110 {
3098   - std::cerr << whoami
3099   - << ": -accessibility=n is ignored for modern"
3100   - << " encryption formats" << std::endl;
  3111 + *(this->m->cerr)
  3112 + << this->m->message_prefix
  3113 + << ": -accessibility=n is ignored for modern"
  3114 + << " encryption formats" << std::endl;
3101 3115 }
3102   - maybe_fix_write_password(R, o, o.user_password);
3103   - maybe_fix_write_password(R, o, o.owner_password);
  3116 + maybeFixWritePassword(R, o.user_password);
  3117 + maybeFixWritePassword(R, o.owner_password);
3104 3118 if ((R < 4) || ((R == 4) && (! o.use_aes)))
3105 3119 {
3106 3120 if (! o.allow_weak_crypto)
... ... @@ -3108,8 +3122,8 @@ static void set_encryption_options(QPDF&amp; pdf, QPDFJob&amp; o, QPDFWriter&amp; w)
3108 3122 // Do not set warnings = true for this case as this does
3109 3123 // not reflect a potential problem with the input file.
3110 3124 QTC::TC("qpdf", "qpdf weak crypto warning");
3111   - std::cerr
3112   - << whoami
  3125 + *(this->m->cerr)
  3126 + << this->m->message_prefix
3113 3127 << ": writing a file with RC4, a weak cryptographic algorithm"
3114 3128 << std::endl
3115 3129 << "Please use 256-bit keys for better security."
... ... @@ -3233,7 +3247,7 @@ QPDFJob::setWriterOptions(QPDF&amp; pdf, QPDFWriter&amp; w)
3233 3247 }
3234 3248 if (o.encrypt)
3235 3249 {
3236   - set_encryption_options(pdf, o, w);
  3250 + setEncryptionOptions(pdf, w);
3237 3251 }
3238 3252 if (o.linearize)
3239 3253 {
... ... @@ -3264,7 +3278,8 @@ QPDFJob::setWriterOptions(QPDF&amp; pdf, QPDFWriter&amp; w)
3264 3278 if (o.progress && o.outfilename)
3265 3279 {
3266 3280 w.registerProgressReporter(
3267   - new ProgressReporter(this->m->whoami, o.outfilename));
  3281 + new ProgressReporter(
  3282 + *(this->m->cout), this->m->message_prefix, o.outfilename));
3268 3283 }
3269 3284 }
3270 3285  
... ... @@ -3378,8 +3393,8 @@ QPDFJob::doSplitPages(QPDF&amp; pdf, bool&amp; warnings)
3378 3393 QPDFWriter w(outpdf, outfile.c_str());
3379 3394 setWriterOptions(outpdf, w);
3380 3395 w.write();
3381   - o.doIfVerbose([&](std::ostream& cout, std::string const& whoami) {
3382   - cout << whoami << ": wrote file " << outfile << std::endl;
  3396 + o.doIfVerbose([&](std::ostream& cout, std::string const& prefix) {
  3397 + cout << prefix << ": wrote file " << outfile << std::endl;
3383 3398 });
3384 3399 if (outpdf.anyWarnings())
3385 3400 {
... ... @@ -3415,8 +3430,8 @@ QPDFJob::writeOutfile(QPDF&amp; pdf)
3415 3430 }
3416 3431 if (o.outfilename)
3417 3432 {
3418   - o.doIfVerbose([&](std::ostream& cout, std::string const& whoami) {
3419   - cout << whoami << ": wrote file " << o.outfilename << std::endl;
  3433 + o.doIfVerbose([&](std::ostream& cout, std::string const& prefix) {
  3434 + cout << prefix << ": wrote file " << o.outfilename << std::endl;
3420 3435 });
3421 3436 }
3422 3437 if (o.replace_input)
... ... @@ -3437,9 +3452,10 @@ QPDFJob::writeOutfile(QPDF&amp; pdf)
3437 3452 QUtil::rename_file(temp_out.c_str(), o.infilename);
3438 3453 if (warnings)
3439 3454 {
3440   - std::cerr << whoami
3441   - << ": there are warnings; original file kept in "
3442   - << backup << std::endl;
  3455 + *(this->m->cerr)
  3456 + << this->m->message_prefix
  3457 + << ": there are warnings; original file kept in "
  3458 + << backup << std::endl;
3443 3459 }
3444 3460 else
3445 3461 {
... ... @@ -3449,8 +3465,8 @@ QPDFJob::writeOutfile(QPDF&amp; pdf)
3449 3465 }
3450 3466 catch (QPDFSystemError& e)
3451 3467 {
3452   - std::cerr
3453   - << whoami
  3468 + *(this->m->cerr)
  3469 + << this->m->message_prefix
3454 3470 << ": unable to delete original file ("
3455 3471 << e.what() << ");"
3456 3472 << " original file left in " << backup
... ...