mirror of
https://github.com/qpdf/qpdf.git
synced 2024-12-22 10:58:58 +00:00
C API: overhaul error handling
* Handle error conditions that occur when using the object handle interfaces. In the past, some exceptions were not correctly converted to errors or warnings. * Add more detailed information to qpdf-c.h * Make it possible to work more explicitly with uninitialized objects
This commit is contained in:
parent
3340dbe976
commit
72c10d8617
18
ChangeLog
18
ChangeLog
@ -1,3 +1,21 @@
|
|||||||
|
2021-12-10 Jay Berkenbilt <ejb@ql.org>
|
||||||
|
|
||||||
|
* C API: Overhaul how errors are handle the C API's object handle
|
||||||
|
interfaces. Clarify documentation regarding object accessors and
|
||||||
|
how type errors and warnings are handled. Many cases that used to
|
||||||
|
crash code that used the C API can now be trapped and will be
|
||||||
|
written stderr if not trapped. The new method
|
||||||
|
qpdf_register_oh_error_handler can be used to specifically handle
|
||||||
|
errors that occur when accessing object handles. See qpdf-c.h for
|
||||||
|
details.
|
||||||
|
|
||||||
|
* C API: Add qpdf_oh_new_uninitialized to explicitly create
|
||||||
|
uninitialized object handles.
|
||||||
|
|
||||||
|
* Add new error code qpdf_e_object that is used for exceptions
|
||||||
|
(including warnings) that are caused by using QPDFObjectHandle
|
||||||
|
methods on object handles of the wrong type.
|
||||||
|
|
||||||
2021-12-02 Jay Berkenbilt <ejb@ql.org>
|
2021-12-02 Jay Berkenbilt <ejb@ql.org>
|
||||||
|
|
||||||
* C API: Add qpdf_oh_is_initialized.
|
* C API: Add qpdf_oh_is_initialized.
|
||||||
|
@ -62,22 +62,27 @@
|
|||||||
* string was just returned.
|
* string was just returned.
|
||||||
*
|
*
|
||||||
* Many functions defined here merely set parameters and therefore
|
* Many functions defined here merely set parameters and therefore
|
||||||
* never return error conditions. Functions that may cause PDF
|
* never return error conditions. Functions that access or return
|
||||||
* files to be read or written may return error conditions. Such
|
* qpdf_oh object handles may generate warnings but have no way to
|
||||||
* functions return an error code. If there were no errors or
|
* return errors, but the errors may be checked afterwards or
|
||||||
* warnings, they return QPDF_SUCCESS. If there were warnings,
|
* handled using a registered handler. This is discussed in more
|
||||||
* the return value has the QPDF_WARNINGS bit set. If there
|
* detail in the section on object handling. Functions that may
|
||||||
* errors, the QPDF_ERRORS bit is set. In other words, if there
|
* cause PDF files to be read or written may return error
|
||||||
* are both warnings and errors, then the return status will be
|
* conditions. Such functions return an error code. If there were
|
||||||
* QPDF_WARNINGS | QPDF_ERRORS. You may also call the
|
* no errors or warnings, they return QPDF_SUCCESS. If there were
|
||||||
|
* warnings, the return value has the QPDF_WARNINGS bit set. If
|
||||||
|
* there were errors, the QPDF_ERRORS bit is set. In other words,
|
||||||
|
* if there are both warnings and errors, then the return status
|
||||||
|
* will be QPDF_WARNINGS | QPDF_ERRORS. You may also call the
|
||||||
* qpdf_more_warnings and qpdf_more_errors functions to test
|
* qpdf_more_warnings and qpdf_more_errors functions to test
|
||||||
* whether there are unseen warning or error conditions. By
|
* whether there are unseen warning or error conditions. By
|
||||||
* default, warnings are written to stderr when detected, but this
|
* default, warnings are written to stderr when detected, but this
|
||||||
* behavior can be suppressed. In all cases, errors and warnings
|
* behavior can be suppressed. In all cases, errors and warnings
|
||||||
* may be retrieved by calling qpdf_next_warning and
|
* may be retrieved by calling qpdf_next_warning and
|
||||||
* qpdf_next_error. All exceptions thrown by the C++ interface
|
* qpdf_get_error. All exceptions thrown by the C++ interface are
|
||||||
* are caught and converted into error messages by the C
|
* caught and converted into error messages by the C interface.
|
||||||
* interface.
|
* Any exceptions to this are qpdf bugs and should be reported at
|
||||||
|
* https://github.com/qpdf/qpdf/issues/new.
|
||||||
*
|
*
|
||||||
* Most functions defined here have obvious counterparts that are
|
* Most functions defined here have obvious counterparts that are
|
||||||
* methods to either QPDF or QPDFWriter. Please see comments in
|
* methods to either QPDF or QPDFWriter. Please see comments in
|
||||||
@ -550,13 +555,51 @@ extern "C" {
|
|||||||
* handle, the object is safely part of the dictionary or array.
|
* handle, the object is safely part of the dictionary or array.
|
||||||
* Similarly, any other object handle refering to the object remains
|
* Similarly, any other object handle refering to the object remains
|
||||||
* valid. Explicitly releasing an object handle is essentially the
|
* valid. Explicitly releasing an object handle is essentially the
|
||||||
* same as letting a QPDFObjectHandle go out of scope in the C++ API.
|
* same as letting a QPDFObjectHandle go out of scope in the C++
|
||||||
|
* API.
|
||||||
|
*
|
||||||
|
* Important note about error handling:
|
||||||
|
*
|
||||||
|
* While many of the functions that operate on the QPDF object
|
||||||
|
* return error codes, the qpdf_oh functions return values such as
|
||||||
|
* object handles or data. They have no way to return error codes.
|
||||||
|
* If they generate warnings, the warnings are handled using the
|
||||||
|
* error/warning handling functions described above. If the
|
||||||
|
* underlying C++ call throws an exception, the error handler
|
||||||
|
* registered with qpdf_register_oh_error_handler() will be
|
||||||
|
* called. If no handler is registered, the exception is written
|
||||||
|
* to STDERR. In either case, a sensible fallback value is
|
||||||
|
* returned (0 for numbers, QPDF_FALSE for booleans, "" for
|
||||||
|
* strings, or a null object). It is sensible for a C program to
|
||||||
|
* use setjmp and longjmp with this error handler since the C++
|
||||||
|
* code has raised an exception, but you can also just set a flag
|
||||||
|
* and check it after each call.
|
||||||
|
*
|
||||||
|
* All conditions under which exceptions would be thrown by object
|
||||||
|
* accessors are caused by programmer error or major problems such
|
||||||
|
* as running out of memory or not being able to read the input
|
||||||
|
* file. If they are ever caused by invalid data in the PDF file,
|
||||||
|
* it is a bug in qpdf, which should be reported at
|
||||||
|
* https://github.com/qpdf/qpdf/issues/new.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* For examples of using this API, see examples/pdf-c-objects.c */
|
/* For examples of using this API, see examples/pdf-c-objects.c */
|
||||||
|
|
||||||
typedef unsigned int qpdf_oh;
|
typedef unsigned int qpdf_oh;
|
||||||
|
|
||||||
|
/* If an exception is thrown by the C++ code when any of the
|
||||||
|
* qpdf_oh functions are called, the registered handle_error
|
||||||
|
* function will be called. The value passed to data will be
|
||||||
|
* passed along to the error handler function. If any errors occur
|
||||||
|
* and no error handler is accessed, a single warning will be
|
||||||
|
* issued, and the error will be written to stderr.
|
||||||
|
*/
|
||||||
|
QPDF_DLL
|
||||||
|
void qpdf_register_oh_error_handler(
|
||||||
|
qpdf_data qpdf,
|
||||||
|
void (*handle_error)(qpdf_data qpdf, qpdf_error error, void* data),
|
||||||
|
void* data);
|
||||||
|
|
||||||
/* Releasing objects -- see comments above. These functions have no
|
/* Releasing objects -- see comments above. These functions have no
|
||||||
* equivalent in the C++ API.
|
* equivalent in the C++ API.
|
||||||
*/
|
*/
|
||||||
@ -659,7 +702,7 @@ extern "C" {
|
|||||||
/* The memory returned by qpdf_oh_dict_next_key is owned by
|
/* The memory returned by qpdf_oh_dict_next_key is owned by
|
||||||
* qpdf_data. It is good until the next call to
|
* qpdf_data. It is good until the next call to
|
||||||
* qpdf_oh_dict_next_key with the same qpdf_data object. Calling
|
* qpdf_oh_dict_next_key with the same qpdf_data object. Calling
|
||||||
* the method again, even with a different dict, invalidates
|
* the function again, even with a different dict, invalidates
|
||||||
* previous return values.
|
* previous return values.
|
||||||
*/
|
*/
|
||||||
QPDF_DLL
|
QPDF_DLL
|
||||||
@ -676,6 +719,8 @@ extern "C" {
|
|||||||
QPDF_BOOL qpdf_oh_is_or_has_name(
|
QPDF_BOOL qpdf_oh_is_or_has_name(
|
||||||
qpdf_data data, qpdf_oh oh, char const* key);
|
qpdf_data data, qpdf_oh oh, char const* key);
|
||||||
|
|
||||||
|
QPDF_DLL
|
||||||
|
qpdf_oh qpdf_oh_new_uninitialized(qpdf_data qpdf);
|
||||||
QPDF_DLL
|
QPDF_DLL
|
||||||
qpdf_oh qpdf_oh_new_null(qpdf_data data);
|
qpdf_oh qpdf_oh_new_null(qpdf_data data);
|
||||||
QPDF_DLL
|
QPDF_DLL
|
||||||
|
@ -41,6 +41,9 @@ struct _qpdf_data
|
|||||||
PointerHolder<Buffer> output_buffer;
|
PointerHolder<Buffer> output_buffer;
|
||||||
|
|
||||||
// QPDFObjectHandle support
|
// QPDFObjectHandle support
|
||||||
|
void (*oh_error_handler)(qpdf_data, qpdf_error, void*);
|
||||||
|
void* oh_error_handler_data;
|
||||||
|
bool default_oh_error_handler_called;
|
||||||
std::map<qpdf_oh, PointerHolder<QPDFObjectHandle>> oh_cache;
|
std::map<qpdf_oh, PointerHolder<QPDFObjectHandle>> oh_cache;
|
||||||
qpdf_oh next_oh;
|
qpdf_oh next_oh;
|
||||||
std::set<std::string> cur_iter_dict_keys;
|
std::set<std::string> cur_iter_dict_keys;
|
||||||
@ -48,8 +51,32 @@ struct _qpdf_data
|
|||||||
std::string cur_dict_key;
|
std::string cur_dict_key;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void default_oh_error_handler(qpdf_data qpdf, qpdf_error e, void* data)
|
||||||
|
{
|
||||||
|
bool* called = reinterpret_cast<bool*>(data);
|
||||||
|
if (called != nullptr)
|
||||||
|
{
|
||||||
|
QTC::TC("qpdf", "qpdf-c warn about oh error", *called ? 0 : 1);
|
||||||
|
if (! *called)
|
||||||
|
{
|
||||||
|
qpdf->warnings.push_back(
|
||||||
|
QPDFExc(
|
||||||
|
qpdf_e_internal,
|
||||||
|
qpdf->qpdf->getFilename(),
|
||||||
|
"", 0,
|
||||||
|
"C API object handle accessor errors occurred,"
|
||||||
|
" and the application did not define an error handler"));
|
||||||
|
*called = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::cerr << e->exc->what() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
_qpdf_data::_qpdf_data() :
|
_qpdf_data::_qpdf_data() :
|
||||||
write_memory(false),
|
write_memory(false),
|
||||||
|
oh_error_handler(default_oh_error_handler),
|
||||||
|
oh_error_handler_data(&this->default_oh_error_handler_called),
|
||||||
|
default_oh_error_handler_called(false),
|
||||||
next_oh(0)
|
next_oh(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -170,6 +197,13 @@ void qpdf_cleanup(qpdf_data* qpdf)
|
|||||||
{
|
{
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_cleanup");
|
QTC::TC("qpdf", "qpdf-c called qpdf_cleanup");
|
||||||
qpdf_oh_release_all(*qpdf);
|
qpdf_oh_release_all(*qpdf);
|
||||||
|
if ((*qpdf)->error.getPointer())
|
||||||
|
{
|
||||||
|
QTC::TC("qpdf", "qpdf-c cleanup warned about unhandled error");
|
||||||
|
std::cerr << "WARNING: application did not handle error: "
|
||||||
|
<< (*qpdf)->error->what() << std::endl;
|
||||||
|
|
||||||
|
}
|
||||||
delete *qpdf;
|
delete *qpdf;
|
||||||
*qpdf = 0;
|
*qpdf = 0;
|
||||||
}
|
}
|
||||||
@ -841,6 +875,38 @@ QPDF_ERROR_CODE qpdf_write(qpdf_data qpdf)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void qpdf_register_oh_error_handler(
|
||||||
|
qpdf_data qpdf,
|
||||||
|
void (*handle_error)(qpdf_data qpdf, qpdf_error error, void* data),
|
||||||
|
void* data)
|
||||||
|
{
|
||||||
|
QTC::TC("qpdf", "qpdf-c registered oh error handler");
|
||||||
|
qpdf->oh_error_handler = handle_error;
|
||||||
|
qpdf->oh_error_handler_data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class RET>
|
||||||
|
static RET trap_oh_errors(
|
||||||
|
qpdf_data qpdf,
|
||||||
|
std::function<RET()> fallback,
|
||||||
|
std::function<RET(qpdf_data)> fn)
|
||||||
|
{
|
||||||
|
// Note: fallback is a function so we don't have to evaluate it
|
||||||
|
// unless needed. This is important because sometimes the fallback
|
||||||
|
// creates an object.
|
||||||
|
RET ret;
|
||||||
|
QPDF_ERROR_CODE status = trap_errors(qpdf, [&ret, &fn] (qpdf_data q) {
|
||||||
|
ret = fn(q);
|
||||||
|
});
|
||||||
|
if (status & QPDF_ERRORS)
|
||||||
|
{
|
||||||
|
(*qpdf->oh_error_handler)(
|
||||||
|
qpdf, qpdf_get_error(qpdf), qpdf->oh_error_handler_data);
|
||||||
|
return fallback();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static qpdf_oh
|
static qpdf_oh
|
||||||
new_object(qpdf_data qpdf, QPDFObjectHandle const& qoh)
|
new_object(qpdf_data qpdf, QPDFObjectHandle const& qoh)
|
||||||
{
|
{
|
||||||
@ -867,310 +933,367 @@ void qpdf_oh_release_all(qpdf_data qpdf)
|
|||||||
qpdf->oh_cache.clear();
|
qpdf->oh_cache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
static std::function<T()> return_T(T const& r)
|
||||||
|
{
|
||||||
|
return [&r]() { return r; };
|
||||||
|
}
|
||||||
|
|
||||||
|
static QPDF_BOOL return_false()
|
||||||
|
{
|
||||||
|
return QPDF_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::function<qpdf_oh()> return_uninitialized(qpdf_data qpdf)
|
||||||
|
{
|
||||||
|
return [qpdf]() { return qpdf_oh_new_uninitialized(qpdf); };
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::function<qpdf_oh()> return_null(qpdf_data qpdf)
|
||||||
|
{
|
||||||
|
return [qpdf]() { return qpdf_oh_new_null(qpdf); };
|
||||||
|
}
|
||||||
|
|
||||||
qpdf_oh qpdf_get_trailer(qpdf_data qpdf)
|
qpdf_oh qpdf_get_trailer(qpdf_data qpdf)
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_get_trailer");
|
QTC::TC("qpdf", "qpdf-c called qpdf_get_trailer");
|
||||||
return new_object(qpdf, qpdf->qpdf->getTrailer());
|
return trap_oh_errors<qpdf_oh>(
|
||||||
|
qpdf, return_uninitialized(qpdf), [] (qpdf_data q) {
|
||||||
|
return new_object(q, q->qpdf->getTrailer());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
qpdf_oh qpdf_get_root(qpdf_data qpdf)
|
qpdf_oh qpdf_get_root(qpdf_data qpdf)
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_get_root");
|
QTC::TC("qpdf", "qpdf-c called qpdf_get_root");
|
||||||
return new_object(qpdf, qpdf->qpdf->getRoot());
|
return trap_oh_errors<qpdf_oh>(
|
||||||
|
qpdf, return_uninitialized(qpdf), [] (qpdf_data q) {
|
||||||
|
return new_object(q, q->qpdf->getRoot());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
template<class RET>
|
||||||
qpdf_oh_valid_internal(qpdf_data qpdf, qpdf_oh oh)
|
static RET do_with_oh(
|
||||||
|
qpdf_data qpdf, qpdf_oh oh,
|
||||||
|
std::function<RET()> fallback,
|
||||||
|
std::function<RET(QPDFObjectHandle&)> fn)
|
||||||
{
|
{
|
||||||
auto i = qpdf->oh_cache.find(oh);
|
return trap_oh_errors<RET>(
|
||||||
bool result = ((i != qpdf->oh_cache.end()) &&
|
qpdf, fallback, [&fn, &oh](qpdf_data q) {
|
||||||
(i->second).getPointer());
|
auto i = q->oh_cache.find(oh);
|
||||||
if (! result)
|
bool result = ((i != q->oh_cache.end()) &&
|
||||||
{
|
(i->second).getPointer());
|
||||||
QTC::TC("qpdf", "qpdf-c invalid object handle");
|
if (! result)
|
||||||
qpdf->warnings.push_back(
|
{
|
||||||
QPDFExc(
|
QTC::TC("qpdf", "qpdf-c invalid object handle");
|
||||||
qpdf_e_damaged_pdf,
|
throw QPDFExc(
|
||||||
qpdf->qpdf->getFilename(),
|
qpdf_e_internal,
|
||||||
std::string("C API object handle ") +
|
q->qpdf->getFilename(),
|
||||||
QUtil::uint_to_string(oh),
|
std::string("C API object handle ") +
|
||||||
0, "attempted access to unknown object handle"));
|
QUtil::uint_to_string(oh),
|
||||||
}
|
0, "attempted access to unknown object handle");
|
||||||
return result;
|
}
|
||||||
|
return fn(*(q->oh_cache[oh]));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_with_oh_void(
|
||||||
|
qpdf_data qpdf, qpdf_oh oh,
|
||||||
|
std::function<void(QPDFObjectHandle&)> fn)
|
||||||
|
{
|
||||||
|
do_with_oh<bool>(
|
||||||
|
qpdf, oh, return_T<bool>(false), [&fn](QPDFObjectHandle& o) {
|
||||||
|
fn(o);
|
||||||
|
return true; // unused
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QPDF_BOOL qpdf_oh_is_initialized(qpdf_data qpdf, qpdf_oh oh)
|
QPDF_BOOL qpdf_oh_is_initialized(qpdf_data qpdf, qpdf_oh oh)
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_initialized");
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_initialized");
|
||||||
return (qpdf_oh_valid_internal(qpdf, oh) &&
|
return do_with_oh<QPDF_BOOL>(
|
||||||
qpdf->oh_cache[oh]->isInitialized());
|
qpdf, oh, return_false, [](QPDFObjectHandle& o) {
|
||||||
|
return o.isInitialized();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QPDF_BOOL qpdf_oh_is_bool(qpdf_data qpdf, qpdf_oh oh)
|
QPDF_BOOL qpdf_oh_is_bool(qpdf_data qpdf, qpdf_oh oh)
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_bool");
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_bool");
|
||||||
return (qpdf_oh_valid_internal(qpdf, oh) &&
|
return do_with_oh<QPDF_BOOL>(
|
||||||
qpdf->oh_cache[oh]->isBool());
|
qpdf, oh, return_false, [](QPDFObjectHandle& o) {
|
||||||
|
return o.isBool();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QPDF_BOOL qpdf_oh_is_null(qpdf_data qpdf, qpdf_oh oh)
|
QPDF_BOOL qpdf_oh_is_null(qpdf_data qpdf, qpdf_oh oh)
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_null");
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_null");
|
||||||
return (qpdf_oh_valid_internal(qpdf, oh) &&
|
return do_with_oh<QPDF_BOOL>(
|
||||||
qpdf->oh_cache[oh]->isNull());
|
qpdf, oh, return_false, [](QPDFObjectHandle& o) {
|
||||||
|
return o.isNull();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QPDF_BOOL qpdf_oh_is_integer(qpdf_data qpdf, qpdf_oh oh)
|
QPDF_BOOL qpdf_oh_is_integer(qpdf_data qpdf, qpdf_oh oh)
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_integer");
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_integer");
|
||||||
return (qpdf_oh_valid_internal(qpdf, oh) &&
|
return do_with_oh<QPDF_BOOL>(
|
||||||
qpdf->oh_cache[oh]->isInteger());
|
qpdf, oh, return_false, [](QPDFObjectHandle& o) {
|
||||||
|
return o.isInteger();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QPDF_BOOL qpdf_oh_is_real(qpdf_data qpdf, qpdf_oh oh)
|
QPDF_BOOL qpdf_oh_is_real(qpdf_data qpdf, qpdf_oh oh)
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_real");
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_real");
|
||||||
return (qpdf_oh_valid_internal(qpdf, oh) &&
|
return do_with_oh<QPDF_BOOL>(
|
||||||
qpdf->oh_cache[oh]->isReal());
|
qpdf, oh, return_false, [](QPDFObjectHandle& o) {
|
||||||
|
return o.isReal();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QPDF_BOOL qpdf_oh_is_name(qpdf_data qpdf, qpdf_oh oh)
|
QPDF_BOOL qpdf_oh_is_name(qpdf_data qpdf, qpdf_oh oh)
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_name");
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_name");
|
||||||
return (qpdf_oh_valid_internal(qpdf, oh) &&
|
return do_with_oh<QPDF_BOOL>(
|
||||||
qpdf->oh_cache[oh]->isName());
|
qpdf, oh, return_false, [](QPDFObjectHandle& o) {
|
||||||
|
return o.isName();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QPDF_BOOL qpdf_oh_is_string(qpdf_data qpdf, qpdf_oh oh)
|
QPDF_BOOL qpdf_oh_is_string(qpdf_data qpdf, qpdf_oh oh)
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_string");
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_string");
|
||||||
return (qpdf_oh_valid_internal(qpdf, oh) &&
|
return do_with_oh<QPDF_BOOL>(
|
||||||
qpdf->oh_cache[oh]->isString());
|
qpdf, oh, return_false, [](QPDFObjectHandle& o) {
|
||||||
|
return o.isString();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QPDF_BOOL qpdf_oh_is_operator(qpdf_data qpdf, qpdf_oh oh)
|
QPDF_BOOL qpdf_oh_is_operator(qpdf_data qpdf, qpdf_oh oh)
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_operator");
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_operator");
|
||||||
return (qpdf_oh_valid_internal(qpdf, oh) &&
|
return do_with_oh<QPDF_BOOL>(
|
||||||
qpdf->oh_cache[oh]->isOperator());
|
qpdf, oh, return_false, [](QPDFObjectHandle& o) {
|
||||||
|
return o.isOperator();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QPDF_BOOL qpdf_oh_is_inline_image(qpdf_data qpdf, qpdf_oh oh)
|
QPDF_BOOL qpdf_oh_is_inline_image(qpdf_data qpdf, qpdf_oh oh)
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_inline_image");
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_inline_image");
|
||||||
return (qpdf_oh_valid_internal(qpdf, oh) &&
|
return do_with_oh<QPDF_BOOL>(
|
||||||
qpdf->oh_cache[oh]->isInlineImage());
|
qpdf, oh, return_false, [](QPDFObjectHandle& o) {
|
||||||
|
return o.isInlineImage();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QPDF_BOOL qpdf_oh_is_array(qpdf_data qpdf, qpdf_oh oh)
|
QPDF_BOOL qpdf_oh_is_array(qpdf_data qpdf, qpdf_oh oh)
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_array");
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_array");
|
||||||
return (qpdf_oh_valid_internal(qpdf, oh) &&
|
return do_with_oh<QPDF_BOOL>(
|
||||||
qpdf->oh_cache[oh]->isArray());
|
qpdf, oh, return_false, [](QPDFObjectHandle& o) {
|
||||||
|
return o.isArray();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QPDF_BOOL qpdf_oh_is_dictionary(qpdf_data qpdf, qpdf_oh oh)
|
QPDF_BOOL qpdf_oh_is_dictionary(qpdf_data qpdf, qpdf_oh oh)
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_dictionary");
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_dictionary");
|
||||||
return (qpdf_oh_valid_internal(qpdf, oh) &&
|
return do_with_oh<QPDF_BOOL>(
|
||||||
qpdf->oh_cache[oh]->isDictionary());
|
qpdf, oh, return_false, [](QPDFObjectHandle& o) {
|
||||||
|
return o.isDictionary();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QPDF_BOOL qpdf_oh_is_stream(qpdf_data qpdf, qpdf_oh oh)
|
QPDF_BOOL qpdf_oh_is_stream(qpdf_data qpdf, qpdf_oh oh)
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_stream");
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_stream");
|
||||||
return (qpdf_oh_valid_internal(qpdf, oh) &&
|
return do_with_oh<QPDF_BOOL>(
|
||||||
qpdf->oh_cache[oh]->isStream());
|
qpdf, oh, return_false, [](QPDFObjectHandle& o) {
|
||||||
|
return o.isStream();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QPDF_BOOL qpdf_oh_is_indirect(qpdf_data qpdf, qpdf_oh oh)
|
QPDF_BOOL qpdf_oh_is_indirect(qpdf_data qpdf, qpdf_oh oh)
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_indirect");
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_indirect");
|
||||||
return (qpdf_oh_valid_internal(qpdf, oh) &&
|
return do_with_oh<QPDF_BOOL>(
|
||||||
qpdf->oh_cache[oh]->isIndirect());
|
qpdf, oh, return_false, [](QPDFObjectHandle& o) {
|
||||||
|
return o.isIndirect();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QPDF_BOOL qpdf_oh_is_scalar(qpdf_data qpdf, qpdf_oh oh)
|
QPDF_BOOL qpdf_oh_is_scalar(qpdf_data qpdf, qpdf_oh oh)
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_scalar");
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_scalar");
|
||||||
return (qpdf_oh_valid_internal(qpdf, oh) &&
|
return do_with_oh<QPDF_BOOL>(
|
||||||
qpdf->oh_cache[oh]->isScalar());
|
qpdf, oh, return_false, [](QPDFObjectHandle& o) {
|
||||||
|
return o.isScalar();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QPDF_BOOL qpdf_oh_is_number(qpdf_data qpdf, qpdf_oh oh)
|
||||||
|
{
|
||||||
|
return do_with_oh<QPDF_BOOL>(
|
||||||
|
qpdf, oh, return_false, [](QPDFObjectHandle& o) {
|
||||||
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_number");
|
||||||
|
return o.isNumber();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
qpdf_oh qpdf_oh_wrap_in_array(qpdf_data qpdf, qpdf_oh oh)
|
qpdf_oh qpdf_oh_wrap_in_array(qpdf_data qpdf, qpdf_oh oh)
|
||||||
{
|
{
|
||||||
if (! qpdf_oh_valid_internal(qpdf, oh))
|
return do_with_oh<qpdf_oh>(
|
||||||
{
|
qpdf, oh,
|
||||||
return qpdf_oh_new_array(qpdf);
|
[&qpdf](){ return qpdf_oh_new_array(qpdf); },
|
||||||
}
|
[&qpdf](QPDFObjectHandle& qoh) {
|
||||||
auto qoh = qpdf->oh_cache[oh];
|
if (qoh.isArray())
|
||||||
if (qoh->isArray())
|
{
|
||||||
{
|
QTC::TC("qpdf", "qpdf-c array to wrap_in_array");
|
||||||
QTC::TC("qpdf", "qpdf-c array to wrap_in_array");
|
return new_object(qpdf, qoh);
|
||||||
return new_object(qpdf, *qoh);
|
}
|
||||||
}
|
else
|
||||||
else
|
{
|
||||||
{
|
QTC::TC("qpdf", "qpdf-c non-array to wrap_in_array");
|
||||||
QTC::TC("qpdf", "qpdf-c non-array to wrap_in_array");
|
return new_object(qpdf,
|
||||||
return new_object(qpdf,
|
QPDFObjectHandle::newArray(
|
||||||
QPDFObjectHandle::newArray(
|
std::vector<QPDFObjectHandle>{qoh}));
|
||||||
std::vector<QPDFObjectHandle>{
|
}
|
||||||
*qpdf->oh_cache[oh]}));
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qpdf_oh qpdf_oh_parse(qpdf_data qpdf, char const* object_str)
|
qpdf_oh qpdf_oh_parse(qpdf_data qpdf, char const* object_str)
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_parse");
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_parse");
|
||||||
return new_object(qpdf, QPDFObjectHandle::parse(object_str));
|
return trap_oh_errors<qpdf_oh>(
|
||||||
|
qpdf, return_uninitialized(qpdf), [&object_str] (qpdf_data q) {
|
||||||
|
return new_object(q, QPDFObjectHandle::parse(object_str));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QPDF_BOOL qpdf_oh_get_bool_value(qpdf_data qpdf, qpdf_oh oh)
|
QPDF_BOOL qpdf_oh_get_bool_value(qpdf_data qpdf, qpdf_oh oh)
|
||||||
{
|
{
|
||||||
if (! qpdf_oh_valid_internal(qpdf, oh))
|
return do_with_oh<QPDF_BOOL>(
|
||||||
{
|
qpdf, oh, return_false, [](QPDFObjectHandle& o) {
|
||||||
return QPDF_FALSE;
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_bool_value");
|
||||||
}
|
return o.getBoolValue();
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_bool_value");
|
});
|
||||||
return qpdf->oh_cache[oh]->getBoolValue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
long long qpdf_oh_get_int_value(qpdf_data qpdf, qpdf_oh oh)
|
long long qpdf_oh_get_int_value(qpdf_data qpdf, qpdf_oh oh)
|
||||||
{
|
{
|
||||||
if (! qpdf_oh_valid_internal(qpdf, oh))
|
return do_with_oh<long long>(
|
||||||
{
|
qpdf, oh, return_T<long long>(0LL), [](QPDFObjectHandle& o) {
|
||||||
return 0LL;
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_int_value");
|
||||||
}
|
return o.getIntValue();
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_int_value");
|
});
|
||||||
return qpdf->oh_cache[oh]->getIntValue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int qpdf_oh_get_int_value_as_int(qpdf_data qpdf, qpdf_oh oh)
|
int qpdf_oh_get_int_value_as_int(qpdf_data qpdf, qpdf_oh oh)
|
||||||
{
|
{
|
||||||
if (! qpdf_oh_valid_internal(qpdf, oh))
|
return do_with_oh<int>(
|
||||||
{
|
qpdf, oh, return_T<int>(0), [](QPDFObjectHandle& o) {
|
||||||
return 0;
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_int_value_as_int");
|
||||||
}
|
return o.getIntValueAsInt();
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_int_value_as_int");
|
});
|
||||||
return qpdf->oh_cache[oh]->getIntValueAsInt();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long long qpdf_oh_get_uint_value(qpdf_data qpdf, qpdf_oh oh)
|
unsigned long long qpdf_oh_get_uint_value(qpdf_data qpdf, qpdf_oh oh)
|
||||||
{
|
{
|
||||||
if (! qpdf_oh_valid_internal(qpdf, oh))
|
return do_with_oh<unsigned long long>(
|
||||||
{
|
qpdf, oh, return_T<unsigned long long>(0ULL), [](QPDFObjectHandle& o) {
|
||||||
return 0ULL;
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_uint_value");
|
||||||
}
|
return o.getUIntValue();
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_uint_value");
|
});
|
||||||
return qpdf->oh_cache[oh]->getUIntValue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int qpdf_oh_get_uint_value_as_uint(qpdf_data qpdf, qpdf_oh oh)
|
unsigned int qpdf_oh_get_uint_value_as_uint(qpdf_data qpdf, qpdf_oh oh)
|
||||||
{
|
{
|
||||||
if (! qpdf_oh_valid_internal(qpdf, oh))
|
return do_with_oh<unsigned int>(
|
||||||
{
|
qpdf, oh, return_T<unsigned int>(0U), [](QPDFObjectHandle& o) {
|
||||||
return 0U;
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_uint_value_as_uint");
|
||||||
}
|
return o.getUIntValueAsUInt();
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_uint_value_as_uint");
|
});
|
||||||
return qpdf->oh_cache[oh]->getUIntValueAsUInt();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char const* qpdf_oh_get_real_value(qpdf_data qpdf, qpdf_oh oh)
|
char const* qpdf_oh_get_real_value(qpdf_data qpdf, qpdf_oh oh)
|
||||||
{
|
{
|
||||||
if (! qpdf_oh_valid_internal(qpdf, oh))
|
return do_with_oh<char const*>(
|
||||||
{
|
qpdf, oh, return_T<char const*>(""), [&qpdf](QPDFObjectHandle& o) {
|
||||||
return "";
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_real_value");
|
||||||
}
|
qpdf->tmp_string = o.getRealValue();
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_real_value");
|
return qpdf->tmp_string.c_str();
|
||||||
qpdf->tmp_string = qpdf->oh_cache[oh]->getRealValue();
|
});
|
||||||
return qpdf->tmp_string.c_str();
|
|
||||||
}
|
|
||||||
|
|
||||||
QPDF_BOOL qpdf_oh_is_number(qpdf_data qpdf, qpdf_oh oh)
|
|
||||||
{
|
|
||||||
if (! qpdf_oh_valid_internal(qpdf, oh))
|
|
||||||
{
|
|
||||||
return QPDF_FALSE;
|
|
||||||
}
|
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_number");
|
|
||||||
return qpdf->oh_cache[oh]->isNumber();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double qpdf_oh_get_numeric_value(qpdf_data qpdf, qpdf_oh oh)
|
double qpdf_oh_get_numeric_value(qpdf_data qpdf, qpdf_oh oh)
|
||||||
{
|
{
|
||||||
if (! qpdf_oh_valid_internal(qpdf, oh))
|
return do_with_oh<double>(
|
||||||
{
|
qpdf, oh, return_T<double>(0.0), [](QPDFObjectHandle& o) {
|
||||||
return 0.0;
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_numeric_value");
|
||||||
}
|
return o.getNumericValue();
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_numeric_value");
|
});
|
||||||
return qpdf->oh_cache[oh]->getNumericValue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char const* qpdf_oh_get_name(qpdf_data qpdf, qpdf_oh oh)
|
char const* qpdf_oh_get_name(qpdf_data qpdf, qpdf_oh oh)
|
||||||
{
|
{
|
||||||
if (! qpdf_oh_valid_internal(qpdf, oh))
|
return do_with_oh<char const*>(
|
||||||
{
|
qpdf, oh, return_T<char const*>(""), [&qpdf](QPDFObjectHandle& o) {
|
||||||
return "";
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_name");
|
||||||
}
|
qpdf->tmp_string = o.getName();
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_name");
|
return qpdf->tmp_string.c_str();
|
||||||
qpdf->tmp_string = qpdf->oh_cache[oh]->getName();
|
});
|
||||||
return qpdf->tmp_string.c_str();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char const* qpdf_oh_get_string_value(qpdf_data qpdf, qpdf_oh oh)
|
char const* qpdf_oh_get_string_value(qpdf_data qpdf, qpdf_oh oh)
|
||||||
{
|
{
|
||||||
if (! qpdf_oh_valid_internal(qpdf, oh))
|
return do_with_oh<char const*>(
|
||||||
{
|
qpdf, oh, return_T<char const*>(""), [&qpdf](QPDFObjectHandle& o) {
|
||||||
return "";
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_string_value");
|
||||||
}
|
qpdf->tmp_string = o.getStringValue();
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_string_value");
|
return qpdf->tmp_string.c_str();
|
||||||
qpdf->tmp_string = qpdf->oh_cache[oh]->getStringValue();
|
});
|
||||||
return qpdf->tmp_string.c_str();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char const* qpdf_oh_get_utf8_value(qpdf_data qpdf, qpdf_oh oh)
|
char const* qpdf_oh_get_utf8_value(qpdf_data qpdf, qpdf_oh oh)
|
||||||
{
|
{
|
||||||
if (! qpdf_oh_valid_internal(qpdf, oh))
|
return do_with_oh<char const*>(
|
||||||
{
|
qpdf, oh, return_T<char const*>(""), [&qpdf](QPDFObjectHandle& o) {
|
||||||
return "";
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_utf8_value");
|
||||||
}
|
qpdf->tmp_string = o.getUTF8Value();
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_utf8_value");
|
return qpdf->tmp_string.c_str();
|
||||||
qpdf->tmp_string = qpdf->oh_cache[oh]->getUTF8Value();
|
});
|
||||||
return qpdf->tmp_string.c_str();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int qpdf_oh_get_array_n_items(qpdf_data qpdf, qpdf_oh oh)
|
int qpdf_oh_get_array_n_items(qpdf_data qpdf, qpdf_oh oh)
|
||||||
{
|
{
|
||||||
if (! qpdf_oh_valid_internal(qpdf, oh))
|
return do_with_oh<int>(
|
||||||
{
|
qpdf, oh, return_T<int>(0), [](QPDFObjectHandle& o) {
|
||||||
return 0;
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_array_n_items");
|
||||||
}
|
return o.getArrayNItems();
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_array_n_items");
|
});
|
||||||
return qpdf->oh_cache[oh]->getArrayNItems();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qpdf_oh qpdf_oh_get_array_item(qpdf_data qpdf, qpdf_oh oh, int n)
|
qpdf_oh qpdf_oh_get_array_item(qpdf_data qpdf, qpdf_oh oh, int n)
|
||||||
{
|
{
|
||||||
if (! qpdf_oh_valid_internal(qpdf, oh))
|
return do_with_oh<qpdf_oh>(
|
||||||
{
|
qpdf, oh, return_null(qpdf), [&qpdf, &n](QPDFObjectHandle& o) {
|
||||||
return qpdf_oh_new_null(qpdf);
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_array_item");
|
||||||
}
|
return new_object(qpdf, o.getArrayItem(n));
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_array_item");
|
});
|
||||||
return new_object(qpdf, qpdf->oh_cache[oh]->getArrayItem(n));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void qpdf_oh_begin_dict_key_iter(qpdf_data qpdf, qpdf_oh oh)
|
void qpdf_oh_begin_dict_key_iter(qpdf_data qpdf, qpdf_oh oh)
|
||||||
{
|
{
|
||||||
if (qpdf_oh_valid_internal(qpdf, oh) &&
|
qpdf->cur_iter_dict_keys = do_with_oh<std::set<std::string>>(
|
||||||
qpdf_oh_is_dictionary(qpdf, oh))
|
qpdf, oh,
|
||||||
{
|
[](){ return std::set<std::string>(); },
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_begin_dict_key_iter");
|
[](QPDFObjectHandle& o) {
|
||||||
qpdf->cur_iter_dict_keys = qpdf->oh_cache[oh]->getKeys();
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_begin_dict_key_iter");
|
||||||
}
|
return o.getKeys();
|
||||||
else
|
});
|
||||||
{
|
|
||||||
qpdf->cur_iter_dict_keys = {};
|
|
||||||
}
|
|
||||||
qpdf->dict_iter = qpdf->cur_iter_dict_keys.begin();
|
qpdf->dict_iter = qpdf->cur_iter_dict_keys.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1197,32 +1320,35 @@ char const* qpdf_oh_dict_next_key(qpdf_data qpdf)
|
|||||||
|
|
||||||
QPDF_BOOL qpdf_oh_has_key(qpdf_data qpdf, qpdf_oh oh, char const* key)
|
QPDF_BOOL qpdf_oh_has_key(qpdf_data qpdf, qpdf_oh oh, char const* key)
|
||||||
{
|
{
|
||||||
if (! qpdf_oh_valid_internal(qpdf, oh))
|
return do_with_oh<QPDF_BOOL>(
|
||||||
{
|
qpdf, oh, return_false, [&key](QPDFObjectHandle& o) {
|
||||||
return QPDF_FALSE;
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_has_key");
|
||||||
}
|
return o.hasKey(key);
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_has_key");
|
});
|
||||||
return qpdf->oh_cache[oh]->hasKey(key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qpdf_oh qpdf_oh_get_key(qpdf_data qpdf, qpdf_oh oh, char const* key)
|
qpdf_oh qpdf_oh_get_key(qpdf_data qpdf, qpdf_oh oh, char const* key)
|
||||||
{
|
{
|
||||||
if (! qpdf_oh_valid_internal(qpdf, oh))
|
return do_with_oh<qpdf_oh>(
|
||||||
{
|
qpdf, oh, return_null(qpdf), [&qpdf, &key](QPDFObjectHandle& o) {
|
||||||
return qpdf_oh_new_null(qpdf);
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_key");
|
||||||
}
|
return new_object(qpdf, o.getKey(key));
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_key");
|
});
|
||||||
return new_object(qpdf, qpdf->oh_cache[oh]->getKey(key));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QPDF_BOOL qpdf_oh_is_or_has_name(qpdf_data qpdf, qpdf_oh oh, char const* key)
|
QPDF_BOOL qpdf_oh_is_or_has_name(qpdf_data qpdf, qpdf_oh oh, char const* key)
|
||||||
{
|
{
|
||||||
if (! qpdf_oh_valid_internal(qpdf, oh))
|
return do_with_oh<QPDF_BOOL>(
|
||||||
{
|
qpdf, oh, return_false, [&key](QPDFObjectHandle& o) {
|
||||||
return QPDF_FALSE;
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_or_has_name");
|
||||||
}
|
return o.isOrHasName(key);
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_or_has_name");
|
});
|
||||||
return qpdf->oh_cache[oh]->isOrHasName(key);
|
}
|
||||||
|
|
||||||
|
qpdf_oh qpdf_oh_new_uninitialized(qpdf_data qpdf)
|
||||||
|
{
|
||||||
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_new_uninitialized");
|
||||||
|
return new_object(qpdf, QPDFObjectHandle());
|
||||||
}
|
}
|
||||||
|
|
||||||
qpdf_oh qpdf_oh_new_null(qpdf_data qpdf)
|
qpdf_oh qpdf_oh_new_null(qpdf_data qpdf)
|
||||||
@ -1288,156 +1414,143 @@ qpdf_oh qpdf_oh_new_dictionary(qpdf_data qpdf)
|
|||||||
|
|
||||||
void qpdf_oh_make_direct(qpdf_data qpdf, qpdf_oh oh)
|
void qpdf_oh_make_direct(qpdf_data qpdf, qpdf_oh oh)
|
||||||
{
|
{
|
||||||
if (qpdf_oh_valid_internal(qpdf, oh))
|
do_with_oh_void(
|
||||||
{
|
qpdf, oh, [](QPDFObjectHandle& o) {
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_make_direct");
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_make_direct");
|
||||||
qpdf->oh_cache[oh]->makeDirect();
|
o.makeDirect();
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static QPDFObjectHandle
|
static QPDFObjectHandle
|
||||||
qpdf_oh_item_internal(qpdf_data qpdf, qpdf_oh item)
|
qpdf_oh_item_internal(qpdf_data qpdf, qpdf_oh item)
|
||||||
{
|
{
|
||||||
if (qpdf_oh_valid_internal(qpdf, item))
|
return do_with_oh<QPDFObjectHandle>(
|
||||||
{
|
qpdf, item,
|
||||||
return *(qpdf->oh_cache[item]);
|
[](){return QPDFObjectHandle::newNull();},
|
||||||
}
|
[](QPDFObjectHandle& o) {
|
||||||
else
|
return o;
|
||||||
{
|
});
|
||||||
return QPDFObjectHandle::newNull();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void qpdf_oh_set_array_item(qpdf_data qpdf, qpdf_oh oh,
|
void qpdf_oh_set_array_item(qpdf_data qpdf, qpdf_oh oh,
|
||||||
int at, qpdf_oh item)
|
int at, qpdf_oh item)
|
||||||
{
|
{
|
||||||
if (qpdf_oh_is_array(qpdf, oh))
|
do_with_oh_void(
|
||||||
{
|
qpdf, oh, [&qpdf, &at, &item](QPDFObjectHandle& o) {
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_set_array_item");
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_set_array_item");
|
||||||
qpdf->oh_cache[oh]->setArrayItem(
|
o.setArrayItem(at, qpdf_oh_item_internal(qpdf, item));
|
||||||
at, qpdf_oh_item_internal(qpdf, item));
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void qpdf_oh_insert_item(qpdf_data qpdf, qpdf_oh oh, int at, qpdf_oh item)
|
void qpdf_oh_insert_item(qpdf_data qpdf, qpdf_oh oh, int at, qpdf_oh item)
|
||||||
{
|
{
|
||||||
if (qpdf_oh_is_array(qpdf, oh))
|
do_with_oh_void(
|
||||||
{
|
qpdf, oh, [&qpdf, &at, &item](QPDFObjectHandle& o) {
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_insert_item");
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_insert_item");
|
||||||
qpdf->oh_cache[oh]->insertItem(
|
o.insertItem(at, qpdf_oh_item_internal(qpdf, item));
|
||||||
at, qpdf_oh_item_internal(qpdf, item));
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void qpdf_oh_append_item(qpdf_data qpdf, qpdf_oh oh, qpdf_oh item)
|
void qpdf_oh_append_item(qpdf_data qpdf, qpdf_oh oh, qpdf_oh item)
|
||||||
{
|
{
|
||||||
if (qpdf_oh_is_array(qpdf, oh))
|
do_with_oh_void(
|
||||||
{
|
qpdf, oh, [&qpdf, &item](QPDFObjectHandle& o) {
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_append_item");
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_append_item");
|
||||||
qpdf->oh_cache[oh]->appendItem(
|
o.appendItem(qpdf_oh_item_internal(qpdf, item));
|
||||||
qpdf_oh_item_internal(qpdf, item));
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void qpdf_oh_erase_item(qpdf_data qpdf, qpdf_oh oh, int at)
|
void qpdf_oh_erase_item(qpdf_data qpdf, qpdf_oh oh, int at)
|
||||||
{
|
{
|
||||||
if (qpdf_oh_is_array(qpdf, oh))
|
do_with_oh_void(
|
||||||
{
|
qpdf, oh, [&at](QPDFObjectHandle& o) {
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_erase_item");
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_erase_item");
|
||||||
qpdf->oh_cache[oh]->eraseItem(at);
|
o.eraseItem(at);
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void qpdf_oh_replace_key(qpdf_data qpdf, qpdf_oh oh,
|
void qpdf_oh_replace_key(qpdf_data qpdf, qpdf_oh oh,
|
||||||
char const* key, qpdf_oh item)
|
char const* key, qpdf_oh item)
|
||||||
{
|
{
|
||||||
if (qpdf_oh_is_dictionary(qpdf, oh))
|
do_with_oh_void(
|
||||||
{
|
qpdf, oh, [&qpdf, &key, &item](QPDFObjectHandle& o) {
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_replace_key");
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_replace_key");
|
||||||
qpdf->oh_cache[oh]->replaceKey(
|
o.replaceKey(key, qpdf_oh_item_internal(qpdf, item));
|
||||||
key, qpdf_oh_item_internal(qpdf, item));
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void qpdf_oh_remove_key(qpdf_data qpdf, qpdf_oh oh, char const* key)
|
void qpdf_oh_remove_key(qpdf_data qpdf, qpdf_oh oh, char const* key)
|
||||||
{
|
{
|
||||||
if (qpdf_oh_is_dictionary(qpdf, oh))
|
do_with_oh_void(
|
||||||
{
|
qpdf, oh, [&key](QPDFObjectHandle& o) {
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_remove_key");
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_remove_key");
|
||||||
qpdf->oh_cache[oh]->removeKey(key);
|
o.removeKey(key);
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void qpdf_oh_replace_or_remove_key(qpdf_data qpdf, qpdf_oh oh,
|
void qpdf_oh_replace_or_remove_key(qpdf_data qpdf, qpdf_oh oh,
|
||||||
char const* key, qpdf_oh item)
|
char const* key, qpdf_oh item)
|
||||||
{
|
{
|
||||||
if (qpdf_oh_is_dictionary(qpdf, oh))
|
do_with_oh_void(
|
||||||
{
|
qpdf, oh, [&qpdf, &key, &item](QPDFObjectHandle& o) {
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_replace_or_remove_key");
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_replace_or_remove_key");
|
||||||
qpdf->oh_cache[oh]->replaceOrRemoveKey(
|
o.replaceOrRemoveKey(key, qpdf_oh_item_internal(qpdf, item));
|
||||||
key, qpdf_oh_item_internal(qpdf, item));
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qpdf_oh qpdf_oh_get_dict(qpdf_data qpdf, qpdf_oh oh)
|
qpdf_oh qpdf_oh_get_dict(qpdf_data qpdf, qpdf_oh oh)
|
||||||
{
|
{
|
||||||
if (! qpdf_oh_valid_internal(qpdf, oh))
|
return do_with_oh<qpdf_oh>(
|
||||||
{
|
qpdf, oh, return_null(qpdf), [&qpdf](QPDFObjectHandle& o) {
|
||||||
return qpdf_oh_new_null(qpdf);
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_dict");
|
||||||
}
|
return new_object(qpdf, o.getDict());
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_dict");
|
});
|
||||||
return new_object(qpdf, qpdf->oh_cache[oh]->getDict());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int qpdf_oh_get_object_id(qpdf_data qpdf, qpdf_oh oh)
|
int qpdf_oh_get_object_id(qpdf_data qpdf, qpdf_oh oh)
|
||||||
{
|
{
|
||||||
if (! qpdf_oh_valid_internal(qpdf, oh))
|
return do_with_oh<int>(
|
||||||
{
|
qpdf, oh, return_T<int>(0), [](QPDFObjectHandle& o) {
|
||||||
return 0;
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_object_id");
|
||||||
}
|
return o.getObjectID();
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_object_id");
|
});
|
||||||
return qpdf->oh_cache[oh]->getObjectID();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int qpdf_oh_get_generation(qpdf_data qpdf, qpdf_oh oh)
|
int qpdf_oh_get_generation(qpdf_data qpdf, qpdf_oh oh)
|
||||||
{
|
{
|
||||||
if (! qpdf_oh_valid_internal(qpdf, oh))
|
return do_with_oh<int>(
|
||||||
{
|
qpdf, oh, return_T<int>(0), [](QPDFObjectHandle& o) {
|
||||||
return 0;
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_generation");
|
||||||
}
|
return o.getGeneration();
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_generation");
|
});
|
||||||
return qpdf->oh_cache[oh]->getGeneration();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char const* qpdf_oh_unparse(qpdf_data qpdf, qpdf_oh oh)
|
char const* qpdf_oh_unparse(qpdf_data qpdf, qpdf_oh oh)
|
||||||
{
|
{
|
||||||
if (! qpdf_oh_valid_internal(qpdf, oh))
|
return do_with_oh<char const*>(
|
||||||
{
|
qpdf, oh, return_T<char const*>(""), [&qpdf](QPDFObjectHandle& o) {
|
||||||
return "";
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_unparse");
|
||||||
}
|
qpdf->tmp_string = o.unparse();
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_unparse");
|
return qpdf->tmp_string.c_str();
|
||||||
qpdf->tmp_string = qpdf->oh_cache[oh]->unparse();
|
});
|
||||||
return qpdf->tmp_string.c_str();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char const* qpdf_oh_unparse_resolved(qpdf_data qpdf, qpdf_oh oh)
|
char const* qpdf_oh_unparse_resolved(qpdf_data qpdf, qpdf_oh oh)
|
||||||
{
|
{
|
||||||
if (! qpdf_oh_valid_internal(qpdf, oh))
|
return do_with_oh<char const*>(
|
||||||
{
|
qpdf, oh, return_T<char const*>(""), [&qpdf](QPDFObjectHandle& o) {
|
||||||
return "";
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_unparse_resolved");
|
||||||
}
|
qpdf->tmp_string = o.unparseResolved();
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_unparse_resolved");
|
return qpdf->tmp_string.c_str();
|
||||||
qpdf->tmp_string = qpdf->oh_cache[oh]->unparseResolved();
|
});
|
||||||
return qpdf->tmp_string.c_str();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char const* qpdf_oh_unparse_binary(qpdf_data qpdf, qpdf_oh oh)
|
char const* qpdf_oh_unparse_binary(qpdf_data qpdf, qpdf_oh oh)
|
||||||
{
|
{
|
||||||
if (! qpdf_oh_valid_internal(qpdf, oh))
|
return do_with_oh<char const*>(
|
||||||
{
|
qpdf, oh, return_T<char const*>(""), [&qpdf](QPDFObjectHandle& o) {
|
||||||
return "";
|
QTC::TC("qpdf", "qpdf-c called qpdf_oh_unparse_binary");
|
||||||
}
|
qpdf->tmp_string = o.unparseBinary();
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_unparse_binary");
|
return qpdf->tmp_string.c_str();
|
||||||
qpdf->tmp_string = qpdf->oh_cache[oh]->unparseBinary();
|
});
|
||||||
return qpdf->tmp_string.c_str();
|
|
||||||
}
|
}
|
||||||
|
@ -5229,6 +5229,19 @@ print "\n";
|
|||||||
discussion.
|
discussion.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Overhaul error handling for the object handle functions in
|
||||||
|
the C API. See comments in the “Object handling”
|
||||||
|
section of <filename>include/qpdf/qpdf-c.h</filename> for
|
||||||
|
details. In particular, exceptions thrown by the underlying
|
||||||
|
C++ code when calling object accessors are caught and
|
||||||
|
converted into errors. The errors can be trapped by
|
||||||
|
registering an error handler with
|
||||||
|
<function>qpdf_register_oh_error_handler</function> or will
|
||||||
|
be written to stderr if no handler is registered.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
Add <function>qpdf_get_last_string_length</function> to the
|
Add <function>qpdf_get_last_string_length</function> to the
|
||||||
@ -5239,9 +5252,9 @@ print "\n";
|
|||||||
</listitem>
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
Add <function>qpdf_oh_is_initialized</function> to the
|
Add <function>qpdf_oh_is_initialized</function> and
|
||||||
C API. While you can't directly create uninitialized objects
|
<function>qpdf_oh_new_uninitialized</function> to the C API
|
||||||
from the C API, you still have to be able to detect them.
|
to make it possible to work with uninitialized objects.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
|
@ -35,28 +35,29 @@ static FILE* safe_fopen(char const* filename, char const* mode)
|
|||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void report_errors()
|
static void print_error(char const* label, qpdf_data qpdf, qpdf_error e)
|
||||||
{
|
{
|
||||||
#define POS_FMT " pos : " LL_FMT "\n"
|
#define POS_FMT " pos : " LL_FMT "\n"
|
||||||
|
printf("%s: %s\n", label, qpdf_get_error_full_text(qpdf, e));
|
||||||
|
printf(" code: %d\n", qpdf_get_error_code(qpdf, e));
|
||||||
|
printf(" file: %s\n", qpdf_get_error_filename(qpdf, e));
|
||||||
|
printf(POS_FMT, qpdf_get_error_file_position(qpdf, e));
|
||||||
|
printf(" text: %s\n", qpdf_get_error_message_detail(qpdf, e));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void report_errors()
|
||||||
|
{
|
||||||
qpdf_error e = 0;
|
qpdf_error e = 0;
|
||||||
while (qpdf_more_warnings(qpdf))
|
while (qpdf_more_warnings(qpdf))
|
||||||
{
|
{
|
||||||
e = qpdf_next_warning(qpdf);
|
e = qpdf_next_warning(qpdf);
|
||||||
printf("warning: %s\n", qpdf_get_error_full_text(qpdf, e));
|
print_error("warning", qpdf, e);
|
||||||
printf(" code: %d\n", qpdf_get_error_code(qpdf, e));
|
|
||||||
printf(" file: %s\n", qpdf_get_error_filename(qpdf, e));
|
|
||||||
printf(POS_FMT, qpdf_get_error_file_position(qpdf, e));
|
|
||||||
printf(" text: %s\n", qpdf_get_error_message_detail(qpdf, e));
|
|
||||||
}
|
}
|
||||||
if (qpdf_has_error(qpdf))
|
if (qpdf_has_error(qpdf))
|
||||||
{
|
{
|
||||||
e = qpdf_get_error(qpdf);
|
e = qpdf_get_error(qpdf);
|
||||||
assert(qpdf_has_error(qpdf) == QPDF_FALSE);
|
assert(qpdf_has_error(qpdf) == QPDF_FALSE);
|
||||||
printf("error: %s\n", qpdf_get_error_full_text(qpdf, e));
|
print_error("error", qpdf, e);
|
||||||
printf(" code: %d\n", qpdf_get_error_code(qpdf, e));
|
|
||||||
printf(" file: %s\n", qpdf_get_error_filename(qpdf, e));
|
|
||||||
printf(POS_FMT, qpdf_get_error_file_position(qpdf, e));
|
|
||||||
printf(" text: %s\n", qpdf_get_error_message_detail(qpdf, e));
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -72,6 +73,16 @@ static void report_errors()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_oh_error(qpdf_data qpdf, qpdf_error error, void* data)
|
||||||
|
{
|
||||||
|
char const* label = "oh error";
|
||||||
|
if (data)
|
||||||
|
{
|
||||||
|
label = *((char const**)data);
|
||||||
|
}
|
||||||
|
print_error(label, qpdf, error);
|
||||||
|
}
|
||||||
|
|
||||||
static void read_file_into_memory(char const* filename,
|
static void read_file_into_memory(char const* filename,
|
||||||
char** buf, unsigned long* size)
|
char** buf, unsigned long* size)
|
||||||
{
|
{
|
||||||
@ -615,8 +626,11 @@ static void test24(char const* infile,
|
|||||||
*/
|
*/
|
||||||
qpdf_oh_replace_key(qpdf, resources, "/ProcSet", procset);
|
qpdf_oh_replace_key(qpdf, resources, "/ProcSet", procset);
|
||||||
|
|
||||||
/* Release and access to exercise warnings and to show that write
|
/* Release and access to exercise handling of object handle errors
|
||||||
* still works after releasing.
|
* and to show that write still works after releasing. This test
|
||||||
|
* uses the default oh error handler, so messages get written to
|
||||||
|
* stderr. The warning about using the default error handler only
|
||||||
|
* appears once.
|
||||||
*/
|
*/
|
||||||
qpdf_oh_release(qpdf, page1);
|
qpdf_oh_release(qpdf, page1);
|
||||||
contents = qpdf_oh_get_key(qpdf, page1, "/Contents");
|
contents = qpdf_oh_get_key(qpdf, page1, "/Contents");
|
||||||
@ -791,6 +805,82 @@ static void test28(char const* infile,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test29(char const* infile,
|
||||||
|
char const* password,
|
||||||
|
char const* outfile,
|
||||||
|
char const* outfile2)
|
||||||
|
{
|
||||||
|
/* Trap exceptions thrown by object accessors. Type mismatches are
|
||||||
|
* errors rather than warnings when they don't have an owning QPDF
|
||||||
|
* object.
|
||||||
|
*/
|
||||||
|
char const* label = "oh error";
|
||||||
|
qpdf_register_oh_error_handler(qpdf, handle_oh_error, (void*)&label);
|
||||||
|
|
||||||
|
/* get_root fails when we have no trailer */
|
||||||
|
label = "get root";
|
||||||
|
qpdf_oh root = qpdf_get_root(qpdf);
|
||||||
|
assert(root != 0);
|
||||||
|
assert(! qpdf_oh_is_initialized(qpdf, root));
|
||||||
|
|
||||||
|
label = "bad parse";
|
||||||
|
assert(! qpdf_oh_is_initialized(qpdf, qpdf_oh_parse(qpdf, "[oops")));
|
||||||
|
report_errors();
|
||||||
|
|
||||||
|
label = "type mismatch";
|
||||||
|
assert(qpdf_oh_get_int_value_as_int(
|
||||||
|
qpdf, qpdf_oh_new_string(qpdf, "x")) == 0);
|
||||||
|
qpdf_oh int_oh = qpdf_oh_new_integer(qpdf, 12);
|
||||||
|
assert(strlen(qpdf_oh_get_string_value(qpdf, int_oh)) == 0);
|
||||||
|
|
||||||
|
// This doesn't test every possible error flow, but it tests each
|
||||||
|
// way of handling errors in the library code.
|
||||||
|
label = "array type mismatch";
|
||||||
|
assert(qpdf_oh_get_array_n_items(qpdf, int_oh) == 0);
|
||||||
|
assert(qpdf_oh_is_null(qpdf, qpdf_oh_get_array_item(qpdf, int_oh, 3)));
|
||||||
|
label = "append to non-array";
|
||||||
|
qpdf_oh_append_item(qpdf, int_oh, qpdf_oh_new_null(qpdf));
|
||||||
|
qpdf_oh array = qpdf_oh_new_array(qpdf);
|
||||||
|
label = "array bounds";
|
||||||
|
assert(qpdf_oh_is_null(qpdf, qpdf_oh_get_array_item(qpdf, array, 3)));
|
||||||
|
|
||||||
|
label = "dictionary iter type mismatch";
|
||||||
|
qpdf_oh_begin_dict_key_iter(qpdf, int_oh);
|
||||||
|
assert(qpdf_oh_dict_more_keys(qpdf) == QPDF_FALSE);
|
||||||
|
label = "dictionary type mismatch";
|
||||||
|
assert(qpdf_oh_is_null(qpdf, qpdf_oh_get_key(qpdf, int_oh, "potato")));
|
||||||
|
assert(qpdf_oh_has_key(qpdf, int_oh, "potato") == QPDF_FALSE);
|
||||||
|
|
||||||
|
report_errors();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test30(char const* infile,
|
||||||
|
char const* password,
|
||||||
|
char const* outfile,
|
||||||
|
char const* outfile2)
|
||||||
|
{
|
||||||
|
assert(qpdf_read(qpdf, infile, password) & QPDF_ERRORS);
|
||||||
|
/* Fail to handle error */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test31(char const* infile,
|
||||||
|
char const* password,
|
||||||
|
char const* outfile,
|
||||||
|
char const* outfile2)
|
||||||
|
{
|
||||||
|
/* Make sure type warnings have a specific error code. This test
|
||||||
|
* case is designed for minimal.pdf.
|
||||||
|
*/
|
||||||
|
qpdf_read(qpdf, infile, password);
|
||||||
|
qpdf_oh trailer = qpdf_get_trailer(qpdf);
|
||||||
|
assert(qpdf_oh_get_int_value(qpdf, trailer) == 0LL);
|
||||||
|
assert(! qpdf_has_error(qpdf));
|
||||||
|
assert(qpdf_more_warnings(qpdf));
|
||||||
|
qpdf_error e = qpdf_next_warning(qpdf);
|
||||||
|
assert(qpdf_get_error_code(qpdf, e) == qpdf_e_object);
|
||||||
|
report_errors();
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
char* p = 0;
|
char* p = 0;
|
||||||
@ -859,6 +949,9 @@ int main(int argc, char* argv[])
|
|||||||
(n == 26) ? test26 :
|
(n == 26) ? test26 :
|
||||||
(n == 27) ? test27 :
|
(n == 27) ? test27 :
|
||||||
(n == 28) ? test28 :
|
(n == 28) ? test28 :
|
||||||
|
(n == 29) ? test29 :
|
||||||
|
(n == 30) ? test30 :
|
||||||
|
(n == 31) ? test31 :
|
||||||
0);
|
0);
|
||||||
|
|
||||||
if (fn == 0)
|
if (fn == 0)
|
||||||
|
@ -602,3 +602,7 @@ QPDFObjectHandle check ownership 0
|
|||||||
qpdf weak crypto warning 0
|
qpdf weak crypto warning 0
|
||||||
qpdf-c called qpdf_oh_is_initialized 0
|
qpdf-c called qpdf_oh_is_initialized 0
|
||||||
qpdf-c registered progress reporter 0
|
qpdf-c registered progress reporter 0
|
||||||
|
qpdf-c called qpdf_oh_new_uninitialized 0
|
||||||
|
qpdf-c warn about oh error 1
|
||||||
|
qpdf-c registered oh error handler 0
|
||||||
|
qpdf-c cleanup warned about unhandled error 0
|
||||||
|
@ -4812,7 +4812,7 @@ foreach my $i (@c_check_types)
|
|||||||
show_ntests();
|
show_ntests();
|
||||||
# ----------
|
# ----------
|
||||||
$td->notify("--- C API Object Handle ---");
|
$td->notify("--- C API Object Handle ---");
|
||||||
$n_tests += 7;
|
$n_tests += 10;
|
||||||
|
|
||||||
$td->runtest("C check object handles",
|
$td->runtest("C check object handles",
|
||||||
{$td->COMMAND => "qpdf-ctest 24 minimal.pdf '' a.pdf"},
|
{$td->COMMAND => "qpdf-ctest 24 minimal.pdf '' a.pdf"},
|
||||||
@ -4843,6 +4843,18 @@ $td->runtest("C wrap and clone objects",
|
|||||||
{$td->COMMAND => "qpdf-ctest 28 minimal.pdf '' ''"},
|
{$td->COMMAND => "qpdf-ctest 28 minimal.pdf '' ''"},
|
||||||
{$td->STRING => "", $td->EXIT_STATUS => 0},
|
{$td->STRING => "", $td->EXIT_STATUS => 0},
|
||||||
$td->NORMALIZE_NEWLINES);
|
$td->NORMALIZE_NEWLINES);
|
||||||
|
$td->runtest("C object handle errors",
|
||||||
|
{$td->COMMAND => "qpdf-ctest 29 minimal.pdf '' ''"},
|
||||||
|
{$td->FILE => "c-oh-errors.out", $td->EXIT_STATUS => 0},
|
||||||
|
$td->NORMALIZE_NEWLINES);
|
||||||
|
$td->runtest("C unhandled error warning",
|
||||||
|
{$td->COMMAND => "qpdf-ctest 30 bad1.pdf '' ''"},
|
||||||
|
{$td->FILE => "c-unhandled-error.out", $td->EXIT_STATUS => 0},
|
||||||
|
$td->NORMALIZE_NEWLINES);
|
||||||
|
$td->runtest("C type mismatch warning",
|
||||||
|
{$td->COMMAND => "qpdf-ctest 31 minimal.pdf '' ''"},
|
||||||
|
{$td->FILE => "c-type-warning.out", $td->EXIT_STATUS => 0},
|
||||||
|
$td->NORMALIZE_NEWLINES);
|
||||||
|
|
||||||
show_ntests();
|
show_ntests();
|
||||||
# ----------
|
# ----------
|
||||||
|
@ -7,18 +7,11 @@ item 0: 0 0.00
|
|||||||
item 1: 0 0.00
|
item 1: 0 0.00
|
||||||
item 2: 612 612.00
|
item 2: 612 612.00
|
||||||
item 3: 792 792.00
|
item 3: 792 792.00
|
||||||
warning: minimal.pdf (C API object handle 6): attempted access to unknown object handle
|
minimal.pdf (C API object handle 6): attempted access to unknown object handle
|
||||||
code: 5
|
minimal.pdf (C API object handle 9): attempted access to unknown object handle
|
||||||
|
minimal.pdf (C API object handle 9): attempted access to unknown object handle
|
||||||
|
warning: minimal.pdf: C API object handle accessor errors occurred, and the application did not define an error handler
|
||||||
|
code: 1
|
||||||
file: minimal.pdf
|
file: minimal.pdf
|
||||||
pos : 0
|
pos : 0
|
||||||
text: attempted access to unknown object handle
|
text: C API object handle accessor errors occurred, and the application did not define an error handler
|
||||||
warning: minimal.pdf (C API object handle 9): attempted access to unknown object handle
|
|
||||||
code: 5
|
|
||||||
file: minimal.pdf
|
|
||||||
pos : 0
|
|
||||||
text: attempted access to unknown object handle
|
|
||||||
warning: minimal.pdf (C API object handle 9): attempted access to unknown object handle
|
|
||||||
code: 5
|
|
||||||
file: minimal.pdf
|
|
||||||
pos : 0
|
|
||||||
text: attempted access to unknown object handle
|
|
||||||
|
55
qpdf/qtest/qpdf/c-oh-errors.out
Normal file
55
qpdf/qtest/qpdf/c-oh-errors.out
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
get root: attempted to dereference an uninitialized QPDFObjectHandle
|
||||||
|
code: 1
|
||||||
|
file:
|
||||||
|
pos : 0
|
||||||
|
text: attempted to dereference an uninitialized QPDFObjectHandle
|
||||||
|
bad parse: parsed object (offset 1): unknown token while reading object; treating as string
|
||||||
|
code: 5
|
||||||
|
file: parsed object
|
||||||
|
pos : 1
|
||||||
|
text: unknown token while reading object; treating as string
|
||||||
|
type mismatch: operation for integer attempted on object of type string: returning 0
|
||||||
|
code: 7
|
||||||
|
file:
|
||||||
|
pos : 0
|
||||||
|
text: operation for integer attempted on object of type string: returning 0
|
||||||
|
type mismatch: operation for string attempted on object of type integer: returning empty string
|
||||||
|
code: 7
|
||||||
|
file:
|
||||||
|
pos : 0
|
||||||
|
text: operation for string attempted on object of type integer: returning empty string
|
||||||
|
array type mismatch: operation for array attempted on object of type integer: treating as empty
|
||||||
|
code: 7
|
||||||
|
file:
|
||||||
|
pos : 0
|
||||||
|
text: operation for array attempted on object of type integer: treating as empty
|
||||||
|
array type mismatch: operation for array attempted on object of type integer: returning null
|
||||||
|
code: 7
|
||||||
|
file:
|
||||||
|
pos : 0
|
||||||
|
text: operation for array attempted on object of type integer: returning null
|
||||||
|
append to non-array: operation for array attempted on object of type integer: ignoring attempt to append item
|
||||||
|
code: 7
|
||||||
|
file:
|
||||||
|
pos : 0
|
||||||
|
text: operation for array attempted on object of type integer: ignoring attempt to append item
|
||||||
|
array bounds: returning null for out of bounds array access
|
||||||
|
code: 7
|
||||||
|
file:
|
||||||
|
pos : 0
|
||||||
|
text: returning null for out of bounds array access
|
||||||
|
dictionary iter type mismatch: operation for dictionary attempted on object of type integer: treating as empty
|
||||||
|
code: 7
|
||||||
|
file:
|
||||||
|
pos : 0
|
||||||
|
text: operation for dictionary attempted on object of type integer: treating as empty
|
||||||
|
dictionary type mismatch: operation for dictionary attempted on object of type integer: returning null for attempted key retrieval
|
||||||
|
code: 7
|
||||||
|
file:
|
||||||
|
pos : 0
|
||||||
|
text: operation for dictionary attempted on object of type integer: returning null for attempted key retrieval
|
||||||
|
dictionary type mismatch: operation for dictionary attempted on object of type integer: returning false for a key containment request
|
||||||
|
code: 7
|
||||||
|
file:
|
||||||
|
pos : 0
|
||||||
|
text: operation for dictionary attempted on object of type integer: returning false for a key containment request
|
1
qpdf/qtest/qpdf/c-type-warning.out
Normal file
1
qpdf/qtest/qpdf/c-type-warning.out
Normal file
@ -0,0 +1 @@
|
|||||||
|
WARNING: minimal.pdf, trailer at offset 715: operation for integer attempted on object of type dictionary: returning 0
|
5
qpdf/qtest/qpdf/c-unhandled-error.out
Normal file
5
qpdf/qtest/qpdf/c-unhandled-error.out
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
WARNING: bad1.pdf: can't find PDF header
|
||||||
|
WARNING: bad1.pdf: file is damaged
|
||||||
|
WARNING: bad1.pdf: can't find startxref
|
||||||
|
WARNING: bad1.pdf: Attempting to reconstruct cross-reference table
|
||||||
|
WARNING: application did not handle error: bad1.pdf: unable to find trailer dictionary while recovering damaged file
|
Loading…
Reference in New Issue
Block a user