Commit 72c10d8617c799432e28dabf1679b1a6f5245c02
1 parent
3340dbe9
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
Showing
11 changed files
with
672 additions
and
320 deletions
ChangeLog
| 1 | +2021-12-10 Jay Berkenbilt <ejb@ql.org> | ||
| 2 | + | ||
| 3 | + * C API: Overhaul how errors are handle the C API's object handle | ||
| 4 | + interfaces. Clarify documentation regarding object accessors and | ||
| 5 | + how type errors and warnings are handled. Many cases that used to | ||
| 6 | + crash code that used the C API can now be trapped and will be | ||
| 7 | + written stderr if not trapped. The new method | ||
| 8 | + qpdf_register_oh_error_handler can be used to specifically handle | ||
| 9 | + errors that occur when accessing object handles. See qpdf-c.h for | ||
| 10 | + details. | ||
| 11 | + | ||
| 12 | + * C API: Add qpdf_oh_new_uninitialized to explicitly create | ||
| 13 | + uninitialized object handles. | ||
| 14 | + | ||
| 15 | + * Add new error code qpdf_e_object that is used for exceptions | ||
| 16 | + (including warnings) that are caused by using QPDFObjectHandle | ||
| 17 | + methods on object handles of the wrong type. | ||
| 18 | + | ||
| 1 | 2021-12-02 Jay Berkenbilt <ejb@ql.org> | 19 | 2021-12-02 Jay Berkenbilt <ejb@ql.org> |
| 2 | 20 | ||
| 3 | * C API: Add qpdf_oh_is_initialized. | 21 | * C API: Add qpdf_oh_is_initialized. |
include/qpdf/qpdf-c.h
| @@ -62,22 +62,27 @@ | @@ -62,22 +62,27 @@ | ||
| 62 | * string was just returned. | 62 | * string was just returned. |
| 63 | * | 63 | * |
| 64 | * Many functions defined here merely set parameters and therefore | 64 | * Many functions defined here merely set parameters and therefore |
| 65 | - * never return error conditions. Functions that may cause PDF | ||
| 66 | - * files to be read or written may return error conditions. Such | ||
| 67 | - * functions return an error code. If there were no errors or | ||
| 68 | - * warnings, they return QPDF_SUCCESS. If there were warnings, | ||
| 69 | - * the return value has the QPDF_WARNINGS bit set. If there | ||
| 70 | - * errors, the QPDF_ERRORS bit is set. In other words, if there | ||
| 71 | - * are both warnings and errors, then the return status will be | ||
| 72 | - * QPDF_WARNINGS | QPDF_ERRORS. You may also call the | 65 | + * never return error conditions. Functions that access or return |
| 66 | + * qpdf_oh object handles may generate warnings but have no way to | ||
| 67 | + * return errors, but the errors may be checked afterwards or | ||
| 68 | + * handled using a registered handler. This is discussed in more | ||
| 69 | + * detail in the section on object handling. Functions that may | ||
| 70 | + * cause PDF files to be read or written may return error | ||
| 71 | + * conditions. Such functions return an error code. If there were | ||
| 72 | + * no errors or warnings, they return QPDF_SUCCESS. If there were | ||
| 73 | + * warnings, the return value has the QPDF_WARNINGS bit set. If | ||
| 74 | + * there were errors, the QPDF_ERRORS bit is set. In other words, | ||
| 75 | + * if there are both warnings and errors, then the return status | ||
| 76 | + * will be QPDF_WARNINGS | QPDF_ERRORS. You may also call the | ||
| 73 | * qpdf_more_warnings and qpdf_more_errors functions to test | 77 | * qpdf_more_warnings and qpdf_more_errors functions to test |
| 74 | - * whether there are unseen warning or error conditions. By | 78 | + * whether there are unseen warning or error conditions. By |
| 75 | * default, warnings are written to stderr when detected, but this | 79 | * default, warnings are written to stderr when detected, but this |
| 76 | - * behavior can be suppressed. In all cases, errors and warnings | 80 | + * behavior can be suppressed. In all cases, errors and warnings |
| 77 | * may be retrieved by calling qpdf_next_warning and | 81 | * may be retrieved by calling qpdf_next_warning and |
| 78 | - * qpdf_next_error. All exceptions thrown by the C++ interface | ||
| 79 | - * are caught and converted into error messages by the C | ||
| 80 | - * interface. | 82 | + * qpdf_get_error. All exceptions thrown by the C++ interface are |
| 83 | + * caught and converted into error messages by the C interface. | ||
| 84 | + * Any exceptions to this are qpdf bugs and should be reported at | ||
| 85 | + * https://github.com/qpdf/qpdf/issues/new. | ||
| 81 | * | 86 | * |
| 82 | * Most functions defined here have obvious counterparts that are | 87 | * Most functions defined here have obvious counterparts that are |
| 83 | * methods to either QPDF or QPDFWriter. Please see comments in | 88 | * methods to either QPDF or QPDFWriter. Please see comments in |
| @@ -550,13 +555,51 @@ extern "C" { | @@ -550,13 +555,51 @@ extern "C" { | ||
| 550 | * handle, the object is safely part of the dictionary or array. | 555 | * handle, the object is safely part of the dictionary or array. |
| 551 | * Similarly, any other object handle refering to the object remains | 556 | * Similarly, any other object handle refering to the object remains |
| 552 | * valid. Explicitly releasing an object handle is essentially the | 557 | * valid. Explicitly releasing an object handle is essentially the |
| 553 | - * same as letting a QPDFObjectHandle go out of scope in the C++ API. | 558 | + * same as letting a QPDFObjectHandle go out of scope in the C++ |
| 559 | + * API. | ||
| 560 | + * | ||
| 561 | + * Important note about error handling: | ||
| 562 | + * | ||
| 563 | + * While many of the functions that operate on the QPDF object | ||
| 564 | + * return error codes, the qpdf_oh functions return values such as | ||
| 565 | + * object handles or data. They have no way to return error codes. | ||
| 566 | + * If they generate warnings, the warnings are handled using the | ||
| 567 | + * error/warning handling functions described above. If the | ||
| 568 | + * underlying C++ call throws an exception, the error handler | ||
| 569 | + * registered with qpdf_register_oh_error_handler() will be | ||
| 570 | + * called. If no handler is registered, the exception is written | ||
| 571 | + * to STDERR. In either case, a sensible fallback value is | ||
| 572 | + * returned (0 for numbers, QPDF_FALSE for booleans, "" for | ||
| 573 | + * strings, or a null object). It is sensible for a C program to | ||
| 574 | + * use setjmp and longjmp with this error handler since the C++ | ||
| 575 | + * code has raised an exception, but you can also just set a flag | ||
| 576 | + * and check it after each call. | ||
| 577 | + * | ||
| 578 | + * All conditions under which exceptions would be thrown by object | ||
| 579 | + * accessors are caused by programmer error or major problems such | ||
| 580 | + * as running out of memory or not being able to read the input | ||
| 581 | + * file. If they are ever caused by invalid data in the PDF file, | ||
| 582 | + * it is a bug in qpdf, which should be reported at | ||
| 583 | + * https://github.com/qpdf/qpdf/issues/new. | ||
| 554 | */ | 584 | */ |
| 555 | 585 | ||
| 556 | /* For examples of using this API, see examples/pdf-c-objects.c */ | 586 | /* For examples of using this API, see examples/pdf-c-objects.c */ |
| 557 | 587 | ||
| 558 | typedef unsigned int qpdf_oh; | 588 | typedef unsigned int qpdf_oh; |
| 559 | 589 | ||
| 590 | + /* If an exception is thrown by the C++ code when any of the | ||
| 591 | + * qpdf_oh functions are called, the registered handle_error | ||
| 592 | + * function will be called. The value passed to data will be | ||
| 593 | + * passed along to the error handler function. If any errors occur | ||
| 594 | + * and no error handler is accessed, a single warning will be | ||
| 595 | + * issued, and the error will be written to stderr. | ||
| 596 | + */ | ||
| 597 | + QPDF_DLL | ||
| 598 | + void qpdf_register_oh_error_handler( | ||
| 599 | + qpdf_data qpdf, | ||
| 600 | + void (*handle_error)(qpdf_data qpdf, qpdf_error error, void* data), | ||
| 601 | + void* data); | ||
| 602 | + | ||
| 560 | /* Releasing objects -- see comments above. These functions have no | 603 | /* Releasing objects -- see comments above. These functions have no |
| 561 | * equivalent in the C++ API. | 604 | * equivalent in the C++ API. |
| 562 | */ | 605 | */ |
| @@ -659,7 +702,7 @@ extern "C" { | @@ -659,7 +702,7 @@ extern "C" { | ||
| 659 | /* The memory returned by qpdf_oh_dict_next_key is owned by | 702 | /* The memory returned by qpdf_oh_dict_next_key is owned by |
| 660 | * qpdf_data. It is good until the next call to | 703 | * qpdf_data. It is good until the next call to |
| 661 | * qpdf_oh_dict_next_key with the same qpdf_data object. Calling | 704 | * qpdf_oh_dict_next_key with the same qpdf_data object. Calling |
| 662 | - * the method again, even with a different dict, invalidates | 705 | + * the function again, even with a different dict, invalidates |
| 663 | * previous return values. | 706 | * previous return values. |
| 664 | */ | 707 | */ |
| 665 | QPDF_DLL | 708 | QPDF_DLL |
| @@ -677,6 +720,8 @@ extern "C" { | @@ -677,6 +720,8 @@ extern "C" { | ||
| 677 | qpdf_data data, qpdf_oh oh, char const* key); | 720 | qpdf_data data, qpdf_oh oh, char const* key); |
| 678 | 721 | ||
| 679 | QPDF_DLL | 722 | QPDF_DLL |
| 723 | + qpdf_oh qpdf_oh_new_uninitialized(qpdf_data qpdf); | ||
| 724 | + QPDF_DLL | ||
| 680 | qpdf_oh qpdf_oh_new_null(qpdf_data data); | 725 | qpdf_oh qpdf_oh_new_null(qpdf_data data); |
| 681 | QPDF_DLL | 726 | QPDF_DLL |
| 682 | qpdf_oh qpdf_oh_new_bool(qpdf_data data, QPDF_BOOL value); | 727 | qpdf_oh qpdf_oh_new_bool(qpdf_data data, QPDF_BOOL value); |
libqpdf/qpdf-c.cc
| @@ -41,6 +41,9 @@ struct _qpdf_data | @@ -41,6 +41,9 @@ struct _qpdf_data | ||
| 41 | PointerHolder<Buffer> output_buffer; | 41 | PointerHolder<Buffer> output_buffer; |
| 42 | 42 | ||
| 43 | // QPDFObjectHandle support | 43 | // QPDFObjectHandle support |
| 44 | + void (*oh_error_handler)(qpdf_data, qpdf_error, void*); | ||
| 45 | + void* oh_error_handler_data; | ||
| 46 | + bool default_oh_error_handler_called; | ||
| 44 | std::map<qpdf_oh, PointerHolder<QPDFObjectHandle>> oh_cache; | 47 | std::map<qpdf_oh, PointerHolder<QPDFObjectHandle>> oh_cache; |
| 45 | qpdf_oh next_oh; | 48 | qpdf_oh next_oh; |
| 46 | std::set<std::string> cur_iter_dict_keys; | 49 | std::set<std::string> cur_iter_dict_keys; |
| @@ -48,8 +51,32 @@ struct _qpdf_data | @@ -48,8 +51,32 @@ struct _qpdf_data | ||
| 48 | std::string cur_dict_key; | 51 | std::string cur_dict_key; |
| 49 | }; | 52 | }; |
| 50 | 53 | ||
| 54 | +static void default_oh_error_handler(qpdf_data qpdf, qpdf_error e, void* data) | ||
| 55 | +{ | ||
| 56 | + bool* called = reinterpret_cast<bool*>(data); | ||
| 57 | + if (called != nullptr) | ||
| 58 | + { | ||
| 59 | + QTC::TC("qpdf", "qpdf-c warn about oh error", *called ? 0 : 1); | ||
| 60 | + if (! *called) | ||
| 61 | + { | ||
| 62 | + qpdf->warnings.push_back( | ||
| 63 | + QPDFExc( | ||
| 64 | + qpdf_e_internal, | ||
| 65 | + qpdf->qpdf->getFilename(), | ||
| 66 | + "", 0, | ||
| 67 | + "C API object handle accessor errors occurred," | ||
| 68 | + " and the application did not define an error handler")); | ||
| 69 | + *called = true; | ||
| 70 | + } | ||
| 71 | + } | ||
| 72 | + std::cerr << e->exc->what() << std::endl; | ||
| 73 | +} | ||
| 74 | + | ||
| 51 | _qpdf_data::_qpdf_data() : | 75 | _qpdf_data::_qpdf_data() : |
| 52 | write_memory(false), | 76 | write_memory(false), |
| 77 | + oh_error_handler(default_oh_error_handler), | ||
| 78 | + oh_error_handler_data(&this->default_oh_error_handler_called), | ||
| 79 | + default_oh_error_handler_called(false), | ||
| 53 | next_oh(0) | 80 | next_oh(0) |
| 54 | { | 81 | { |
| 55 | } | 82 | } |
| @@ -170,6 +197,13 @@ void qpdf_cleanup(qpdf_data* qpdf) | @@ -170,6 +197,13 @@ void qpdf_cleanup(qpdf_data* qpdf) | ||
| 170 | { | 197 | { |
| 171 | QTC::TC("qpdf", "qpdf-c called qpdf_cleanup"); | 198 | QTC::TC("qpdf", "qpdf-c called qpdf_cleanup"); |
| 172 | qpdf_oh_release_all(*qpdf); | 199 | qpdf_oh_release_all(*qpdf); |
| 200 | + if ((*qpdf)->error.getPointer()) | ||
| 201 | + { | ||
| 202 | + QTC::TC("qpdf", "qpdf-c cleanup warned about unhandled error"); | ||
| 203 | + std::cerr << "WARNING: application did not handle error: " | ||
| 204 | + << (*qpdf)->error->what() << std::endl; | ||
| 205 | + | ||
| 206 | + } | ||
| 173 | delete *qpdf; | 207 | delete *qpdf; |
| 174 | *qpdf = 0; | 208 | *qpdf = 0; |
| 175 | } | 209 | } |
| @@ -841,6 +875,38 @@ QPDF_ERROR_CODE qpdf_write(qpdf_data qpdf) | @@ -841,6 +875,38 @@ QPDF_ERROR_CODE qpdf_write(qpdf_data qpdf) | ||
| 841 | return status; | 875 | return status; |
| 842 | } | 876 | } |
| 843 | 877 | ||
| 878 | +void qpdf_register_oh_error_handler( | ||
| 879 | + qpdf_data qpdf, | ||
| 880 | + void (*handle_error)(qpdf_data qpdf, qpdf_error error, void* data), | ||
| 881 | + void* data) | ||
| 882 | +{ | ||
| 883 | + QTC::TC("qpdf", "qpdf-c registered oh error handler"); | ||
| 884 | + qpdf->oh_error_handler = handle_error; | ||
| 885 | + qpdf->oh_error_handler_data = data; | ||
| 886 | +} | ||
| 887 | + | ||
| 888 | +template<class RET> | ||
| 889 | +static RET trap_oh_errors( | ||
| 890 | + qpdf_data qpdf, | ||
| 891 | + std::function<RET()> fallback, | ||
| 892 | + std::function<RET(qpdf_data)> fn) | ||
| 893 | +{ | ||
| 894 | + // Note: fallback is a function so we don't have to evaluate it | ||
| 895 | + // unless needed. This is important because sometimes the fallback | ||
| 896 | + // creates an object. | ||
| 897 | + RET ret; | ||
| 898 | + QPDF_ERROR_CODE status = trap_errors(qpdf, [&ret, &fn] (qpdf_data q) { | ||
| 899 | + ret = fn(q); | ||
| 900 | + }); | ||
| 901 | + if (status & QPDF_ERRORS) | ||
| 902 | + { | ||
| 903 | + (*qpdf->oh_error_handler)( | ||
| 904 | + qpdf, qpdf_get_error(qpdf), qpdf->oh_error_handler_data); | ||
| 905 | + return fallback(); | ||
| 906 | + } | ||
| 907 | + return ret; | ||
| 908 | +} | ||
| 909 | + | ||
| 844 | static qpdf_oh | 910 | static qpdf_oh |
| 845 | new_object(qpdf_data qpdf, QPDFObjectHandle const& qoh) | 911 | new_object(qpdf_data qpdf, QPDFObjectHandle const& qoh) |
| 846 | { | 912 | { |
| @@ -867,310 +933,367 @@ void qpdf_oh_release_all(qpdf_data qpdf) | @@ -867,310 +933,367 @@ void qpdf_oh_release_all(qpdf_data qpdf) | ||
| 867 | qpdf->oh_cache.clear(); | 933 | qpdf->oh_cache.clear(); |
| 868 | } | 934 | } |
| 869 | 935 | ||
| 936 | +template <class T> | ||
| 937 | +static std::function<T()> return_T(T const& r) | ||
| 938 | +{ | ||
| 939 | + return [&r]() { return r; }; | ||
| 940 | +} | ||
| 941 | + | ||
| 942 | +static QPDF_BOOL return_false() | ||
| 943 | +{ | ||
| 944 | + return QPDF_FALSE; | ||
| 945 | +} | ||
| 946 | + | ||
| 947 | +static std::function<qpdf_oh()> return_uninitialized(qpdf_data qpdf) | ||
| 948 | +{ | ||
| 949 | + return [qpdf]() { return qpdf_oh_new_uninitialized(qpdf); }; | ||
| 950 | +} | ||
| 951 | + | ||
| 952 | +static std::function<qpdf_oh()> return_null(qpdf_data qpdf) | ||
| 953 | +{ | ||
| 954 | + return [qpdf]() { return qpdf_oh_new_null(qpdf); }; | ||
| 955 | +} | ||
| 956 | + | ||
| 870 | qpdf_oh qpdf_get_trailer(qpdf_data qpdf) | 957 | qpdf_oh qpdf_get_trailer(qpdf_data qpdf) |
| 871 | { | 958 | { |
| 872 | QTC::TC("qpdf", "qpdf-c called qpdf_get_trailer"); | 959 | QTC::TC("qpdf", "qpdf-c called qpdf_get_trailer"); |
| 873 | - return new_object(qpdf, qpdf->qpdf->getTrailer()); | 960 | + return trap_oh_errors<qpdf_oh>( |
| 961 | + qpdf, return_uninitialized(qpdf), [] (qpdf_data q) { | ||
| 962 | + return new_object(q, q->qpdf->getTrailer()); | ||
| 963 | + }); | ||
| 874 | } | 964 | } |
| 875 | 965 | ||
| 876 | qpdf_oh qpdf_get_root(qpdf_data qpdf) | 966 | qpdf_oh qpdf_get_root(qpdf_data qpdf) |
| 877 | { | 967 | { |
| 878 | QTC::TC("qpdf", "qpdf-c called qpdf_get_root"); | 968 | QTC::TC("qpdf", "qpdf-c called qpdf_get_root"); |
| 879 | - return new_object(qpdf, qpdf->qpdf->getRoot()); | ||
| 880 | -} | ||
| 881 | - | ||
| 882 | -static bool | ||
| 883 | -qpdf_oh_valid_internal(qpdf_data qpdf, qpdf_oh oh) | ||
| 884 | -{ | ||
| 885 | - auto i = qpdf->oh_cache.find(oh); | ||
| 886 | - bool result = ((i != qpdf->oh_cache.end()) && | ||
| 887 | - (i->second).getPointer()); | ||
| 888 | - if (! result) | ||
| 889 | - { | ||
| 890 | - QTC::TC("qpdf", "qpdf-c invalid object handle"); | ||
| 891 | - qpdf->warnings.push_back( | ||
| 892 | - QPDFExc( | ||
| 893 | - qpdf_e_damaged_pdf, | ||
| 894 | - qpdf->qpdf->getFilename(), | ||
| 895 | - std::string("C API object handle ") + | ||
| 896 | - QUtil::uint_to_string(oh), | ||
| 897 | - 0, "attempted access to unknown object handle")); | ||
| 898 | - } | ||
| 899 | - return result; | 969 | + return trap_oh_errors<qpdf_oh>( |
| 970 | + qpdf, return_uninitialized(qpdf), [] (qpdf_data q) { | ||
| 971 | + return new_object(q, q->qpdf->getRoot()); | ||
| 972 | + }); | ||
| 973 | +} | ||
| 974 | + | ||
| 975 | +template<class RET> | ||
| 976 | +static RET do_with_oh( | ||
| 977 | + qpdf_data qpdf, qpdf_oh oh, | ||
| 978 | + std::function<RET()> fallback, | ||
| 979 | + std::function<RET(QPDFObjectHandle&)> fn) | ||
| 980 | +{ | ||
| 981 | + return trap_oh_errors<RET>( | ||
| 982 | + qpdf, fallback, [&fn, &oh](qpdf_data q) { | ||
| 983 | + auto i = q->oh_cache.find(oh); | ||
| 984 | + bool result = ((i != q->oh_cache.end()) && | ||
| 985 | + (i->second).getPointer()); | ||
| 986 | + if (! result) | ||
| 987 | + { | ||
| 988 | + QTC::TC("qpdf", "qpdf-c invalid object handle"); | ||
| 989 | + throw QPDFExc( | ||
| 990 | + qpdf_e_internal, | ||
| 991 | + q->qpdf->getFilename(), | ||
| 992 | + std::string("C API object handle ") + | ||
| 993 | + QUtil::uint_to_string(oh), | ||
| 994 | + 0, "attempted access to unknown object handle"); | ||
| 995 | + } | ||
| 996 | + return fn(*(q->oh_cache[oh])); | ||
| 997 | + }); | ||
| 998 | +} | ||
| 999 | + | ||
| 1000 | +static void do_with_oh_void( | ||
| 1001 | + qpdf_data qpdf, qpdf_oh oh, | ||
| 1002 | + std::function<void(QPDFObjectHandle&)> fn) | ||
| 1003 | +{ | ||
| 1004 | + do_with_oh<bool>( | ||
| 1005 | + qpdf, oh, return_T<bool>(false), [&fn](QPDFObjectHandle& o) { | ||
| 1006 | + fn(o); | ||
| 1007 | + return true; // unused | ||
| 1008 | + }); | ||
| 900 | } | 1009 | } |
| 901 | 1010 | ||
| 902 | QPDF_BOOL qpdf_oh_is_initialized(qpdf_data qpdf, qpdf_oh oh) | 1011 | QPDF_BOOL qpdf_oh_is_initialized(qpdf_data qpdf, qpdf_oh oh) |
| 903 | { | 1012 | { |
| 904 | QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_initialized"); | 1013 | QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_initialized"); |
| 905 | - return (qpdf_oh_valid_internal(qpdf, oh) && | ||
| 906 | - qpdf->oh_cache[oh]->isInitialized()); | 1014 | + return do_with_oh<QPDF_BOOL>( |
| 1015 | + qpdf, oh, return_false, [](QPDFObjectHandle& o) { | ||
| 1016 | + return o.isInitialized(); | ||
| 1017 | + }); | ||
| 907 | } | 1018 | } |
| 908 | 1019 | ||
| 909 | QPDF_BOOL qpdf_oh_is_bool(qpdf_data qpdf, qpdf_oh oh) | 1020 | QPDF_BOOL qpdf_oh_is_bool(qpdf_data qpdf, qpdf_oh oh) |
| 910 | { | 1021 | { |
| 911 | QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_bool"); | 1022 | QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_bool"); |
| 912 | - return (qpdf_oh_valid_internal(qpdf, oh) && | ||
| 913 | - qpdf->oh_cache[oh]->isBool()); | 1023 | + return do_with_oh<QPDF_BOOL>( |
| 1024 | + qpdf, oh, return_false, [](QPDFObjectHandle& o) { | ||
| 1025 | + return o.isBool(); | ||
| 1026 | + }); | ||
| 914 | } | 1027 | } |
| 915 | 1028 | ||
| 916 | QPDF_BOOL qpdf_oh_is_null(qpdf_data qpdf, qpdf_oh oh) | 1029 | QPDF_BOOL qpdf_oh_is_null(qpdf_data qpdf, qpdf_oh oh) |
| 917 | { | 1030 | { |
| 918 | QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_null"); | 1031 | QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_null"); |
| 919 | - return (qpdf_oh_valid_internal(qpdf, oh) && | ||
| 920 | - qpdf->oh_cache[oh]->isNull()); | 1032 | + return do_with_oh<QPDF_BOOL>( |
| 1033 | + qpdf, oh, return_false, [](QPDFObjectHandle& o) { | ||
| 1034 | + return o.isNull(); | ||
| 1035 | + }); | ||
| 921 | } | 1036 | } |
| 922 | 1037 | ||
| 923 | QPDF_BOOL qpdf_oh_is_integer(qpdf_data qpdf, qpdf_oh oh) | 1038 | QPDF_BOOL qpdf_oh_is_integer(qpdf_data qpdf, qpdf_oh oh) |
| 924 | { | 1039 | { |
| 925 | QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_integer"); | 1040 | QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_integer"); |
| 926 | - return (qpdf_oh_valid_internal(qpdf, oh) && | ||
| 927 | - qpdf->oh_cache[oh]->isInteger()); | 1041 | + return do_with_oh<QPDF_BOOL>( |
| 1042 | + qpdf, oh, return_false, [](QPDFObjectHandle& o) { | ||
| 1043 | + return o.isInteger(); | ||
| 1044 | + }); | ||
| 928 | } | 1045 | } |
| 929 | 1046 | ||
| 930 | QPDF_BOOL qpdf_oh_is_real(qpdf_data qpdf, qpdf_oh oh) | 1047 | QPDF_BOOL qpdf_oh_is_real(qpdf_data qpdf, qpdf_oh oh) |
| 931 | { | 1048 | { |
| 932 | QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_real"); | 1049 | QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_real"); |
| 933 | - return (qpdf_oh_valid_internal(qpdf, oh) && | ||
| 934 | - qpdf->oh_cache[oh]->isReal()); | 1050 | + return do_with_oh<QPDF_BOOL>( |
| 1051 | + qpdf, oh, return_false, [](QPDFObjectHandle& o) { | ||
| 1052 | + return o.isReal(); | ||
| 1053 | + }); | ||
| 935 | } | 1054 | } |
| 936 | 1055 | ||
| 937 | QPDF_BOOL qpdf_oh_is_name(qpdf_data qpdf, qpdf_oh oh) | 1056 | QPDF_BOOL qpdf_oh_is_name(qpdf_data qpdf, qpdf_oh oh) |
| 938 | { | 1057 | { |
| 939 | QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_name"); | 1058 | QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_name"); |
| 940 | - return (qpdf_oh_valid_internal(qpdf, oh) && | ||
| 941 | - qpdf->oh_cache[oh]->isName()); | 1059 | + return do_with_oh<QPDF_BOOL>( |
| 1060 | + qpdf, oh, return_false, [](QPDFObjectHandle& o) { | ||
| 1061 | + return o.isName(); | ||
| 1062 | + }); | ||
| 942 | } | 1063 | } |
| 943 | 1064 | ||
| 944 | QPDF_BOOL qpdf_oh_is_string(qpdf_data qpdf, qpdf_oh oh) | 1065 | QPDF_BOOL qpdf_oh_is_string(qpdf_data qpdf, qpdf_oh oh) |
| 945 | { | 1066 | { |
| 946 | QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_string"); | 1067 | QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_string"); |
| 947 | - return (qpdf_oh_valid_internal(qpdf, oh) && | ||
| 948 | - qpdf->oh_cache[oh]->isString()); | 1068 | + return do_with_oh<QPDF_BOOL>( |
| 1069 | + qpdf, oh, return_false, [](QPDFObjectHandle& o) { | ||
| 1070 | + return o.isString(); | ||
| 1071 | + }); | ||
| 949 | } | 1072 | } |
| 950 | 1073 | ||
| 951 | QPDF_BOOL qpdf_oh_is_operator(qpdf_data qpdf, qpdf_oh oh) | 1074 | QPDF_BOOL qpdf_oh_is_operator(qpdf_data qpdf, qpdf_oh oh) |
| 952 | { | 1075 | { |
| 953 | QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_operator"); | 1076 | QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_operator"); |
| 954 | - return (qpdf_oh_valid_internal(qpdf, oh) && | ||
| 955 | - qpdf->oh_cache[oh]->isOperator()); | 1077 | + return do_with_oh<QPDF_BOOL>( |
| 1078 | + qpdf, oh, return_false, [](QPDFObjectHandle& o) { | ||
| 1079 | + return o.isOperator(); | ||
| 1080 | + }); | ||
| 956 | } | 1081 | } |
| 957 | 1082 | ||
| 958 | QPDF_BOOL qpdf_oh_is_inline_image(qpdf_data qpdf, qpdf_oh oh) | 1083 | QPDF_BOOL qpdf_oh_is_inline_image(qpdf_data qpdf, qpdf_oh oh) |
| 959 | { | 1084 | { |
| 960 | QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_inline_image"); | 1085 | QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_inline_image"); |
| 961 | - return (qpdf_oh_valid_internal(qpdf, oh) && | ||
| 962 | - qpdf->oh_cache[oh]->isInlineImage()); | 1086 | + return do_with_oh<QPDF_BOOL>( |
| 1087 | + qpdf, oh, return_false, [](QPDFObjectHandle& o) { | ||
| 1088 | + return o.isInlineImage(); | ||
| 1089 | + }); | ||
| 963 | } | 1090 | } |
| 964 | 1091 | ||
| 965 | QPDF_BOOL qpdf_oh_is_array(qpdf_data qpdf, qpdf_oh oh) | 1092 | QPDF_BOOL qpdf_oh_is_array(qpdf_data qpdf, qpdf_oh oh) |
| 966 | { | 1093 | { |
| 967 | QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_array"); | 1094 | QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_array"); |
| 968 | - return (qpdf_oh_valid_internal(qpdf, oh) && | ||
| 969 | - qpdf->oh_cache[oh]->isArray()); | 1095 | + return do_with_oh<QPDF_BOOL>( |
| 1096 | + qpdf, oh, return_false, [](QPDFObjectHandle& o) { | ||
| 1097 | + return o.isArray(); | ||
| 1098 | + }); | ||
| 970 | } | 1099 | } |
| 971 | 1100 | ||
| 972 | QPDF_BOOL qpdf_oh_is_dictionary(qpdf_data qpdf, qpdf_oh oh) | 1101 | QPDF_BOOL qpdf_oh_is_dictionary(qpdf_data qpdf, qpdf_oh oh) |
| 973 | { | 1102 | { |
| 974 | QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_dictionary"); | 1103 | QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_dictionary"); |
| 975 | - return (qpdf_oh_valid_internal(qpdf, oh) && | ||
| 976 | - qpdf->oh_cache[oh]->isDictionary()); | 1104 | + return do_with_oh<QPDF_BOOL>( |
| 1105 | + qpdf, oh, return_false, [](QPDFObjectHandle& o) { | ||
| 1106 | + return o.isDictionary(); | ||
| 1107 | + }); | ||
| 977 | } | 1108 | } |
| 978 | 1109 | ||
| 979 | QPDF_BOOL qpdf_oh_is_stream(qpdf_data qpdf, qpdf_oh oh) | 1110 | QPDF_BOOL qpdf_oh_is_stream(qpdf_data qpdf, qpdf_oh oh) |
| 980 | { | 1111 | { |
| 981 | QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_stream"); | 1112 | QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_stream"); |
| 982 | - return (qpdf_oh_valid_internal(qpdf, oh) && | ||
| 983 | - qpdf->oh_cache[oh]->isStream()); | 1113 | + return do_with_oh<QPDF_BOOL>( |
| 1114 | + qpdf, oh, return_false, [](QPDFObjectHandle& o) { | ||
| 1115 | + return o.isStream(); | ||
| 1116 | + }); | ||
| 984 | } | 1117 | } |
| 985 | 1118 | ||
| 986 | QPDF_BOOL qpdf_oh_is_indirect(qpdf_data qpdf, qpdf_oh oh) | 1119 | QPDF_BOOL qpdf_oh_is_indirect(qpdf_data qpdf, qpdf_oh oh) |
| 987 | { | 1120 | { |
| 988 | QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_indirect"); | 1121 | QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_indirect"); |
| 989 | - return (qpdf_oh_valid_internal(qpdf, oh) && | ||
| 990 | - qpdf->oh_cache[oh]->isIndirect()); | 1122 | + return do_with_oh<QPDF_BOOL>( |
| 1123 | + qpdf, oh, return_false, [](QPDFObjectHandle& o) { | ||
| 1124 | + return o.isIndirect(); | ||
| 1125 | + }); | ||
| 991 | } | 1126 | } |
| 992 | 1127 | ||
| 993 | QPDF_BOOL qpdf_oh_is_scalar(qpdf_data qpdf, qpdf_oh oh) | 1128 | QPDF_BOOL qpdf_oh_is_scalar(qpdf_data qpdf, qpdf_oh oh) |
| 994 | { | 1129 | { |
| 995 | QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_scalar"); | 1130 | QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_scalar"); |
| 996 | - return (qpdf_oh_valid_internal(qpdf, oh) && | ||
| 997 | - qpdf->oh_cache[oh]->isScalar()); | 1131 | + return do_with_oh<QPDF_BOOL>( |
| 1132 | + qpdf, oh, return_false, [](QPDFObjectHandle& o) { | ||
| 1133 | + return o.isScalar(); | ||
| 1134 | + }); | ||
| 1135 | +} | ||
| 1136 | + | ||
| 1137 | +QPDF_BOOL qpdf_oh_is_number(qpdf_data qpdf, qpdf_oh oh) | ||
| 1138 | +{ | ||
| 1139 | + return do_with_oh<QPDF_BOOL>( | ||
| 1140 | + qpdf, oh, return_false, [](QPDFObjectHandle& o) { | ||
| 1141 | + QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_number"); | ||
| 1142 | + return o.isNumber(); | ||
| 1143 | + }); | ||
| 998 | } | 1144 | } |
| 999 | 1145 | ||
| 1000 | qpdf_oh qpdf_oh_wrap_in_array(qpdf_data qpdf, qpdf_oh oh) | 1146 | qpdf_oh qpdf_oh_wrap_in_array(qpdf_data qpdf, qpdf_oh oh) |
| 1001 | { | 1147 | { |
| 1002 | - if (! qpdf_oh_valid_internal(qpdf, oh)) | ||
| 1003 | - { | ||
| 1004 | - return qpdf_oh_new_array(qpdf); | ||
| 1005 | - } | ||
| 1006 | - auto qoh = qpdf->oh_cache[oh]; | ||
| 1007 | - if (qoh->isArray()) | ||
| 1008 | - { | ||
| 1009 | - QTC::TC("qpdf", "qpdf-c array to wrap_in_array"); | ||
| 1010 | - return new_object(qpdf, *qoh); | ||
| 1011 | - } | ||
| 1012 | - else | ||
| 1013 | - { | ||
| 1014 | - QTC::TC("qpdf", "qpdf-c non-array to wrap_in_array"); | ||
| 1015 | - return new_object(qpdf, | ||
| 1016 | - QPDFObjectHandle::newArray( | ||
| 1017 | - std::vector<QPDFObjectHandle>{ | ||
| 1018 | - *qpdf->oh_cache[oh]})); | ||
| 1019 | - } | 1148 | + return do_with_oh<qpdf_oh>( |
| 1149 | + qpdf, oh, | ||
| 1150 | + [&qpdf](){ return qpdf_oh_new_array(qpdf); }, | ||
| 1151 | + [&qpdf](QPDFObjectHandle& qoh) { | ||
| 1152 | + if (qoh.isArray()) | ||
| 1153 | + { | ||
| 1154 | + QTC::TC("qpdf", "qpdf-c array to wrap_in_array"); | ||
| 1155 | + return new_object(qpdf, qoh); | ||
| 1156 | + } | ||
| 1157 | + else | ||
| 1158 | + { | ||
| 1159 | + QTC::TC("qpdf", "qpdf-c non-array to wrap_in_array"); | ||
| 1160 | + return new_object(qpdf, | ||
| 1161 | + QPDFObjectHandle::newArray( | ||
| 1162 | + std::vector<QPDFObjectHandle>{qoh})); | ||
| 1163 | + } | ||
| 1164 | + }); | ||
| 1020 | } | 1165 | } |
| 1021 | 1166 | ||
| 1022 | qpdf_oh qpdf_oh_parse(qpdf_data qpdf, char const* object_str) | 1167 | qpdf_oh qpdf_oh_parse(qpdf_data qpdf, char const* object_str) |
| 1023 | { | 1168 | { |
| 1024 | QTC::TC("qpdf", "qpdf-c called qpdf_oh_parse"); | 1169 | QTC::TC("qpdf", "qpdf-c called qpdf_oh_parse"); |
| 1025 | - return new_object(qpdf, QPDFObjectHandle::parse(object_str)); | 1170 | + return trap_oh_errors<qpdf_oh>( |
| 1171 | + qpdf, return_uninitialized(qpdf), [&object_str] (qpdf_data q) { | ||
| 1172 | + return new_object(q, QPDFObjectHandle::parse(object_str)); | ||
| 1173 | + }); | ||
| 1026 | } | 1174 | } |
| 1027 | 1175 | ||
| 1028 | QPDF_BOOL qpdf_oh_get_bool_value(qpdf_data qpdf, qpdf_oh oh) | 1176 | QPDF_BOOL qpdf_oh_get_bool_value(qpdf_data qpdf, qpdf_oh oh) |
| 1029 | { | 1177 | { |
| 1030 | - if (! qpdf_oh_valid_internal(qpdf, oh)) | ||
| 1031 | - { | ||
| 1032 | - return QPDF_FALSE; | ||
| 1033 | - } | ||
| 1034 | - QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_bool_value"); | ||
| 1035 | - return qpdf->oh_cache[oh]->getBoolValue(); | 1178 | + return do_with_oh<QPDF_BOOL>( |
| 1179 | + qpdf, oh, return_false, [](QPDFObjectHandle& o) { | ||
| 1180 | + QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_bool_value"); | ||
| 1181 | + return o.getBoolValue(); | ||
| 1182 | + }); | ||
| 1036 | } | 1183 | } |
| 1037 | 1184 | ||
| 1038 | long long qpdf_oh_get_int_value(qpdf_data qpdf, qpdf_oh oh) | 1185 | long long qpdf_oh_get_int_value(qpdf_data qpdf, qpdf_oh oh) |
| 1039 | { | 1186 | { |
| 1040 | - if (! qpdf_oh_valid_internal(qpdf, oh)) | ||
| 1041 | - { | ||
| 1042 | - return 0LL; | ||
| 1043 | - } | ||
| 1044 | - QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_int_value"); | ||
| 1045 | - return qpdf->oh_cache[oh]->getIntValue(); | 1187 | + return do_with_oh<long long>( |
| 1188 | + qpdf, oh, return_T<long long>(0LL), [](QPDFObjectHandle& o) { | ||
| 1189 | + QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_int_value"); | ||
| 1190 | + return o.getIntValue(); | ||
| 1191 | + }); | ||
| 1046 | } | 1192 | } |
| 1047 | 1193 | ||
| 1048 | int qpdf_oh_get_int_value_as_int(qpdf_data qpdf, qpdf_oh oh) | 1194 | int qpdf_oh_get_int_value_as_int(qpdf_data qpdf, qpdf_oh oh) |
| 1049 | { | 1195 | { |
| 1050 | - if (! qpdf_oh_valid_internal(qpdf, oh)) | ||
| 1051 | - { | ||
| 1052 | - return 0; | ||
| 1053 | - } | ||
| 1054 | - QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_int_value_as_int"); | ||
| 1055 | - return qpdf->oh_cache[oh]->getIntValueAsInt(); | 1196 | + return do_with_oh<int>( |
| 1197 | + qpdf, oh, return_T<int>(0), [](QPDFObjectHandle& o) { | ||
| 1198 | + QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_int_value_as_int"); | ||
| 1199 | + return o.getIntValueAsInt(); | ||
| 1200 | + }); | ||
| 1056 | } | 1201 | } |
| 1057 | 1202 | ||
| 1058 | unsigned long long qpdf_oh_get_uint_value(qpdf_data qpdf, qpdf_oh oh) | 1203 | unsigned long long qpdf_oh_get_uint_value(qpdf_data qpdf, qpdf_oh oh) |
| 1059 | { | 1204 | { |
| 1060 | - if (! qpdf_oh_valid_internal(qpdf, oh)) | ||
| 1061 | - { | ||
| 1062 | - return 0ULL; | ||
| 1063 | - } | ||
| 1064 | - QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_uint_value"); | ||
| 1065 | - return qpdf->oh_cache[oh]->getUIntValue(); | 1205 | + return do_with_oh<unsigned long long>( |
| 1206 | + qpdf, oh, return_T<unsigned long long>(0ULL), [](QPDFObjectHandle& o) { | ||
| 1207 | + QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_uint_value"); | ||
| 1208 | + return o.getUIntValue(); | ||
| 1209 | + }); | ||
| 1066 | } | 1210 | } |
| 1067 | 1211 | ||
| 1068 | unsigned int qpdf_oh_get_uint_value_as_uint(qpdf_data qpdf, qpdf_oh oh) | 1212 | unsigned int qpdf_oh_get_uint_value_as_uint(qpdf_data qpdf, qpdf_oh oh) |
| 1069 | { | 1213 | { |
| 1070 | - if (! qpdf_oh_valid_internal(qpdf, oh)) | ||
| 1071 | - { | ||
| 1072 | - return 0U; | ||
| 1073 | - } | ||
| 1074 | - QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_uint_value_as_uint"); | ||
| 1075 | - return qpdf->oh_cache[oh]->getUIntValueAsUInt(); | 1214 | + return do_with_oh<unsigned int>( |
| 1215 | + qpdf, oh, return_T<unsigned int>(0U), [](QPDFObjectHandle& o) { | ||
| 1216 | + QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_uint_value_as_uint"); | ||
| 1217 | + return o.getUIntValueAsUInt(); | ||
| 1218 | + }); | ||
| 1076 | } | 1219 | } |
| 1077 | 1220 | ||
| 1078 | char const* qpdf_oh_get_real_value(qpdf_data qpdf, qpdf_oh oh) | 1221 | char const* qpdf_oh_get_real_value(qpdf_data qpdf, qpdf_oh oh) |
| 1079 | { | 1222 | { |
| 1080 | - if (! qpdf_oh_valid_internal(qpdf, oh)) | ||
| 1081 | - { | ||
| 1082 | - return ""; | ||
| 1083 | - } | ||
| 1084 | - QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_real_value"); | ||
| 1085 | - qpdf->tmp_string = qpdf->oh_cache[oh]->getRealValue(); | ||
| 1086 | - return qpdf->tmp_string.c_str(); | ||
| 1087 | -} | ||
| 1088 | - | ||
| 1089 | -QPDF_BOOL qpdf_oh_is_number(qpdf_data qpdf, qpdf_oh oh) | ||
| 1090 | -{ | ||
| 1091 | - if (! qpdf_oh_valid_internal(qpdf, oh)) | ||
| 1092 | - { | ||
| 1093 | - return QPDF_FALSE; | ||
| 1094 | - } | ||
| 1095 | - QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_number"); | ||
| 1096 | - return qpdf->oh_cache[oh]->isNumber(); | 1223 | + return do_with_oh<char const*>( |
| 1224 | + qpdf, oh, return_T<char const*>(""), [&qpdf](QPDFObjectHandle& o) { | ||
| 1225 | + QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_real_value"); | ||
| 1226 | + qpdf->tmp_string = o.getRealValue(); | ||
| 1227 | + return qpdf->tmp_string.c_str(); | ||
| 1228 | + }); | ||
| 1097 | } | 1229 | } |
| 1098 | 1230 | ||
| 1099 | double qpdf_oh_get_numeric_value(qpdf_data qpdf, qpdf_oh oh) | 1231 | double qpdf_oh_get_numeric_value(qpdf_data qpdf, qpdf_oh oh) |
| 1100 | { | 1232 | { |
| 1101 | - if (! qpdf_oh_valid_internal(qpdf, oh)) | ||
| 1102 | - { | ||
| 1103 | - return 0.0; | ||
| 1104 | - } | ||
| 1105 | - QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_numeric_value"); | ||
| 1106 | - return qpdf->oh_cache[oh]->getNumericValue(); | 1233 | + return do_with_oh<double>( |
| 1234 | + qpdf, oh, return_T<double>(0.0), [](QPDFObjectHandle& o) { | ||
| 1235 | + QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_numeric_value"); | ||
| 1236 | + return o.getNumericValue(); | ||
| 1237 | + }); | ||
| 1107 | } | 1238 | } |
| 1108 | 1239 | ||
| 1109 | char const* qpdf_oh_get_name(qpdf_data qpdf, qpdf_oh oh) | 1240 | char const* qpdf_oh_get_name(qpdf_data qpdf, qpdf_oh oh) |
| 1110 | { | 1241 | { |
| 1111 | - if (! qpdf_oh_valid_internal(qpdf, oh)) | ||
| 1112 | - { | ||
| 1113 | - return ""; | ||
| 1114 | - } | ||
| 1115 | - QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_name"); | ||
| 1116 | - qpdf->tmp_string = qpdf->oh_cache[oh]->getName(); | ||
| 1117 | - return qpdf->tmp_string.c_str(); | 1242 | + return do_with_oh<char const*>( |
| 1243 | + qpdf, oh, return_T<char const*>(""), [&qpdf](QPDFObjectHandle& o) { | ||
| 1244 | + QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_name"); | ||
| 1245 | + qpdf->tmp_string = o.getName(); | ||
| 1246 | + return qpdf->tmp_string.c_str(); | ||
| 1247 | + }); | ||
| 1118 | } | 1248 | } |
| 1119 | 1249 | ||
| 1120 | char const* qpdf_oh_get_string_value(qpdf_data qpdf, qpdf_oh oh) | 1250 | char const* qpdf_oh_get_string_value(qpdf_data qpdf, qpdf_oh oh) |
| 1121 | { | 1251 | { |
| 1122 | - if (! qpdf_oh_valid_internal(qpdf, oh)) | ||
| 1123 | - { | ||
| 1124 | - return ""; | ||
| 1125 | - } | ||
| 1126 | - QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_string_value"); | ||
| 1127 | - qpdf->tmp_string = qpdf->oh_cache[oh]->getStringValue(); | ||
| 1128 | - return qpdf->tmp_string.c_str(); | 1252 | + return do_with_oh<char const*>( |
| 1253 | + qpdf, oh, return_T<char const*>(""), [&qpdf](QPDFObjectHandle& o) { | ||
| 1254 | + QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_string_value"); | ||
| 1255 | + qpdf->tmp_string = o.getStringValue(); | ||
| 1256 | + return qpdf->tmp_string.c_str(); | ||
| 1257 | + }); | ||
| 1129 | } | 1258 | } |
| 1130 | 1259 | ||
| 1131 | char const* qpdf_oh_get_utf8_value(qpdf_data qpdf, qpdf_oh oh) | 1260 | char const* qpdf_oh_get_utf8_value(qpdf_data qpdf, qpdf_oh oh) |
| 1132 | { | 1261 | { |
| 1133 | - if (! qpdf_oh_valid_internal(qpdf, oh)) | ||
| 1134 | - { | ||
| 1135 | - return ""; | ||
| 1136 | - } | ||
| 1137 | - QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_utf8_value"); | ||
| 1138 | - qpdf->tmp_string = qpdf->oh_cache[oh]->getUTF8Value(); | ||
| 1139 | - return qpdf->tmp_string.c_str(); | 1262 | + return do_with_oh<char const*>( |
| 1263 | + qpdf, oh, return_T<char const*>(""), [&qpdf](QPDFObjectHandle& o) { | ||
| 1264 | + QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_utf8_value"); | ||
| 1265 | + qpdf->tmp_string = o.getUTF8Value(); | ||
| 1266 | + return qpdf->tmp_string.c_str(); | ||
| 1267 | + }); | ||
| 1140 | } | 1268 | } |
| 1141 | 1269 | ||
| 1142 | int qpdf_oh_get_array_n_items(qpdf_data qpdf, qpdf_oh oh) | 1270 | int qpdf_oh_get_array_n_items(qpdf_data qpdf, qpdf_oh oh) |
| 1143 | { | 1271 | { |
| 1144 | - if (! qpdf_oh_valid_internal(qpdf, oh)) | ||
| 1145 | - { | ||
| 1146 | - return 0; | ||
| 1147 | - } | ||
| 1148 | - QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_array_n_items"); | ||
| 1149 | - return qpdf->oh_cache[oh]->getArrayNItems(); | 1272 | + return do_with_oh<int>( |
| 1273 | + qpdf, oh, return_T<int>(0), [](QPDFObjectHandle& o) { | ||
| 1274 | + QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_array_n_items"); | ||
| 1275 | + return o.getArrayNItems(); | ||
| 1276 | + }); | ||
| 1150 | } | 1277 | } |
| 1151 | 1278 | ||
| 1152 | qpdf_oh qpdf_oh_get_array_item(qpdf_data qpdf, qpdf_oh oh, int n) | 1279 | qpdf_oh qpdf_oh_get_array_item(qpdf_data qpdf, qpdf_oh oh, int n) |
| 1153 | { | 1280 | { |
| 1154 | - if (! qpdf_oh_valid_internal(qpdf, oh)) | ||
| 1155 | - { | ||
| 1156 | - return qpdf_oh_new_null(qpdf); | ||
| 1157 | - } | ||
| 1158 | - QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_array_item"); | ||
| 1159 | - return new_object(qpdf, qpdf->oh_cache[oh]->getArrayItem(n)); | 1281 | + return do_with_oh<qpdf_oh>( |
| 1282 | + qpdf, oh, return_null(qpdf), [&qpdf, &n](QPDFObjectHandle& o) { | ||
| 1283 | + QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_array_item"); | ||
| 1284 | + return new_object(qpdf, o.getArrayItem(n)); | ||
| 1285 | + }); | ||
| 1160 | } | 1286 | } |
| 1161 | 1287 | ||
| 1162 | void qpdf_oh_begin_dict_key_iter(qpdf_data qpdf, qpdf_oh oh) | 1288 | void qpdf_oh_begin_dict_key_iter(qpdf_data qpdf, qpdf_oh oh) |
| 1163 | { | 1289 | { |
| 1164 | - if (qpdf_oh_valid_internal(qpdf, oh) && | ||
| 1165 | - qpdf_oh_is_dictionary(qpdf, oh)) | ||
| 1166 | - { | ||
| 1167 | - QTC::TC("qpdf", "qpdf-c called qpdf_oh_begin_dict_key_iter"); | ||
| 1168 | - qpdf->cur_iter_dict_keys = qpdf->oh_cache[oh]->getKeys(); | ||
| 1169 | - } | ||
| 1170 | - else | ||
| 1171 | - { | ||
| 1172 | - qpdf->cur_iter_dict_keys = {}; | ||
| 1173 | - } | 1290 | + qpdf->cur_iter_dict_keys = do_with_oh<std::set<std::string>>( |
| 1291 | + qpdf, oh, | ||
| 1292 | + [](){ return std::set<std::string>(); }, | ||
| 1293 | + [](QPDFObjectHandle& o) { | ||
| 1294 | + QTC::TC("qpdf", "qpdf-c called qpdf_oh_begin_dict_key_iter"); | ||
| 1295 | + return o.getKeys(); | ||
| 1296 | + }); | ||
| 1174 | qpdf->dict_iter = qpdf->cur_iter_dict_keys.begin(); | 1297 | qpdf->dict_iter = qpdf->cur_iter_dict_keys.begin(); |
| 1175 | } | 1298 | } |
| 1176 | 1299 | ||
| @@ -1197,32 +1320,35 @@ char const* qpdf_oh_dict_next_key(qpdf_data qpdf) | @@ -1197,32 +1320,35 @@ char const* qpdf_oh_dict_next_key(qpdf_data qpdf) | ||
| 1197 | 1320 | ||
| 1198 | QPDF_BOOL qpdf_oh_has_key(qpdf_data qpdf, qpdf_oh oh, char const* key) | 1321 | QPDF_BOOL qpdf_oh_has_key(qpdf_data qpdf, qpdf_oh oh, char const* key) |
| 1199 | { | 1322 | { |
| 1200 | - if (! qpdf_oh_valid_internal(qpdf, oh)) | ||
| 1201 | - { | ||
| 1202 | - return QPDF_FALSE; | ||
| 1203 | - } | ||
| 1204 | - QTC::TC("qpdf", "qpdf-c called qpdf_oh_has_key"); | ||
| 1205 | - return qpdf->oh_cache[oh]->hasKey(key); | 1323 | + return do_with_oh<QPDF_BOOL>( |
| 1324 | + qpdf, oh, return_false, [&key](QPDFObjectHandle& o) { | ||
| 1325 | + QTC::TC("qpdf", "qpdf-c called qpdf_oh_has_key"); | ||
| 1326 | + return o.hasKey(key); | ||
| 1327 | + }); | ||
| 1206 | } | 1328 | } |
| 1207 | 1329 | ||
| 1208 | qpdf_oh qpdf_oh_get_key(qpdf_data qpdf, qpdf_oh oh, char const* key) | 1330 | qpdf_oh qpdf_oh_get_key(qpdf_data qpdf, qpdf_oh oh, char const* key) |
| 1209 | { | 1331 | { |
| 1210 | - if (! qpdf_oh_valid_internal(qpdf, oh)) | ||
| 1211 | - { | ||
| 1212 | - return qpdf_oh_new_null(qpdf); | ||
| 1213 | - } | ||
| 1214 | - QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_key"); | ||
| 1215 | - return new_object(qpdf, qpdf->oh_cache[oh]->getKey(key)); | 1332 | + return do_with_oh<qpdf_oh>( |
| 1333 | + qpdf, oh, return_null(qpdf), [&qpdf, &key](QPDFObjectHandle& o) { | ||
| 1334 | + QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_key"); | ||
| 1335 | + return new_object(qpdf, o.getKey(key)); | ||
| 1336 | + }); | ||
| 1216 | } | 1337 | } |
| 1217 | 1338 | ||
| 1218 | QPDF_BOOL qpdf_oh_is_or_has_name(qpdf_data qpdf, qpdf_oh oh, char const* key) | 1339 | QPDF_BOOL qpdf_oh_is_or_has_name(qpdf_data qpdf, qpdf_oh oh, char const* key) |
| 1219 | { | 1340 | { |
| 1220 | - if (! qpdf_oh_valid_internal(qpdf, oh)) | ||
| 1221 | - { | ||
| 1222 | - return QPDF_FALSE; | ||
| 1223 | - } | ||
| 1224 | - QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_or_has_name"); | ||
| 1225 | - return qpdf->oh_cache[oh]->isOrHasName(key); | 1341 | + return do_with_oh<QPDF_BOOL>( |
| 1342 | + qpdf, oh, return_false, [&key](QPDFObjectHandle& o) { | ||
| 1343 | + QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_or_has_name"); | ||
| 1344 | + return o.isOrHasName(key); | ||
| 1345 | + }); | ||
| 1346 | +} | ||
| 1347 | + | ||
| 1348 | +qpdf_oh qpdf_oh_new_uninitialized(qpdf_data qpdf) | ||
| 1349 | +{ | ||
| 1350 | + QTC::TC("qpdf", "qpdf-c called qpdf_oh_new_uninitialized"); | ||
| 1351 | + return new_object(qpdf, QPDFObjectHandle()); | ||
| 1226 | } | 1352 | } |
| 1227 | 1353 | ||
| 1228 | qpdf_oh qpdf_oh_new_null(qpdf_data qpdf) | 1354 | qpdf_oh qpdf_oh_new_null(qpdf_data qpdf) |
| @@ -1288,156 +1414,143 @@ qpdf_oh qpdf_oh_new_dictionary(qpdf_data qpdf) | @@ -1288,156 +1414,143 @@ qpdf_oh qpdf_oh_new_dictionary(qpdf_data qpdf) | ||
| 1288 | 1414 | ||
| 1289 | void qpdf_oh_make_direct(qpdf_data qpdf, qpdf_oh oh) | 1415 | void qpdf_oh_make_direct(qpdf_data qpdf, qpdf_oh oh) |
| 1290 | { | 1416 | { |
| 1291 | - if (qpdf_oh_valid_internal(qpdf, oh)) | ||
| 1292 | - { | ||
| 1293 | - QTC::TC("qpdf", "qpdf-c called qpdf_oh_make_direct"); | ||
| 1294 | - qpdf->oh_cache[oh]->makeDirect(); | ||
| 1295 | - } | 1417 | + do_with_oh_void( |
| 1418 | + qpdf, oh, [](QPDFObjectHandle& o) { | ||
| 1419 | + QTC::TC("qpdf", "qpdf-c called qpdf_oh_make_direct"); | ||
| 1420 | + o.makeDirect(); | ||
| 1421 | + }); | ||
| 1296 | } | 1422 | } |
| 1297 | 1423 | ||
| 1298 | static QPDFObjectHandle | 1424 | static QPDFObjectHandle |
| 1299 | qpdf_oh_item_internal(qpdf_data qpdf, qpdf_oh item) | 1425 | qpdf_oh_item_internal(qpdf_data qpdf, qpdf_oh item) |
| 1300 | { | 1426 | { |
| 1301 | - if (qpdf_oh_valid_internal(qpdf, item)) | ||
| 1302 | - { | ||
| 1303 | - return *(qpdf->oh_cache[item]); | ||
| 1304 | - } | ||
| 1305 | - else | ||
| 1306 | - { | ||
| 1307 | - return QPDFObjectHandle::newNull(); | ||
| 1308 | - } | 1427 | + return do_with_oh<QPDFObjectHandle>( |
| 1428 | + qpdf, item, | ||
| 1429 | + [](){return QPDFObjectHandle::newNull();}, | ||
| 1430 | + [](QPDFObjectHandle& o) { | ||
| 1431 | + return o; | ||
| 1432 | + }); | ||
| 1309 | } | 1433 | } |
| 1310 | 1434 | ||
| 1311 | void qpdf_oh_set_array_item(qpdf_data qpdf, qpdf_oh oh, | 1435 | void qpdf_oh_set_array_item(qpdf_data qpdf, qpdf_oh oh, |
| 1312 | int at, qpdf_oh item) | 1436 | int at, qpdf_oh item) |
| 1313 | { | 1437 | { |
| 1314 | - if (qpdf_oh_is_array(qpdf, oh)) | ||
| 1315 | - { | ||
| 1316 | - QTC::TC("qpdf", "qpdf-c called qpdf_oh_set_array_item"); | ||
| 1317 | - qpdf->oh_cache[oh]->setArrayItem( | ||
| 1318 | - at, qpdf_oh_item_internal(qpdf, item)); | ||
| 1319 | - } | 1438 | + do_with_oh_void( |
| 1439 | + qpdf, oh, [&qpdf, &at, &item](QPDFObjectHandle& o) { | ||
| 1440 | + QTC::TC("qpdf", "qpdf-c called qpdf_oh_set_array_item"); | ||
| 1441 | + o.setArrayItem(at, qpdf_oh_item_internal(qpdf, item)); | ||
| 1442 | + }); | ||
| 1320 | } | 1443 | } |
| 1321 | 1444 | ||
| 1322 | void qpdf_oh_insert_item(qpdf_data qpdf, qpdf_oh oh, int at, qpdf_oh item) | 1445 | void qpdf_oh_insert_item(qpdf_data qpdf, qpdf_oh oh, int at, qpdf_oh item) |
| 1323 | { | 1446 | { |
| 1324 | - if (qpdf_oh_is_array(qpdf, oh)) | ||
| 1325 | - { | ||
| 1326 | - QTC::TC("qpdf", "qpdf-c called qpdf_oh_insert_item"); | ||
| 1327 | - qpdf->oh_cache[oh]->insertItem( | ||
| 1328 | - at, qpdf_oh_item_internal(qpdf, item)); | ||
| 1329 | - } | 1447 | + do_with_oh_void( |
| 1448 | + qpdf, oh, [&qpdf, &at, &item](QPDFObjectHandle& o) { | ||
| 1449 | + QTC::TC("qpdf", "qpdf-c called qpdf_oh_insert_item"); | ||
| 1450 | + o.insertItem(at, qpdf_oh_item_internal(qpdf, item)); | ||
| 1451 | + }); | ||
| 1330 | } | 1452 | } |
| 1331 | 1453 | ||
| 1332 | void qpdf_oh_append_item(qpdf_data qpdf, qpdf_oh oh, qpdf_oh item) | 1454 | void qpdf_oh_append_item(qpdf_data qpdf, qpdf_oh oh, qpdf_oh item) |
| 1333 | { | 1455 | { |
| 1334 | - if (qpdf_oh_is_array(qpdf, oh)) | ||
| 1335 | - { | ||
| 1336 | - QTC::TC("qpdf", "qpdf-c called qpdf_oh_append_item"); | ||
| 1337 | - qpdf->oh_cache[oh]->appendItem( | ||
| 1338 | - qpdf_oh_item_internal(qpdf, item)); | ||
| 1339 | - } | 1456 | + do_with_oh_void( |
| 1457 | + qpdf, oh, [&qpdf, &item](QPDFObjectHandle& o) { | ||
| 1458 | + QTC::TC("qpdf", "qpdf-c called qpdf_oh_append_item"); | ||
| 1459 | + o.appendItem(qpdf_oh_item_internal(qpdf, item)); | ||
| 1460 | + }); | ||
| 1340 | } | 1461 | } |
| 1341 | 1462 | ||
| 1342 | void qpdf_oh_erase_item(qpdf_data qpdf, qpdf_oh oh, int at) | 1463 | void qpdf_oh_erase_item(qpdf_data qpdf, qpdf_oh oh, int at) |
| 1343 | { | 1464 | { |
| 1344 | - if (qpdf_oh_is_array(qpdf, oh)) | ||
| 1345 | - { | ||
| 1346 | - QTC::TC("qpdf", "qpdf-c called qpdf_oh_erase_item"); | ||
| 1347 | - qpdf->oh_cache[oh]->eraseItem(at); | ||
| 1348 | - } | 1465 | + do_with_oh_void( |
| 1466 | + qpdf, oh, [&at](QPDFObjectHandle& o) { | ||
| 1467 | + QTC::TC("qpdf", "qpdf-c called qpdf_oh_erase_item"); | ||
| 1468 | + o.eraseItem(at); | ||
| 1469 | + }); | ||
| 1349 | } | 1470 | } |
| 1350 | 1471 | ||
| 1351 | void qpdf_oh_replace_key(qpdf_data qpdf, qpdf_oh oh, | 1472 | void qpdf_oh_replace_key(qpdf_data qpdf, qpdf_oh oh, |
| 1352 | char const* key, qpdf_oh item) | 1473 | char const* key, qpdf_oh item) |
| 1353 | { | 1474 | { |
| 1354 | - if (qpdf_oh_is_dictionary(qpdf, oh)) | ||
| 1355 | - { | ||
| 1356 | - QTC::TC("qpdf", "qpdf-c called qpdf_oh_replace_key"); | ||
| 1357 | - qpdf->oh_cache[oh]->replaceKey( | ||
| 1358 | - key, qpdf_oh_item_internal(qpdf, item)); | ||
| 1359 | - } | 1475 | + do_with_oh_void( |
| 1476 | + qpdf, oh, [&qpdf, &key, &item](QPDFObjectHandle& o) { | ||
| 1477 | + QTC::TC("qpdf", "qpdf-c called qpdf_oh_replace_key"); | ||
| 1478 | + o.replaceKey(key, qpdf_oh_item_internal(qpdf, item)); | ||
| 1479 | + }); | ||
| 1360 | } | 1480 | } |
| 1361 | 1481 | ||
| 1362 | void qpdf_oh_remove_key(qpdf_data qpdf, qpdf_oh oh, char const* key) | 1482 | void qpdf_oh_remove_key(qpdf_data qpdf, qpdf_oh oh, char const* key) |
| 1363 | { | 1483 | { |
| 1364 | - if (qpdf_oh_is_dictionary(qpdf, oh)) | ||
| 1365 | - { | ||
| 1366 | - QTC::TC("qpdf", "qpdf-c called qpdf_oh_remove_key"); | ||
| 1367 | - qpdf->oh_cache[oh]->removeKey(key); | ||
| 1368 | - } | 1484 | + do_with_oh_void( |
| 1485 | + qpdf, oh, [&key](QPDFObjectHandle& o) { | ||
| 1486 | + QTC::TC("qpdf", "qpdf-c called qpdf_oh_remove_key"); | ||
| 1487 | + o.removeKey(key); | ||
| 1488 | + }); | ||
| 1369 | } | 1489 | } |
| 1370 | 1490 | ||
| 1371 | void qpdf_oh_replace_or_remove_key(qpdf_data qpdf, qpdf_oh oh, | 1491 | void qpdf_oh_replace_or_remove_key(qpdf_data qpdf, qpdf_oh oh, |
| 1372 | char const* key, qpdf_oh item) | 1492 | char const* key, qpdf_oh item) |
| 1373 | { | 1493 | { |
| 1374 | - if (qpdf_oh_is_dictionary(qpdf, oh)) | ||
| 1375 | - { | ||
| 1376 | - QTC::TC("qpdf", "qpdf-c called qpdf_oh_replace_or_remove_key"); | ||
| 1377 | - qpdf->oh_cache[oh]->replaceOrRemoveKey( | ||
| 1378 | - key, qpdf_oh_item_internal(qpdf, item)); | ||
| 1379 | - } | 1494 | + do_with_oh_void( |
| 1495 | + qpdf, oh, [&qpdf, &key, &item](QPDFObjectHandle& o) { | ||
| 1496 | + QTC::TC("qpdf", "qpdf-c called qpdf_oh_replace_or_remove_key"); | ||
| 1497 | + o.replaceOrRemoveKey(key, qpdf_oh_item_internal(qpdf, item)); | ||
| 1498 | + }); | ||
| 1380 | } | 1499 | } |
| 1381 | 1500 | ||
| 1382 | qpdf_oh qpdf_oh_get_dict(qpdf_data qpdf, qpdf_oh oh) | 1501 | qpdf_oh qpdf_oh_get_dict(qpdf_data qpdf, qpdf_oh oh) |
| 1383 | { | 1502 | { |
| 1384 | - if (! qpdf_oh_valid_internal(qpdf, oh)) | ||
| 1385 | - { | ||
| 1386 | - return qpdf_oh_new_null(qpdf); | ||
| 1387 | - } | ||
| 1388 | - QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_dict"); | ||
| 1389 | - return new_object(qpdf, qpdf->oh_cache[oh]->getDict()); | 1503 | + return do_with_oh<qpdf_oh>( |
| 1504 | + qpdf, oh, return_null(qpdf), [&qpdf](QPDFObjectHandle& o) { | ||
| 1505 | + QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_dict"); | ||
| 1506 | + return new_object(qpdf, o.getDict()); | ||
| 1507 | + }); | ||
| 1390 | } | 1508 | } |
| 1391 | 1509 | ||
| 1392 | int qpdf_oh_get_object_id(qpdf_data qpdf, qpdf_oh oh) | 1510 | int qpdf_oh_get_object_id(qpdf_data qpdf, qpdf_oh oh) |
| 1393 | { | 1511 | { |
| 1394 | - if (! qpdf_oh_valid_internal(qpdf, oh)) | ||
| 1395 | - { | ||
| 1396 | - return 0; | ||
| 1397 | - } | ||
| 1398 | - QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_object_id"); | ||
| 1399 | - return qpdf->oh_cache[oh]->getObjectID(); | 1512 | + return do_with_oh<int>( |
| 1513 | + qpdf, oh, return_T<int>(0), [](QPDFObjectHandle& o) { | ||
| 1514 | + QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_object_id"); | ||
| 1515 | + return o.getObjectID(); | ||
| 1516 | + }); | ||
| 1400 | } | 1517 | } |
| 1401 | 1518 | ||
| 1402 | int qpdf_oh_get_generation(qpdf_data qpdf, qpdf_oh oh) | 1519 | int qpdf_oh_get_generation(qpdf_data qpdf, qpdf_oh oh) |
| 1403 | { | 1520 | { |
| 1404 | - if (! qpdf_oh_valid_internal(qpdf, oh)) | ||
| 1405 | - { | ||
| 1406 | - return 0; | ||
| 1407 | - } | ||
| 1408 | - QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_generation"); | ||
| 1409 | - return qpdf->oh_cache[oh]->getGeneration(); | 1521 | + return do_with_oh<int>( |
| 1522 | + qpdf, oh, return_T<int>(0), [](QPDFObjectHandle& o) { | ||
| 1523 | + QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_generation"); | ||
| 1524 | + return o.getGeneration(); | ||
| 1525 | + }); | ||
| 1410 | } | 1526 | } |
| 1411 | 1527 | ||
| 1412 | char const* qpdf_oh_unparse(qpdf_data qpdf, qpdf_oh oh) | 1528 | char const* qpdf_oh_unparse(qpdf_data qpdf, qpdf_oh oh) |
| 1413 | { | 1529 | { |
| 1414 | - if (! qpdf_oh_valid_internal(qpdf, oh)) | ||
| 1415 | - { | ||
| 1416 | - return ""; | ||
| 1417 | - } | ||
| 1418 | - QTC::TC("qpdf", "qpdf-c called qpdf_oh_unparse"); | ||
| 1419 | - qpdf->tmp_string = qpdf->oh_cache[oh]->unparse(); | ||
| 1420 | - return qpdf->tmp_string.c_str(); | 1530 | + return do_with_oh<char const*>( |
| 1531 | + qpdf, oh, return_T<char const*>(""), [&qpdf](QPDFObjectHandle& o) { | ||
| 1532 | + QTC::TC("qpdf", "qpdf-c called qpdf_oh_unparse"); | ||
| 1533 | + qpdf->tmp_string = o.unparse(); | ||
| 1534 | + return qpdf->tmp_string.c_str(); | ||
| 1535 | + }); | ||
| 1421 | } | 1536 | } |
| 1422 | 1537 | ||
| 1423 | char const* qpdf_oh_unparse_resolved(qpdf_data qpdf, qpdf_oh oh) | 1538 | char const* qpdf_oh_unparse_resolved(qpdf_data qpdf, qpdf_oh oh) |
| 1424 | { | 1539 | { |
| 1425 | - if (! qpdf_oh_valid_internal(qpdf, oh)) | ||
| 1426 | - { | ||
| 1427 | - return ""; | ||
| 1428 | - } | ||
| 1429 | - QTC::TC("qpdf", "qpdf-c called qpdf_oh_unparse_resolved"); | ||
| 1430 | - qpdf->tmp_string = qpdf->oh_cache[oh]->unparseResolved(); | ||
| 1431 | - return qpdf->tmp_string.c_str(); | 1540 | + return do_with_oh<char const*>( |
| 1541 | + qpdf, oh, return_T<char const*>(""), [&qpdf](QPDFObjectHandle& o) { | ||
| 1542 | + QTC::TC("qpdf", "qpdf-c called qpdf_oh_unparse_resolved"); | ||
| 1543 | + qpdf->tmp_string = o.unparseResolved(); | ||
| 1544 | + return qpdf->tmp_string.c_str(); | ||
| 1545 | + }); | ||
| 1432 | } | 1546 | } |
| 1433 | 1547 | ||
| 1434 | char const* qpdf_oh_unparse_binary(qpdf_data qpdf, qpdf_oh oh) | 1548 | char const* qpdf_oh_unparse_binary(qpdf_data qpdf, qpdf_oh oh) |
| 1435 | { | 1549 | { |
| 1436 | - if (! qpdf_oh_valid_internal(qpdf, oh)) | ||
| 1437 | - { | ||
| 1438 | - return ""; | ||
| 1439 | - } | ||
| 1440 | - QTC::TC("qpdf", "qpdf-c called qpdf_oh_unparse_binary"); | ||
| 1441 | - qpdf->tmp_string = qpdf->oh_cache[oh]->unparseBinary(); | ||
| 1442 | - return qpdf->tmp_string.c_str(); | 1550 | + return do_with_oh<char const*>( |
| 1551 | + qpdf, oh, return_T<char const*>(""), [&qpdf](QPDFObjectHandle& o) { | ||
| 1552 | + QTC::TC("qpdf", "qpdf-c called qpdf_oh_unparse_binary"); | ||
| 1553 | + qpdf->tmp_string = o.unparseBinary(); | ||
| 1554 | + return qpdf->tmp_string.c_str(); | ||
| 1555 | + }); | ||
| 1443 | } | 1556 | } |
manual/qpdf-manual.xml
| @@ -5231,6 +5231,19 @@ print "\n"; | @@ -5231,6 +5231,19 @@ print "\n"; | ||
| 5231 | </listitem> | 5231 | </listitem> |
| 5232 | <listitem> | 5232 | <listitem> |
| 5233 | <para> | 5233 | <para> |
| 5234 | + Overhaul error handling for the object handle functions in | ||
| 5235 | + the C API. See comments in the “Object handling” | ||
| 5236 | + section of <filename>include/qpdf/qpdf-c.h</filename> for | ||
| 5237 | + details. In particular, exceptions thrown by the underlying | ||
| 5238 | + C++ code when calling object accessors are caught and | ||
| 5239 | + converted into errors. The errors can be trapped by | ||
| 5240 | + registering an error handler with | ||
| 5241 | + <function>qpdf_register_oh_error_handler</function> or will | ||
| 5242 | + be written to stderr if no handler is registered. | ||
| 5243 | + </para> | ||
| 5244 | + </listitem> | ||
| 5245 | + <listitem> | ||
| 5246 | + <para> | ||
| 5234 | Add <function>qpdf_get_last_string_length</function> to the | 5247 | Add <function>qpdf_get_last_string_length</function> to the |
| 5235 | C API to get the length of the last string that was | 5248 | C API to get the length of the last string that was |
| 5236 | returned. This is needed to handle strings that contain | 5249 | returned. This is needed to handle strings that contain |
| @@ -5239,9 +5252,9 @@ print "\n"; | @@ -5239,9 +5252,9 @@ print "\n"; | ||
| 5239 | </listitem> | 5252 | </listitem> |
| 5240 | <listitem> | 5253 | <listitem> |
| 5241 | <para> | 5254 | <para> |
| 5242 | - Add <function>qpdf_oh_is_initialized</function> to the | ||
| 5243 | - C API. While you can't directly create uninitialized objects | ||
| 5244 | - from the C API, you still have to be able to detect them. | 5255 | + Add <function>qpdf_oh_is_initialized</function> and |
| 5256 | + <function>qpdf_oh_new_uninitialized</function> to the C API | ||
| 5257 | + to make it possible to work with uninitialized objects. | ||
| 5245 | </para> | 5258 | </para> |
| 5246 | </listitem> | 5259 | </listitem> |
| 5247 | <listitem> | 5260 | <listitem> |
qpdf/qpdf-ctest.c
| @@ -35,28 +35,29 @@ static FILE* safe_fopen(char const* filename, char const* mode) | @@ -35,28 +35,29 @@ static FILE* safe_fopen(char const* filename, char const* mode) | ||
| 35 | return f; | 35 | return f; |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | -static void report_errors() | 38 | +static void print_error(char const* label, qpdf_data qpdf, qpdf_error e) |
| 39 | { | 39 | { |
| 40 | #define POS_FMT " pos : " LL_FMT "\n" | 40 | #define POS_FMT " pos : " LL_FMT "\n" |
| 41 | + printf("%s: %s\n", label, qpdf_get_error_full_text(qpdf, e)); | ||
| 42 | + printf(" code: %d\n", qpdf_get_error_code(qpdf, e)); | ||
| 43 | + printf(" file: %s\n", qpdf_get_error_filename(qpdf, e)); | ||
| 44 | + printf(POS_FMT, qpdf_get_error_file_position(qpdf, e)); | ||
| 45 | + printf(" text: %s\n", qpdf_get_error_message_detail(qpdf, e)); | ||
| 46 | +} | ||
| 47 | + | ||
| 48 | +static void report_errors() | ||
| 49 | +{ | ||
| 41 | qpdf_error e = 0; | 50 | qpdf_error e = 0; |
| 42 | while (qpdf_more_warnings(qpdf)) | 51 | while (qpdf_more_warnings(qpdf)) |
| 43 | { | 52 | { |
| 44 | e = qpdf_next_warning(qpdf); | 53 | e = qpdf_next_warning(qpdf); |
| 45 | - printf("warning: %s\n", qpdf_get_error_full_text(qpdf, e)); | ||
| 46 | - printf(" code: %d\n", qpdf_get_error_code(qpdf, e)); | ||
| 47 | - printf(" file: %s\n", qpdf_get_error_filename(qpdf, e)); | ||
| 48 | - printf(POS_FMT, qpdf_get_error_file_position(qpdf, e)); | ||
| 49 | - printf(" text: %s\n", qpdf_get_error_message_detail(qpdf, e)); | 54 | + print_error("warning", qpdf, e); |
| 50 | } | 55 | } |
| 51 | if (qpdf_has_error(qpdf)) | 56 | if (qpdf_has_error(qpdf)) |
| 52 | { | 57 | { |
| 53 | e = qpdf_get_error(qpdf); | 58 | e = qpdf_get_error(qpdf); |
| 54 | assert(qpdf_has_error(qpdf) == QPDF_FALSE); | 59 | assert(qpdf_has_error(qpdf) == QPDF_FALSE); |
| 55 | - printf("error: %s\n", qpdf_get_error_full_text(qpdf, e)); | ||
| 56 | - printf(" code: %d\n", qpdf_get_error_code(qpdf, e)); | ||
| 57 | - printf(" file: %s\n", qpdf_get_error_filename(qpdf, e)); | ||
| 58 | - printf(POS_FMT, qpdf_get_error_file_position(qpdf, e)); | ||
| 59 | - printf(" text: %s\n", qpdf_get_error_message_detail(qpdf, e)); | 60 | + print_error("error", qpdf, e); |
| 60 | } | 61 | } |
| 61 | else | 62 | else |
| 62 | { | 63 | { |
| @@ -72,6 +73,16 @@ static void report_errors() | @@ -72,6 +73,16 @@ static void report_errors() | ||
| 72 | } | 73 | } |
| 73 | } | 74 | } |
| 74 | 75 | ||
| 76 | +static void handle_oh_error(qpdf_data qpdf, qpdf_error error, void* data) | ||
| 77 | +{ | ||
| 78 | + char const* label = "oh error"; | ||
| 79 | + if (data) | ||
| 80 | + { | ||
| 81 | + label = *((char const**)data); | ||
| 82 | + } | ||
| 83 | + print_error(label, qpdf, error); | ||
| 84 | +} | ||
| 85 | + | ||
| 75 | static void read_file_into_memory(char const* filename, | 86 | static void read_file_into_memory(char const* filename, |
| 76 | char** buf, unsigned long* size) | 87 | char** buf, unsigned long* size) |
| 77 | { | 88 | { |
| @@ -615,8 +626,11 @@ static void test24(char const* infile, | @@ -615,8 +626,11 @@ static void test24(char const* infile, | ||
| 615 | */ | 626 | */ |
| 616 | qpdf_oh_replace_key(qpdf, resources, "/ProcSet", procset); | 627 | qpdf_oh_replace_key(qpdf, resources, "/ProcSet", procset); |
| 617 | 628 | ||
| 618 | - /* Release and access to exercise warnings and to show that write | ||
| 619 | - * still works after releasing. | 629 | + /* Release and access to exercise handling of object handle errors |
| 630 | + * and to show that write still works after releasing. This test | ||
| 631 | + * uses the default oh error handler, so messages get written to | ||
| 632 | + * stderr. The warning about using the default error handler only | ||
| 633 | + * appears once. | ||
| 620 | */ | 634 | */ |
| 621 | qpdf_oh_release(qpdf, page1); | 635 | qpdf_oh_release(qpdf, page1); |
| 622 | contents = qpdf_oh_get_key(qpdf, page1, "/Contents"); | 636 | contents = qpdf_oh_get_key(qpdf, page1, "/Contents"); |
| @@ -791,6 +805,82 @@ static void test28(char const* infile, | @@ -791,6 +805,82 @@ static void test28(char const* infile, | ||
| 791 | } | 805 | } |
| 792 | } | 806 | } |
| 793 | 807 | ||
| 808 | +static void test29(char const* infile, | ||
| 809 | + char const* password, | ||
| 810 | + char const* outfile, | ||
| 811 | + char const* outfile2) | ||
| 812 | +{ | ||
| 813 | + /* Trap exceptions thrown by object accessors. Type mismatches are | ||
| 814 | + * errors rather than warnings when they don't have an owning QPDF | ||
| 815 | + * object. | ||
| 816 | + */ | ||
| 817 | + char const* label = "oh error"; | ||
| 818 | + qpdf_register_oh_error_handler(qpdf, handle_oh_error, (void*)&label); | ||
| 819 | + | ||
| 820 | + /* get_root fails when we have no trailer */ | ||
| 821 | + label = "get root"; | ||
| 822 | + qpdf_oh root = qpdf_get_root(qpdf); | ||
| 823 | + assert(root != 0); | ||
| 824 | + assert(! qpdf_oh_is_initialized(qpdf, root)); | ||
| 825 | + | ||
| 826 | + label = "bad parse"; | ||
| 827 | + assert(! qpdf_oh_is_initialized(qpdf, qpdf_oh_parse(qpdf, "[oops"))); | ||
| 828 | + report_errors(); | ||
| 829 | + | ||
| 830 | + label = "type mismatch"; | ||
| 831 | + assert(qpdf_oh_get_int_value_as_int( | ||
| 832 | + qpdf, qpdf_oh_new_string(qpdf, "x")) == 0); | ||
| 833 | + qpdf_oh int_oh = qpdf_oh_new_integer(qpdf, 12); | ||
| 834 | + assert(strlen(qpdf_oh_get_string_value(qpdf, int_oh)) == 0); | ||
| 835 | + | ||
| 836 | + // This doesn't test every possible error flow, but it tests each | ||
| 837 | + // way of handling errors in the library code. | ||
| 838 | + label = "array type mismatch"; | ||
| 839 | + assert(qpdf_oh_get_array_n_items(qpdf, int_oh) == 0); | ||
| 840 | + assert(qpdf_oh_is_null(qpdf, qpdf_oh_get_array_item(qpdf, int_oh, 3))); | ||
| 841 | + label = "append to non-array"; | ||
| 842 | + qpdf_oh_append_item(qpdf, int_oh, qpdf_oh_new_null(qpdf)); | ||
| 843 | + qpdf_oh array = qpdf_oh_new_array(qpdf); | ||
| 844 | + label = "array bounds"; | ||
| 845 | + assert(qpdf_oh_is_null(qpdf, qpdf_oh_get_array_item(qpdf, array, 3))); | ||
| 846 | + | ||
| 847 | + label = "dictionary iter type mismatch"; | ||
| 848 | + qpdf_oh_begin_dict_key_iter(qpdf, int_oh); | ||
| 849 | + assert(qpdf_oh_dict_more_keys(qpdf) == QPDF_FALSE); | ||
| 850 | + label = "dictionary type mismatch"; | ||
| 851 | + assert(qpdf_oh_is_null(qpdf, qpdf_oh_get_key(qpdf, int_oh, "potato"))); | ||
| 852 | + assert(qpdf_oh_has_key(qpdf, int_oh, "potato") == QPDF_FALSE); | ||
| 853 | + | ||
| 854 | + report_errors(); | ||
| 855 | +} | ||
| 856 | + | ||
| 857 | +static void test30(char const* infile, | ||
| 858 | + char const* password, | ||
| 859 | + char const* outfile, | ||
| 860 | + char const* outfile2) | ||
| 861 | +{ | ||
| 862 | + assert(qpdf_read(qpdf, infile, password) & QPDF_ERRORS); | ||
| 863 | + /* Fail to handle error */ | ||
| 864 | +} | ||
| 865 | + | ||
| 866 | +static void test31(char const* infile, | ||
| 867 | + char const* password, | ||
| 868 | + char const* outfile, | ||
| 869 | + char const* outfile2) | ||
| 870 | +{ | ||
| 871 | + /* Make sure type warnings have a specific error code. This test | ||
| 872 | + * case is designed for minimal.pdf. | ||
| 873 | + */ | ||
| 874 | + qpdf_read(qpdf, infile, password); | ||
| 875 | + qpdf_oh trailer = qpdf_get_trailer(qpdf); | ||
| 876 | + assert(qpdf_oh_get_int_value(qpdf, trailer) == 0LL); | ||
| 877 | + assert(! qpdf_has_error(qpdf)); | ||
| 878 | + assert(qpdf_more_warnings(qpdf)); | ||
| 879 | + qpdf_error e = qpdf_next_warning(qpdf); | ||
| 880 | + assert(qpdf_get_error_code(qpdf, e) == qpdf_e_object); | ||
| 881 | + report_errors(); | ||
| 882 | +} | ||
| 883 | + | ||
| 794 | int main(int argc, char* argv[]) | 884 | int main(int argc, char* argv[]) |
| 795 | { | 885 | { |
| 796 | char* p = 0; | 886 | char* p = 0; |
| @@ -859,6 +949,9 @@ int main(int argc, char* argv[]) | @@ -859,6 +949,9 @@ int main(int argc, char* argv[]) | ||
| 859 | (n == 26) ? test26 : | 949 | (n == 26) ? test26 : |
| 860 | (n == 27) ? test27 : | 950 | (n == 27) ? test27 : |
| 861 | (n == 28) ? test28 : | 951 | (n == 28) ? test28 : |
| 952 | + (n == 29) ? test29 : | ||
| 953 | + (n == 30) ? test30 : | ||
| 954 | + (n == 31) ? test31 : | ||
| 862 | 0); | 955 | 0); |
| 863 | 956 | ||
| 864 | if (fn == 0) | 957 | if (fn == 0) |
qpdf/qpdf.testcov
| @@ -602,3 +602,7 @@ QPDFObjectHandle check ownership 0 | @@ -602,3 +602,7 @@ QPDFObjectHandle check ownership 0 | ||
| 602 | qpdf weak crypto warning 0 | 602 | qpdf weak crypto warning 0 |
| 603 | qpdf-c called qpdf_oh_is_initialized 0 | 603 | qpdf-c called qpdf_oh_is_initialized 0 |
| 604 | qpdf-c registered progress reporter 0 | 604 | qpdf-c registered progress reporter 0 |
| 605 | +qpdf-c called qpdf_oh_new_uninitialized 0 | ||
| 606 | +qpdf-c warn about oh error 1 | ||
| 607 | +qpdf-c registered oh error handler 0 | ||
| 608 | +qpdf-c cleanup warned about unhandled error 0 |
qpdf/qtest/qpdf.test
| @@ -4812,7 +4812,7 @@ foreach my $i (@c_check_types) | @@ -4812,7 +4812,7 @@ foreach my $i (@c_check_types) | ||
| 4812 | show_ntests(); | 4812 | show_ntests(); |
| 4813 | # ---------- | 4813 | # ---------- |
| 4814 | $td->notify("--- C API Object Handle ---"); | 4814 | $td->notify("--- C API Object Handle ---"); |
| 4815 | -$n_tests += 7; | 4815 | +$n_tests += 10; |
| 4816 | 4816 | ||
| 4817 | $td->runtest("C check object handles", | 4817 | $td->runtest("C check object handles", |
| 4818 | {$td->COMMAND => "qpdf-ctest 24 minimal.pdf '' a.pdf"}, | 4818 | {$td->COMMAND => "qpdf-ctest 24 minimal.pdf '' a.pdf"}, |
| @@ -4843,6 +4843,18 @@ $td->runtest("C wrap and clone objects", | @@ -4843,6 +4843,18 @@ $td->runtest("C wrap and clone objects", | ||
| 4843 | {$td->COMMAND => "qpdf-ctest 28 minimal.pdf '' ''"}, | 4843 | {$td->COMMAND => "qpdf-ctest 28 minimal.pdf '' ''"}, |
| 4844 | {$td->STRING => "", $td->EXIT_STATUS => 0}, | 4844 | {$td->STRING => "", $td->EXIT_STATUS => 0}, |
| 4845 | $td->NORMALIZE_NEWLINES); | 4845 | $td->NORMALIZE_NEWLINES); |
| 4846 | +$td->runtest("C object handle errors", | ||
| 4847 | + {$td->COMMAND => "qpdf-ctest 29 minimal.pdf '' ''"}, | ||
| 4848 | + {$td->FILE => "c-oh-errors.out", $td->EXIT_STATUS => 0}, | ||
| 4849 | + $td->NORMALIZE_NEWLINES); | ||
| 4850 | +$td->runtest("C unhandled error warning", | ||
| 4851 | + {$td->COMMAND => "qpdf-ctest 30 bad1.pdf '' ''"}, | ||
| 4852 | + {$td->FILE => "c-unhandled-error.out", $td->EXIT_STATUS => 0}, | ||
| 4853 | + $td->NORMALIZE_NEWLINES); | ||
| 4854 | +$td->runtest("C type mismatch warning", | ||
| 4855 | + {$td->COMMAND => "qpdf-ctest 31 minimal.pdf '' ''"}, | ||
| 4856 | + {$td->FILE => "c-type-warning.out", $td->EXIT_STATUS => 0}, | ||
| 4857 | + $td->NORMALIZE_NEWLINES); | ||
| 4846 | 4858 | ||
| 4847 | show_ntests(); | 4859 | show_ntests(); |
| 4848 | # ---------- | 4860 | # ---------- |
qpdf/qtest/qpdf/c-object-handles.out
| @@ -7,18 +7,11 @@ item 0: 0 0.00 | @@ -7,18 +7,11 @@ item 0: 0 0.00 | ||
| 7 | item 1: 0 0.00 | 7 | item 1: 0 0.00 |
| 8 | item 2: 612 612.00 | 8 | item 2: 612 612.00 |
| 9 | item 3: 792 792.00 | 9 | item 3: 792 792.00 |
| 10 | -warning: minimal.pdf (C API object handle 6): attempted access to unknown object handle | ||
| 11 | - code: 5 | 10 | +minimal.pdf (C API object handle 6): attempted access to unknown object handle |
| 11 | +minimal.pdf (C API object handle 9): attempted access to unknown object handle | ||
| 12 | +minimal.pdf (C API object handle 9): attempted access to unknown object handle | ||
| 13 | +warning: minimal.pdf: C API object handle accessor errors occurred, and the application did not define an error handler | ||
| 14 | + code: 1 | ||
| 12 | file: minimal.pdf | 15 | file: minimal.pdf |
| 13 | pos : 0 | 16 | pos : 0 |
| 14 | - text: attempted access to unknown object handle | ||
| 15 | -warning: minimal.pdf (C API object handle 9): attempted access to unknown object handle | ||
| 16 | - code: 5 | ||
| 17 | - file: minimal.pdf | ||
| 18 | - pos : 0 | ||
| 19 | - text: attempted access to unknown object handle | ||
| 20 | -warning: minimal.pdf (C API object handle 9): attempted access to unknown object handle | ||
| 21 | - code: 5 | ||
| 22 | - file: minimal.pdf | ||
| 23 | - pos : 0 | ||
| 24 | - text: attempted access to unknown object handle | 17 | + text: C API object handle accessor errors occurred, and the application did not define an error handler |
qpdf/qtest/qpdf/c-oh-errors.out
0 โ 100644
| 1 | +get root: attempted to dereference an uninitialized QPDFObjectHandle | ||
| 2 | + code: 1 | ||
| 3 | + file: | ||
| 4 | + pos : 0 | ||
| 5 | + text: attempted to dereference an uninitialized QPDFObjectHandle | ||
| 6 | +bad parse: parsed object (offset 1): unknown token while reading object; treating as string | ||
| 7 | + code: 5 | ||
| 8 | + file: parsed object | ||
| 9 | + pos : 1 | ||
| 10 | + text: unknown token while reading object; treating as string | ||
| 11 | +type mismatch: operation for integer attempted on object of type string: returning 0 | ||
| 12 | + code: 7 | ||
| 13 | + file: | ||
| 14 | + pos : 0 | ||
| 15 | + text: operation for integer attempted on object of type string: returning 0 | ||
| 16 | +type mismatch: operation for string attempted on object of type integer: returning empty string | ||
| 17 | + code: 7 | ||
| 18 | + file: | ||
| 19 | + pos : 0 | ||
| 20 | + text: operation for string attempted on object of type integer: returning empty string | ||
| 21 | +array type mismatch: operation for array attempted on object of type integer: treating as empty | ||
| 22 | + code: 7 | ||
| 23 | + file: | ||
| 24 | + pos : 0 | ||
| 25 | + text: operation for array attempted on object of type integer: treating as empty | ||
| 26 | +array type mismatch: operation for array attempted on object of type integer: returning null | ||
| 27 | + code: 7 | ||
| 28 | + file: | ||
| 29 | + pos : 0 | ||
| 30 | + text: operation for array attempted on object of type integer: returning null | ||
| 31 | +append to non-array: operation for array attempted on object of type integer: ignoring attempt to append item | ||
| 32 | + code: 7 | ||
| 33 | + file: | ||
| 34 | + pos : 0 | ||
| 35 | + text: operation for array attempted on object of type integer: ignoring attempt to append item | ||
| 36 | +array bounds: returning null for out of bounds array access | ||
| 37 | + code: 7 | ||
| 38 | + file: | ||
| 39 | + pos : 0 | ||
| 40 | + text: returning null for out of bounds array access | ||
| 41 | +dictionary iter type mismatch: operation for dictionary attempted on object of type integer: treating as empty | ||
| 42 | + code: 7 | ||
| 43 | + file: | ||
| 44 | + pos : 0 | ||
| 45 | + text: operation for dictionary attempted on object of type integer: treating as empty | ||
| 46 | +dictionary type mismatch: operation for dictionary attempted on object of type integer: returning null for attempted key retrieval | ||
| 47 | + code: 7 | ||
| 48 | + file: | ||
| 49 | + pos : 0 | ||
| 50 | + text: operation for dictionary attempted on object of type integer: returning null for attempted key retrieval | ||
| 51 | +dictionary type mismatch: operation for dictionary attempted on object of type integer: returning false for a key containment request | ||
| 52 | + code: 7 | ||
| 53 | + file: | ||
| 54 | + pos : 0 | ||
| 55 | + text: operation for dictionary attempted on object of type integer: returning false for a key containment request |
qpdf/qtest/qpdf/c-type-warning.out
0 โ 100644
| 1 | +WARNING: minimal.pdf, trailer at offset 715: operation for integer attempted on object of type dictionary: returning 0 |
qpdf/qtest/qpdf/c-unhandled-error.out
0 โ 100644
| 1 | +WARNING: bad1.pdf: can't find PDF header | ||
| 2 | +WARNING: bad1.pdf: file is damaged | ||
| 3 | +WARNING: bad1.pdf: can't find startxref | ||
| 4 | +WARNING: bad1.pdf: Attempting to reconstruct cross-reference table | ||
| 5 | +WARNING: application did not handle error: bad1.pdf: unable to find trailer dictionary while recovering damaged file |