2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-05-29 16:30:53 +00:00

Use "save" logger when saving data to standard output

This includes the output PDF, streams from --show-object and
attachments from --save-attachment. This also enables --verbose and
--progress to work with saving to stdout.
This commit is contained in:
Jay Berkenbilt 2022-06-18 09:40:41 -04:00
parent 641e92c6a7
commit 83be2191b4
7 changed files with 60 additions and 23 deletions

View File

@ -1,3 +1,9 @@
2022-06-18 Jay Berkenbilt <ejb@ql.org>
* When --progress or --verbose is combined with writing to
standard output, progress reporting and verbose messages go to
standard error. Previously it was disabled in this case.
2022-06-05 Jay Berkenbilt <ejb@ql.org> 2022-06-05 Jay Berkenbilt <ejb@ql.org>
* QPDFJob: API breaking change: QPDFJob::doIfVerbose passes a * QPDFJob: API breaking change: QPDFJob::doIfVerbose passes a

3
TODO
View File

@ -79,9 +79,6 @@ Find all places in the library that write to stdout/stderr/cout/cerr.
Also find places that raise exceptions if unable to warn. These should Also find places that raise exceptions if unable to warn. These should
use the global output writer. use the global output writer.
Figure out a good way to use the save pipeline for QPDFWriter as well
as saving attachments, showing stream data, etc.
QPDFPagesTree QPDFPagesTree
============= =============

View File

@ -691,22 +691,21 @@ QPDFJob::checkConfiguration()
" before the -- that follows --encrypt."); " before the -- that follows --encrypt.");
} }
bool save_to_stdout = false;
if (m->require_outfile && m->outfilename && if (m->require_outfile && m->outfilename &&
(strcmp(m->outfilename.get(), "-") == 0)) { (strcmp(m->outfilename.get(), "-") == 0)) {
if (m->split_pages) { if (m->split_pages) {
usage("--split-pages may not be used when" usage("--split-pages may not be used when"
" writing to standard output"); " writing to standard output");
} }
if (this->m->verbose) { save_to_stdout = true;
usage("--verbose may not be used when" }
" writing to standard output"); if (!m->attachment_to_show.empty()) {
} save_to_stdout = true;
if (m->progress) { }
usage("--progress may not be used when" if (save_to_stdout) {
" writing to standard output"); this->m->log->saveToStandardOutput();
}
} }
if ((!m->split_pages) && if ((!m->split_pages) &&
QUtil::same_file(m->infilename.get(), m->outfilename.get())) { QUtil::same_file(m->infilename.get(), m->outfilename.get())) {
QTC::TC("qpdf", "QPDFJob same file error"); QTC::TC("qpdf", "QPDFJob same file error");
@ -918,10 +917,11 @@ QPDFJob::doShowObj(QPDF& pdf)
obj.warnIfPossible("unable to filter stream data"); obj.warnIfPossible("unable to filter stream data");
error = true; error = true;
} else { } else {
QUtil::binary_stdout(); // If anything has been written to standard output,
Pl_StdioFile out("stdout", stdout); // this will fail.
this->m->log->saveToStandardOutput();
obj.pipeStreamData( obj.pipeStreamData(
&out, this->m->log->getSave().get(),
(filter && m->normalize) ? qpdf_ef_normalize : 0, (filter && m->normalize) ? qpdf_ef_normalize : 0,
filter ? qpdf_dl_all : qpdf_dl_none); filter ? qpdf_dl_all : qpdf_dl_none);
} }
@ -1023,9 +1023,10 @@ QPDFJob::doShowAttachment(QPDF& pdf)
"attachment " + m->attachment_to_show + " not found"); "attachment " + m->attachment_to_show + " not found");
} }
auto efs = fs->getEmbeddedFileStream(); auto efs = fs->getEmbeddedFileStream();
QUtil::binary_stdout(); // saveToStandardOutput has already been called, but it's harmless
Pl_StdioFile out("stdout", stdout); // to call it again, so do as defensive coding.
efs.pipeStreamData(&out, 0, qpdf_dl_all); this->m->log->saveToStandardOutput();
efs.pipeStreamData(this->m->log->getSave().get(), 0, qpdf_dl_all);
} }
void void
@ -3138,14 +3139,17 @@ QPDFJob::setWriterOptions(QPDF& pdf, QPDFWriter& w)
parse_version(m->force_version, version, extension_level); parse_version(m->force_version, version, extension_level);
w.forcePDFVersion(version, extension_level); w.forcePDFVersion(version, extension_level);
} }
if (m->progress && m->outfilename) { if (m->progress) {
char const* outfilename = this->m->outfilename
? this->m->outfilename.get()
: "standard output";
w.registerProgressReporter( w.registerProgressReporter(
std::shared_ptr<QPDFWriter::ProgressReporter>( std::shared_ptr<QPDFWriter::ProgressReporter>(
// line-break // line-break
new ProgressReporter( new ProgressReporter(
*this->m->log->getInfo(), *this->m->log->getInfo(),
this->m->message_prefix, this->m->message_prefix,
m->outfilename.get()))); outfilename)));
} }
} }
@ -3273,7 +3277,15 @@ QPDFJob::writeOutfile(QPDF& pdf)
} else { } else {
// QPDFWriter must have block scope so the output file will be // QPDFWriter must have block scope so the output file will be
// closed after write() finishes. // closed after write() finishes.
QPDFWriter w(pdf, m->outfilename.get()); QPDFWriter w(pdf);
if (this->m->outfilename) {
w.setOutputFilename(m->outfilename.get());
} else {
// saveToStandardOutput has already been called, but
// calling it again is defensive and harmless.
this->m->log->saveToStandardOutput();
w.setOutputPipeline(this->m->log->getSave().get());
}
setWriterOptions(pdf, w); setWriterOptions(pdf, w);
w.write(); w.write();
} }

View File

@ -2,6 +2,7 @@
#include <qpdf/Pl_Discard.hh> #include <qpdf/Pl_Discard.hh>
#include <qpdf/Pl_OStream.hh> #include <qpdf/Pl_OStream.hh>
#include <qpdf/QUtil.hh>
#include <iostream> #include <iostream>
#include <stdexcept> #include <stdexcept>
@ -182,6 +183,9 @@ QPDFLogger::setError(std::shared_ptr<Pipeline> p)
void void
QPDFLogger::setSave(std::shared_ptr<Pipeline> p) QPDFLogger::setSave(std::shared_ptr<Pipeline> p)
{ {
if (this->m->p_save == p) {
return;
}
if (p == this->m->p_stdout) { if (p == this->m->p_stdout) {
auto pt = dynamic_cast<Pl_Track*>(p.get()); auto pt = dynamic_cast<Pl_Track*>(p.get());
if (pt->getUsed()) { if (pt->getUsed()) {
@ -192,6 +196,7 @@ QPDFLogger::setSave(std::shared_ptr<Pipeline> p)
if (this->m->p_info == this->m->p_stdout) { if (this->m->p_info == this->m->p_stdout) {
this->m->p_info = this->m->p_stderr; this->m->p_info = this->m->p_stderr;
} }
QUtil::binary_stdout();
} }
this->m->p_save = p; this->m->p_save = p;
} }

View File

@ -133,6 +133,10 @@ For a detailed list of changes, please see the file
user password is not recoverable from the owner password when user password is not recoverable from the owner password when
256-bit keys are in use. 256-bit keys are in use.
- ``--verbose`` and ``--progress`` may be now used when writing
the output PDF to standard output. In that case, the verbose and
progress messages are written to standard error.
- Library Enhancements - Library Enhancements
- New methods ``insertItemAndGet``, ``appendItemAndGet``, - New methods ``insertItemAndGet``, ``appendItemAndGet``,

View File

@ -14,13 +14,23 @@ cleanup();
my $td = new TestDriver('progress-reporting'); my $td = new TestDriver('progress-reporting');
my $n_tests = 1; my $n_tests = 3;
$td->runtest("progress report on small file", $td->runtest("progress report on small file",
{$td->COMMAND => "qpdf --progress minimal.pdf a.pdf", {$td->COMMAND =>
"qpdf --progress --deterministic-id minimal.pdf a.pdf",
$td->FILTER => "perl filter-progress.pl"}, $td->FILTER => "perl filter-progress.pl"},
{$td->FILE => "small-progress.out", $td->EXIT_STATUS => 0}, {$td->FILE => "small-progress.out", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES); $td->NORMALIZE_NEWLINES);
$td->runtest("progress report to stdout",
{$td->COMMAND =>
"qpdf --progress --deterministic-id minimal.pdf - > b.pdf",
$td->FILTER => "perl filter-progress.pl"},
{$td->FILE => "small-stdout-progress.out", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("compare",
{$td->FILE => "a.pdf"},
{$td->FILE => "b.pdf"});
cleanup(); cleanup();
$td->report($n_tests); $td->report($n_tests);

View File

@ -0,0 +1,3 @@
qpdf: standard output: write progress: 0%
....other write progress....
qpdf: standard output: write progress: 100%