diff --git a/include/qpdf/Buffer.hh b/include/qpdf/Buffer.hh index eaa84c9..9e6b624 100644 --- a/include/qpdf/Buffer.hh +++ b/include/qpdf/Buffer.hh @@ -33,15 +33,17 @@ class Buffer QPDF_DLL Buffer(); - // Create a Buffer object whose memory is owned by the class and will be freed when the Buffer - // object is destroyed. + /*! \brief Create a Buffer object whose memory is owned by the class and will be freed when the Buffer + * object is destroyed. + */ QPDF_DLL Buffer(size_t size); QPDF_DLL Buffer(std::string&& content); - // Create a Buffer object whose memory is owned by the caller and will not be freed when the - // Buffer is destroyed. + /*! \brief Create a Buffer object whose memory is owned by the caller and will not be freed when the + * Buffer is destroyed. + */ QPDF_DLL Buffer(unsigned char* buf, size_t size); QPDF_DLL @@ -63,21 +65,23 @@ class Buffer QPDF_DLL unsigned char* getBuffer(); - // Create a new copy of the Buffer. The new Buffer owns an independent copy of the data. + /*! \brief Create a new copy of the Buffer. The new Buffer owns an independent copy of the data. */ QPDF_DLL Buffer copy() const; - // Move the content of the Buffer. After calling this method, the Buffer will be empty if the - // buffer owns its memory. Otherwise, the Buffer will be unchanged. + /*! \brief Move the content of the Buffer. After calling this method, the Buffer will be empty if the + * buffer owns its memory. Otherwise, the Buffer will be unchanged. + */ QPDF_DLL std::string move(); - // Return a string_view to the data. + /*! \brief Return a string_view to the data. */ QPDF_DLL std::string_view view() const; - // Return a pointer to the data. NB: Unlike getBuffer, this method returns a valid pointer even - // if the Buffer is empty. + /*! \return a pointer to the data. NB: Unlike getBuffer, this method returns a valid pointer even + * if the Buffer is empty. + */ QPDF_DLL char const* data() const; diff --git a/include/qpdf/BufferInputSource.hh b/include/qpdf/BufferInputSource.hh index 0b857b8..28aaba3 100644 --- a/include/qpdf/BufferInputSource.hh +++ b/include/qpdf/BufferInputSource.hh @@ -28,8 +28,9 @@ class QPDF_DLL_CLASS BufferInputSource: public InputSource { public: - // If own_memory is true, BufferInputSource will delete the buffer when finished with it. - // Otherwise, the caller owns the memory. + /*! \brief If own_memory is true, BufferInputSource will delete the buffer when finished with it. + * Otherwise, the caller owns the memory. + */ QPDF_DLL BufferInputSource(std::string const& description, Buffer* buf, bool own_memory = false); diff --git a/include/qpdf/ClosedFileInputSource.hh b/include/qpdf/ClosedFileInputSource.hh index 56b2cb1..4c1fae4 100644 --- a/include/qpdf/ClosedFileInputSource.hh +++ b/include/qpdf/ClosedFileInputSource.hh @@ -26,10 +26,11 @@ class FileInputSource; -// This is an input source that reads from files, like FileInputSource, except that it opens and -// closes the file surrounding every operation. This decreases efficiency, but it allows many more -// of these to exist at once than the maximum number of open file descriptors. This is used for -// merging large numbers of files. +/*! \brief This is an input source that reads from files, like FileInputSource, except that it opens and + * closes the file surrounding every operation. This decreases efficiency, but it allows many more + * of these to exist at once than the maximum number of open file descriptors. This is used for + * merging large numbers of files. + */ class QPDF_DLL_CLASS ClosedFileInputSource: public InputSource { public: @@ -56,9 +57,10 @@ class QPDF_DLL_CLASS ClosedFileInputSource: public InputSource QPDF_DLL void unreadCh(char ch) override; - // The file stays open between calls to stayOpen(true) and stayOpen(false). You can use this to - // surround multiple operations on a single ClosedFileInputSource to reduce the overhead of a - // separate open/close on each call. + /*! \brief The file stays open between calls to stayOpen(true) and stayOpen(false). You can use this to + * surround multiple operations on a single ClosedFileInputSource to reduce the overhead of a + * separate open/close on each call. + */ QPDF_DLL void stayOpen(bool); diff --git a/include/qpdf/Constants.h b/include/qpdf/Constants.h index 4b32713..ef3d465 100644 --- a/include/qpdf/Constants.h +++ b/include/qpdf/Constants.h @@ -31,42 +31,41 @@ * interfaces. */ -/* ****************************** NOTE ****************************** - -Tl;Dr: new values must be added to the end such that no constant's -numerical value changes, even across major releases. - -Details: - -As new values are added to existing enumerated types in this file, -it is important not to change the actual values of any constants. -This means that, in the absence of explicit assignment of values, -the order of entries can't change even across major releases. Why? -Here are the reasons: - -* Many of these constants are used by the C API. The C API is used - through foreign function call interfaces by users of other languages - who may not have access to or the ability to parse a C header file. - As such, users are likely to hard-code numerical values or create - their own constants whose values match. If we change values here, - their code would break, and there would be no way to detect it short - of noticing a bug. Furthermore, it would be difficult to write code - that properly handled more than one version of the qpdf shared - object (e.g. DLL) since the information about what version of qpdf - is involved is only available at runtime. - -- It has happened from time to time that a user builds an application - with an incorrectly installed qpdf, such as having mismatched header - files and library files. In the event that they are only using qpdf - interfaces that have been stable across the versions in question, - this turns out to be harmless. If they happen to use non-compatible - interfaces, this results usually in a failure to load or an obvious - runtime error. If we change values of constants, it is possible that - code that links and runs may have mismatched values for constants. - This would create a bug that would be extremely difficult to track - down and impossible for qpdf maintainers to reproduce. - -*/ +/*! \note ****************************** NOTE ****************************** + * + * Tl;Dr: new values must be added to the end such that no constant's + * numerical value changes, even across major releases. + * + * Details: + * + * As new values are added to existing enumerated types in this file, + * it is important not to change the actual values of any constants. + * This means that, in the absence of explicit assignment of values, + * the order of entries can't change even across major releases. Why? + * Here are the reasons: + * + * * Many of these constants are used by the C API. The C API is used + * through foreign function call interfaces by users of other languages + * who may not have access to or the ability to parse a C header file. + * As such, users are likely to hard-code numerical values or create + * their own constants whose values match. If we change values here, + * their code would break, and there would be no way to detect it short + * of noticing a bug. Furthermore, it would be difficult to write code + * that properly handled more than one version of the qpdf shared + * object (e.g. DLL) since the information about what version of qpdf + * is involved is only available at runtime. + * + * - It has happened from time to time that a user builds an application + * with an incorrectly installed qpdf, such as having mismatched header + * files and library files. In the event that they are only using qpdf + * interfaces that have been stable across the versions in question, + * this turns out to be harmless. If they happen to use non-compatible + * interfaces, this results usually in a failure to load or an obvious + * runtime error. If we change values of constants, it is possible that + * code that links and runs may have mismatched values for constants. + * This would create a bug that would be extremely difficult to track + * down and impossible for qpdf maintainers to reproduce. + */ /* Exit Codes from QPDFJob and the qpdf CLI */ @@ -97,7 +96,7 @@ enum qpdf_error_code_e { /* Object Types */ -/* PDF objects represented by QPDFObjectHandle or, in the C API, by +/*! \brief PDF objects represented by QPDFObjectHandle or, in the C API, by * qpdf_oh, have a unique type code that has one of the values in the * list below. As new object types are added to qpdf, additional items * may be added to the list, so code that switches on these values @@ -171,7 +170,7 @@ enum qpdf_r3_print_e { qpdf_r3p_none /* allow no printing */ }; -/* qpdf_r3_modify_e doesn't allow the full flexibility of the spec. It +/*! \brief qpdf_r3_modify_e doesn't allow the full flexibility of the spec. It * corresponds to options in Acrobat 5's menus. The new interface in * QPDFWriter offers more granularity and no longer uses this type. */ diff --git a/include/qpdf/DLL.h b/include/qpdf/DLL.h index 08f49fb..792d8e5 100644 --- a/include/qpdf/DLL.h +++ b/include/qpdf/DLL.h @@ -35,8 +35,7 @@ # define QPDF_VERSION "12.3.3" #endif -/* - * This file defines symbols that control the which functions, +/*! \brief This file defines symbols that control the which functions, * classes, and methods are exposed to the public ABI (application * binary interface). See below for a detailed explanation. */ @@ -61,7 +60,7 @@ # define QPDF_DLL_CLASS #endif -/* +/*! \brief Here's what's happening. See also https://gcc.gnu.org/wiki/Visibility for a more in-depth discussion. diff --git a/include/qpdf/QPDFJob.hh b/include/qpdf/QPDFJob.hh index 9feb543..547d297 100644 --- a/include/qpdf/QPDFJob.hh +++ b/include/qpdf/QPDFJob.hh @@ -59,78 +59,83 @@ class QPDFJob // SETUP FUNCTIONS - // Initialize a QPDFJob object from argv, which must be a null-terminated array of - // null-terminated UTF-8-encoded C strings. The progname_env argument is the name of an - // environment variable which, if set, overrides the name of the executable for purposes of - // generating the --completion options. See QPDFArgParser for details. If a null pointer is - // passed in, the default value of "QPDF_EXECUTABLE" is used. This is used by the QPDF cli, - // which just initializes a QPDFJob from argv, calls run(), and handles errors and exit status - // issues. You can perform much of the cli functionality programmatically in this way rather - // than using the regular API. This is exposed in the C API, which makes it easier to get - // certain high-level qpdf functionality from other languages. If there are any command-line - // errors, this method will throw QPDFUsage which is derived from std::runtime_error. Other - // exceptions may be thrown in some cases. Note that argc, and argv should be UTF-8 encoded. If - // you are calling this from a Windows Unicode-aware main (wmain), see - // QUtil::call_main_from_wmain for information about converting arguments to UTF-8. This method - // will mutate arguments that are passed to it. + /*! \brief Initialize a QPDFJob object from argv, which must be a null-terminated array of + * null-terminated UTF-8-encoded C strings. The progname_env argument is the name of an + * environment variable which, if set, overrides the name of the executable for purposes of + * generating the --completion options. See QPDFArgParser for details. If a null pointer is + * passed in, the default value of "QPDF_EXECUTABLE" is used. This is used by the QPDF cli, + * which just initializes a QPDFJob from argv, calls run(), and handles errors and exit status + * issues. You can perform much of the cli functionality programmatically in this way rather + * than using the regular API. This is exposed in the C API, which makes it easier to get + * certain high-level qpdf functionality from other languages. If there are any command-line + * errors, this method will throw QPDFUsage which is derived from std::runtime_error. Other + * exceptions may be thrown in some cases. Note that argc, and argv should be UTF-8 encoded. If + * you are calling this from a Windows Unicode-aware main (wmain), see + * QUtil::call_main_from_wmain for information about converting arguments to UTF-8. This method + * will mutate arguments that are passed to it. + */ QPDF_DLL void initializeFromArgv(char const* const argv[], char const* progname_env = nullptr); - // Initialize a QPDFJob from json. Passing partial = true prevents this method from doing the - // final checks (calling checkConfiguration) after processing the json file. This makes it - // possible to initialize QPDFJob in stages using multiple json files or to have a json file - // that can be processed from the CLI with --job-json-file and be combined with other arguments. - // For example, you might include only encryption parameters, leaving it up to the rest of the - // command-line arguments to provide input and output files. initializeFromJson is called with - // partial = true when invoked from the command line. To make sure that the json file is fully - // valid on its own, just don't specify any other command-line flags. If there are any - // configuration errors, QPDFUsage is thrown. Some error messages may be CLI-centric. If an - // exception tells you to use the "--some-option" option, set the "someOption" key in the JSON - // object instead. + /*! \brief Initialize a QPDFJob from json. Passing partial = true prevents this method from doing the + * final checks (calling checkConfiguration) after processing the json file. This makes it + * possible to initialize QPDFJob in stages using multiple json files or to have a json file + * that can be processed from the CLI with --job-json-file and be combined with other arguments. + * For example, you might include only encryption parameters, leaving it up to the rest of the + * command-line arguments to provide input and output files. initializeFromJson is called with + * partial = true when invoked from the command line. To make sure that the json file is fully + * valid on its own, just don't specify any other command-line flags. If there are any + * configuration errors, QPDFUsage is thrown. Some error messages may be CLI-centric. If an + * exception tells you to use the "--some-option" option, set the "someOption" key in the JSON + * object instead. + */ QPDF_DLL void initializeFromJson(std::string const& json, bool partial = false); - // Set name that is used to prefix verbose messages, progress messages, and other things that - // the library writes to output and error streams on the caller's behalf. Defaults to "qpdf". + /*! \brief Set name that is used to prefix verbose messages, progress messages, and other things that + * the library writes to output and error streams on the caller's behalf. Defaults to "qpdf". + */ QPDF_DLL void setMessagePrefix(std::string const&); QPDF_DLL std::string getMessagePrefix() const; - // To capture or redirect output, configure the logger returned by getLogger(). By default, all - // QPDF and QPDFJob objects share the global logger. If you need a private logger for some - // reason, pass a new one to setLogger(). See comments in QPDFLogger.hh for details on - // configuring the logger. - // - // If you set a custom logger here, the logger will be passed to all subsequent QPDF objects - // created by this QPDFJob object. - QPDF_DLL - std::shared_ptr getLogger(); - QPDF_DLL - void setLogger(std::shared_ptr); - - // This deprecated method is the old way to capture output, but it didn't capture all output. - // See comments above for getLogger and setLogger. This will be removed in QPDF 12. For now, it - // configures a private logger, separating this object from the default logger, and calls - // setOutputStreams on that logger. See QPDFLogger.hh for additional details. - [[deprecated("configure logger from getLogger() or call setLogger()")]] QPDF_DLL void - setOutputStreams(std::ostream* out_stream, std::ostream* err_stream); - - // You can register a custom progress reporter to be called by QPDFWriter (see - // QPDFWriter::registerProgressReporter). This is only called if you also request progress - // reporting through normal configuration methods (e.g., pass --progress, call - // config()->progress, etc.) + /*! \brief To capture or redirect output, configure the logger returned by getLogger(). By default, all + * QPDF and QPDFJob objects share the global logger. If you need a private logger for some + * reason, pass a new one to setLogger(). See comments in QPDFLogger.hh for details on + * configuring the logger. + * + * If you set a custom logger here, the logger will be passed to all subsequent QPDF objects + * created by this QPDFJob object. + */ + QPDF_DLL std::shared_ptr getLogger(); + QPDF_DLL void setLogger(std::shared_ptr); + + /*! \brief This deprecated method is the old way to capture output, but it didn't capture all output. + * See comments above for getLogger and setLogger. This will be removed in QPDF 12. For now, it + * configures a private logger, separating this object from the default logger, and calls + * setOutputStreams on that logger. See QPDFLogger.hh for additional details. + */ + [[deprecated("configure logger from getLogger() or call setLogger()")]] + QPDF_DLL void setOutputStreams(std::ostream* out_stream, std::ostream* err_stream); + + /*! \brief You can register a custom progress reporter to be called by QPDFWriter (see + * QPDFWriter::registerProgressReporter). This is only called if you also request progress + * reporting through normal configuration methods (e.g., pass --progress, call + * config()->progress, etc.) + */ QPDF_DLL void registerProgressReporter(std::function); - // Check to make sure no contradictory options have been specified. This is called automatically - // after initializing from argv or json and is also called by run, but you can call it manually - // as well. It throws a QPDFUsage exception if there are any errors. This Config object (see - // CONFIGURATION) also has a checkConfiguration method which calls this one. + /*! \brief Check to make sure no contradictory options have been specified. This is called automatically + * after initializing from argv or json and is also called by run, but you can call it manually + * as well. It throws a QPDFUsage exception if there are any errors. This Config object (see + * CONFIGURATION) also has a checkConfiguration method which calls this one. + */ QPDF_DLL void checkConfiguration(); - // Returns true if output is created by the specified job. + /*! \brief Returns true if output is created by the specified job. */ QPDF_DLL bool createsOutput() const; @@ -161,27 +166,28 @@ class QPDFJob // Configuration classes are implemented in QPDFJob_config.cc. - // The config() method returns a shared pointer to a Config object. The Config object contains - // methods that correspond with qpdf command-line arguments. You can use a fluent interface to - // configure a QPDFJob object that would do exactly the same thing as a specific qpdf command. - // The example qpdf-job.cc contains an example of this usage. You can also use - // initializeFromJson or initializeFromArgv to initialize a QPDFJob object. - - // Notes about the Config methods: - // - // * Most of the method declarations are automatically generated in header files that are - // included within the class definitions. They correspond in predictable ways to the - // command-line arguments and are generated from the same code that generates the command-line - // argument parsing code. - // - // * Methods return pointers, rather than references, to configuration objects. References - // might feel more familiar to users of fluent interfaces, so why do we use pointers? The - // main methods that create them return smart pointers so that users can initialize them when - // needed, which you can't do with references. Returning pointers instead of references makes - // for a more uniform interface. - - // Maintainer documentation: see the section in README-developer called "HOW TO ADD A - // COMMAND-LINE ARGUMENT", which contains references to additional places in the documentation. + /*! \brief The config() method returns a shared pointer to a Config object. The Config object contains + * methods that correspond with qpdf command-line arguments. You can use a fluent interface to + * configure a QPDFJob object that would do exactly the same thing as a specific qpdf command. + * The example qpdf-job.cc contains an example of this usage. You can also use + * initializeFromJson or initializeFromArgv to initialize a QPDFJob object. + * + * \note About the Config methods: + * + * * Most of the method declarations are automatically generated in header files that are + * included within the class definitions. They correspond in predictable ways to the + * command-line arguments and are generated from the same code that generates the command-line + * argument parsing code. + * + * * Methods return pointers, rather than references, to configuration objects. References + * might feel more familiar to users of fluent interfaces, so why do we use pointers? The + * main methods that create them return smart pointers so that users can initialize them when + * needed, which you can't do with references. Returning pointers instead of references makes + * for a more uniform interface. + * + * Maintainer documentation: see the section in README-developer called "HOW TO ADD A + * COMMAND-LINE ARGUMENT", which contains references to additional places in the documentation. + */ class Config; @@ -235,8 +241,10 @@ class QPDFJob public: QPDF_DLL Config* endPages(); - // From qpdf 11.9.0, you can call file(), range(), and password(). Each call to file() - // starts a new page spec. + + /*! \brief From qpdf 11.9.0, you can call file(), range(), and password(). Each call to file() + * starts a new page spec. + */ QPDF_DLL PagesConfig* pageSpec( std::string const& filename, std::string const& range, char const* password = nullptr); @@ -372,11 +380,12 @@ class QPDFJob QPDFJob& o; }; - // Return a top-level configuration item. See CONFIGURATION above for details. If an invalid - // configuration is created (such as supplying contradictory options, omitting an input file, - // etc.), QPDFUsage is thrown. Note that error messages are CLI-centric, but you can map them - // into config calls. For example, if an exception tells you to use the --some-option flag, you - // should call config()->someOption() instead. + /*! \return a top-level configuration item. See CONFIGURATION above for details. If an invalid + * configuration is created (such as supplying contradictory options, omitting an input file, + * etc.), QPDFUsage is thrown. Note that error messages are CLI-centric, but you can map them + * into config calls. For example, if an exception tells you to use the --some-option flag, you + * should call config()->someOption() instead. + */ QPDF_DLL std::shared_ptr config(); @@ -384,15 +393,16 @@ class QPDFJob QPDF_DLL void run(); - // The following two methods allow a job to be run in two stages - creation of a QPDF object and - // writing of the QPDF object. This allows the QPDF object to be modified prior to writing it - // out. See examples/qpdfjob-remove-annotations for an illustration of its use. + /*! \brief The following two methods allow a job to be run in two stages - creation of a QPDF object and + * writing of the QPDF object. This allows the QPDF object to be modified prior to writing it + * out. See examples/qpdfjob-remove-annotations for an illustration of its use. + */ - // Run the first stage of the job. Return a nullptr if the configuration is not valid. + /*! \brief Run the first stage of the job. Return a nullptr if the configuration is not valid. */ QPDF_DLL std::unique_ptr createQPDF(); - // Run the second stage of the job. Do nothing if a nullptr is passed as parameter. + /*! \brief Run the second stage of the job. Do nothing if a nullptr is passed as parameter. */ QPDF_DLL void writeQPDF(QPDF& qpdf); @@ -401,34 +411,37 @@ class QPDFJob QPDF_DLL bool hasWarnings() const; - // Return one of the EXIT_* constants defined at the top of the class declaration. This may be - // called after run() when run() did not throw an exception. Takes into consideration whether - // isEncrypted or requiresPassword was called. Note that this function does not know whether - // run() threw an exception, so code that uses this to determine how to exit should explicitly - // use EXIT_ERROR if run() threw an exception. + /*! \brief Return one of the EXIT_* constants defined at the top of the class declaration. This may be + * called after run() when run() did not throw an exception. Takes into consideration whether + * isEncrypted or requiresPassword was called. Note that this function does not know whether + * run() threw an exception, so code that uses this to determine how to exit should explicitly + * use EXIT_ERROR if run() threw an exception. + */ QPDF_DLL int getExitCode() const; - // Return value is bitwise OR of values from qpdf_encryption_status_e + /*! \return value is bitwise OR of values from qpdf_encryption_status_e */ QPDF_DLL unsigned long getEncryptionStatus(); // HELPER FUNCTIONS -- methods useful for calling in handlers that interact with QPDFJob during // run or initialization. - // If in verbose mode, call the given function, passing in the output stream and message prefix. + /*! \brief If in verbose mode, call the given function, passing in the output stream and message prefix. */ QPDF_DLL void doIfVerbose(std::function fn); - // Provide a string that is the help information ("schema" for the qpdf-specific JSON object) - // for the specified version of JSON output. + /*! \brief Provide a string that is the help information ("schema" for the qpdf-specific JSON object) + * for the specified version of JSON output. + */ QPDF_DLL static std::string json_out_schema(int version); [[deprecated("use json_out_schema(version)")]] static std::string QPDF_DLL json_out_schema_v1(); - // Provide a string that is the help information for specified version of JSON format for - // QPDFJob. + /*! \brief Provide a string that is the help information for specified version of JSON format for + * QPDFJob. + */ QPDF_DLL static std::string job_json_schema(int version); diff --git a/include/qpdf/QPDFObjectHandle.hh b/include/qpdf/QPDFObjectHandle.hh index 9fef4e6..f7d83c4 100644 --- a/include/qpdf/QPDFObjectHandle.hh +++ b/include/qpdf/QPDFObjectHandle.hh @@ -71,9 +71,10 @@ class QPDFObjectHandle: public qpdf::BaseHandle friend class qpdf::impl::Parser; public: - // This class is used by replaceStreamData. It provides an alternative way of associating - // stream data with a stream. See comments on replaceStreamData and newStream for additional - // details. + /*! \brief This class is used by replaceStreamData. It provides an alternative way of associating + * stream data with a stream. See comments on replaceStreamData and newStream for additional + * details. + */ class QPDF_DLL_CLASS StreamDataProvider { public: @@ -82,40 +83,41 @@ class QPDFObjectHandle: public qpdf::BaseHandle QPDF_DLL virtual ~StreamDataProvider(); - // The implementation of this function must write stream data to the given pipeline. The - // stream data must conform to whatever filters are explicitly associated with the stream. - // QPDFWriter may, in some cases, add compression, but if it does, it will update the - // filters as needed. Every call to provideStreamData for a given stream must write the same - // data. Note that, when writing linearized files, qpdf will call your provideStreamData - // twice, and if it generates different output, you risk generating invalid output or having - // qpdf throw an exception. The object ID and generation passed to this method are those - // that belong to the stream on behalf of which the provider is called. They may be ignored - // or used by the implementation for indexing or other purposes. This information is made - // available just to make it more convenient to use a single StreamDataProvider object to - // provide data for multiple streams. - - // A few things to keep in mind: - // - // * Stream data providers must not modify any objects since they may be called after some - // parts of the file have already been written. - // - // * Since qpdf may call provideStreamData multiple times when writing linearized files, if - // the work done by your stream data provider is slow or computationally intensive, you - // might want to implement your own cache. - // - // * Once you have called replaceStreamData, the original stream data is no longer directly - // accessible from the stream, but this is easy to work around by copying the stream to - // a separate QPDF object. The qpdf library implements this very efficiently without - // actually making a copy of the stream data. You can find examples of this pattern in - // some of the examples, including pdf-custom-filter.cc and pdf-invert-images.cc. - - // Prior to qpdf 10.0.0, it was not possible to handle errors the way pipeStreamData does or - // to pass back success. Starting in qpdf 10.0.0, those capabilities have been added by - // allowing an alternative provideStreamData to be implemented. You must implement at least - // one of the versions of provideStreamData below. If you implement the version that - // supports retry and returns a value, you should pass true as the value of supports_retry - // in the base class constructor. This will cause the library to call that version of the - // method, which should also return a boolean indicating whether it ran without errors. + /*! \brief The implementation of this function must write stream data to the given pipeline. The + * stream data must conform to whatever filters are explicitly associated with the stream. + * QPDFWriter may, in some cases, add compression, but if it does, it will update the + * filters as needed. Every call to provideStreamData for a given stream must write the same + * data. Note that, when writing linearized files, qpdf will call your provideStreamData + * twice, and if it generates different output, you risk generating invalid output or having + * qpdf throw an exception. The object ID and generation passed to this method are those + * that belong to the stream on behalf of which the provider is called. They may be ignored + * or used by the implementation for indexing or other purposes. This information is made + * available just to make it more convenient to use a single StreamDataProvider object to + * provide data for multiple streams. + * + * A few things to keep in mind: + * + * * Stream data providers must not modify any objects since they may be called after some + * parts of the file have already been written. + * + * * Since qpdf may call provideStreamData multiple times when writing linearized files, if + * the work done by your stream data provider is slow or computationally intensive, you + * might want to implement your own cache. + * + * * Once you have called replaceStreamData, the original stream data is no longer directly + * accessible from the stream, but this is easy to work around by copying the stream to + * a separate QPDF object. The qpdf library implements this very efficiently without + * actually making a copy of the stream data. You can find examples of this pattern in + * some of the examples, including pdf-custom-filter.cc and pdf-invert-images.cc. + * + * Prior to qpdf 10.0.0, it was not possible to handle errors the way pipeStreamData does or + * to pass back success. Starting in qpdf 10.0.0, those capabilities have been added by + * allowing an alternative provideStreamData to be implemented. You must implement at least + * one of the versions of provideStreamData below. If you implement the version that + * supports retry and returns a value, you should pass true as the value of supports_retry + * in the base class constructor. This will cause the library to call that version of the + * method, which should also return a boolean indicating whether it ran without errors. + */ QPDF_DLL virtual void provideStreamData(QPDFObjGen const& og, Pipeline* pipeline); QPDF_DLL @@ -131,31 +133,32 @@ class QPDFObjectHandle: public qpdf::BaseHandle bool supports_retry; }; - // The TokenFilter class provides a way to filter content streams in a lexically aware fashion. - // TokenFilters can be attached to streams using the addTokenFilter or addContentTokenFilter - // methods or can be applied on the spot by filterPageContents. You may also use - // Pl_QPDFTokenizer directly if you need full control. - // - // The handleToken method is called for each token, including the eof token, and then handleEOF - // is called at the very end. Handlers may call write (or writeToken) to pass data downstream. - // Please see examples/pdf-filter-tokens.cc and examples/pdf-count-strings.cc for examples of - // using TokenFilters. - // - // Please note that when you call token.getValue() on a token of type tt_string or tt_name, you - // get the canonical, "parsed" representation of the token. For a string, this means that there - // are no delimiters, and for a name, it means that all escaping (# followed by two hex digits) - // has been resolved. qpdf's internal representation of a name includes the leading slash. As - // such, you can't write the value of token.getValue() directly to output that is supposed to be - // valid PDF syntax. If you want to do that, you need to call writeToken() instead, or you can - // retrieve the token as it appeared in the input with token.getRawValue(). To construct a new - // string or name token from a canonical representation, use - // QPDFTokenizer::Token(QPDFTokenizer::tt_string, "parsed-str") or - // QPDFTokenizer::Token(QPDFTokenizer::tt_name, - // "/Canonical-Name"). Tokens created this way won't have a PDF-syntax raw value, but you can - // still write them with writeToken(). Example: - // writeToken(QPDFTokenizer::Token(QPDFTokenizer::tt_name, "/text/plain")) - // would write `/text#2fplain`, and - // writeToken(QPDFTokenizer::Token(QPDFTokenizer::tt_string, "a\\(b")) would write `(a\(b)`. + /*! \brief The TokenFilter class provides a way to filter content streams in a lexically aware fashion. + * TokenFilters can be attached to streams using the addTokenFilter or addContentTokenFilter + * methods or can be applied on the spot by filterPageContents. You may also use + * Pl_QPDFTokenizer directly if you need full control. + * + * The handleToken method is called for each token, including the eof token, and then handleEOF + * is called at the very end. Handlers may call write (or writeToken) to pass data downstream. + * Please see examples/pdf-filter-tokens.cc and examples/pdf-count-strings.cc for examples of + * using TokenFilters. + * + * Please note that when you call token.getValue() on a token of type tt_string or tt_name, you + * get the canonical, "parsed" representation of the token. For a string, this means that there + * are no delimiters, and for a name, it means that all escaping (# followed by two hex digits) + * has been resolved. qpdf's internal representation of a name includes the leading slash. As + * such, you can't write the value of token.getValue() directly to output that is supposed to be + * valid PDF syntax. If you want to do that, you need to call writeToken() instead, or you can + * retrieve the token as it appeared in the input with token.getRawValue(). To construct a new + * string or name token from a canonical representation, use + * QPDFTokenizer::Token(QPDFTokenizer::tt_string, "parsed-str") or + * QPDFTokenizer::Token(QPDFTokenizer::tt_name, + * "/Canonical-Name"). Tokens created this way won't have a PDF-syntax raw value, but you can + * still write them with writeToken(). Example: + * writeToken(QPDFTokenizer::Token(QPDFTokenizer::tt_name, "/text/plain")) + * would write `/text#2fplain`, and + * writeToken(QPDFTokenizer::Token(QPDFTokenizer::tt_string, "a\\(b")) would write `(a\(b)`. + */ class QPDF_DLL_CLASS TokenFilter { public: @@ -192,8 +195,9 @@ class QPDFObjectHandle: public qpdf::BaseHandle Pipeline* pipeline; }; - // This class is used by parse to decrypt strings when reading an object that contains encrypted - // strings. + /*! \brief This class is used by parse to decrypt strings when reading an object that contains encrypted + * strings. + */ class StringDecrypter { public: @@ -201,12 +205,14 @@ class QPDFObjectHandle: public qpdf::BaseHandle virtual void decryptString(std::string& val) = 0; }; - // This class is used by parsePageContents. Callers must instantiate a subclass of this with - // handlers defined to accept QPDFObjectHandles that are parsed from the stream. + /*! \brief This class is used by parsePageContents. Callers must instantiate a subclass of this with + * handlers defined to accept QPDFObjectHandles that are parsed from the stream. + */ class QPDF_DLL_CLASS ParserCallbacks { public: virtual ~ParserCallbacks() = default; + // One of the handleObject methods must be overridden. QPDF_DLL virtual void handleObject(QPDFObjectHandle); @@ -215,14 +221,16 @@ class QPDFObjectHandle: public qpdf::BaseHandle virtual void handleEOF() = 0; - // Override this if you want to know the full size of the contents, possibly after - // concatenation of multiple streams. This is called before the first call to handleObject. + /*! \brief Override this if you want to know the full size of the contents, possibly after + * concatenation of multiple streams. This is called before the first call to handleObject. + */ QPDF_DLL virtual void contentSize(size_t); protected: - // Implementors may call this method during parsing to terminate parsing early. This method - // throws an exception that is caught by parsePageContents, so its effect is immediate. + /*! \brief Implementors may call this method during parsing to terminate parsing early. This method + * throws an exception that is caught by parsePageContents, so its effect is immediate. + */ QPDF_DLL void terminateParsing(); }; @@ -238,6 +246,7 @@ class QPDFObjectHandle: public qpdf::BaseHandle ury(0.0) { } + Rectangle(double llx, double lly, double urx, double ury) : llx(llx), lly(lly), @@ -252,9 +261,10 @@ class QPDFObjectHandle: public qpdf::BaseHandle double ury; }; - // Convenience object for transformation matrices. See also QPDFMatrix. Unfortunately we can't - // replace this with QPDFMatrix because QPDFMatrix's default constructor creates the identity - // transform matrix and this one is all zeroes. + /*! \brief Convenience object for transformation matrices. See also QPDFMatrix. Unfortunately we can't + * replace this with QPDFMatrix because QPDFMatrix's default constructor creates the identity + * transform matrix and this one is all zeroes. + */ class Matrix { public: @@ -267,6 +277,7 @@ class QPDFObjectHandle: public qpdf::BaseHandle f(0.0) { } + Matrix(double a, double b, double c, double d, double e, double f) : a(a), b(b), @@ -291,26 +302,30 @@ class QPDFObjectHandle: public qpdf::BaseHandle QPDFObjectHandle(QPDFObjectHandle&&) = default; QPDFObjectHandle& operator=(QPDFObjectHandle&&) = default; - // This method is provided for backward compatibility only. New code should convert to bool - // instead. + /*! \brief This method is provided for backward compatibility only. New code should convert to bool + * instead. + */ inline bool isInitialized() const; - // This method returns true if the QPDFObjectHandle objects point to exactly the same underlying - // object, meaning that changes to one are reflected in the other, or "if you paint one, the - // other one changes color." This does not perform a structural comparison of the contents of - // the objects. + /*! \brief This method returns true if the QPDFObjectHandle objects point to exactly the same underlying + * object, meaning that changes to one are reflected in the other, or "if you paint one, the + * other one changes color." This does not perform a structural comparison of the contents of + * the objects. + */ QPDF_DLL bool isSameObjectAs(QPDFObjectHandle const&) const; - // Return type code and type name of underlying object. These are useful for doing rapid type - // tests (like switch statements) or for testing and debugging. + /*! \brief Return type code and type name of underlying object. These are useful for doing rapid type + * tests (like switch statements) or for testing and debugging. + */ QPDF_DLL qpdf_object_type_e getTypeCode() const; QPDF_DLL char const* getTypeName() const; - // Exactly one of these will return true for any initialized object. Operator and InlineImage - // are only allowed in content streams. + /*! \brief Exactly one of these will return true for any initialized object. Operator and InlineImage + * are only allowed in content streams. + */ QPDF_DLL bool isBool() const; QPDF_DLL @@ -336,68 +351,73 @@ class QPDFObjectHandle: public qpdf::BaseHandle QPDF_DLL bool isReserved() const; - // True for objects that are direct nulls. Does not attempt to resolve objects. This is intended - // for internal use, but it can be used as an efficient way to check for nulls that are not - // indirect objects. + /*! \brief True for objects that are direct nulls. Does not attempt to resolve objects. This is intended + * for internal use, but it can be used as an efficient way to check for nulls that are not + * indirect objects. QPDF_DLL bool isDirectNull() const; - // This returns true in addition to the query for the specific type for indirect objects. + /*! \brief This returns true in addition to the query for the specific type for indirect objects. */ QPDF_DLL bool isIndirect() const; - // This returns true for indirect objects from a QPDF that has been destroyed. Trying unparse - // such an object will throw a logic_error. + /*! \brief This returns true for indirect objects from a QPDF that has been destroyed. Trying unparse + * such an object will throw a logic_error. + */ QPDF_DLL bool isDestroyed() const; - // True for everything except array, dictionary, stream, word, and inline image. + /*! \brief True for everything except array, dictionary, stream, word, and inline image. */ QPDF_DLL bool isScalar() const; - // True if the object is a name object representing the provided name. + /*! \brief True if the object is a name object representing the provided name. */ QPDF_DLL bool isNameAndEquals(std::string const& name) const; - // True if the object is a dictionary of the specified type and subtype, if any. + /*! \brief True if the object is a dictionary of the specified type and subtype, if any. */ QPDF_DLL bool isDictionaryOfType(std::string const& type, std::string const& subtype = "") const; - // True if the object is a stream of the specified type and subtype, if any. + /*! \brief True if the object is a stream of the specified type and subtype, if any. */ QPDF_DLL bool isStreamOfType(std::string const& type, std::string const& subtype = "") const; // Public factory methods - // Wrap an object in an array if it is not already an array. This is a helper for cases in which - // something in a PDF may either be a single item or an array of items, which is a common idiom. + /*! \brief Wrap an object in an array if it is not already an array. This is a helper for cases in which + * something in a PDF may either be a single item or an array of items, which is a common idiom. + */ QPDF_DLL QPDFObjectHandle wrapInArray(); - // Construct an object of any type from a string representation of the object. Throws QPDFExc - // with an empty filename and an offset into the string if there is an error. Any indirect - // object syntax (obj gen R) will cause a logic_error exception to be thrown. If - // object_description is provided, it will appear in the message of any QPDFExc exception thrown - // for invalid syntax. See also the global `operator ""_qpdf` defined below. + /*! \brief Construct an object of any type from a string representation of the object. Throws QPDFExc + * with an empty filename and an offset into the string if there is an error. Any indirect + * object syntax (obj gen R) will cause a logic_error exception to be thrown. If + * object_description is provided, it will appear in the message of any QPDFExc exception thrown + * for invalid syntax. See also the global `operator ""_qpdf` defined below. + */ QPDF_DLL static QPDFObjectHandle parse(std::string const& object_str, std::string const& object_description = ""); - // Construct an object of any type from a string representation of the object. Indirect object - // syntax (obj gen R) is allowed and will create indirect references within the passed-in - // context. If object_description is provided, it will appear in the message of any QPDFExc - // exception thrown for invalid syntax. Note that you can't parse an indirect object reference - // all by itself as parse will stop at the end of the first complete object, which will just be - // the first number and will report that there is trailing data at the end of the string. + /*! \brief Construct an object of any type from a string representation of the object. Indirect object + * syntax (obj gen R) is allowed and will create indirect references within the passed-in + * context. If object_description is provided, it will appear in the message of any QPDFExc + * exception thrown for invalid syntax. Note that you can't parse an indirect object reference + * all by itself as parse will stop at the end of the first complete object, which will just be + * the first number and will report that there is trailing data at the end of the string. + */ QPDF_DLL static QPDFObjectHandle parse(QPDF* context, std::string const& object_str, std::string const& object_description = ""); - // Construct an object as above by reading from the given InputSource at its current position - // and using the tokenizer you supply. Indirect objects and encrypted strings are permitted. - // This method was intended to be called by QPDF for parsing objects that are read from the - // object's input stream. To be removed in qpdf 13. See - // . + /*! \brief Construct an object as above by reading from the given InputSource at its current position + * and using the tokenizer you supply. Indirect objects and encrypted strings are permitted. + * This method was intended to be called by QPDF for parsing objects that are read from the + * object's input stream. To be removed in qpdf 13. See + * . + */ [[deprecated("to be removed in qpdf 13")]] QPDF_DLL static QPDFObjectHandle parse( std::shared_ptr input, std::string const& object_description, @@ -406,63 +426,71 @@ class QPDFObjectHandle: public qpdf::BaseHandle StringDecrypter* decrypter, QPDF* context); - // Return the offset where the object was found when parsed. A negative value means that the - // object was created without parsing. If the object is in a stream, the offset is from the - // beginning of the stream. Otherwise, the offset is from the beginning of the file. + /*! \brief Return the offset where the object was found when parsed. A negative value means that the + * object was created without parsing. If the object is in a stream, the offset is from the + * beginning of the stream. Otherwise, the offset is from the beginning of the file. + */ QPDF_DLL qpdf_offset_t getParsedOffset() const; - // Older method: stream_or_array should be the value of /Contents from a page object. It's more - // convenient to just call QPDFPageObjectHelper::parsePageContents on the page object, and error - // messages will also be more useful because the page object information will be known. + /*! \brief Older method: stream_or_array should be the value of /Contents from a page object. It's more + * convenient to just call QPDFPageObjectHelper::parsePageContents on the page object, and error + * messages will also be more useful because the page object information will be known. + */ QPDF_DLL static void parseContentStream(QPDFObjectHandle stream_or_array, ParserCallbacks* callbacks); - // When called on a stream or stream array that is some page's content streams, do the same as - // pipePageContents. This method is a lower level way to do what - // QPDFPageObjectHelper::pipePageContents does, but it allows you to perform this operation on a - // contents object that is disconnected from a page object. The description argument should - // describe the containing page and is used in error messages. The all_description argument is - // initialized to something that could be used to describe the result of the pipeline. It is the - // description amended with the identifiers of the underlying objects. Please note that if there - // is an array of content streams, p->finish() is called after each stream. If you pass a - // pipeline that doesn't allow write() to be called after finish(), you can wrap it in an - // instance of Pl_Concatenate and then call manualFinish() on the Pl_Concatenate pipeline at the - // end. + /*! \brief When called on a stream or stream array that is some page's content streams, do the same as + * pipePageContents. This method is a lower level way to do what + * QPDFPageObjectHelper::pipePageContents does, but it allows you to perform this operation on a + * contents object that is disconnected from a page object. The description argument should + * describe the containing page and is used in error messages. The all_description argument is + * initialized to something that could be used to describe the result of the pipeline. It is the + * description amended with the identifiers of the underlying objects. Please note that if there + * is an array of content streams, p->finish() is called after each stream. If you pass a + * pipeline that doesn't allow write() to be called after finish(), you can wrap it in an + * instance of Pl_Concatenate and then call manualFinish() on the Pl_Concatenate pipeline at the + * end. + */ QPDF_DLL void pipeContentStreams(Pipeline* p, std::string const& description, std::string& all_description); - // As of qpdf 8, it is possible to add custom token filters to a stream. The tokenized stream - // data is passed through the token filter after all original filters but before content stream - // normalization if requested. This is a low-level interface to add it to a stream. You will - // usually want to call QPDFPageObjectHelper::addContentTokenFilter instead, which can be - // applied to a page object, and which will automatically handle the case of pages whose - // contents are split across multiple streams. + /*! \brief As of qpdf 8, it is possible to add custom token filters to a stream. The tokenized stream + * data is passed through the token filter after all original filters but before content stream + * normalization if requested. This is a low-level interface to add it to a stream. You will + * usually want to call QPDFPageObjectHelper::addContentTokenFilter instead, which can be + * applied to a page object, and which will automatically handle the case of pages whose + * contents are split across multiple streams. + */ QPDF_DLL void addTokenFilter(std::shared_ptr token_filter); - // Legacy helpers for parsing content streams. These methods are not going away, but newer code - // should call the correspond methods in QPDFPageObjectHelper instead. The specification and - // behavior of these methods are the same as the identically named methods in that class, but - // newer functionality will be added there. + /*! \brief Legacy helpers for parsing content streams. These methods are not going away, but newer code + * should call the correspond methods in QPDFPageObjectHelper instead. The specification and + * behavior of these methods are the same as the identically named methods in that class, but + * newer functionality will be added there. + */ QPDF_DLL void parsePageContents(ParserCallbacks* callbacks); + QPDF_DLL void filterPageContents(TokenFilter* filter, Pipeline* next = nullptr); - // See comments for QPDFPageObjectHelper::pipeContents. - QPDF_DLL - void pipePageContents(Pipeline* p); - QPDF_DLL - void addContentTokenFilter(std::shared_ptr token_filter); + + /*! \brief See comments for QPDFPageObjectHelper::pipeContents. */ + QPDF_DLL void pipePageContents(Pipeline* p); + QPDF_DLL void addContentTokenFilter(std::shared_ptr token_filter); // End legacy content stream helpers - // Called on a stream to filter the stream as if it were page contents. This can be used to - // apply a TokenFilter to a form XObject, whose data is in the same format as a content stream. + /*! \brief Called on a stream to filter the stream as if it were page contents. This can be used to + * apply a TokenFilter to a form XObject, whose data is in the same format as a content stream. + */ QPDF_DLL void filterAsContents(TokenFilter* filter, Pipeline* next = nullptr); - // Called on a stream to parse the stream as page contents. This can be used to parse a form - // XObject. + + /*! \brief Called on a stream to parse the stream as page contents. This can be used to parse a form + * XObject. + */ QPDF_DLL void parseAsContents(ParserCallbacks* callbacks); @@ -478,25 +506,29 @@ class QPDFObjectHandle: public qpdf::BaseHandle QPDF_DLL static QPDFObjectHandle newReal(double value, int decimal_places = 0, bool trim_trailing_zeroes = true); - // Note about name objects: qpdf's internal representation of a PDF name is a sequence of bytes, - // excluding the NUL character, and starting with a slash. Name objects as represented in the - // PDF specification can contain characters escaped with #, but such escaping is not of concern - // when calling QPDFObjectHandle methods not directly relating to parsing. For example, - // newName("/text/plain").getName() and parse("/text#2fplain").getName() both return - // "/text/plain", while newName("/text/plain").unparse() and parse("/text#2fplain").unparse() - // both return "/text#2fplain". When working with the qpdf API for creating, retrieving, and - // modifying objects, you want to work with the internal, canonical representation. For names - // containing alphanumeric characters, dashes, and underscores, there is no difference between - // the two representations. For a lengthy discussion, see - // https://github.com/qpdf/qpdf/discussions/625. + + /*! \brief Note about name objects: qpdf's internal representation of a PDF name is a sequence of bytes, + * excluding the NUL character, and starting with a slash. Name objects as represented in the + * PDF specification can contain characters escaped with #, but such escaping is not of concern + * when calling QPDFObjectHandle methods not directly relating to parsing. For example, + * newName("/text/plain").getName() and parse("/text#2fplain").getName() both return + * "/text/plain", while newName("/text/plain").unparse() and parse("/text#2fplain").unparse() + * both return "/text#2fplain". When working with the qpdf API for creating, retrieving, and + * modifying objects, you want to work with the internal, canonical representation. For names + * containing alphanumeric characters, dashes, and underscores, there is no difference between + * the two representations. For a lengthy discussion, see + * https://github.com/qpdf/qpdf/discussions/625. + */ QPDF_DLL static QPDFObjectHandle newName(std::string const& name); QPDF_DLL static QPDFObjectHandle newString(std::string const& str); - // Create a string encoded from the given utf8-encoded string appropriately encoded to appear in - // PDF files outside of content streams, such as in document metadata form field values, page - // labels, outlines, and similar locations. We try ASCII first, then PDFDocEncoding, then UTF-16 - // as needed to successfully encode all the characters. + + /*! \brief Create a string encoded from the given utf8-encoded string appropriately encoded to appear in + * PDF files outside of content streams, such as in document metadata form field values, page + * labels, outlines, and similar locations. We try ASCII first, then PDFDocEncoding, then UTF-16 + * as needed to successfully encode all the characters. + */ QPDF_DLL static QPDFObjectHandle newUnicodeString(std::string const& utf8_str); QPDF_DLL @@ -518,67 +550,73 @@ class QPDFObjectHandle: public qpdf::BaseHandle QPDF_DLL static QPDFObjectHandle newDictionary(std::map const& items); - // Create an array from a rectangle. Equivalent to the rectangle form of newArray. + /*! \brief Create an array from a rectangle. Equivalent to the rectangle form of newArray. */ QPDF_DLL static QPDFObjectHandle newFromRectangle(Rectangle const&); - // Create an array from a matrix. Equivalent to the matrix form of newArray. + + /*! \brief Create an array from a matrix. Equivalent to the matrix form of newArray. */ QPDF_DLL static QPDFObjectHandle newFromMatrix(Matrix const&); QPDF_DLL static QPDFObjectHandle newFromMatrix(QPDFMatrix const&); - // Note: new stream creation methods have were added to the QPDF class starting with - // version 11.2.0. The ones in this class are here for backward compatibility. - - // Create a new stream and associate it with the given qpdf object. A subsequent call must be - // made to replaceStreamData() to provide data for the stream. The stream's dictionary may be - // retrieved by calling getDict(), and the resulting dictionary may be modified. Alternatively, - // you can create a new dictionary and call replaceDict to install it. From QPDF 11.2, you can - // call QPDF::newStream() instead. + /*! \note: new stream creation methods have were added to the QPDF class starting with + * version 11.2.0. The ones in this class are here for backward compatibility. + * + * \brief Create a new stream and associate it with the given qpdf object. A subsequent call must be + * made to replaceStreamData() to provide data for the stream. The stream's dictionary may be + * retrieved by calling getDict(), and the resulting dictionary may be modified. Alternatively, + * you can create a new dictionary and call replaceDict to install it. From QPDF 11.2, you can + * call QPDF::newStream() instead. + */ QPDF_DLL static QPDFObjectHandle newStream(QPDF* qpdf); - // Create a new stream and associate it with the given qpdf object. Use the given buffer as the - // stream data. The stream dictionary's /Length key will automatically be set to the size of the - // data buffer. If additional keys are required, the stream's dictionary may be retrieved by - // calling getDict(), and the resulting dictionary may be modified. This method is just a - // convenient wrapper around the newStream() and replaceStreamData(). It is a convenience - // methods for streams that require no parameters beyond the stream length. Note that you don't - // have to deal with compression yourself if you use QPDFWriter. By default, QPDFWriter will - // automatically compress uncompressed stream data. Example programs are provided that - // illustrate this. From QPDF 11.2, you can call QPDF::newStream() - // instead. + /*! \brief Create a new stream and associate it with the given qpdf object. Use the given buffer as the + * stream data. The stream dictionary's /Length key will automatically be set to the size of the + * data buffer. If additional keys are required, the stream's dictionary may be retrieved by + * calling getDict(), and the resulting dictionary may be modified. This method is just a + * convenient wrapper around the newStream() and replaceStreamData(). It is a convenience + * methods for streams that require no parameters beyond the stream length. Note that you don't + * have to deal with compression yourself if you use QPDFWriter. By default, QPDFWriter will + * automatically compress uncompressed stream data. Example programs are provided that + * illustrate this. From QPDF 11.2, you can call QPDF::newStream() + * instead. + */ QPDF_DLL static QPDFObjectHandle newStream(QPDF* qpdf, std::shared_ptr data); - // Create new stream with data from string. This method will create a copy of the data rather - // than using the user-provided buffer as in the std::shared_ptr version of newStream. - // From QPDF 11.2, you can call QPDF::newStream() instead. + /*! \brief Create new stream with data from string. This method will create a copy of the data rather + * than using the user-provided buffer as in the std::shared_ptr version of newStream. + * From QPDF 11.2, you can call QPDF::newStream() instead. + */ QPDF_DLL static QPDFObjectHandle newStream(QPDF* qpdf, std::string const& data); - // A reserved object is a special sentinel used for qpdf to reserve a spot for an object that is - // going to be added to the QPDF object. Normally you don't have to use this type since you can - // just call QPDF::makeIndirectObject. However, in some cases, if you have to create objects - // with circular references, you may need to create a reserved object so that you can have a - // reference to it and then replace the object later. Reserved objects have the special - // property that they can't be resolved to direct objects. This makes it possible to replace a - // reserved object with a new object while preserving existing references to them. When you are - // ready to replace a reserved object with its replacement, use QPDF::replaceReserved for this - // purpose rather than the more general QPDF::replaceObject. It is an error to try to write a - // QPDF with QPDFWriter if it has any reserved objects in it. From QPDF 11.4, you can call - // QPDF::newReserved() instead. + /*! \brief A reserved object is a special sentinel used for qpdf to reserve a spot for an object that is + * going to be added to the QPDF object. Normally you don't have to use this type since you can + * just call QPDF::makeIndirectObject. However, in some cases, if you have to create objects + * with circular references, you may need to create a reserved object so that you can have a + * reference to it and then replace the object later. Reserved objects have the special + * property that they can't be resolved to direct objects. This makes it possible to replace a + * reserved object with a new object while preserving existing references to them. When you are + * ready to replace a reserved object with its replacement, use QPDF::replaceReserved for this + * purpose rather than the more general QPDF::replaceObject. It is an error to try to write a + * QPDF with QPDFWriter if it has any reserved objects in it. From QPDF 11.4, you can call + * QPDF::newReserved() instead. + */ QPDF_DLL static QPDFObjectHandle newReserved(QPDF* qpdf); - // Provide an owning qpdf and object description. The library does this automatically with - // objects that are read from the input PDF and with objects that are created programmatically - // and inserted into the QPDF as a new indirect object. Most end user code will not need to call - // this. If an object has an owning qpdf and object description, it enables qpdf to give - // warnings with proper context in some cases where it would otherwise raise exceptions. It is - // okay to add objects without an owning_qpdf to objects that have one, but it is an error to - // have a QPDF contain objects with owning_qpdf set to something else. To add objects from - // another qpdf, use copyForeignObject instead. + /*! \brief Provide an owning qpdf and object description. The library does this automatically with + * objects that are read from the input PDF and with objects that are created programmatically + * and inserted into the QPDF as a new indirect object. Most end user code will not need to call + * this. If an object has an owning qpdf and object description, it enables qpdf to give + * warnings with proper context in some cases where it would otherwise raise exceptions. It is + * okay to add objects without an owning_qpdf to objects that have one, but it is an error to + * have a QPDF contain objects with owning_qpdf set to something else. To add objects from + * another qpdf, use copyForeignObject instead. + */ QPDF_DLL void setObjectDescription(QPDF* owning_qpdf, std::string const& object_description); QPDF_DLL @@ -636,10 +674,11 @@ class QPDFObjectHandle: public qpdf::BaseHandle QPDF_DLL bool getValueAsBool(bool&) const; - // Methods for integer objects. Note: if an integer value is too big (too far away from zero in - // either direction) to fit in the requested return type, the maximum or minimum value for that - // return type may be returned. For example, on a system with 32-bit int, a numeric object with - // a value of 2^40 (or anything too big for 32 bits) will be returned as INT_MAX. + /*! \brief Methods for integer objects. Note: if an integer value is too big (too far away from zero in + * either direction) to fit in the requested return type, the maximum or minimum value for that + * return type may be returned. For example, on a system with 32-bit int, a numeric object with + * a value of 2^40 (or anything too big for 32 bits) will be returned as INT_MAX. + */ QPDF_DLL long long getIntValue() const; QPDF_DLL @@ -671,30 +710,30 @@ class QPDFObjectHandle: public qpdf::BaseHandle QPDF_DLL bool getValueAsNumber(double&) const; - // Methods for name objects. The returned name value is in qpdf's canonical form with all - // escaping resolved. See comments for newName() for details. + /*! \brief Methods for name objects. The returned name value is in qpdf's canonical form with all + * escaping resolved. See comments for newName() for details. + */ QPDF_DLL std::string getName() const; QPDF_DLL bool getValueAsName(std::string&) const; - // Methods for string objects + /*! \brief Methods for string objects */ QPDF_DLL std::string getStringValue() const; QPDF_DLL bool getValueAsString(std::string&) const; - // If a string starts with the UTF-16 marker, it is converted from UTF-16 to UTF-8. Otherwise, - // it is treated as a string encoded with PDF Doc Encoding. PDF Doc Encoding is identical to - // ISO-8859-1 except in the range from 0200 through 0240, where there is a mapping of characters - // to Unicode. QPDF versions prior to version 8.0.0 erroneously left characters in that range - // unmapped. - QPDF_DLL - std::string getUTF8Value() const; - QPDF_DLL - bool getValueAsUTF8(std::string&) const; + /*! \brief If a string starts with the UTF-16 marker, it is converted from UTF-16 to UTF-8. Otherwise, + * it is treated as a string encoded with PDF Doc Encoding. PDF Doc Encoding is identical to + * ISO-8859-1 except in the range from 0200 through 0240, where there is a mapping of characters + * to Unicode. QPDF versions prior to version 8.0.0 erroneously left characters in that range + * unmapped. + */ + QPDF_DLL std::string getUTF8Value() const; + QPDF_DLL bool getValueAsUTF8(std::string&) const; - // Methods for content stream objects + /*! \brief Methods for content stream objects */ QPDF_DLL std::string getOperatorValue() const; QPDF_DLL @@ -704,14 +743,14 @@ class QPDFObjectHandle: public qpdf::BaseHandle QPDF_DLL bool getValueAsInlineImage(std::string&) const; - // Methods for array objects; see also name and array objects. - - // Return an object that enables iteration over members. You can do - // - // for (auto iter: obj.aitems()) - // { - // // iter is an array element - // } + /*! \brief Methods for array objects; see also name and array objects. + * Return an object that enables iteration over members. You can do + * + * for (auto iter: obj.aitems()) + * { + * // iter is an array element + * } + */ class QPDFArrayItems; QPDF_DLL QPDFArrayItems aitems(); @@ -720,195 +759,220 @@ class QPDFObjectHandle: public qpdf::BaseHandle int getArrayNItems() const; QPDF_DLL QPDFObjectHandle getArrayItem(int n) const; - // Note: QPDF arrays internally optimize memory for arrays containing lots of nulls. Calling - // getArrayAsVector may cause a lot of memory to be allocated for very large arrays with lots of - // nulls. + + /*! \note: QPDF arrays internally optimize memory for arrays containing lots of nulls. Calling + * getArrayAsVector may cause a lot of memory to be allocated for very large arrays with lots of + * nulls. + */ QPDF_DLL std::vector getArrayAsVector() const; QPDF_DLL bool isRectangle() const; - // If the array is an array of four numeric values, return as a rectangle. Otherwise, return the - // rectangle [0, 0, 0, 0] + + /*! \brief If the array is an array of four numeric values, return as a rectangle. Otherwise, return the + * rectangle [0, 0, 0, 0] + */ QPDF_DLL Rectangle getArrayAsRectangle() const; QPDF_DLL bool isMatrix() const; - // If the array is an array of six numeric values, return as a matrix. Otherwise, return the - // matrix [1, 0, 0, 1, 0, 0] + + /*! \brief If the array is an array of six numeric values, return as a matrix. Otherwise, return the + * matrix [1, 0, 0, 1, 0, 0] + */ QPDF_DLL Matrix getArrayAsMatrix() const; - // Methods for dictionary objects. In all dictionary methods, keys are specified/represented as - // canonical name strings starting with a leading slash and not containing any PDF syntax - // escaping. See comments for getName() for details. - - // Return an object that enables iteration over members. You can do - // - // for (auto iter: obj.ditems()) - // { - // // iter.first is the key - // // iter.second is the value - // } + /*! \brief Methods for dictionary objects. In all dictionary methods, keys are specified/represented as + * canonical name strings starting with a leading slash and not containing any PDF syntax + * escaping. See comments for getName() for details. + * + * Return an object that enables iteration over members. You can do + * + * for (auto iter: obj.ditems()) + * { + * // iter.first is the key + * // iter.second is the value + * } + */ class QPDFDictItems; QPDF_DLL QPDFDictItems ditems(); - // Return true if key is present. Keys with null values are treated as if they are not present. - // This is as per the PDF spec. + /*! \return true if key is present. Keys with null values are treated as if they are not present. + * This is as per the PDF spec. + */ QPDF_DLL bool hasKey(std::string const&) const; - // Return the value for the key. If the key is not present, null is returned. + + /*! \return the value for the key. If the key is not present, null is returned. */ QPDF_DLL QPDFObjectHandle getKey(std::string const&) const; - // If the object is null, return null. Otherwise, call getKey(). This makes it easier to access - // lower-level dictionaries, as in - // auto font = page.getKeyIfDict("/Resources").getKeyIfDict("/Font"); + + /*! \brief If the object is null, return null. Otherwise, call getKey(). This makes it easier to access + * lower-level dictionaries, as in + * auto font = page.getKeyIfDict("/Resources").getKeyIfDict("/Font"); + */ QPDF_DLL QPDFObjectHandle getKeyIfDict(std::string const&) const; - // Return all keys. Keys with null values are treated as if they are not present. This is as - // per the PDF spec. + + /*! \brief Return all keys. Keys with null values are treated as if they are not present. This is as + * per the PDF spec. + */ QPDF_DLL std::set getKeys() const; - // Return dictionary as a map. Entries with null values are included. + + /*! \return dictionary as a map. Entries with null values are included. */ QPDF_DLL std::map getDictAsMap() const; - // Methods for name and array objects. The name value is in qpdf's canonical form with all - // escaping resolved. See comments for newName() for details. + /*! \brief Methods for name and array objects. The name value is in qpdf's canonical form with all + * escaping resolved. See comments for newName() for details. + */ QPDF_DLL bool isOrHasName(std::string const&) const; - // Make all resources in a resource dictionary indirect. This just goes through all entries of - // top-level subdictionaries and converts any direct objects to indirect objects. This can be - // useful to call before mergeResources if it is going to be called multiple times to prevent - // resources from being copied multiple times. + /*! \brief Make all resources in a resource dictionary indirect. This just goes through all entries of + * top-level subdictionaries and converts any direct objects to indirect objects. This can be + * useful to call before mergeResources if it is going to be called multiple times to prevent + * resources from being copied multiple times. + */ QPDF_DLL void makeResourcesIndirect(QPDF& owning_qpdf); - // Merge resource dictionaries. If the "conflicts" parameter is provided, conflicts in - // dictionary subitems are resolved, and "conflicts" is initialized to a map such that - // conflicts[resource_type][old_key] == [new_key] - // - // See also makeResourcesIndirect, which can be useful to call before calling this. - // - // This method does nothing if both this object and the other object are not dictionaries. - // Otherwise, it has following behavior, where "object" refers to the object whose method is - // invoked, and "other" refers to the argument: - // - // * For each key in "other" whose value is an array: - // * If "object" does not have that entry, shallow copy it. - // * Otherwise, if "object" has an array in the same place, append to that array any objects - // in "other"'s array that are not already present. - // * For each key in "other" whose value is a dictionary: - // * If "object" does not have that entry, shallow copy it. - // * Otherwise, for each key in the subdictionary: - // * If key is not present in "object"'s entry, shallow copy it if direct or just add it if - // indirect. - // * Otherwise, if conflicts are being detected: - // * If there is a key (oldkey) already in the dictionary that points to the same indirect - // destination as key, indicate that key was replaced by oldkey. This would happen if - // these two resource dictionaries have previously been merged. - // * Otherwise pick a new key (newkey) that is unique within the resource dictionary, - // store that in the resource dictionary with key's destination as its destination, and - // indicate that key was replaced by newkey. - // - // The primary purpose of this method is to facilitate merging of resource dictionaries that are - // supposed to have the same scope as each other. For example, this can be used to merge a form - // XObject's /Resources dictionary with a form field's /DR or to merge two /DR dictionaries. The - // "conflicts" parameter may be previously initialized. This method adds to whatever is already - // there, which can be useful when merging with multiple things. + /*! \brief Merge resource dictionaries. If the "conflicts" parameter is provided, conflicts in + * dictionary subitems are resolved, and "conflicts" is initialized to a map such that + * conflicts[resource_type][old_key] == [new_key] + * + * See also makeResourcesIndirect, which can be useful to call before calling this. + * + * This method does nothing if both this object and the other object are not dictionaries. + * Otherwise, it has following behavior, where "object" refers to the object whose method is + * invoked, and "other" refers to the argument: + * + * * For each key in "other" whose value is an array: + * * If "object" does not have that entry, shallow copy it. + * * Otherwise, if "object" has an array in the same place, append to that array any objects + * in "other"'s array that are not already present. + * * For each key in "other" whose value is a dictionary: + * * If "object" does not have that entry, shallow copy it. + * * Otherwise, for each key in the subdictionary: + * * If key is not present in "object"'s entry, shallow copy it if direct or just add it if + * indirect. + * * Otherwise, if conflicts are being detected: + * * If there is a key (oldkey) already in the dictionary that points to the same indirect + * destination as key, indicate that key was replaced by oldkey. This would happen if + * these two resource dictionaries have previously been merged. + * * Otherwise pick a new key (newkey) that is unique within the resource dictionary, + * store that in the resource dictionary with key's destination as its destination, and + * indicate that key was replaced by newkey. + * + * The primary purpose of this method is to facilitate merging of resource dictionaries that are + * supposed to have the same scope as each other. For example, this can be used to merge a form + * XObject's /Resources dictionary with a form field's /DR or to merge two /DR dictionaries. The + * "conflicts" parameter may be previously initialized. This method adds to whatever is already + * there, which can be useful when merging with multiple things. + */ QPDF_DLL void mergeResources( QPDFObjectHandle other, std::map>* conflicts = nullptr); - // Get all resource names from a resource dictionary. If this object is a dictionary, this - // method returns a set of all the keys in all top-level subdictionaries. For resources - // dictionaries, this is the collection of names that may be referenced in the content stream. + /*! \brief Get all resource names from a resource dictionary. If this object is a dictionary, this + * method returns a set of all the keys in all top-level subdictionaries. For resources + * dictionaries, this is the collection of names that may be referenced in the content stream. + */ QPDF_DLL std::set getResourceNames() const; - // Find a unique name within a resource dictionary starting with a given prefix. This method - // works by appending a number to the given prefix. It searches starting with min_suffix and - // sets min_suffix to selected value upon return. This can be used to increase efficiency if - // adding multiple items with the same prefix. (Why doesn't it set min_suffix to the next - // number? Well, maybe you aren't going to actually use the name it returns.) If you are calling - // this multiple times on the same resource dictionary, you can initialize resource_names by - // calling getResourceNames(), incrementally update it as you add resources, and keep passing it - // in so that getUniqueResourceName doesn't have to traverse the resource dictionary each time - // it's called. + /*! \brief Find a unique name within a resource dictionary starting with a given prefix. This method + * works by appending a number to the given prefix. It searches starting with min_suffix and + * sets min_suffix to selected value upon return. This can be used to increase efficiency if + * adding multiple items with the same prefix. (Why doesn't it set min_suffix to the next + * number? Well, maybe you aren't going to actually use the name it returns.) If you are calling + * this multiple times on the same resource dictionary, you can initialize resource_names by + * calling getResourceNames(), incrementally update it as you add resources, and keep passing it + * in so that getUniqueResourceName doesn't have to traverse the resource dictionary each time + * it's called. + */ QPDF_DLL std::string getUniqueResourceName( std::string const& prefix, int& min_suffix, std::set* resource_names = nullptr) const; - // A QPDFObjectHandle has an owning QPDF if it is associated with ("owned by") a specific QPDF - // object. Indirect objects always have an owning QPDF. Direct objects that are read from the - // input source will also have an owning QPDF. Programmatically created objects will only have - // one if setObjectDescription was called. - // - // When the QPDF object that owns an object is destroyed, the object is changed into a null, and - // its owner is cleared. Therefore you should not retain the value of an owning QPDF beyond the - // life of the QPDF. If in doubt, ask for it each time you need it. - - // getOwningQPDF returns a pointer to the owning QPDF is the object has one. Otherwise, it - // returns a null pointer. Use this when you are able to handle the case of an object that - // doesn't have an owning QPDF. + /*! \brief A QPDFObjectHandle has an owning QPDF if it is associated with ("owned by") a specific QPDF + * object. Indirect objects always have an owning QPDF. Direct objects that are read from the + * input source will also have an owning QPDF. Programmatically created objects will only have + * one if setObjectDescription was called. + * + * When the QPDF object that owns an object is destroyed, the object is changed into a null, and + * its owner is cleared. Therefore you should not retain the value of an owning QPDF beyond the + * life of the QPDF. If in doubt, ask for it each time you need it. + * + * getOwningQPDF returns a pointer to the owning QPDF is the object has one. Otherwise, it + * returns a null pointer. Use this when you are able to handle the case of an object that + * doesn't have an owning QPDF. + */ QPDF_DLL QPDF* getOwningQPDF() const; - // getQPDF, new in qpdf 11, returns a reference owning QPDF. If there is none, it throws a - // runtime_error. Use this when you know the object has to have an owning QPDF, such as when - // it's a known indirect object. Since streams are always indirect objects, this method can be - // used safely for streams. If error_msg is specified, it will be used at the contents of the - // runtime_error if there is now owner. + /*! \brief getQPDF, new in qpdf 11, returns a reference owning QPDF. If there is none, it throws a + * runtime_error. Use this when you know the object has to have an owning QPDF, such as when + * it's a known indirect object. Since streams are always indirect objects, this method can be + * used safely for streams. If error_msg is specified, it will be used at the contents of the + * runtime_error if there is now owner. + */ QPDF_DLL QPDF& getQPDF(std::string const& error_msg = "") const; - // Create a shallow copy of an object as a direct object, but do not traverse across indirect - // object boundaries. That means that, for dictionaries and arrays, any keys or items that were - // indirect objects will still be indirect objects that point to the same place. In the - // strictest sense, this is not a shallow copy because it recursively descends arrays and - // dictionaries; it just doesn't cross over indirect objects. See also unsafeShallowCopy(). You - // can't copy a stream this way. See copyStream() instead. + /*! \brief Create a shallow copy of an object as a direct object, but do not traverse across indirect + * object boundaries. That means that, for dictionaries and arrays, any keys or items that were + * indirect objects will still be indirect objects that point to the same place. In the + * strictest sense, this is not a shallow copy because it recursively descends arrays and + * dictionaries; it just doesn't cross over indirect objects. See also unsafeShallowCopy(). You + * can't copy a stream this way. See copyStream() instead. + */ QPDF_DLL QPDFObjectHandle shallowCopy(); - // Create a true shallow copy of an array or dictionary, just copying the immediate items - // (array) or keys (dictionary). This is "unsafe" because, if you *modify* any of the items in - // the copy, you are modifying the original, which is almost never what you want. However, if - // your intention is merely to *replace* top-level items or keys and not to modify lower-level - // items in the copy, this method is much faster than shallowCopy(). + /*! \brief Create a true shallow copy of an array or dictionary, just copying the immediate items + * (array) or keys (dictionary). This is "unsafe" because, if you *modify* any of the items in + * the copy, you are modifying the original, which is almost never what you want. However, if + * your intention is merely to *replace* top-level items or keys and not to modify lower-level + * items in the copy, this method is much faster than shallowCopy(). + */ QPDF_DLL QPDFObjectHandle unsafeShallowCopy(); - // Create a copy of this stream. The new stream and the old stream are independent: after the - // copy, either the original or the copy's dictionary or data can be modified without affecting - // the other. This uses StreamDataProvider internally, so no unnecessary copies of the stream's - // data are made. If the source stream's data is already being provided by a StreamDataProvider, - // the new stream will use the same one, so you have to make sure your StreamDataProvider can - // handle that case. But if you're already using a StreamDataProvider, you probably don't need - // to call this method. + /*! \brief Create a copy of this stream. The new stream and the old stream are independent: after the + * copy, either the original or the copy's dictionary or data can be modified without affecting + * the other. This uses StreamDataProvider internally, so no unnecessary copies of the stream's + * data are made. If the source stream's data is already being provided by a StreamDataProvider, + * the new stream will use the same one, so you have to make sure your StreamDataProvider can + * handle that case. But if you're already using a StreamDataProvider, you probably don't need + * to call this method. + */ QPDF_DLL QPDFObjectHandle copyStream(); // Mutator methods. - // Since qpdf 11: for mutators that may add or remove an item, there are additional versions - // whose names contain "AndGet" that return the added or removed item. For example: - // - // auto new_dict = dict.replaceKeyAndGetNew( - // "/New", QPDFObjectHandle::newDictionary()); - // - // auto old_value = dict.replaceKeyAndGetOld( - // "/New", "(something)"_qpdf); - - // Recursively copy this object, making it direct. An exception is thrown if a loop is detected. - // With allow_streams true, keep indirect object references to streams. Otherwise, throw an - // exception if any sub-object is a stream. Note that, when allow_streams is true and a stream - // is found, the resulting object is still associated with the containing qpdf. When - // allow_streams is false, the object will no longer be connected to the original QPDF object - // after this call completes successfully. + /*! \brief Since qpdf 11: for mutators that may add or remove an item, there are additional versions + * whose names contain "AndGet" that return the added or removed item. For example: + * + * auto new_dict = dict.replaceKeyAndGetNew( + * "/New", QPDFObjectHandle::newDictionary()); + * + * auto old_value = dict.replaceKeyAndGetOld( + * "/New", "(something)"_qpdf); + * + * Recursively copy this object, making it direct. An exception is thrown if a loop is detected. + * With allow_streams true, keep indirect object references to streams. Otherwise, throw an + * exception if any sub-object is a stream. Note that, when allow_streams is true and a stream + * is found, the resulting object is still associated with the containing qpdf. When + * allow_streams is false, the object will no longer be connected to the original QPDF object + * after this call completes successfully. + */ QPDF_DLL void makeDirect(bool allow_streams = false); @@ -917,41 +981,52 @@ class QPDFObjectHandle: public qpdf::BaseHandle void setArrayItem(int, QPDFObjectHandle const&); QPDF_DLL void setArrayFromVector(std::vector const& items); - // Insert an item before the item at the given position ("at") so that it has that position - // after insertion. If "at" is equal to the size of the array, insert the item at the end. + + /*! \brief Insert an item before the item at the given position ("at") so that it has that position + * after insertion. If "at" is equal to the size of the array, insert the item at the end. + */ QPDF_DLL void insertItem(int at, QPDFObjectHandle const& item); - // Like insertItem but return the item that was inserted. + + /*! \brief Like insertItem but return the item that was inserted. */ QPDF_DLL QPDFObjectHandle insertItemAndGetNew(int at, QPDFObjectHandle const& item); - // Append an item to an array. + + /*! \brief Append an item to an array. */ QPDF_DLL void appendItem(QPDFObjectHandle const& item); - // Append an item, and return the newly added item. + + /*! \brief Append an item, and return the newly added item. */ QPDF_DLL QPDFObjectHandle appendItemAndGetNew(QPDFObjectHandle const& item); - // Remove the item at that position, reducing the size of the array by one. + + /*! \brief Remove the item at that position, reducing the size of the array by one. */ QPDF_DLL void eraseItem(int at); - // Erase and item and return the item that was removed. + + /*! \brief Erase and item and return the item that was removed. */ QPDF_DLL QPDFObjectHandle eraseItemAndGetOld(int at); // Mutator methods for dictionary objects - // Replace value of key, adding it if it does not exist. If value is null, remove the key. + /*! \brief Replace value of key, adding it if it does not exist. If value is null, remove the key. */ QPDF_DLL void replaceKey(std::string const& key, QPDFObjectHandle const& value); - // Replace value of key and return the value. + + /*! \brief Replace value of key and return the value. */ QPDF_DLL QPDFObjectHandle replaceKeyAndGetNew(std::string const& key, QPDFObjectHandle const& value); - // Replace value of key and return the old value, or null if the key was previously not present. + + /*! \brief Replace value of key and return the old value, or null if the key was previously not present. */ QPDF_DLL QPDFObjectHandle replaceKeyAndGetOld(std::string const& key, QPDFObjectHandle const& value); - // Remove key, doing nothing if key does not exist. + + /*! \brief Remove key, doing nothing if key does not exist. */ QPDF_DLL void removeKey(std::string const& key); - // Remove key and return the old value. If the old value didn't exist, return a null object. + + /*! \brief Remove key and return the old value. If the old value didn't exist, return a null object. */ QPDF_DLL QPDFObjectHandle removeKeyAndGetOld(std::string const& key); @@ -959,76 +1034,80 @@ class QPDFObjectHandle: public qpdf::BaseHandle QPDF_DLL QPDFObjectHandle getDict() const; - // By default, or if true passed, QPDFWriter will attempt to filter a stream based on decode - // level, whether compression is enabled, and its ability to filter. Passing false will prevent - // QPDFWriter from attempting to filter the stream even if it can. This includes both decoding - // and compressing. This makes it possible for you to prevent QPDFWriter from uncompressing and - // recompressing a stream that it knows how to operate on for any application-specific reason, - // such as that you have already optimized its filtering. Note that this doesn't affect any - // other ways to get the stream's data, such as pipeStreamData or getStreamData. + /*! \brief By default, or if true passed, QPDFWriter will attempt to filter a stream based on decode + * level, whether compression is enabled, and its ability to filter. Passing false will prevent + * QPDFWriter from attempting to filter the stream even if it can. This includes both decoding + * and compressing. This makes it possible for you to prevent QPDFWriter from uncompressing and + * recompressing a stream that it knows how to operate on for any application-specific reason, + * such as that you have already optimized its filtering. Note that this doesn't affect any + * other ways to get the stream's data, such as pipeStreamData or getStreamData. + */ QPDF_DLL void setFilterOnWrite(bool); QPDF_DLL bool getFilterOnWrite(); - // If addTokenFilter has been called for this stream, then the original data should be - // considered to be modified. This means we should avoid optimizations such as not filtering a - // stream that is already compressed. + /*! \brief If addTokenFilter has been called for this stream, then the original data should be + * considered to be modified. This means we should avoid optimizations such as not filtering a + * stream that is already compressed. + */ QPDF_DLL bool isDataModified(); - // Returns filtered (uncompressed) stream data. Throws an exception if the stream is filtered - // and we can't decode it. + /*! \brief Returns filtered (uncompressed) stream data. Throws an exception if the stream is filtered + * and we can't decode it. + */ QPDF_DLL std::shared_ptr getStreamData(qpdf_stream_decode_level_e level = qpdf_dl_generalized); - // Returns unfiltered (raw) stream data. + /*! \brief Returns unfiltered (raw) stream data. */ QPDF_DLL std::shared_ptr getRawStreamData(); - // Write stream data through the given pipeline. A null pipeline value may be used if all you - // want to do is determine whether a stream is filterable and would be filtered based on the - // provided flags. If flags is 0, write raw stream data and return false. Otherwise, the flags - // alter the behavior in the following way: - // - // encode_flags: - // - // qpdf_sf_compress -- compress data with /FlateDecode if no other compression filters are - // applied. - // - // qpdf_sf_normalize -- tokenize as content stream and normalize tokens - // - // decode_level: - // - // qpdf_dl_none -- do not decode any streams. - // - // qpdf_dl_generalized -- decode supported general-purpose filters. This includes - // /ASCIIHexDecode, /ASCII85Decode, /LZWDecode, and /FlateDecode. - // - // qpdf_dl_specialized -- in addition to generalized filters, also decode supported non-lossy - // specialized filters. This includes /RunLengthDecode. - // - // qpdf_dl_all -- in addition to generalized and non-lossy specialized filters, decode supported - // lossy filters. This includes /DCTDecode. - // - // If, based on the flags and the filters and decode parameters, we determine that we know how - // to apply all requested filters, do so and return true if we are successful. - // - // The exact meaning of the return value differs the different versions of this function, but - // for any version, the meaning has been the same. For the main version, added in qpdf 10, the - // return value indicates whether the overall operation succeeded. The filter parameter, if - // specified, will be set to whether or not filtering was attempted. If filtering was not - // requested, this value will be false even if the overall operation succeeded. - // - // If filtering is requested but this method returns false, it means there was some error in the - // filtering, in which case the resulting data is likely partially filtered and/or incomplete - // and may not be consistent with the configured filters. QPDFWriter handles this by attempting - // to get the stream data without filtering, but callers should consider a false return value - // when decode_level is not qpdf_dl_none to be a potential loss of data. If you intend to retry - // in that case, pass true as the value of will_retry. This changes the warning issued by the - // library to indicate that the operation will be retried without filtering to avoid data loss. - - // Return value is overall success, even if filtering is not requested. + /*! \brief Write stream data through the given pipeline. A null pipeline value may be used if all you + * want to do is determine whether a stream is filterable and would be filtered based on the + * provided flags. If flags is 0, write raw stream data and return false. Otherwise, the flags + * alter the behavior in the following way: + * + * encode_flags: + * + * qpdf_sf_compress -- compress data with /FlateDecode if no other compression filters are + * applied. + * + * qpdf_sf_normalize -- tokenize as content stream and normalize tokens + * + * decode_level: + * + * qpdf_dl_none -- do not decode any streams. + * + * qpdf_dl_generalized -- decode supported general-purpose filters. This includes + * /ASCIIHexDecode, /ASCII85Decode, /LZWDecode, and /FlateDecode. + * + * qpdf_dl_specialized -- in addition to generalized filters, also decode supported non-lossy + * specialized filters. This includes /RunLengthDecode. + * + * qpdf_dl_all -- in addition to generalized and non-lossy specialized filters, decode supported + * lossy filters. This includes /DCTDecode. + * + * If, based on the flags and the filters and decode parameters, we determine that we know how + * to apply all requested filters, do so and return true if we are successful. + * + * The exact meaning of the return value differs the different versions of this function, but + * for any version, the meaning has been the same. For the main version, added in qpdf 10, the + * return value indicates whether the overall operation succeeded. The filter parameter, if + * specified, will be set to whether or not filtering was attempted. If filtering was not + * requested, this value will be false even if the overall operation succeeded. + * + * If filtering is requested but this method returns false, it means there was some error in the + * filtering, in which case the resulting data is likely partially filtered and/or incomplete + * and may not be consistent with the configured filters. QPDFWriter handles this by attempting + * to get the stream data without filtering, but callers should consider a false return value + * when decode_level is not qpdf_dl_none to be a potential loss of data. If you intend to retry + * in that case, pass true as the value of will_retry. This changes the warning issued by the + * library to indicate that the operation will be retried without filtering to avoid data loss. + + * Return value is overall success, even if filtering is not requested. + */ QPDF_DLL bool pipeStreamData( Pipeline*, @@ -1038,8 +1117,9 @@ class QPDFObjectHandle: public qpdf::BaseHandle bool suppress_warnings = false, bool will_retry = false); - // Legacy version. Return value is whether filtering was attempted. There is no way to determine - // success if filtering was not attempted. + /*! \brief Legacy version. Return value is whether filtering was attempted. There is no way to determine + * success if filtering was not attempted. + */ QPDF_DLL bool pipeStreamData( Pipeline*, @@ -1048,99 +1128,107 @@ class QPDFObjectHandle: public qpdf::BaseHandle bool suppress_warnings = false, bool will_retry = false); - // Legacy pipeStreamData. This maps to the the flags-based pipeStreamData as follows: - // filter = false -> encode_flags = 0 - // filter = true -> decode_level = qpdf_dl_generalized - // normalize = true -> encode_flags |= qpdf_sf_normalize - // compress = true -> encode_flags |= qpdf_sf_compress - // Return value is whether filtering was attempted. + /*! \brief Legacy pipeStreamData. This maps to the the flags-based pipeStreamData as follows: + * filter = false -> encode_flags = 0 + * filter = true -> decode_level = qpdf_dl_generalized + * normalize = true -> encode_flags |= qpdf_sf_normalize + * compress = true -> encode_flags |= qpdf_sf_compress + * Return value is whether filtering was attempted. + */ QPDF_DLL bool pipeStreamData(Pipeline*, bool filter, bool normalize, bool compress); - // Replace a stream's dictionary. The new dictionary must be consistent with the stream's data. - // This is most appropriately used when creating streams from scratch that will use a stream - // data provider and therefore start with an empty dictionary. It may be more convenient in - // this case than calling getDict and modifying it for each key. The pdf-create example does - // this. + /*! \brief Replace a stream's dictionary. The new dictionary must be consistent with the stream's data. + * This is most appropriately used when creating streams from scratch that will use a stream + * data provider and therefore start with an empty dictionary. It may be more convenient in + * this case than calling getDict and modifying it for each key. The pdf-create example does + * this. + */ QPDF_DLL void replaceDict(QPDFObjectHandle const&); - // Test whether a stream is the root XMP /Metadata object of its owning QPDF. + /*! \brief Test whether a stream is the root XMP /Metadata object of its owning QPDF. */ QPDF_DLL bool isRootMetadata() const; // REPLACING STREAM DATA - // Note about all replaceStreamData methods: whatever values are passed as filter and - // decode_parms will overwrite /Filter and /DecodeParms in the stream. Passing a null object - // (QPDFObjectHandle::newNull()) will remove those values from the stream dictionary. From qpdf - // 11, passing an *uninitialized* QPDFObjectHandle (QPDFObjectHandle()) will leave any existing - // values untouched. + /*! \note About all replaceStreamData methods: whatever values are passed as filter and + * decode_parms will overwrite /Filter and /DecodeParms in the stream. Passing a null object + * (QPDFObjectHandle::newNull()) will remove those values from the stream dictionary. From qpdf + * 11, passing an *uninitialized* QPDFObjectHandle (QPDFObjectHandle()) will leave any existing + * values untouched. + */ - // Replace this stream's stream data with the given data buffer. The stream's /Length key is - // replaced with the length of the data buffer. The stream is interpreted as if the data read - // from the file, after any decryption filters have been applied, is as presented. + /*! \brief Replace this stream's stream data with the given data buffer. The stream's /Length key is + * replaced with the length of the data buffer. The stream is interpreted as if the data read + * from the file, after any decryption filters have been applied, is as presented. + */ QPDF_DLL void replaceStreamData( std::shared_ptr data, QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms); - // Replace the stream's stream data with the given string. This method will create a copy of the - // data rather than using the user-provided buffer as in the std::shared_ptr version of - // replaceStreamData. + /*! \brief Replace the stream's stream data with the given string. This method will create a copy of the + * data rather than using the user-provided buffer as in the std::shared_ptr version of + * replaceStreamData. + */ QPDF_DLL void replaceStreamData( std::string const& data, QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms); - // As above, replace this stream's stream data. Instead of directly providing a buffer with the - // stream data, call the given provider's provideStreamData method. See comments on the - // StreamDataProvider class (defined above) for details on the method. The data must be - // consistent with filter and decode_parms as provided. Although it is more complex to use this - // form of replaceStreamData than the one that takes a buffer, it makes it possible to avoid - // allocating memory for the stream data. Example programs are provided that use both forms of - // replaceStreamData. - - // Note about stream length: for any given stream, the provider must provide the same amount of - // data each time it is called. This is critical for making linearization work properly. - // Versions of qpdf before 3.0.0 required a length to be specified here. Starting with - // version 3.0.0, this is no longer necessary (or permitted). The first time the stream data - // provider is invoked for a given stream, the actual length is stored. Subsequent times, it is - // enforced that the length be the same as the first time. - - // If you have gotten a compile error here while building code that worked with older versions - // of qpdf, just omit the length parameter. You can also simplify your code by not having to - // compute the length in advance. + /*! \brief As above, replace this stream's stream data. Instead of directly providing a buffer with the + * stream data, call the given provider's provideStreamData method. See comments on the + * StreamDataProvider class (defined above) for details on the method. The data must be + * consistent with filter and decode_parms as provided. Although it is more complex to use this + * form of replaceStreamData than the one that takes a buffer, it makes it possible to avoid + * allocating memory for the stream data. Example programs are provided that use both forms of + * replaceStreamData. + * + * Note about stream length: for any given stream, the provider must provide the same amount of + * data each time it is called. This is critical for making linearization work properly. + * Versions of qpdf before 3.0.0 required a length to be specified here. Starting with + * version 3.0.0, this is no longer necessary (or permitted). The first time the stream data + * provider is invoked for a given stream, the actual length is stored. Subsequent times, it is + * enforced that the length be the same as the first time. + * + * If you have gotten a compile error here while building code that worked with older versions + * of qpdf, just omit the length parameter. You can also simplify your code by not having to + * compute the length in advance. + */ QPDF_DLL void replaceStreamData( std::shared_ptr provider, QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms); - // Starting in qpdf 10.2, you can use C++-11 function objects instead of StreamDataProvider. - - // The provider should write the stream data to the pipeline. For a one-liner to replace stream - // data with the contents of a file, pass QUtil::file_provider(filename) as provider. + /*! \brief Starting in qpdf 10.2, you can use C++-11 function objects instead of StreamDataProvider. + * The provider should write the stream data to the pipeline. For a one-liner to replace stream + * data with the contents of a file, pass QUtil::file_provider(filename) as provider. + */ QPDF_DLL void replaceStreamData( std::function provider, QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms); - // The provider should write the stream data to the pipeline, returning true if it succeeded - // without errors. + + /*! \brief The provider should write the stream data to the pipeline, returning true if it succeeded + * without errors. + */ QPDF_DLL void replaceStreamData( std::function provider, QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms); - // Access object ID and generation. For direct objects, return object ID 0. - - // NOTE: Be careful about calling getObjectID() and getGeneration() directly as this can lead to - // the pattern of depending on object ID or generation without the other. In general, when - // keeping track of object IDs, it's better to use QPDFObjGen instead. + /*! \brief Access object ID and generation. For direct objects, return object ID 0. + * \note: Be careful about calling getObjectID() and getGeneration() directly as this can lead to + * the pattern of depending on object ID or generation without the other. In general, when + * keeping track of object IDs, it's better to use QPDFObjGen instead. + */ QPDF_DLL QPDFObjGen getObjGen() const; @@ -1153,73 +1241,77 @@ class QPDFObjectHandle: public qpdf::BaseHandle std::string unparse() const; QPDF_DLL std::string unparseResolved() const; - // For strings only, force binary representation. Otherwise, same as unparse. + + /*! \brief For strings only, force binary representation. Otherwise, same as unparse. */ QPDF_DLL std::string unparseBinary() const; - // Return encoded as JSON. The constant JSON::LATEST can be used to specify the latest available - // JSON version. The JSON is generated as follows: - // * Arrays, dictionaries, booleans, nulls, integers, and real numbers are represented by their - // native JSON types. - // * Names are encoded as strings representing the canonical representation (after parsing #xx) - // and preceded by a slash, just as unparse() returns. For example, the JSON for the - // PDF-syntax name /Text#2fPlain would be "/Text/Plain". - // * Indirect references are encoded as strings containing "obj gen R" - // * Strings - // * JSON v1: Strings are encoded as UTF-8 strings with unrepresentable binary characters - // encoded as \uHHHH. Characters in PDF Doc encoding that don't have bidirectional unicode - // mappings are not reversible. There is no way to tell the difference between a string that - // looks like a name or indirect object from an actual name or indirect object. - // * JSON v2: - // * Unicode strings and strings encoded with PDF Doc encoding that can be bidirectionally - // mapped to Unicode (which is all strings without undefined characters) are represented - // as "u:" followed by the UTF-8 encoded string. Example: - // "u:potato". - // * All other strings are represented as "b:" followed by a hexadecimal encoding of the - // string. Example: "b:0102cacb" - // * Streams - // * JSON v1: Only the stream's dictionary is encoded. There is no way to tell a stream from a - // dictionary other than context. - // * JSON v2: A stream is encoded as {"dict": {...}} with the value being the encoding of the - // stream's dictionary. Since "dict" does not otherwise represent anything, this is - // unambiguous. The getStreamJSON() call can be used to add encoding of the stream's data. - // * Object types that are only valid in content streams (inline image, operator) are serialized - // as "null". Attempting to serialize a "reserved" object is an error. - // If dereference_indirect is true and this is an indirect object, show the actual contents of - // the object. The effect of dereference_indirect applies only to this object. It is not - // recursive. + /*! \brief Return encoded as JSON. The constant JSON::LATEST can be used to specify the latest available + * JSON version. The JSON is generated as follows: + * * Arrays, dictionaries, booleans, nulls, integers, and real numbers are represented by their + * native JSON types. + * * Names are encoded as strings representing the canonical representation (after parsing #xx) + * and preceded by a slash, just as unparse() returns. For example, the JSON for the + * PDF-syntax name /Text#2fPlain would be "/Text/Plain". + * * Indirect references are encoded as strings containing "obj gen R" + * * Strings + * * JSON v1: Strings are encoded as UTF-8 strings with unrepresentable binary characters + * encoded as \uHHHH. Characters in PDF Doc encoding that don't have bidirectional unicode + * mappings are not reversible. There is no way to tell the difference between a string that + * looks like a name or indirect object from an actual name or indirect object. + * * JSON v2: + * * Unicode strings and strings encoded with PDF Doc encoding that can be bidirectionally + * mapped to Unicode (which is all strings without undefined characters) are represented + * as "u:" followed by the UTF-8 encoded string. Example: + * "u:potato". + * * All other strings are represented as "b:" followed by a hexadecimal encoding of the + * string. Example: "b:0102cacb" + * * Streams + * * JSON v1: Only the stream's dictionary is encoded. There is no way to tell a stream from a + * dictionary other than context. + * * JSON v2: A stream is encoded as {"dict": {...}} with the value being the encoding of the + * stream's dictionary. Since "dict" does not otherwise represent anything, this is + * unambiguous. The getStreamJSON() call can be used to add encoding of the stream's data. + * * Object types that are only valid in content streams (inline image, operator) are serialized + * as "null". Attempting to serialize a "reserved" object is an error. + * If dereference_indirect is true and this is an indirect object, show the actual contents of + * the object. The effect of dereference_indirect applies only to this object. It is not + * recursive. + */ QPDF_DLL JSON getJSON(int json_version, bool dereference_indirect = false) const; - // Write the object encoded as JSON to a pipeline. This is equivalent to, but more efficient - // than, calling getJSON(json_version, dereference_indirect).write(p, depth). See the - // documentation for getJSON and JSON::write for further detail. + /*! \brief Write the object encoded as JSON to a pipeline. This is equivalent to, but more efficient + * than, calling getJSON(json_version, dereference_indirect).write(p, depth). See the + * documentation for getJSON and JSON::write for further detail. + */ QPDF_DLL void writeJSON( int json_version, Pipeline* p, bool dereference_indirect = false, size_t depth = 0) const; - // This method can be called on a stream to get a more extended JSON representation of the - // stream that includes the stream's data. The JSON object returned is always a dictionary whose - // "dict" key is an encoding of the stream's dictionary. The representation of the data is - // determined by the json_data field. - // - // The json_data field may have the value qpdf_sj_none, qpdf_sj_inline, or qpdf_sj_file. - // - // If json_data is qpdf_sj_none, stream data is not represented. - // - // If json_data is qpdf_sj_inline or qpdf_sj_file, then stream data is filtered or not based on - // the value of decode_level, which has the same meaning as with pipeStreamData. - // - // If json_data is qpdf_sj_inline, the base64-encoded stream data is included in the "data" - // field of the dictionary that is returned. - // - // If json_data is qpdf_sj_file, then the Pipeline ("p") and data_filename argument must be - // supplied. The value of data_filename is stored in the resulting json in the "datafile" key - // but is not otherwise use. The stream data itself (raw or filtered depending on decode level), - // is written to the pipeline via pipeStreamData(). - // - // NOTE: When json_data is qpdf_sj_inline, the QPDF object from which the stream originates must - // remain valid until after the JSON object is written. + /*! \brief This method can be called on a stream to get a more extended JSON representation of the + * stream that includes the stream's data. The JSON object returned is always a dictionary whose + * "dict" key is an encoding of the stream's dictionary. The representation of the data is + * determined by the json_data field. + * + * The json_data field may have the value qpdf_sj_none, qpdf_sj_inline, or qpdf_sj_file. + * + * If json_data is qpdf_sj_none, stream data is not represented. + * + * If json_data is qpdf_sj_inline or qpdf_sj_file, then stream data is filtered or not based on + * the value of decode_level, which has the same meaning as with pipeStreamData. + * + * If json_data is qpdf_sj_inline, the base64-encoded stream data is included in the "data" + * field of the dictionary that is returned. + * + * If json_data is qpdf_sj_file, then the Pipeline ("p") and data_filename argument must be + * supplied. The value of data_filename is stored in the resulting json in the "datafile" key + * but is not otherwise use. The stream data itself (raw or filtered depending on decode level), + * is written to the pipeline via pipeStreamData(). + * + * \note : When json_data is qpdf_sj_inline, the QPDF object from which the stream originates must + * remain valid until after the JSON object is written. + */ QPDF_DLL JSON getStreamJSON( int json_version, @@ -1228,9 +1320,10 @@ class QPDFObjectHandle: public qpdf::BaseHandle Pipeline* p, std::string const& data_filename); - // Legacy helper methods for commonly performed operations on pages. Newer code should use - // QPDFPageObjectHelper instead. The specification and behavior of these methods are the same as - // the identically named methods in that class, but newer functionality will be added there. + /*! \brief Legacy helper methods for commonly performed operations on pages. Newer code should use + * QPDFPageObjectHelper instead. The specification and behavior of these methods are the same as + * the identically named methods in that class, but newer functionality will be added there. + */ QPDF_DLL std::map getPageImages(); QPDF_DLL @@ -1257,58 +1350,40 @@ class QPDFObjectHandle: public qpdf::BaseHandle QPDF_DLL void assertInitialized() const; - QPDF_DLL - void assertNull() const; - QPDF_DLL - void assertBool() const; - QPDF_DLL - void assertInteger() const; - QPDF_DLL - void assertReal() const; - QPDF_DLL - void assertName() const; - QPDF_DLL - void assertString() const; - QPDF_DLL - void assertOperator() const; - QPDF_DLL - void assertInlineImage() const; - QPDF_DLL - void assertArray() const; - QPDF_DLL - void assertDictionary() const; - QPDF_DLL - void assertStream() const; - QPDF_DLL - void assertReserved() const; - - QPDF_DLL - void assertIndirect() const; - QPDF_DLL - void assertScalar() const; - QPDF_DLL - void assertNumber() const; - - // The isPageObject method checks the /Type key of the object. This is not completely reliable - // as there are some otherwise valid files whose /Type is wrong for page objects. qpdf is - // slightly more accepting but may still return false here when treating the object as a page - // would work. Use this sparingly. - QPDF_DLL - bool isPageObject() const; - QPDF_DLL - bool isPagesObject() const; - QPDF_DLL - void assertPageObject() const; - - QPDF_DLL - bool isFormXObject() const; - - // Indicate if this is an image. If exclude_imagemask is true, don't count image masks as - // images. - QPDF_DLL - bool isImage(bool exclude_imagemask = true) const; - - // The following methods do not form part of the public API and are for internal use only. + QPDF_DLL void assertNull() const; + QPDF_DLL void assertBool() const; + QPDF_DLL void assertInteger() const; + QPDF_DLL void assertReal() const; + QPDF_DLL void assertName() const; + QPDF_DLL void assertString() const; + QPDF_DLL void assertOperator() const; + QPDF_DLL void assertInlineImage() const; + QPDF_DLL void assertArray() const; + QPDF_DLL void assertDictionary() const; + QPDF_DLL void assertStream() const; + QPDF_DLL void assertReserved() const; + + QPDF_DLL void assertIndirect() const; + QPDF_DLL void assertScalar() const; + QPDF_DLL void assertNumber() const; + + /*! \brief The isPageObject method checks the /Type key of the object. This is not completely reliable + * as there are some otherwise valid files whose /Type is wrong for page objects. qpdf is + * slightly more accepting but may still return false here when treating the object as a page + * would work. Use this sparingly. + */ + QPDF_DLL bool isPageObject() const; + QPDF_DLL bool isPagesObject() const; + QPDF_DLL void assertPageObject() const; + + QPDF_DLL bool isFormXObject() const; + + /*! \brief Indicate if this is an image. If exclude_imagemask is true, don't count image masks as + * images. + */ + QPDF_DLL bool isImage(bool exclude_imagemask = true) const; + + /*! \brief The following methods do not form part of the public API and are for internal use only. */ QPDFObjectHandle(std::shared_ptr const& obj) : qpdf::BaseHandle(obj) @@ -1348,17 +1423,18 @@ class QPDFObjectHandle: public qpdf::BaseHandle }; #ifndef QPDF_NO_QPDF_STRING -// This is short for QPDFObjectHandle::parse, so you can do - -// auto oh = "<< /Key (value) >>"_qpdf; - -// If this is causing problems in your code, define QPDF_NO_QPDF_STRING to prevent the declaration -// from being here. - -/* clang-format off */ - // Disable formatting for this declaration: emacs font-lock in cc-mode (as of 28.1) treats the rest - // of the file as a string if clang-format removes the space after "operator", and as of - // clang-format 15, there's no way to prevent it from doing so. +/*! \brief This is short for QPDFObjectHandle::parse, so you can do + * + * auto oh = "<< /Key (value) >>"_qpdf; + * + * If this is causing problems in your code, define QPDF_NO_QPDF_STRING to prevent the declaration + * from being here. + * + * clang-format off + * Disable formatting for this declaration: emacs font-lock in cc-mode (as of 28.1) treats the rest + * of the file as a string if clang-format removes the space after "operator", and as of + * clang-format 15, there's no way to prevent it from doing so. + */ QPDF_DLL QPDFObjectHandle operator ""_qpdf(char const* v, size_t len); /* clang-format on */ @@ -1367,16 +1443,17 @@ class QPDFObjectHandle: public qpdf::BaseHandle class QPDFObjectHandle::QPDFDictItems { - // This class allows C++-style iteration, including range-for iteration, around dictionaries. - // You can write - - // for (auto iter: QPDFDictItems(dictionary_obj)) - // { - // // iter.first is a string - // // iter.second is a QPDFObjectHandle - // } - - // See examples/pdf-name-number-tree.cc for a demonstration of using this API. + /*! \brief This class allows C++-style iteration, including range-for iteration, around dictionaries. + * You can write + * + * for (auto iter: QPDFDictItems(dictionary_obj)) + * { + * // iter.first is a string + * // iter.second is a QPDFObjectHandle + * } + * + * See examples/pdf-name-number-tree.cc for a demonstration of using this API. + */ public: QPDF_DLL @@ -1459,17 +1536,20 @@ class QPDFObjectHandle::QPDFDictItems QPDFObjectHandle oh; }; +/*! + * \class QPDFArrayItems + * \brief This class allows C++-style iteration, including range-for iteration, around arrays. You can + * write + * + * for (auto iter: QPDFArrayItems(array_obj)) + * { + * // iter is a QPDFObjectHandle + * } + * + * See examples/pdf-name-number-tree.cc for a demonstration of using this API. + */ class QPDFObjectHandle::QPDFArrayItems { - // This class allows C++-style iteration, including range-for iteration, around arrays. You can - // write - - // for (auto iter: QPDFArrayItems(array_obj)) - // { - // // iter is a QPDFObjectHandle - // } - - // See examples/pdf-name-number-tree.cc for a demonstration of using this API. public: QPDF_DLL diff --git a/include/qpdf/QPDFObjectHelper.hh b/include/qpdf/QPDFObjectHelper.hh index d19ba3b..11bc679 100644 --- a/include/qpdf/QPDFObjectHelper.hh +++ b/include/qpdf/QPDFObjectHelper.hh @@ -24,13 +24,14 @@ #include -// This is a base class for QPDF Object Helper classes. Object helpers are classes that provide a -// convenient, higher-level API for working with specific types of QPDF objects. Object helpers are -// always initialized with a QPDFObjectHandle, and the underlying object handle can always be -// retrieved. The intention is that you may freely intermix use of object helpers with the -// underlying QPDF objects unless there is a specific comment in a specific helper method that says -// otherwise. The pattern of using helper objects was introduced to allow creation of higher level -// helper functions without polluting the public interface of QPDFObjectHandle. +/*! \brief This is a base class for QPDF Object Helper classes. Object helpers are classes that provide a + * convenient, higher-level API for working with specific types of QPDF objects. Object helpers are + * always initialized with a QPDFObjectHandle, and the underlying object handle can always be + * retrieved. The intention is that you may freely intermix use of object helpers with the + * underlying QPDF objects unless there is a specific comment in a specific helper method that says + * otherwise. The pattern of using helper objects was introduced to allow creation of higher level + * helper functions without polluting the public interface of QPDFObjectHandle. + */ class QPDF_DLL_CLASS QPDFObjectHelper: public qpdf::BaseHandle { public: diff --git a/include/qpdf/QPDFWriter.hh b/include/qpdf/QPDFWriter.hh index 3c3c0b9..0512029 100644 --- a/include/qpdf/QPDFWriter.hh +++ b/include/qpdf/QPDFWriter.hh @@ -50,25 +50,29 @@ namespace qpdf class QPDF; -// This class implements a simple writer for saving QPDF objects to new PDF files. See comments -// through the header file for additional details. +/*! \brief This class implements a simple writer for saving QPDF objects to new PDF files. See comments + * through the header file for additional details. + */ class QPDFWriter { public: - // Construct a QPDFWriter object without specifying output. You must call one of the output - // setting routines defined below. + /*! \brief Construct a QPDFWriter object without specifying output. You must call one of the output + * setting routines defined below. + */ QPDF_DLL QPDFWriter(QPDF& pdf); - // Create a QPDFWriter object that writes its output to a file or to stdout. This is equivalent - // to using the previous constructor and then calling setOutputFilename(). See - // setOutputFilename() for details. + /*! \brief Create a QPDFWriter object that writes its output to a file or to stdout. This is equivalent + * to using the previous constructor and then calling setOutputFilename(). See + * setOutputFilename() for details. + */ QPDF_DLL QPDFWriter(QPDF& pdf, char const* filename); - // Create a QPDFWriter object that writes its output to an already open FILE*. This is - // equivalent to calling the first constructor and then calling setOutputFile(). See - // setOutputFile() for details. + /*! \brief Create a QPDFWriter object that writes its output to an already open FILE*. This is + * equivalent to calling the first constructor and then calling setOutputFile(). See + * setOutputFile() for details. + */ QPDF_DLL QPDFWriter(QPDF& pdf, char const* description, FILE* file, bool close_file); @@ -80,13 +84,15 @@ class QPDFWriter QPDF_DLL virtual ~ProgressReporter(); - // This method is called with a value from 0 to 100 to indicate approximate progress through - // the write process. See registerProgressReporter. + /*! \brief This method is called with a value from 0 to 100 to indicate approximate progress through + * the write process. See registerProgressReporter. + */ virtual void reportProgress(int) = 0; }; - // This is a progress reporter that takes a function. It is used by the C APIs, but it is - // available if you want to just register a C function as a handler. + /*! \brief This is a progress reporter that takes a function. It is used by the C APIs, but it is + * available if you want to just register a C function as a handler. + */ class QPDF_DLL_CLASS FunctionProgressReporter: public ProgressReporter { public: @@ -101,230 +107,253 @@ class QPDFWriter std::function handler; }; - // Setting Output. Output may be set only one time. If you don't use the filename version of - // the QPDFWriter constructor, you must call exactly one of these methods. - - // Passing nullptr as filename means write to stdout. QPDFWriter will create a zero-length - // output file upon construction. If write fails, the empty or partially written file will not - // be deleted. This is by design: sometimes the partial file may be useful for tracking down - // problems. If your application doesn't want the partially written file to be left behind, you - // should delete it if the eventual call to write fails. + /*! \brief Setting Output. Output may be set only one time. If you don't use the filename version of + * the QPDFWriter constructor, you must call exactly one of these methods. + * + * Passing nullptr as filename means write to stdout. QPDFWriter will create a zero-length + * output file upon construction. If write fails, the empty or partially written file will not + * be deleted. This is by design: sometimes the partial file may be useful for tracking down + * problems. If your application doesn't want the partially written file to be left behind, you + * should delete it if the eventual call to write fails. + */ QPDF_DLL void setOutputFilename(char const* filename); - // Write to the given FILE*, which must be opened by the caller. If close_file is true, - // QPDFWriter will close the file. Otherwise, the caller must close the file. The file does not - // need to be seekable; it will be written to in a single pass. It must be open in binary mode. + /*! \brief Write to the given FILE*, which must be opened by the caller. If close_file is true, + * QPDFWriter will close the file. Otherwise, the caller must close the file. The file does not + * need to be seekable; it will be written to in a single pass. It must be open in binary mode. + */ QPDF_DLL void setOutputFile(char const* description, FILE* file, bool close_file); - // Indicate that QPDFWriter should create a memory buffer to contain the final PDF file. Obtain - // the memory by calling getBuffer(). + /*! \brief Indicate that QPDFWriter should create a memory buffer to contain the final PDF file. Obtain + * the memory by calling getBuffer(). + */ QPDF_DLL void setOutputMemory(); - // Return the buffer object containing the PDF file. If setOutputMemory() has been called, this - // method may be called exactly one time after write() has returned. The caller is responsible - // for deleting the buffer when done. See also getBufferSharedPointer(). + /*! \brief Return the buffer object containing the PDF file. If setOutputMemory() has been called, this + * method may be called exactly one time after write() has returned. The caller is responsible + * for deleting the buffer when done. See also getBufferSharedPointer(). + */ QPDF_DLL Buffer* getBuffer(); - // Return getBuffer() in a shared pointer. + /*! \brief Return getBuffer() in a shared pointer. */ QPDF_DLL std::shared_ptr getBufferSharedPointer(); - // Supply your own pipeline object. Output will be written to this pipeline, and QPDFWriter - // will call finish() on the pipeline. It is the caller's responsibility to manage the memory - // for the pipeline. The pipeline is never deleted by QPDFWriter, which makes it possible for - // you to call additional methods on the pipeline after the writing is finished. + /*! \brief Supply your own pipeline object. Output will be written to this pipeline, and QPDFWriter + * will call finish() on the pipeline. It is the caller's responsibility to manage the memory + * for the pipeline. The pipeline is never deleted by QPDFWriter, which makes it possible for + * you to call additional methods on the pipeline after the writing is finished. + */ QPDF_DLL void setOutputPipeline(Pipeline*); // Setting Parameters - // Set the value of object stream mode. In disable mode, we never generate any object streams. - // In preserve mode, we preserve object stream structure from the original file. In generate - // mode, we generate our own object streams. In all cases, we generate a conventional - // cross-reference table if there are no object streams and a cross-reference stream if there - // are object streams. The default is o_preserve. + /*! \brief Set the value of object stream mode. In disable mode, we never generate any object streams. + * In preserve mode, we preserve object stream structure from the original file. In generate + * mode, we generate our own object streams. In all cases, we generate a conventional + * cross-reference table if there are no object streams and a cross-reference stream if there + * are object streams. The default is o_preserve. + */ QPDF_DLL void setObjectStreamMode(qpdf_object_stream_e); - // Set value of stream data mode. This is an older interface. Instead of using this, prefer - // setCompressStreams() and setDecodeLevel(). This method is retained for compatibility, but it - // does not cover the full range of available configurations. The mapping between this and the - // new methods is as follows: - // - // qpdf_s_uncompress: - // setCompressStreams(false) - // setDecodeLevel(qpdf_dl_generalized) - // qpdf_s_preserve: - // setCompressStreams(false) - // setDecodeLevel(qpdf_dl_none) - // qpdf_s_compress: - // setCompressStreams(true) - // setDecodeLevel(qpdf_dl_generalized) - // - // The default is qpdf_s_compress. + /*! \brief Set value of stream data mode. This is an older interface. Instead of using this, prefer + * setCompressStreams() and setDecodeLevel(). This method is retained for compatibility, but it + * does not cover the full range of available configurations. The mapping between this and the + * new methods is as follows: + * + * qpdf_s_uncompress: + * setCompressStreams(false) + * setDecodeLevel(qpdf_dl_generalized) + * qpdf_s_preserve: + * setCompressStreams(false) + * setDecodeLevel(qpdf_dl_none) + * qpdf_s_compress: + * setCompressStreams(true) + * setDecodeLevel(qpdf_dl_generalized) + * + * The default is qpdf_s_compress. + */ QPDF_DLL void setStreamDataMode(qpdf_stream_data_e); - // If true, compress any uncompressed streams when writing them. Metadata streams are a special - // case and are not compressed even if this is true. This is true by default for QPDFWriter. If - // you want QPDFWriter to leave uncompressed streams uncompressed, pass false to this method. + /*! \brief If true, compress any uncompressed streams when writing them. Metadata streams are a special + * case and are not compressed even if this is true. This is true by default for QPDFWriter. If + * you want QPDFWriter to leave uncompressed streams uncompressed, pass false to this method. + */ QPDF_DLL void setCompressStreams(bool); - // When QPDFWriter encounters streams, this parameter controls the behavior with respect to - // attempting to apply any filters to the streams when copying to the output. The decode levels - // are as follows: - // - // qpdf_dl_none: Do not attempt to apply any filters. Streams remain as they appear in the - // original file. Note that uncompressed streams may still be compressed on output. You can - // disable that by calling setCompressStreams(false). - // - // qpdf_dl_generalized: This is the default. QPDFWriter will apply LZWDecode, ASCII85Decode, - // ASCIIHexDecode, and FlateDecode filters on the input. When combined with - // setCompressStreams(true), which is the default, the effect of this is that streams filtered - // with these older and less efficient filters will be recompressed with the Flate filter. By - // default, as a special case, if a stream is already compressed with FlateDecode and - // setCompressStreams is enabled, the original compressed data will be preserved. This behavior - // can be overridden by calling setRecompressFlate(true). - // - // qpdf_dl_specialized: In addition to uncompressing the generalized compression formats, - // supported non-lossy compression will also be decoded. At present, this includes the - // RunLengthDecode filter. - // - // qpdf_dl_all: In addition to generalized and non-lossy specialized filters, supported lossy - // compression filters will be applied. At present, this includes DCTDecode (JPEG) compression. - // Note that compressing the resulting data with DCTDecode again will accumulate loss, so avoid - // multiple compression and decompression cycles. This is mostly useful for retrieving image - // data. + /*! \brief When QPDFWriter encounters streams, this parameter controls the behavior with respect to + * attempting to apply any filters to the streams when copying to the output. The decode levels + * are as follows: + * + * qpdf_dl_none: Do not attempt to apply any filters. Streams remain as they appear in the + * original file. Note that uncompressed streams may still be compressed on output. You can + * disable that by calling setCompressStreams(false). + * + * qpdf_dl_generalized: This is the default. QPDFWriter will apply LZWDecode, ASCII85Decode, + * ASCIIHexDecode, and FlateDecode filters on the input. When combined with + * setCompressStreams(true), which is the default, the effect of this is that streams filtered + * with these older and less efficient filters will be recompressed with the Flate filter. By + * default, as a special case, if a stream is already compressed with FlateDecode and + * setCompressStreams is enabled, the original compressed data will be preserved. This behavior + * can be overridden by calling setRecompressFlate(true). + * + * qpdf_dl_specialized: In addition to uncompressing the generalized compression formats, + * supported non-lossy compression will also be decoded. At present, this includes the + * RunLengthDecode filter. + * + * qpdf_dl_all: In addition to generalized and non-lossy specialized filters, supported lossy + * compression filters will be applied. At present, this includes DCTDecode (JPEG) compression. + * Note that compressing the resulting data with DCTDecode again will accumulate loss, so avoid + * multiple compression and decompression cycles. This is mostly useful for retrieving image + * data. + */ QPDF_DLL void setDecodeLevel(qpdf_stream_decode_level_e); - // By default, when both the input and output contents of a stream are compressed with Flate, - // qpdf does not uncompress and recompress the stream. Passing true here causes it to do so. - // This can be useful if recompressing all streams with a higher compression level, which can be - // set by calling the static method Pl_Flate::setCompressionLevel. + /*! \brief By default, when both the input and output contents of a stream are compressed with Flate, + * qpdf does not uncompress and recompress the stream. Passing true here causes it to do so. + * This can be useful if recompressing all streams with a higher compression level, which can be + * set by calling the static method Pl_Flate::setCompressionLevel. + */ QPDF_DLL void setRecompressFlate(bool); - // Set value of content stream normalization. The default is "false". If true, we attempt to - // normalize newlines inside of content streams. Some constructs such as inline images may - // thwart our efforts. There may be some cases where this can damage the content stream. This - // flag should be used only for debugging and experimenting with PDF content streams. Never use - // it for production files. + /*! \brief Set value of content stream normalization. The default is "false". If true, we attempt to + * normalize newlines inside of content streams. Some constructs such as inline images may + * thwart our efforts. There may be some cases where this can damage the content stream. This + * flag should be used only for debugging and experimenting with PDF content streams. Never use + * it for production files. + */ QPDF_DLL void setContentNormalization(bool); - // Set QDF mode. QDF mode causes special "pretty printing" of PDF objects, adds comments for - // easier perusing of files. Resulting PDF files can be edited in a text editor and then run - // through fix-qdf to update cross reference tables and stream lengths. + /*! \brief Set QDF mode. QDF mode causes special "pretty printing" of PDF objects, adds comments for + * easier perusing of files. Resulting PDF files can be edited in a text editor and then run + * through fix-qdf to update cross reference tables and stream lengths. + */ QPDF_DLL void setQDFMode(bool); - // Preserve unreferenced objects. The default behavior is to discard any object that is not - // visited during a traversal of the object structure from the trailer. + /*! \brief Preserve unreferenced objects. The default behavior is to discard any object that is not + * visited during a traversal of the object structure from the trailer. QPDF_DLL void setPreserveUnreferencedObjects(bool); - // Always write a newline before the endstream keyword. This helps with PDF/A compliance, though - // it is not sufficient for it. + /*! \brief Always write a newline before the endstream keyword. This helps with PDF/A compliance, though + * it is not sufficient for it. + */ QPDF_DLL void setNewlineBeforeEndstream(bool); - // Set the minimum PDF version. If the PDF version of the input file (or previously set minimum - // version) is less than the version passed to this method, the PDF version of the output file - // will be set to this value. If the original PDF file's version or previously set minimum - // version is already this version or later, the original file's version will be used. - // QPDFWriter automatically sets the minimum version to 1.4 when R3 encryption parameters are - // used, and to 1.5 when object streams are used. + /*! \brief Set the minimum PDF version. If the PDF version of the input file (or previously set minimum + * version) is less than the version passed to this method, the PDF version of the output file + * will be set to this value. If the original PDF file's version or previously set minimum + * version is already this version or later, the original file's version will be used. + * QPDFWriter automatically sets the minimum version to 1.4 when R3 encryption parameters are + * used, and to 1.5 when object streams are used. + */ QPDF_DLL void setMinimumPDFVersion(std::string const&, int extension_level = 0); QPDF_DLL void setMinimumPDFVersion(PDFVersion const&); - // Force the PDF version of the output file to be a given version. Use of this function may - // create PDF files that will not work properly with older PDF viewers. When a PDF version is - // set using this function, qpdf will use this version even if the file contains features that - // are not supported in that version of PDF. In other words, you should only use this function - // if you are sure the PDF file in question has no features of newer versions of PDF or if you - // are willing to create files that old viewers may try to open but not be able to properly - // interpret. If any encryption has been applied to the document either explicitly or by - // preserving the encryption of the source document, forcing the PDF version to a value too low - // to support that type of encryption will explicitly disable decryption. Additionally, forcing - // to a version below 1.5 will disable object streams. + /*! \brief Force the PDF version of the output file to be a given version. Use of this function may + * create PDF files that will not work properly with older PDF viewers. When a PDF version is + * set using this function, qpdf will use this version even if the file contains features that + * are not supported in that version of PDF. In other words, you should only use this function + * if you are sure the PDF file in question has no features of newer versions of PDF or if you + * are willing to create files that old viewers may try to open but not be able to properly + * interpret. If any encryption has been applied to the document either explicitly or by + * preserving the encryption of the source document, forcing the PDF version to a value too low + * to support that type of encryption will explicitly disable decryption. Additionally, forcing + * to a version below 1.5 will disable object streams. + */ QPDF_DLL void forcePDFVersion(std::string const&, int extension_level = 0); - // Provide additional text to insert in the PDF file somewhere near the beginning of the file. - // This can be used to add comments to the beginning of a PDF file, for example, if those - // comments are to be consumed by some other application. No checks are performed to ensure - // that the text inserted here is valid PDF. If you want to insert multiline comments, you will - // need to include \n in the string yourself and start each line with %. An extra newline will - // be appended if one is not already present at the end of your text. + /*! \brief Provide additional text to insert in the PDF file somewhere near the beginning of the file. + * This can be used to add comments to the beginning of a PDF file, for example, if those + * comments are to be consumed by some other application. No checks are performed to ensure + * that the text inserted here is valid PDF. If you want to insert multiline comments, you will + * need to include \n in the string yourself and start each line with %. An extra newline will + * be appended if one is not already present at the end of your text. + */ QPDF_DLL void setExtraHeaderText(std::string const&); - // Causes a deterministic /ID value to be generated. When this is set, the current time and - // output file name are not used as part of /ID generation. Instead, a digest of all significant - // parts of the output file's contents is included in the /ID calculation. Use of a - // deterministic /ID can be handy when it is desirable for a repeat of the same qpdf operation - // on the same inputs being written to the same outputs with the same parameters to generate - // exactly the same results. This feature is incompatible with encrypted files because, for - // encrypted files, the /ID is generated before any part of the file is written since it is an - // input to the encryption process. + /*! \brief Causes a deterministic /ID value to be generated. When this is set, the current time and + * output file name are not used as part of /ID generation. Instead, a digest of all significant + * parts of the output file's contents is included in the /ID calculation. Use of a + * deterministic /ID can be handy when it is desirable for a repeat of the same qpdf operation + * on the same inputs being written to the same outputs with the same parameters to generate + * exactly the same results. This feature is incompatible with encrypted files because, for + * encrypted files, the /ID is generated before any part of the file is written since it is an + * input to the encryption process. + */ QPDF_DLL void setDeterministicID(bool); - // Cause a static /ID value to be generated. Use only in test suites. See also - // setDeterministicID. + /*! \brief Cause a static /ID value to be generated. Use only in test suites. See also + * setDeterministicID. + */ QPDF_DLL void setStaticID(bool); - // Use a fixed initialization vector for AES-CBC encryption. This is not secure. It should be - // used only in test suites for creating predictable encrypted output. + /*! \brief Use a fixed initialization vector for AES-CBC encryption. This is not secure. It should be + * used only in test suites for creating predictable encrypted output. + */ QPDF_DLL void setStaticAesIV(bool); - // Suppress inclusion of comments indicating original object IDs when writing QDF files. This - // can also be useful for testing, particularly when using comparison of two qdf files to - // determine whether two PDF files have identical content. + /*! \brief Suppress inclusion of comments indicating original object IDs when writing QDF files. This + * can also be useful for testing, particularly when using comparison of two qdf files to + * determine whether two PDF files have identical content. + */ QPDF_DLL void setSuppressOriginalObjectIDs(bool); - // Preserve encryption. The default is true unless prefiltering, content normalization, or qdf - // mode has been selected in which case encryption is never preserved. Encryption is also not - // preserved if we explicitly set encryption parameters. + /*! \brief Preserve encryption. The default is true unless prefiltering, content normalization, or qdf + * mode has been selected in which case encryption is never preserved. Encryption is also not + * preserved if we explicitly set encryption parameters. + */ QPDF_DLL void setPreserveEncryption(bool); - // Copy encryption parameters from another QPDF object. If you want to copy encryption from the - // object you are writing, call setPreserveEncryption(true) instead. + /*! \brief Copy encryption parameters from another QPDF object. If you want to copy encryption from the + * object you are writing, call setPreserveEncryption(true) instead. + */ QPDF_DLL void copyEncryptionParameters(QPDF&); - // Set up for encrypted output. User and owner password both must be specified. Either or both - // may be the empty string. Note that qpdf does not apply any special treatment to the empty - // string, which makes it possible to create encrypted files with empty owner passwords and - // non-empty user passwords or with the same password for both user and owner. Some PDF reading - // products don't handle such files very well. Enabling encryption disables stream prefiltering - // and content normalization. Note that setting R2 encryption parameters sets the PDF version - // to at least 1.3, setting R3 encryption parameters pushes the PDF version number to at - // least 1.4, setting R4 parameters pushes the version to at least 1.5, or if AES is used, 1.6, - // and setting R5 or R6 parameters pushes the version to at least 1.7 with extension level 3. - // - // Note about Unicode passwords: the PDF specification requires passwords to be encoded with PDF - // Doc encoding for R <= 4 and UTF-8 for R >= 5. In all cases, these methods take strings of - // bytes as passwords. It is up to the caller to ensure that passwords are properly encoded. The - // qpdf command-line tool tries to do this, as discussed in the manual. If you are doing this - // from your own application, QUtil contains many transcoding functions that could be useful to - // you, most notably utf8_to_pdf_doc. - - // R2 uses RC4, which is a weak cryptographic algorithm. Don't use it unless you have to. See - // "Weak Cryptography" in the manual. This encryption format is deprecated in the PDF 2.0 - // specification. + /*! \brief Set up for encrypted output. User and owner password both must be specified. Either or both + * may be the empty string. Note that qpdf does not apply any special treatment to the empty + * string, which makes it possible to create encrypted files with empty owner passwords and + * non-empty user passwords or with the same password for both user and owner. Some PDF reading + * products don't handle such files very well. Enabling encryption disables stream prefiltering + * and content normalization. Note that setting R2 encryption parameters sets the PDF version + * to at least 1.3, setting R3 encryption parameters pushes the PDF version number to at + * least 1.4, setting R4 parameters pushes the version to at least 1.5, or if AES is used, 1.6, + * and setting R5 or R6 parameters pushes the version to at least 1.7 with extension level 3. + * + * Note about Unicode passwords: the PDF specification requires passwords to be encoded with PDF + * Doc encoding for R <= 4 and UTF-8 for R >= 5. In all cases, these methods take strings of + * bytes as passwords. It is up to the caller to ensure that passwords are properly encoded. The + * qpdf command-line tool tries to do this, as discussed in the manual. If you are doing this + * from your own application, QUtil contains many transcoding functions that could be useful to + * you, most notably utf8_to_pdf_doc. + * + * R2 uses RC4, which is a weak cryptographic algorithm. Don't use it unless you have to. See + * "Weak Cryptography" in the manual. This encryption format is deprecated in the PDF 2.0 + * specification. + */ QPDF_DLL void setR2EncryptionParametersInsecure( char const* user_password, @@ -333,9 +362,11 @@ class QPDFWriter bool allow_modify, bool allow_extract, bool allow_annotate); - // R3 uses RC4, which is a weak cryptographic algorithm. Don't use it unless you have to. See - // "Weak Cryptography" in the manual. This encryption format is deprecated in the PDF 2.0 - // specification. + + /*! \brief R3 uses RC4, which is a weak cryptographic algorithm. Don't use it unless you have to. See + * "Weak Cryptography" in the manual. This encryption format is deprecated in the PDF 2.0 + * specification. + */ QPDF_DLL void setR3EncryptionParametersInsecure( char const* user_password, @@ -347,10 +378,12 @@ class QPDFWriter bool allow_form_filling, bool allow_modify_other, qpdf_r3_print_e print); - // When use_aes=false, this call enables R4 with RC4, which is a weak cryptographic algorithm. - // Even with use_aes=true, the overall encryption scheme is weak. Don't use it unless you have - // to. See "Weak Cryptography" in the manual. This encryption format is deprecated in the - // PDF 2.0 specification. + + /*! \brief When use_aes=false, this call enables R4 with RC4, which is a weak cryptographic algorithm. + * Even with use_aes=true, the overall encryption scheme is weak. Don't use it unless you have + * to. See "Weak Cryptography" in the manual. This encryption format is deprecated in the + * PDF 2.0 specification. + */ QPDF_DLL void setR4EncryptionParametersInsecure( char const* user_password, @@ -364,8 +397,10 @@ class QPDFWriter qpdf_r3_print_e print, bool encrypt_metadata, bool use_aes); - // R5 is deprecated. Do not use it for production use. Writing R5 is supported by qpdf - // primarily to generate test files for applications that may need to test R5 support. + + /*! \brief R5 is deprecated. Do not use it for production use. Writing R5 is supported by qpdf + * primarily to generate test files for applications that may need to test R5 support. + */ QPDF_DLL void setR5EncryptionParameters( char const* user_password, @@ -378,7 +413,8 @@ class QPDFWriter bool allow_modify_other, qpdf_r3_print_e print, bool encrypt_metadata); - // This is the only password-based encryption format supported by the PDF specification. + + /*! \brief This is the only password-based encryption format supported by the PDF specification. */ QPDF_DLL void setR6EncryptionParameters( char const* user_password, @@ -392,53 +428,59 @@ class QPDFWriter qpdf_r3_print_e print, bool encrypt_metadata_aes); - // Create linearized output. Disables qdf mode, content normalization, and stream prefiltering. + /*! \brief Create linearized output. Disables qdf mode, content normalization, and stream prefiltering. */ QPDF_DLL void setLinearization(bool); - // For debugging QPDF: provide the name of a file to write pass1 of linearization to. The only - // reason to use this is to debug QPDF. To linearize, QPDF writes out the file in two passes. - // Usually the first pass is discarded, but lots of computations are made in pass 1. If a - // linearized file comes out wrong, it can be helpful to look at the first pass. + /*! \brief For debugging QPDF: provide the name of a file to write pass1 of linearization to. The only + * reason to use this is to debug QPDF. To linearize, QPDF writes out the file in two passes. + * Usually the first pass is discarded, but lots of computations are made in pass 1. If a + * linearized file comes out wrong, it can be helpful to look at the first pass. + */ QPDF_DLL void setLinearizationPass1Filename(std::string const&); - // Create PCLm output. This is only useful for clients that know how to create PCLm files. If a - // file is structured exactly as PCLm requires, this call will tell QPDFWriter to write the PCLm - // header, create certain unreferenced streams required by the standard, and write the objects - // in the required order. Calling this on an ordinary PDF serves no purpose. There is no - // command-line argument that causes this method to be called. + /*! \brief Create PCLm output. This is only useful for clients that know how to create PCLm files. If a + * file is structured exactly as PCLm requires, this call will tell QPDFWriter to write the PCLm + * header, create certain unreferenced streams required by the standard, and write the objects + * in the required order. Calling this on an ordinary PDF serves no purpose. There is no + * command-line argument that causes this method to be called. + */ QPDF_DLL void setPCLm(bool); - // If you want to be notified of progress, derive a class from ProgressReporter and override the - // reportProgress method. + /*! \brief If you want to be notified of progress, derive a class from ProgressReporter and override the + * reportProgress method. + */ QPDF_DLL void registerProgressReporter(std::shared_ptr); - // Return the PDF version that will be written into the header. Calling this method does all the - // preparation for writing, so it is an error to call any methods that may cause a change to the - // version. Adding new objects to the original file after calling this may also cause problems. - // It is safe to update existing objects or stream contents after calling this method, e.g., to - // include the final version number in metadata. + /*! \brief Return the PDF version that will be written into the header. Calling this method does all the + * preparation for writing, so it is an error to call any methods that may cause a change to the + * version. Adding new objects to the original file after calling this may also cause problems. + * It is safe to update existing objects or stream contents after calling this method, e.g., to + * include the final version number in metadata. + */ QPDF_DLL std::string getFinalVersion(); - // Write the final file. There is no expectation of being able to call write() more than once. + /*! \brief Write the final file. There is no expectation of being able to call write() more than once. */ QPDF_DLL void write(); - // Return renumbered ObjGen that was written into the final file. This method can be used after - // calling write(). + /*! \brief Return renumbered ObjGen that was written into the final file. This method can be used after + * calling write(). + */ QPDF_DLL QPDFObjGen getRenumberedObjGen(QPDFObjGen); - // Return XRef entry that was written into the final file. This method can be used after calling - // write(). + /*! \brief Return XRef entry that was written into the final file. This method can be used after calling + * write(). + */ QPDF_DLL std::map getWrittenXRefTable(); - // The following structs / classes are not part of the public API. + /*! \brief The following structs / classes are not part of the public API. */ struct Object; struct NewObject; class ObjTable;