From 02333ba1e9670ff1f7fe7170d3e0cc229755dc7b Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Sun, 27 Sep 2009 03:11:29 +0000 Subject: [PATCH] checkpoint -- first crack at C API, minor refactoring of encryption functions git-svn-id: svn+q:///qpdf/trunk@720 71b93d88-0707-0410-a8cf-f5a4172ac649 --- include/qpdf/QPDF.hh | 14 +++- include/qpdf/qpdf-c.h | 142 +++++++++++++++++++++++++++++++++++++ libqpdf/QPDFWriter.cc | 2 +- libqpdf/QPDF_encryption.cc | 18 ++++- libqpdf/build.mk | 3 +- libqpdf/qpdf-c.cc | 18 +++++ qpdf/qpdf.cc | 9 ++- 7 files changed, 197 insertions(+), 9 deletions(-) create mode 100644 include/qpdf/qpdf-c.h create mode 100644 libqpdf/qpdf-c.cc diff --git a/include/qpdf/QPDF.hh b/include/qpdf/QPDF.hh index 9ac0b7d4..6b848f63 100644 --- a/include/qpdf/QPDF.hh +++ b/include/qpdf/QPDF.hh @@ -122,6 +122,12 @@ class QPDF std::string id1; }; + DLL_EXPORT + bool isEncrypted() const; + + // Helper function to trim padding from user password. Calling + // trim_user_password on the result of getPaddedUserPassword gives + // getTrimmedUserPassword's result. DLL_EXPORT static void trim_user_password(std::string& user_password); DLL_EXPORT @@ -137,8 +143,14 @@ class QPDF int V, int R, int key_len, int P, std::string const& id1, std::string& O, std::string& U); + // Return the full user password as stored in the PDF file. If + // you are attempting to recover the user password in a + // user-presentable form, call getTrimmedUserPassword() instead. DLL_EXPORT - std::string const& getUserPassword() const; + std::string const& getPaddedUserPassword() const; + // Return human-readable form of user password. + DLL_EXPORT + std::string getTrimmedUserPassword() const; // Linearization support diff --git a/include/qpdf/qpdf-c.h b/include/qpdf/qpdf-c.h new file mode 100644 index 00000000..57a08e54 --- /dev/null +++ b/include/qpdf/qpdf-c.h @@ -0,0 +1,142 @@ +#ifndef __QPDF_C_H__ +#define __QPDF_C_H__ + +/* + * This file defines a basic "C" API for qpdf. It provides access to + * 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. + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + typedef struct _qpdf_data* qpdf_data; + + /* Many functions return an integer error code. Codes are defined + * below. See ERROR REPORTING below. + */ + typedef int QPDF_ERROR_CODE; +# define QPDF_SUCCESS 0 +# define QPDF_WARNINGS 1 +# define QPDF_ERRORS 2 + + 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. + */ + DLL_EXPORT + qpdf_data qpdf_init(); + + /* Pass a pointer to the qpdf_data pointer created by qpdf_init to + * clean up resoures. + */ + DLL_EXPORT + void qpdf_cleanup(qpdf_data* qpdf); + + /* ERROR REPORTING */ + + /* Returns 1 if there are any errors or warnings, and zero + * otherwise. + */ + 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); + + /* These functions are analogous to the "error" counterparts but + * apply to warnings. + */ + + DLL_EXPORT + QPDF_BOOL qpdf_more_warnings(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. + */ + DLL_EXPORT + void qpdf_set_suppress_warnings(qpdf_data qpdf, QPDF_BOOL val); + + /* READ FUNCTIONS */ + + /* POST-READ QUERY FUNCTIONS */ + + /* These functions are invalid until after qpdf_read has been + * called. */ + + /* Return the version of the PDF file. */ + DLL_EXPORT + char const* qpdf_get_pdf_version(qpdf_data qpdf); + + /* Return the user password. If the file is opened using the + * owner password, the user password may be retrieved using this + * function. If the file is opened using the user password, this + * function will return that user password. + */ + DLL_EXPORT + char const* qpdf_get_user_password(qpdf_data qpdf); + + /* Indicate whether the input file is linearized. */ + DLL_EXPORT + QPDF_BOOL qpdf_is_linearized(qpdf_data qpdf); + + /* Indicate whether the input file is encrypted. */ + DLL_EXPORT + QPDF_BOOL qpdf_is_encrypted(qpdf_data qpdf); + + /* WRITE FUNCTIONS */ + + /* Set up for writing. No writing is actually performed until the + * call to qpdf_write(). + */ + + /* Supply the name of the file to be written and initialize the + * qpdf_data object to handle writing operations. This function + * also attempts to create the file. The PDF data is not written + * until the call to qpdf_write. + */ + DLL_EXPORT + QPDF_ERROR_CODE qpdf_init_write(qpdf_data data, char const* filename); + + /* XXX Get public interface from QPDFWriter */ + + /* Perform the actual write operation. */ + DLL_EXPORT + QPDF_ERROR_CODE qpdf_write(); + +#ifdef __cplusplus +} +#endif + + +#endif /* __QPDF_C_H__ */ diff --git a/libqpdf/QPDFWriter.cc b/libqpdf/QPDFWriter.cc index 88dc9e8f..4191e906 100644 --- a/libqpdf/QPDFWriter.cc +++ b/libqpdf/QPDFWriter.cc @@ -277,7 +277,7 @@ QPDFWriter::copyEncryptionParameters() encrypt.getKey("/O").getStringValue(), encrypt.getKey("/U").getStringValue(), this->id1, // this->id1 == the other file's id1 - pdf.getUserPassword()); + pdf.getPaddedUserPassword()); } } diff --git a/libqpdf/QPDF_encryption.cc b/libqpdf/QPDF_encryption.cc index 00766b60..2e0e59e7 100644 --- a/libqpdf/QPDF_encryption.cc +++ b/libqpdf/QPDF_encryption.cc @@ -443,7 +443,23 @@ QPDF::compute_encryption_O_U( DLL_EXPORT std::string const& -QPDF::getUserPassword() const +QPDF::getPaddedUserPassword() const { return this->user_password; } + +DLL_EXPORT +std::string +QPDF::getTrimmedUserPassword() const +{ + std::string result = this->user_password; + trim_user_password(result); + return result; +} + +DLL_EXPORT +bool +QPDF::isEncrypted() const +{ + return this->encrypted; +} diff --git a/libqpdf/build.mk b/libqpdf/build.mk index 6d807a6a..da87b7db 100644 --- a/libqpdf/build.mk +++ b/libqpdf/build.mk @@ -43,7 +43,8 @@ SRCS_libqpdf = \ libqpdf/QPDF_optimization.cc \ libqpdf/QTC.cc \ libqpdf/QUtil.cc \ - libqpdf/RC4.cc + libqpdf/RC4.cc \ + libqpdf/qpdf-c.cc # ----- diff --git a/libqpdf/qpdf-c.cc b/libqpdf/qpdf-c.cc new file mode 100644 index 00000000..3dd7fbe7 --- /dev/null +++ b/libqpdf/qpdf-c.cc @@ -0,0 +1,18 @@ +#include + +class _qpdf_data +{ +}; + +DLL_EXPORT +qpdf_data qpdf_init() +{ + return new _qpdf_data(); +} + +DLL_EXPORT +void qpdf_cleanup(qpdf_data* qpdf) +{ + delete *qpdf; + *qpdf = 0; +} diff --git a/qpdf/qpdf.cc b/qpdf/qpdf.cc index bcf2e33e..40a83a87 100644 --- a/qpdf/qpdf.cc +++ b/qpdf/qpdf.cc @@ -168,18 +168,17 @@ void usage(std::string const& msg) static void show_encryption(QPDF& pdf) { // Extract /P from /Encrypt - QPDFObjectHandle trailer = pdf.getTrailer(); - QPDFObjectHandle encrypt = trailer.getKey("/Encrypt"); - if (encrypt.isNull()) + if (! pdf.isEncrypted()) { std::cout << "File is not encrypted" << std::endl; } else { + QPDFObjectHandle trailer = pdf.getTrailer(); + QPDFObjectHandle encrypt = trailer.getKey("/Encrypt"); QPDFObjectHandle P = encrypt.getKey("/P"); std::cout << "P = " << P.getIntValue() << std::endl; - std::string user_password = pdf.getUserPassword(); - QPDF::trim_user_password(user_password); + std::string user_password = pdf.getTrimmedUserPassword(); std::cout << "User password = " << user_password << std::endl; } }