qpdf/include/qpdf/QPDFWriter.hh

353 lines
14 KiB
C++
Raw Normal View History

// Copyright (c) 2005-2011 Jay Berkenbilt
//
// This file is part of qpdf. This software may be distributed under
// the terms of version 2 of the Artistic License which may be found
// in the source distribution. It is provided "as is" without express
// or implied warranty.
// This class implements a simple writer for saving QPDF objects to
// new PDF files. See comments through the header file for additional
// details.
#ifndef __QPDFWRITER_HH__
#define __QPDFWRITER_HH__
2012-06-21 17:47:41 +00:00
#include <qpdf/DLL.h>
#include <qpdf/Types.h>
#include <stdio.h>
#include <string>
#include <list>
#include <vector>
#include <set>
#include <map>
#include <qpdf/Constants.h>
#include <qpdf/QPDFXRefEntry.hh>
#include <qpdf/Pl_Buffer.hh>
#include <qpdf/PointerHolder.hh>
#include <qpdf/Pipeline.hh>
#include <qpdf/Buffer.hh>
class QPDF;
class QPDFObjectHandle;
class Pl_Count;
class QPDFWriter
{
public:
// 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.
QPDF_DLL
QPDFWriter(QPDF& pdf, char const* filename);
QPDF_DLL
~QPDFWriter();
// 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 null 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 the eventual call to write fails.
2011-08-11 19:55:06 +00:00
QPDF_DLL
void setOutputFilename(char const* filename);
// Indicate that QPDFWriter should create a memory buffer to
// contain the final PDF file. Obtain the memory by calling
// getBuffer().
2011-08-11 19:55:06 +00:00
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.
2011-08-11 19:55:06 +00:00
QPDF_DLL
Buffer* getBuffer();
// 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.
QPDF_DLL
void setObjectStreamMode(qpdf_object_stream_e);
// Set value of stream data mode. In uncompress mode, we attempt
// to uncompress any stream that we can. In preserve mode, we
// preserve any filtering applied to streams. In compress mode,
// if we can apply all filters and the stream is not already
// optimally compressed, recompress the stream.
QPDF_DLL
void setStreamDataMode(qpdf_stream_data_e);
// 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.
QPDF_DLL
void setQDFMode(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.
QPDF_DLL
void setMinimumPDFVersion(std::string 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.
QPDF_DLL
void forcePDFVersion(std::string const&);
// Cause a static /ID value to be generated. Use only in test
// suites.
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.
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.
QPDF_DLL
void setSuppressOriginalObjectIDs(bool);
// Preserve encryption. The default is true unless prefilering,
// 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);
// Set up for encrypted output. 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, and setting R4 parameters pushes the version to at least
// 1.5, or if AES is used, 1.6.
QPDF_DLL
void setR2EncryptionParameters(
char const* user_password, char const* owner_password,
bool allow_print, bool allow_modify,
bool allow_extract, bool allow_annotate);
QPDF_DLL
void setR3EncryptionParameters(
char const* user_password, char const* owner_password,
bool allow_accessibility, bool allow_extract,
qpdf_r3_print_e print, qpdf_r3_modify_e modify);
QPDF_DLL
void setR4EncryptionParameters(
char const* user_password, char const* owner_password,
bool allow_accessibility, bool allow_extract,
qpdf_r3_print_e print, qpdf_r3_modify_e modify,
bool encrypt_metadata, bool use_aes);
// Create linearized output. Disables qdf mode, content
// normalization, and stream prefiltering.
QPDF_DLL
void setLinearization(bool);
QPDF_DLL
void write();
private:
// flags used by unparseObject
static int const f_stream = 1 << 0;
static int const f_filtered = 1 << 1;
static int const f_in_ostream = 1 << 2;
enum trailer_e { t_normal, t_lin_first, t_lin_second };
void init();
int bytesNeeded(unsigned long n);
void writeBinary(unsigned long val, unsigned int bytes);
void writeString(std::string const& str);
void writeBuffer(PointerHolder<Buffer>&);
void writeStringQDF(std::string const& str);
void writeStringNoQDF(std::string const& str);
void writePad(int nspaces);
void assignCompressedObjectNumbers(int objid);
void enqueueObject(QPDFObjectHandle object);
void writeObjectStreamOffsets(std::vector<off_t>& offsets, int first_obj);
void writeObjectStream(QPDFObjectHandle object);
void writeObject(QPDFObjectHandle object, int object_stream_index = -1);
void writeTrailer(trailer_e which, int size,
bool xref_stream, int prev = 0);
void unparseObject(QPDFObjectHandle object, int level,
unsigned int flags);
void unparseObject(QPDFObjectHandle object, int level,
unsigned int flags,
// for stream dictionaries
size_t stream_length, bool compress);
void unparseChild(QPDFObjectHandle child, int level, int flags);
void initializeSpecialStreams();
void preserveObjectStreams();
void generateObjectStreams();
void generateID();
void interpretR3EncryptionParameters(
std::set<int>& bits_to_clear,
char const* user_password, char const* owner_password,
bool allow_accessibility, bool allow_extract,
qpdf_r3_print_e print, qpdf_r3_modify_e modify);
void disableIncompatibleEncryption(int major, int minor);
void parseVersion(std::string const& version, int& major, int& minor) const;
int compareVersions(int major1, int minor1, int major2, int minor2) const;
void setEncryptionParameters(
char const* user_password, char const* owner_password,
int V, int R, int key_len, std::set<int>& bits_to_clear);
void setEncryptionParametersInternal(
int V, int R, int key_len, long P,
std::string const& O, std::string const& U,
std::string const& id1, std::string const& user_password);
void copyEncryptionParameters();
void setDataKey(int objid);
int openObject(int objid = 0);
void closeObject(int objid);
void writeStandard();
void writeLinearized();
void enqueuePart(std::vector<QPDFObjectHandle>& part);
void writeEncryptionDictionary();
void writeHeader();
void writeHintStream(int hint_id);
int writeXRefTable(trailer_e which, int first, int last, int size);
int writeXRefTable(trailer_e which, int first, int last, int size,
// for linearization
int prev,
bool suppress_offsets,
int hint_id,
off_t hint_offset,
off_t hint_length);
int writeXRefStream(int objid, int max_id, int max_offset,
trailer_e which, int first, int last, int size);
int writeXRefStream(int objid, int max_id, int max_offset,
trailer_e which, int first, int last, int size,
// for linearization
int prev,
int hint_id,
off_t hint_offset,
off_t hint_length,
bool skip_compression);
int calculateXrefStreamPadding(int xref_bytes);
// When filtering subsections, push additional pipelines to the
// stack. When ready to switch, activate the pipeline stack.
// Pipelines passed to pushPipeline are deleted when
// clearPipelineStack is called.
Pipeline* pushPipeline(Pipeline*);
void activatePipelineStack();
void initializePipelineStack(Pipeline *);
// Calls finish on the current pipeline and pops the pipeline
// stack until the top of stack is a previous active top of stack,
// and restores the pipeline to that point. Deletes any pipelines
// that it pops. If the bp argument is non-null and any of the
// stack items are of type Pl_Buffer, the buffer is retrieved.
void popPipelineStack(PointerHolder<Buffer>* bp = 0);
void adjustAESStreamLength(size_t& length);
void pushEncryptionFilter();
void pushDiscardFilter();
QPDF& pdf;
char const* filename;
FILE* file;
bool close_file;
Pl_Buffer* buffer_pipeline;
Buffer* output_buffer;
bool normalize_content_set;
bool normalize_content;
bool stream_data_mode_set;
qpdf_stream_data_e stream_data_mode;
bool qdf_mode;
bool static_id;
bool suppress_original_object_ids;
bool direct_stream_lengths;
bool encrypted;
bool preserve_encryption;
bool linearized;
qpdf_object_stream_e object_stream_mode;
std::string encryption_key;
bool encrypt_metadata;
bool encrypt_use_aes;
std::map<std::string, std::string> encryption_dictionary;
std::string id1; // for /ID key of
std::string id2; // trailer dictionary
std::string min_pdf_version;
std::string forced_pdf_version;
int encryption_dict_objid;
std::string cur_data_key;
std::list<PointerHolder<Pipeline> > to_delete;
Pl_Count* pipeline;
std::list<QPDFObjectHandle> object_queue;
std::map<int, int> obj_renumber;
std::map<int, QPDFXRefEntry> xref;
std::map<int, size_t> lengths;
int next_objid;
int cur_stream_length_id;
size_t cur_stream_length;
bool added_newline;
int max_ostream_index;
std::set<int> normalized_streams;
std::map<int, int> page_object_to_seq;
std::map<int, int> contents_to_page_seq;
std::map<int, int> object_to_object_stream;
std::map<int, std::set<int> > object_stream_to_objects;
std::list<Pipeline*> pipeline_stack;
};
#endif // __QPDFWRITER_HH__