From 84ec83e92589461e6da68029ed7148ba48198215 Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Sun, 27 Sep 2009 14:39:04 +0000 Subject: basic implementation of C API git-svn-id: svn+q:///qpdf/trunk@725 71b93d88-0707-0410-a8cf-f5a4172ac649 --- TODO | 3 - include/qpdf/QPDF.hh | 2 +- include/qpdf/qpdf-c.h | 191 +++++++++++++++++++++------- libqpdf/QPDF.cc | 5 +- libqpdf/qpdf-c.cc | 335 +++++++++++++++++++++++++++++++++++++++++++++++++- qpdf/qpdf.testcov | 26 ++++ 6 files changed, 513 insertions(+), 49 deletions(-) diff --git a/TODO b/TODO index 8a56811e..d352e7ae 100644 --- a/TODO +++ b/TODO @@ -23,9 +23,6 @@ * See if it is possible to support rewriting a file in place or at least to detect and block this - * Spell check to fix typos in messages and comments. Known typo in - "damanged". - General ======= diff --git a/include/qpdf/QPDF.hh b/include/qpdf/QPDF.hh index 6b848f63..08f82efb 100644 --- a/include/qpdf/QPDF.hh +++ b/include/qpdf/QPDF.hh @@ -41,7 +41,7 @@ class QPDF // Prior to calling this, the only methods that are allowed are // those that set parameters. DLL_EXPORT - void processFile(char const* filename, char const* password = ""); + void processFile(char const* filename, char const* password = 0); // Parameter settings diff --git a/include/qpdf/qpdf-c.h b/include/qpdf/qpdf-c.h index 57a08e54..2f0096f5 100644 --- a/include/qpdf/qpdf-c.h +++ b/include/qpdf/qpdf-c.h @@ -6,9 +6,59 @@ * a subset of the QPDF library's capabilities to make them accessible * to callers who can't handle calling C++ functions or working with * C++ classes. This may be especially useful to Windows users who - * are accessing the qpdflib DLL directly or to other people - * programming in non-C/C++ languages that can call C code but not C++ - * code. + * are accessing the qpdf DLL directly or to other people programming + * in non-C/C++ languages that can call C code but not C++ code. + * + * There are several things to keep in mind when using the C API. + * + * The C API is not as rich as the C++ API. For any operations + * that involve actually manipulating PDF objects, you must use + * the C++ API. The C API is primarily useful for doing basic + * transformations on PDF files similar to what you might do with + * the qpdf command-line tool. + * + * These functions store their state in a qpdf_data object. + * Individual instances of qpdf_data are not thread-safe: although + * you may access different qpdf_data objects from different + * threads, you may not access one qpdf_data simultaneously from + * multiple threads. + * + * All dynamic memory, except for that of the qpdf_data object + * itself, is managed by the library. You must create a qpdf_data + * object using qpdf_init and free it using qpdf_cleanup. + * + * Many functions return char*. In all cases, the char* values + * returned are pointers to data inside the qpdf_data object. As + * such, they are always freed by qpdf_cleanup. In most cases, + * strings returned by functions here may be invalidated by + * subsequent function calls, sometimes even to different + * functions. If you want a string to last past the next qpdf + * call or after a call to qpdf_cleanup, you should make a copy of + * it. + * + * Many functions defined here merely set parameters and therefore + * never return error conditions. Functions that may cause PDF + * files to be read or written may return error conditions. Such + * functions return an error code. If there were no errors or + * warnings, they return QPDF_SUCCESS. If there were warnings, + * the return value has the QPDF_WARNINGS bit set. If there + * 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 + * whether there are unseen warning or error conditions. By + * default, warnings are written to stderr when detected, but this + * behavior can be suppressed. In all cases, errors and warnings + * may be retrieved by calling qpdf_next_warning and + * qpdf_next_error. All exceptions thrown by the C++ interface + * are caught and converted into error messages by the C + * interface. + * + * Most functions defined here have obvious counterparts that are + * methods to either QPDF or QPDFWriter. Please see comments in + * QPDF.hh and QPDFWriter.hh for details on their use. In order + * to avoid duplication of information, comments here focus + * primarily on differences between the C and C++ API. */ #include @@ -20,34 +70,26 @@ extern "C" { typedef struct _qpdf_data* qpdf_data; /* Many functions return an integer error code. Codes are defined - * below. See ERROR REPORTING below. + * below. See comments at the top of the file for details. Note + * that the values below can be logically orred together. */ typedef int QPDF_ERROR_CODE; # define QPDF_SUCCESS 0 -# define QPDF_WARNINGS 1 -# define QPDF_ERRORS 2 +# define QPDF_WARNINGS 1 << 0 +# define QPDF_ERRORS 1 << 1 typedef int QPDF_BOOL; # define QPDF_TRUE 1 # define QPDF_FALSE 0 /* Returns dynamically allocated qpdf_data pointer; must be freed - * by calling qpdf_cleanup. Note that qpdf_data is not - * thread-safe: although you may access different qpdf_data - * objects from different threads, you may not access one - * qpdf_data simultaneously from multiple threads. Many functions - * defined below return char*. In all cases, the char* values - * returned are pointers to data inside the qpdf_data object. As - * such, they are always freed by qpdf_cleanup. In some cases, - * strings returned by functions here may be overwritten by - * additional function calls, so if you really want a string to - * last past the next qpdf call, you should make a copy of it. + * by calling qpdf_cleanup. */ DLL_EXPORT qpdf_data qpdf_init(); /* Pass a pointer to the qpdf_data pointer created by qpdf_init to - * clean up resoures. + * clean up resources. */ DLL_EXPORT void qpdf_cleanup(qpdf_data* qpdf); @@ -59,40 +101,45 @@ extern "C" { */ DLL_EXPORT QPDF_BOOL qpdf_more_errors(qpdf_data qpdf); - - /* If there are any errors, returns a pointer to the next error. - * Otherwise returns a null pointer. The error value returned is - * a pointer to data inside the qpdf_data object. It will become - * valid the next time a qpdf function that returns a string is - * called or after a call to qpdf_cleanup. - */ DLL_EXPORT - char const* qpdf_next_error(qpdf_data qpdf); + QPDF_BOOL qpdf_more_warnings(qpdf_data qpdf); - /* These functions are analogous to the "error" counterparts but - * apply to warnings. + /* If there are any errors/warnings, returns a pointer to the next + * error or warning. Otherwise returns a null pointer. */ - DLL_EXPORT - QPDF_BOOL qpdf_more_warnings(qpdf_data qpdf); + char const* qpdf_next_error(qpdf_data qpdf); DLL_EXPORT char const* qpdf_next_warning(qpdf_data qpdf); - /* READ PARAMETER FUNCTIONS */ - /* By default, warnings are written to stderr. Passing true to - this function will prevent warnings from being written to stderr. - They will still be available by calls to qpdf_next_warning. - */ + * this function will prevent warnings from being written to + * stderr. They will still be available by calls to + * qpdf_next_warning. + */ DLL_EXPORT - void qpdf_set_suppress_warnings(qpdf_data qpdf, QPDF_BOOL val); + void qpdf_set_suppress_warnings(qpdf_data qpdf, QPDF_BOOL value); /* READ FUNCTIONS */ - /* POST-READ QUERY FUNCTIONS */ + /* READ PARAMETER FUNCTIONS -- must be called before qpdf_read */ - /* These functions are invalid until after qpdf_read has been - * called. */ + DLL_EXPORT + void qpdf_set_ignore_xref_streams(qpdf_data qpdf, QPDF_BOOL value); + + DLL_EXPORT + void qpdf_set_attempt_recovery(qpdf_data qpdf, QPDF_BOOL value); + + /* Calling qpdf_read causes processFile to be called in the C++ + * API. Basic parsing is performed, but data from the file is + * only read as needed. For files without passwords, pass a null + * pointer as the password. + */ + DLL_EXPORT + QPDF_ERROR_CODE qpdf_read(qpdf_data qpdf, char const* filename, + char const* password); + + /* Read functions below must be called after qpdf_read. */ /* Return the version of the PDF file. */ DLL_EXPORT @@ -126,13 +173,73 @@ extern "C" { * until the call to qpdf_write. */ DLL_EXPORT - QPDF_ERROR_CODE qpdf_init_write(qpdf_data data, char const* filename); + QPDF_ERROR_CODE qpdf_init_write(qpdf_data qpdf, char const* filename); + +# define QPDF_OBJECT_STREAM_DISABLE 0 +# define QPDF_OBJECT_STREAM_PRESERVE 1 +# define QPDF_OBJECT_STREAM_GENERATE 2 + + /* For mode, pass one of the QPDF_OBJECT_STREAM constants. */ + DLL_EXPORT + void qpdf_set_object_stream_mode(qpdf_data qpdf, int mode); - /* XXX Get public interface from QPDFWriter */ +# define QPDF_STREAM_DATA_UNCOMPRESS 0 +# define QPDF_STREAM_DATA_PRESERVE 1 +# define QPDF_STREAM_DATA_COMPRESS 2 + /* For mode, pass one of the QPDF_STREAM_DATA constants. */ + DLL_EXPORT + void qpdf_set_stream_data_mode(qpdf_data qpdf, int mode); + + DLL_EXPORT + void qpdf_set_content_normalization(qpdf_data qpdf, QPDF_BOOL value); + + DLL_EXPORT + void qpdf_set_qdf_mode(qpdf_data qpdf, QPDF_BOOL value); + + /* Never use qpdf_set_static_ID except in test suites to suppress + * generation of a random /ID. + */ + DLL_EXPORT + void qpdf_set_static_ID(qpdf_data qpdf, QPDF_BOOL value); + + DLL_EXPORT + void qpdf_set_suppress_original_object_IDs( + qpdf_data qpdf, QPDF_BOOL value); + + DLL_EXPORT + void qpdf_set_preserve_encryption(qpdf_data qpdf, QPDF_BOOL value); + + DLL_EXPORT + void qpdf_set_r2_encryption_parameters( + qpdf_data qpdf, char const* user_password, char const* owner_password, + QPDF_BOOL allow_print, QPDF_BOOL allow_modify, + QPDF_BOOL allow_extract, QPDF_BOOL allow_annotate); + +# define QPDF_R3_PRINT_FULL 0 +# define QPDF_R3_PRINT_LOW 1 +# define QPDF_R3_PRINT_NONE 2 + +# define QPDF_R3_MODIFY_ALL 0 +# define QPDF_R3_MODIFY_ANNOTATE 1 +# define QPDF_R3_MODIFY_FORM 2 +# define QPDF_R3_MODIFY_ASSEMBLY 3 +# define QPDF_R3_MODIFY_NONE 4 + + /* Value of print should be one of the QPDF_R3_PRINT constants. + * Value of modify should be one of the QPDF_R3_MODIFY constants. + */ + DLL_EXPORT + void qpdf_set_r3_encryption_parameters( + qpdf_data qpdf, char const* user_password, char const* owner_password, + QPDF_BOOL allow_accessibility, QPDF_BOOL allow_extract, + int print, int modify); + + DLL_EXPORT + void qpdf_set_linearization(qpdf_data qpdf, QPDF_BOOL value); - /* Perform the actual write operation. */ + /* Do actual write operation. */ DLL_EXPORT - QPDF_ERROR_CODE qpdf_write(); + QPDF_ERROR_CODE qpdf_write(qpdf_data qpdf); #ifdef __cplusplus } diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index d49ad5f1..8f275b74 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -271,7 +271,10 @@ void QPDF::processFile(char const* filename, char const* password) { this->file.setFilename(filename); - this->provided_password = password; + if (password) + { + this->provided_password = password; + } parse(); } diff --git a/libqpdf/qpdf-c.cc b/libqpdf/qpdf-c.cc index 3dd7fbe7..4e60c525 100644 --- a/libqpdf/qpdf-c.cc +++ b/libqpdf/qpdf-c.cc @@ -1,18 +1,349 @@ #include -class _qpdf_data +#include +#include +#include + +#include +#include +#include + +struct _qpdf_data { + _qpdf_data(); + ~_qpdf_data(); + + QPDF* qpdf; + QPDFWriter* qpdf_writer; + + std::string error; + std::list warnings; + std::string tmp_string; }; +_qpdf_data::_qpdf_data() : + qpdf(0), + qpdf_writer(0) +{ +} + +_qpdf_data::~_qpdf_data() +{ + delete qpdf_writer; + delete qpdf; +} + DLL_EXPORT qpdf_data qpdf_init() { - return new _qpdf_data(); + QTC::TC("qpdf", "qpdf-c called qpdf_init"); + qpdf_data qpdf = new _qpdf_data(); + qpdf->qpdf = new QPDF(); + return qpdf; } DLL_EXPORT void qpdf_cleanup(qpdf_data* qpdf) { + QTC::TC("qpdf", "qpdf-c called qpdf_cleanup"); delete *qpdf; *qpdf = 0; } + +DLL_EXPORT +QPDF_BOOL qpdf_more_errors(qpdf_data qpdf) +{ + QTC::TC("qpdf", "qpdf-c called qpdf_more_errors"); + return (qpdf->error.empty() ? QPDF_FALSE : QPDF_TRUE); +} + +DLL_EXPORT +QPDF_BOOL qpdf_more_warnings(qpdf_data qpdf) +{ + QTC::TC("qpdf", "qpdf-c called qpdf_more_warnings"); + + if (qpdf->warnings.empty()) + { + std::vector w = qpdf->qpdf->getWarnings(); + if (! w.empty()) + { + qpdf->warnings.assign(w.begin(), w.end()); + } + } + if (qpdf->warnings.empty()) + { + return QPDF_FALSE; + } + else + { + return QPDF_TRUE; + } +} + +DLL_EXPORT +char const* qpdf_next_error(qpdf_data qpdf) +{ + QTC::TC("qpdf", "qpdf-c called qpdf_next_error"); + if (qpdf_more_errors(qpdf)) + { + qpdf->tmp_string = qpdf->error; + qpdf->error.clear(); + return qpdf->tmp_string.c_str(); + } + else + { + return 0; + } +} + +DLL_EXPORT +char const* qpdf_next_warning(qpdf_data qpdf) +{ + QTC::TC("qpdf", "qpdf-c called qpdf_next_warning"); + if (qpdf_more_warnings(qpdf)) + { + qpdf->tmp_string = qpdf->warnings.front(); + qpdf->warnings.pop_front(); + return qpdf->tmp_string.c_str(); + } + else + { + return 0; + } +} + +DLL_EXPORT +void qpdf_set_suppress_warnings(qpdf_data qpdf, QPDF_BOOL value) +{ + QTC::TC("qpdf", "qpdf-c called qpdf_set_suppress_warnings"); + qpdf->qpdf->setSuppressWarnings(value); +} + +DLL_EXPORT +void qpdf_set_ignore_xref_streams(qpdf_data qpdf, QPDF_BOOL value) +{ + QTC::TC("qpdf", "qpdf-c called qpdf_set_ignore_xref_streams"); + qpdf->qpdf->setIgnoreXRefStreams(value); +} + +DLL_EXPORT +void qpdf_set_attempt_recovery(qpdf_data qpdf, QPDF_BOOL value) +{ + QTC::TC("qpdf", "qpdf-c called qpdf_set_attempt_recovery"); + qpdf->qpdf->setAttemptRecovery(value); +} + +DLL_EXPORT +QPDF_ERROR_CODE qpdf_read(qpdf_data qpdf, char const* filename, + char const* password) +{ + QPDF_ERROR_CODE status = QPDF_SUCCESS; + try + { + qpdf->qpdf->processFile(filename, password); + } + catch (std::exception& e) + { + qpdf->error = e.what(); + status |= QPDF_ERRORS; + } + if (qpdf_more_warnings(qpdf)) + { + status |= QPDF_WARNINGS; + } + QTC::TC("qpdf", "qpdf-c called qpdf_read", status); + return status; +} + +DLL_EXPORT +char const* qpdf_get_pdf_version(qpdf_data qpdf) +{ + QTC::TC("qpdf", "qpdf-c called qpdf_get_pdf_version"); + qpdf->tmp_string = qpdf->qpdf->getPDFVersion(); + return qpdf->tmp_string.c_str(); +} + +DLL_EXPORT +char const* qpdf_get_user_password(qpdf_data qpdf) +{ + QTC::TC("qpdf", "qpdf-c called qpdf_get_user_password"); + qpdf->tmp_string = qpdf->qpdf->getTrimmedUserPassword(); + return qpdf->tmp_string.c_str(); +} + +DLL_EXPORT +QPDF_BOOL qpdf_is_linearized(qpdf_data qpdf) +{ + QTC::TC("qpdf", "qpdf-c called qpdf_is_linearized"); + return (qpdf->qpdf->isLinearized() ? QPDF_TRUE : QPDF_FALSE); +} + +DLL_EXPORT +QPDF_BOOL qpdf_is_encrypted(qpdf_data qpdf) +{ + QTC::TC("qpdf", "qpdf-c called qpdf_is_encrypted"); + return (qpdf->qpdf->isEncrypted() ? QPDF_TRUE : QPDF_FALSE); +} + +DLL_EXPORT +QPDF_ERROR_CODE qpdf_init_write(qpdf_data qpdf, char const* filename) +{ + QPDF_ERROR_CODE status = QPDF_SUCCESS; + try + { + qpdf->qpdf_writer = new QPDFWriter(*(qpdf->qpdf), filename); + } + catch (std::exception& e) + { + qpdf->error = e.what(); + status |= QPDF_ERRORS; + } + if (qpdf_more_warnings(qpdf)) + { + status |= QPDF_WARNINGS; + } + QTC::TC("qpdf", "qpdf-c called qpdf_init_write", status); + return status; +} + +DLL_EXPORT +void qpdf_set_object_stream_mode(qpdf_data qpdf, int mode) +{ + QTC::TC("qpdf", "qpdf-c called qpdf_set_object_stream_mode"); + QPDFWriter::object_stream_e omode = QPDFWriter::o_preserve; + switch (mode) + { + case QPDF_OBJECT_STREAM_DISABLE: + omode = QPDFWriter::o_disable; + break; + + case QPDF_OBJECT_STREAM_GENERATE: + omode = QPDFWriter::o_generate; + break; + + default: + // already set to o_preserve; treate out of range values as + // the default. + break; + } + + qpdf->qpdf_writer->setObjectStreamMode(omode); +} + +DLL_EXPORT +void qpdf_set_stream_data_mode(qpdf_data qpdf, int mode) +{ + QTC::TC("qpdf", "qpdf-c called qpdf_set_stream_data_mode"); + QPDFWriter::stream_data_e smode = QPDFWriter::s_preserve; + switch (mode) + { + case QPDF_STREAM_DATA_UNCOMPRESS: + smode = QPDFWriter::s_uncompress; + break; + + case QPDF_STREAM_DATA_COMPRESS: + smode = QPDFWriter::s_compress; + break; + + default: + // Treat anything else as default + break; + } + qpdf->qpdf_writer->setStreamDataMode(smode); +} + +DLL_EXPORT +void qpdf_set_content_normalization(qpdf_data qpdf, QPDF_BOOL value) +{ + QTC::TC("qpdf", "qpdf-c called qpdf_set_content_normalization"); + qpdf->qpdf_writer->setContentNormalization(value); +} + +DLL_EXPORT +void qpdf_set_qdf_mode(qpdf_data qpdf, QPDF_BOOL value) +{ + QTC::TC("qpdf", "qpdf-c called qpdf_set_qdf_mode"); + qpdf->qpdf_writer->setQDFMode(value); +} + +DLL_EXPORT +void qpdf_set_static_ID(qpdf_data qpdf, QPDF_BOOL value) +{ + QTC::TC("qpdf", "qpdf-c called qpdf_set_static_ID"); + qpdf->qpdf_writer->setStaticID(value); +} + +DLL_EXPORT +void qpdf_set_suppress_original_object_IDs( + qpdf_data qpdf, QPDF_BOOL value) +{ + QTC::TC("qpdf", "qpdf-c called qpdf_set_suppress_original_object_IDs"); + qpdf->qpdf_writer->setSuppressOriginalObjectIDs(value); +} + +DLL_EXPORT +void qpdf_set_preserve_encryption(qpdf_data qpdf, QPDF_BOOL value) +{ + QTC::TC("qpdf", "qpdf-c called qpdf_set_preserve_encryption"); + qpdf->qpdf_writer->setPreserveEncryption(value); +} + +DLL_EXPORT +void qpdf_set_r2_encryption_parameters( + qpdf_data qpdf, char const* user_password, char const* owner_password, + QPDF_BOOL allow_print, QPDF_BOOL allow_modify, + QPDF_BOOL allow_extract, QPDF_BOOL allow_annotate) +{ + QTC::TC("qpdf", "qpdf-c called qpdf_set_r2_encryption_parameters"); + qpdf->qpdf_writer->setR2EncryptionParameters( + user_password, owner_password, + allow_print, allow_modify, allow_extract, allow_annotate); +} + +DLL_EXPORT +void qpdf_set_r3_encryption_parameters( + qpdf_data qpdf, char const* user_password, char const* owner_password, + QPDF_BOOL allow_accessibility, QPDF_BOOL allow_extract, + int print, int modify) +{ + QTC::TC("qpdf", "qpdf-c called qpdf_set_r3_encryption_parameters"); + qpdf->qpdf_writer->setR3EncryptionParameters( + user_password, owner_password, + allow_accessibility, allow_extract, + ((print == QPDF_R3_PRINT_LOW) ? QPDFWriter::r3p_low : + (print == QPDF_R3_PRINT_NONE) ? QPDFWriter::r3p_none : + QPDFWriter::r3p_full), + ((print == QPDF_R3_MODIFY_ANNOTATE) ? QPDFWriter::r3m_annotate : + (print == QPDF_R3_MODIFY_FORM) ? QPDFWriter::r3m_form : + (print == QPDF_R3_MODIFY_ASSEMBLY) ? QPDFWriter::r3m_assembly : + (print == QPDF_R3_MODIFY_NONE) ? QPDFWriter::r3m_none : + QPDFWriter::r3m_all)); +} + +DLL_EXPORT +void qpdf_set_linearization(qpdf_data qpdf, QPDF_BOOL value) +{ + QTC::TC("qpdf", "qpdf-c called qpdf_set_linearization"); + qpdf->qpdf_writer->setLinearization(value); +} + +DLL_EXPORT +QPDF_ERROR_CODE qpdf_write(qpdf_data qpdf) +{ + QPDF_ERROR_CODE status = QPDF_SUCCESS; + try + { + qpdf->qpdf_writer->write(); + } + catch (std::exception& e) + { + qpdf->error = e.what(); + status |= QPDF_ERRORS; + } + if (qpdf_more_warnings(qpdf)) + { + status |= QPDF_WARNINGS; + } + QTC::TC("qpdf", "qpdf-c called qpdf_write", status); + return status; +} diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov index 3fe63e33..f0bd8688 100644 --- a/qpdf/qpdf.testcov +++ b/qpdf/qpdf.testcov @@ -118,3 +118,29 @@ QPDF_String non-trivial UTF-16 0 QPDF xref overwrite object 0 QPDF decoding error warning 0 QPDF_Stream ignore non-dictionary DecodeParms 0 +qpdf-c called qpdf_init 0 +qpdf-c called qpdf_cleanup 0 +qpdf-c called qpdf_more_errors 0 +qpdf-c called qpdf_more_warnings 0 +qpdf-c called qpdf_next_error 0 +qpdf-c called qpdf_next_warning 0 +qpdf-c called qpdf_set_suppress_warnings 0 +qpdf-c called qpdf_set_ignore_xref_streams 0 +qpdf-c called qpdf_set_attempt_recovery 0 +qpdf-c called qpdf_read 3 +qpdf-c called qpdf_get_pdf_version 0 +qpdf-c called qpdf_get_user_password 0 +qpdf-c called qpdf_is_linearized 0 +qpdf-c called qpdf_is_encrypted 0 +qpdf-c called qpdf_init_write 3 +qpdf-c called qpdf_set_object_stream_mode 0 +qpdf-c called qpdf_set_stream_data_mode 0 +qpdf-c called qpdf_set_content_normalization 0 +qpdf-c called qpdf_set_qdf_mode 0 +qpdf-c called qpdf_set_static_ID 0 +qpdf-c called qpdf_set_suppress_original_object_IDs 0 +qpdf-c called qpdf_set_preserve_encryption 0 +qpdf-c called qpdf_set_r2_encryption_parameters 0 +qpdf-c called qpdf_set_r3_encryption_parameters 0 +qpdf-c called qpdf_set_linearization 0 +qpdf-c called qpdf_write 3 -- cgit v1.2.3-54-g00ecf