mirror of
https://github.com/qpdf/qpdf.git
synced 2024-12-22 10:58:58 +00:00
Use the default logger for other writes to stdout/stderr
When there is no context for writing output or error messages, use the default logger.
This commit is contained in:
parent
83be2191b4
commit
e0720eaa78
20
TODO
20
TODO
@ -55,30 +55,10 @@ Output Capture
|
||||
|
||||
See https://github.com/qpdf/qpdf/issues/691
|
||||
|
||||
QPDFLogger maintains pipelines for info, warn, error, and save.
|
||||
|
||||
There is a singleton, default QPDFLogger which all QPDF and QPDFJob
|
||||
objects get on construction. In most cases, it is not necessary to
|
||||
override this. Allow QPDFJob and QPDF to be passed a new logger
|
||||
instance. QPDFJob should pass its QPDFLogger to all QPDF objects it
|
||||
creates. The main uses cases for this would be for multithreading or
|
||||
for having a library that uses QPDF privately and modifies logger
|
||||
settings so that it wouldn't interfere with a downstream library or
|
||||
application also using qpdf.
|
||||
|
||||
There needs to be a C API to QPDFLogger. Use functions like this:
|
||||
|
||||
void set_info((*f)(char* data, unsigned int len, void* udata), void* udata);
|
||||
|
||||
We should probably deprecate the output/error setters in QPDF and
|
||||
QPDFJob. In the meantime, document that they won't work anymore to set
|
||||
different outputs with different QPDF objects. We may need to delete
|
||||
rather than deprecate these methods.
|
||||
|
||||
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
|
||||
use the global output writer.
|
||||
|
||||
|
||||
QPDFPagesTree
|
||||
=============
|
||||
|
@ -33,6 +33,19 @@ class QPDFLogger
|
||||
QPDF_DLL
|
||||
QPDFLogger();
|
||||
|
||||
// Return the default logger. In general, you should use the
|
||||
// default logger. You can also create your own loggers and use
|
||||
// them QPDF and QPDFJob objects, but there are few reasons to do
|
||||
// so. One reason may if you are using multiple QPDF or QPDFJob
|
||||
// objects in different threads and want to capture output and
|
||||
// errors to different streams. (Note that a single QPDF or
|
||||
// QPDFJob can't be safely used from multiple threads, but it is
|
||||
// safe to use separate QPDF and QPDFJob objects on separate
|
||||
// threads.) Another possible reason would be if you are writing
|
||||
// an application that uses the qpdf library directly and qpdf is
|
||||
// also used by a downstream library or if you are using qpdf from
|
||||
// a library and don't want to interfere with potential uses of
|
||||
// qpdf by other libraries or applications.
|
||||
QPDF_DLL
|
||||
static std::shared_ptr<QPDFLogger> defaultLogger();
|
||||
|
||||
|
@ -1411,14 +1411,14 @@ class QPDFObjectHandle
|
||||
// End legacy page helpers
|
||||
|
||||
// Issue a warning about this object if possible. If the object
|
||||
// has a description, a warning will be issued. Otherwise, if
|
||||
// throw_if_no_description is true, throw an exception. Otherwise
|
||||
// do nothing. Objects read normally from the file have
|
||||
// has a description, a warning will be issued using the owning
|
||||
// QPDF as context. Otherwise, a message will be written to the
|
||||
// default logger's error stream, which is standard error if not
|
||||
// overridden. Objects read normally from the file have
|
||||
// descriptions. See comments on setObjectDescription for
|
||||
// additional details.
|
||||
QPDF_DLL
|
||||
void warnIfPossible(
|
||||
std::string const& warning, bool throw_if_no_description = false);
|
||||
void warnIfPossible(std::string const& warning);
|
||||
|
||||
// Initializers for objects. This Factory class gives the QPDF
|
||||
// class specific permission to call factory methods without
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include <qpdf/QPDFArgParser.hh>
|
||||
|
||||
#include <qpdf/QIntC.hh>
|
||||
#include <qpdf/QPDFLogger.hh>
|
||||
#include <qpdf/QPDFUsage.hh>
|
||||
#include <qpdf/QTC.hh>
|
||||
#include <qpdf/QUtil.hh>
|
||||
@ -235,7 +236,7 @@ QPDFArgParser::argCompletionZsh()
|
||||
void
|
||||
QPDFArgParser::argHelp(std::string const& p)
|
||||
{
|
||||
std::cout << getHelp(p);
|
||||
QPDFLogger::defaultLogger()->info(getHelp(p));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <qpdf/QPDFArgParser.hh>
|
||||
#include <qpdf/QPDFCryptoProvider.hh>
|
||||
#include <qpdf/QPDFJob.hh>
|
||||
#include <qpdf/QPDFLogger.hh>
|
||||
#include <qpdf/QTC.hh>
|
||||
#include <qpdf/QUtil.hh>
|
||||
|
||||
@ -104,10 +105,10 @@ void
|
||||
ArgParser::argVersion()
|
||||
{
|
||||
auto whoami = this->ap.getProgname();
|
||||
std::cout << whoami << " version " << QPDF::QPDFVersion() << std::endl
|
||||
<< "Run " << whoami
|
||||
<< " --copyright to see copyright and license information."
|
||||
<< std::endl;
|
||||
*QPDFLogger::defaultLogger()->getInfo()
|
||||
<< whoami << " version " << QPDF::QPDFVersion() << "\n"
|
||||
<< "Run " << whoami
|
||||
<< " --copyright to see copyright and license information.\n";
|
||||
}
|
||||
|
||||
void
|
||||
@ -117,48 +118,35 @@ ArgParser::argCopyright()
|
||||
// Make sure the output looks right on an 80-column display.
|
||||
// 1 2 3 4 5 6 7 8
|
||||
// 12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
std::cout
|
||||
*QPDFLogger::defaultLogger()->getInfo()
|
||||
<< this->ap.getProgname()
|
||||
<< " version " << QPDF::QPDFVersion() << std::endl
|
||||
<< std::endl
|
||||
<< "Copyright (c) 2005-2022 Jay Berkenbilt"
|
||||
<< std::endl
|
||||
<< "QPDF is licensed under the Apache License, Version 2.0 (the \"License\");"
|
||||
<< std::endl
|
||||
<< "you may not use this file except in compliance with the License."
|
||||
<< std::endl
|
||||
<< "You may obtain a copy of the License at"
|
||||
<< std::endl
|
||||
<< std::endl
|
||||
<< " http://www.apache.org/licenses/LICENSE-2.0"
|
||||
<< std::endl
|
||||
<< std::endl
|
||||
<< "Unless required by applicable law or agreed to in writing, software"
|
||||
<< std::endl
|
||||
<< "distributed under the License is distributed on an \"AS IS\" BASIS,"
|
||||
<< std::endl
|
||||
<< "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied."
|
||||
<< std::endl
|
||||
<< "See the License for the specific language governing permissions and"
|
||||
<< std::endl
|
||||
<< "limitations under the License."
|
||||
<< std::endl
|
||||
<< std::endl
|
||||
<< "Versions of qpdf prior to version 7 were released under the terms"
|
||||
<< std::endl
|
||||
<< "of version 2.0 of the Artistic License. At your option, you may"
|
||||
<< std::endl
|
||||
<< "continue to consider qpdf to be licensed under those terms. Please"
|
||||
<< std::endl
|
||||
<< "see the manual for additional information."
|
||||
<< std::endl;
|
||||
<< " version " << QPDF::QPDFVersion() << "\n"
|
||||
<< "\n"
|
||||
<< "Copyright (c) 2005-2022 Jay Berkenbilt\n"
|
||||
<< "QPDF is licensed under the Apache License, Version 2.0 (the \"License\");\n"
|
||||
<< "you may not use this file except in compliance with the License.\n"
|
||||
<< "You may obtain a copy of the License at\n"
|
||||
<< "\n"
|
||||
<< " http://www.apache.org/licenses/LICENSE-2.0\n"
|
||||
<< "\n"
|
||||
<< "Unless required by applicable law or agreed to in writing, software\n"
|
||||
<< "distributed under the License is distributed on an \"AS IS\" BASIS,\n"
|
||||
<< "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
|
||||
<< "See the License for the specific language governing permissions and\n"
|
||||
<< "limitations under the License.\n"
|
||||
<< "\n"
|
||||
<< "Versions of qpdf prior to version 7 were released under the terms\n"
|
||||
<< "of version 2.0 of the Artistic License. At your option, you may\n"
|
||||
<< "continue to consider qpdf to be licensed under those terms. Please\n"
|
||||
<< "see the manual for additional information.\n";
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
void
|
||||
ArgParser::argJsonHelp()
|
||||
{
|
||||
std::cout << QPDFJob::json_out_schema_v1() << std::endl;
|
||||
*QPDFLogger::defaultLogger()->getInfo()
|
||||
<< QPDFJob::json_out_schema_v1() << "\n";
|
||||
}
|
||||
|
||||
void
|
||||
@ -166,10 +154,10 @@ ArgParser::argShowCrypto()
|
||||
{
|
||||
auto crypto = QPDFCryptoProvider::getRegisteredImpls();
|
||||
std::string default_crypto = QPDFCryptoProvider::getDefaultProvider();
|
||||
std::cout << default_crypto << std::endl;
|
||||
*QPDFLogger::defaultLogger()->getInfo() << default_crypto << "\n";
|
||||
for (auto const& iter: crypto) {
|
||||
if (iter != default_crypto) {
|
||||
std::cout << iter << std::endl;
|
||||
*QPDFLogger::defaultLogger()->getInfo() << iter << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -407,7 +395,8 @@ ArgParser::argEndCopyAttachment()
|
||||
void
|
||||
ArgParser::argJobJsonHelp()
|
||||
{
|
||||
std::cout << QPDFJob::job_json_schema_v1() << std::endl;
|
||||
*QPDFLogger::defaultLogger()->getInfo()
|
||||
<< QPDFJob::job_json_schema_v1() << "\n";
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include <qpdf/QPDFJob.hh>
|
||||
|
||||
#include <qpdf/QPDFLogger.hh>
|
||||
#include <qpdf/QTC.hh>
|
||||
#include <qpdf/QUtil.hh>
|
||||
|
||||
@ -648,9 +649,10 @@ QPDFJob::Config::passwordFile(std::string const& parameter)
|
||||
o.m->password = QUtil::make_shared_cstr(lines.front());
|
||||
|
||||
if (lines.size() > 1) {
|
||||
std::cerr << this->o.m->message_prefix
|
||||
<< ": WARNING: all but the first line of"
|
||||
<< " the password file are ignored" << std::endl;
|
||||
*QPDFLogger::defaultLogger()->getError()
|
||||
<< this->o.m->message_prefix
|
||||
<< ": WARNING: all but the first line of"
|
||||
<< " the password file are ignored\n";
|
||||
}
|
||||
}
|
||||
return this;
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <qpdf/Pl_QPDFTokenizer.hh>
|
||||
#include <qpdf/QPDF.hh>
|
||||
#include <qpdf/QPDFExc.hh>
|
||||
#include <qpdf/QPDFLogger.hh>
|
||||
#include <qpdf/QPDFMatrix.hh>
|
||||
#include <qpdf/QPDFPageObjectHelper.hh>
|
||||
#include <qpdf/QPDF_Array.hh>
|
||||
@ -578,13 +579,12 @@ QPDFObjectHandle::getIntValueAsInt()
|
||||
if (v < INT_MIN) {
|
||||
QTC::TC("qpdf", "QPDFObjectHandle int returning INT_MIN");
|
||||
warnIfPossible(
|
||||
"requested value of integer is too small; returning INT_MIN",
|
||||
false);
|
||||
"requested value of integer is too small; returning INT_MIN");
|
||||
result = INT_MIN;
|
||||
} else if (v > INT_MAX) {
|
||||
QTC::TC("qpdf", "QPDFObjectHandle int returning INT_MAX");
|
||||
warnIfPossible(
|
||||
"requested value of integer is too big; returning INT_MAX", false);
|
||||
"requested value of integer is too big; returning INT_MAX");
|
||||
result = INT_MAX;
|
||||
} else {
|
||||
result = static_cast<int>(v);
|
||||
@ -610,7 +610,7 @@ QPDFObjectHandle::getUIntValue()
|
||||
if (v < 0) {
|
||||
QTC::TC("qpdf", "QPDFObjectHandle uint returning 0");
|
||||
warnIfPossible(
|
||||
"unsigned value request for negative number; returning 0", false);
|
||||
"unsigned value request for negative number; returning 0");
|
||||
} else {
|
||||
result = static_cast<unsigned long long>(v);
|
||||
}
|
||||
@ -635,15 +635,12 @@ QPDFObjectHandle::getUIntValueAsUInt()
|
||||
if (v < 0) {
|
||||
QTC::TC("qpdf", "QPDFObjectHandle uint uint returning 0");
|
||||
warnIfPossible(
|
||||
"unsigned integer value request for negative number; returning 0",
|
||||
false);
|
||||
"unsigned integer value request for negative number; returning 0");
|
||||
result = 0;
|
||||
} else if (v > UINT_MAX) {
|
||||
QTC::TC("qpdf", "QPDFObjectHandle uint returning UINT_MAX");
|
||||
warnIfPossible(
|
||||
"requested value of unsigned integer is too big;"
|
||||
" returning UINT_MAX",
|
||||
false);
|
||||
warnIfPossible("requested value of unsigned integer is too big;"
|
||||
" returning UINT_MAX");
|
||||
result = UINT_MAX;
|
||||
} else {
|
||||
result = static_cast<unsigned int>(v);
|
||||
@ -3000,16 +2997,15 @@ QPDFObjectHandle::typeWarning(
|
||||
}
|
||||
|
||||
void
|
||||
QPDFObjectHandle::warnIfPossible(
|
||||
std::string const& warning, bool throw_if_no_description)
|
||||
QPDFObjectHandle::warnIfPossible(std::string const& warning)
|
||||
{
|
||||
QPDF* context = 0;
|
||||
std::string description;
|
||||
dereference();
|
||||
if (this->obj->getDescription(context, description)) {
|
||||
warn(context, QPDFExc(qpdf_e_damaged_pdf, "", description, 0, warning));
|
||||
} else if (throw_if_no_description) {
|
||||
throw std::runtime_error(warning);
|
||||
} else {
|
||||
*QPDFLogger::defaultLogger()->getError() << warning << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <qpdf/Pl_Discard.hh>
|
||||
#include <qpdf/QIntC.hh>
|
||||
#include <qpdf/QPDFExc.hh>
|
||||
#include <qpdf/QPDFLogger.hh>
|
||||
#include <qpdf/QPDFWriter.hh>
|
||||
#include <qpdf/QTC.hh>
|
||||
#include <qpdf/QUtil.hh>
|
||||
@ -185,8 +186,9 @@ qpdf_cleanup(qpdf_data* qpdf)
|
||||
qpdf_oh_release_all(*qpdf);
|
||||
if ((*qpdf)->error.get()) {
|
||||
QTC::TC("qpdf", "qpdf-c cleanup warned about unhandled error");
|
||||
std::cerr << "WARNING: application did not handle error: "
|
||||
<< (*qpdf)->error->what() << std::endl;
|
||||
*QPDFLogger::defaultLogger()->getWarn()
|
||||
<< "WARNING: application did not handle error: "
|
||||
<< (*qpdf)->error->what() << "\n";
|
||||
}
|
||||
delete *qpdf;
|
||||
*qpdf = 0;
|
||||
@ -898,7 +900,8 @@ trap_oh_errors(
|
||||
" to ERROR HANDLING in qpdf-c.h"));
|
||||
qpdf->oh_error_occurred = true;
|
||||
}
|
||||
std::cerr << qpdf->error->what() << std::endl;
|
||||
*QPDFLogger::defaultLogger()->getError()
|
||||
<< qpdf->error->what() << "\n";
|
||||
}
|
||||
return fallback();
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include <qpdf/qpdfjob-c.h>
|
||||
|
||||
#include <qpdf/QPDFJob.hh>
|
||||
#include <qpdf/QPDFLogger.hh>
|
||||
#include <qpdf/QPDFUsage.hh>
|
||||
#include <qpdf/QUtil.hh>
|
||||
|
||||
@ -19,7 +20,8 @@ qpdfjob_run_from_argv(char const* const argv[])
|
||||
j.initializeFromArgv(argv);
|
||||
j.run();
|
||||
} catch (std::exception& e) {
|
||||
std::cerr << whoami << ": " << e.what() << std::endl;
|
||||
*QPDFLogger::defaultLogger()->getError()
|
||||
<< whoami << ": " << e.what() << "\n";
|
||||
return QPDFJob::EXIT_ERROR;
|
||||
}
|
||||
return j.getExitCode();
|
||||
@ -48,7 +50,8 @@ qpdfjob_run_from_json(char const* json)
|
||||
j.initializeFromJson(json);
|
||||
j.run();
|
||||
} catch (std::exception& e) {
|
||||
std::cerr << "qpdfjob json: " << e.what() << std::endl;
|
||||
*QPDFLogger::defaultLogger()->getError()
|
||||
<< "qpdfjob json: " << e.what() << "\n";
|
||||
return QPDFJob::EXIT_ERROR;
|
||||
}
|
||||
return j.getExitCode();
|
||||
|
@ -120,6 +120,11 @@ For a detailed list of changes, please see the file
|
||||
- See :ref:`breaking-crypto-api` for specific details, and see
|
||||
:ref:`weak-crypto` for a general discussion.
|
||||
|
||||
- QPDFObjectHandle::warnIfPossible no longer takes an optional
|
||||
argument to throw an exception if there is no description. If
|
||||
there is no description, it writes to the default logger's error
|
||||
stream.
|
||||
|
||||
- CLI Enhancements
|
||||
|
||||
- ``qpdf --list-attachments --verbose`` include some additional
|
||||
@ -139,6 +144,20 @@ For a detailed list of changes, please see the file
|
||||
|
||||
- Library Enhancements
|
||||
|
||||
- A new object ``QPDFLogger`` has been added. Details are in
|
||||
:file:`include/qpdf/QPDFLogger.hh`.
|
||||
|
||||
- ``QPDF`` and ``QPDFJob`` both use the default logger by
|
||||
default but can have their loggers overridden. The
|
||||
``setOutputStreams`` method is deprecated in both classes.
|
||||
|
||||
- A few things from ``QPDFObjectHandle`` that used to be
|
||||
exceptions now write errors with the default logger.
|
||||
|
||||
- By configuring the default logger, it is possible to capture
|
||||
output and errors that slipped through the cracks with
|
||||
``setOutputStreams``.
|
||||
|
||||
- New methods ``insertItemAndGet``, ``appendItemAndGet``,
|
||||
``eraseItemAndGet``, ``replaceKeyAndGet``, and
|
||||
``removeKeyAndGet`` return the newly added or removed object.
|
||||
|
@ -111,11 +111,11 @@ $td->runtest("C API: no recovery",
|
||||
|
||||
$td->runtest("integer type checks",
|
||||
{$td->COMMAND => "test_driver 62 minimal.pdf"},
|
||||
{$td->STRING => "test 62 done\n", $td->EXIT_STATUS => 0},
|
||||
{$td->FILE => "test62.out", $td->EXIT_STATUS => 0},
|
||||
$td->NORMALIZE_NEWLINES);
|
||||
$td->runtest("getValueAs... accessor checks",
|
||||
{$td->COMMAND => "test_driver 85 -"},
|
||||
{$td->STRING => "test 85 done\n", $td->EXIT_STATUS => 0},
|
||||
{$td->FILE => "test85.out", $td->EXIT_STATUS => 0},
|
||||
$td->NORMALIZE_NEWLINES);
|
||||
|
||||
$n_tests += @badfiles + 11;
|
||||
|
7
qpdf/qtest/qpdf/test62.out
Normal file
7
qpdf/qtest/qpdf/test62.out
Normal file
@ -0,0 +1,7 @@
|
||||
requested value of integer is too big; returning INT_MAX
|
||||
requested value of unsigned integer is too big; returning UINT_MAX
|
||||
unsigned value request for negative number; returning 0
|
||||
requested value of integer is too small; returning INT_MIN
|
||||
unsigned integer value request for negative number; returning 0
|
||||
requested value of integer is too big; returning INT_MAX
|
||||
test 62 done
|
6
qpdf/qtest/qpdf/test85.out
Normal file
6
qpdf/qtest/qpdf/test85.out
Normal file
@ -0,0 +1,6 @@
|
||||
requested value of integer is too big; returning INT_MAX
|
||||
requested value of integer is too small; returning INT_MIN
|
||||
unsigned value request for negative number; returning 0
|
||||
unsigned integer value request for negative number; returning 0
|
||||
requested value of unsigned integer is too big; returning UINT_MAX
|
||||
test 85 done
|
Loading…
Reference in New Issue
Block a user