aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJay Berkenbilt <ejb@ql.org>2009-09-27 16:39:04 +0200
committerJay Berkenbilt <ejb@ql.org>2009-09-27 16:39:04 +0200
commit84ec83e92589461e6da68029ed7148ba48198215 (patch)
tree3852446d3320d6212f34433c84f8f4d08019de9c
parent02333ba1e9670ff1f7fe7170d3e0cc229755dc7b (diff)
downloadqpdf-84ec83e92589461e6da68029ed7148ba48198215.tar.zst
basic implementation of C API
git-svn-id: svn+q:///qpdf/trunk@725 71b93d88-0707-0410-a8cf-f5a4172ac649
-rw-r--r--TODO3
-rw-r--r--include/qpdf/QPDF.hh2
-rw-r--r--include/qpdf/qpdf-c.h191
-rw-r--r--libqpdf/QPDF.cc5
-rw-r--r--libqpdf/qpdf-c.cc335
-rw-r--r--qpdf/qpdf.testcov26
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 <qpdf/DLL.hh>
@@ -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 <qpdf/qpdf-c.h>
-class _qpdf_data
+#include <qpdf/QPDF.hh>
+#include <qpdf/QPDFWriter.hh>
+#include <qpdf/QTC.hh>
+
+#include <list>
+#include <string>
+#include <stdexcept>
+
+struct _qpdf_data
{
+ _qpdf_data();
+ ~_qpdf_data();
+
+ QPDF* qpdf;
+ QPDFWriter* qpdf_writer;
+
+ std::string error;
+ std::list<std::string> 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<std::string> 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