Coverage Report

Created: 2025-07-12 06:29

/src/qpdf/include/qpdf/QPDFWriter.hh
Line
Count
Source
1
// Copyright (c) 2005-2021 Jay Berkenbilt
2
// Copyright (c) 2022-2025 Jay Berkenbilt and Manfred Holger
3
//
4
// This file is part of qpdf.
5
//
6
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
7
// in compliance with the License. You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing, software distributed under the License
12
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
13
// or implied. See the License for the specific language governing permissions and limitations under
14
// the License.
15
//
16
// Versions of qpdf prior to version 7 were released under the terms of version 2.0 of the Artistic
17
// License. At your option, you may continue to consider qpdf to be licensed under those terms.
18
// Please see the manual for additional information.
19
20
#ifndef QPDFWRITER_HH
21
#define QPDFWRITER_HH
22
23
#include <qpdf/DLL.h>
24
#include <qpdf/Types.h>
25
26
#include <bitset>
27
#include <cstdio>
28
#include <functional>
29
#include <list>
30
#include <map>
31
#include <memory>
32
#include <set>
33
#include <string>
34
#include <string_view>
35
#include <vector>
36
37
#include <qpdf/Constants.h>
38
39
#include <qpdf/Buffer.hh>
40
#include <qpdf/PDFVersion.hh>
41
#include <qpdf/Pipeline.hh>
42
#include <qpdf/Pl_Buffer.hh>
43
#include <qpdf/QPDFObjGen.hh>
44
#include <qpdf/QPDFObjectHandle.hh>
45
#include <qpdf/QPDFXRefEntry.hh>
46
47
namespace qpdf::pl
48
{
49
    struct Link;
50
}
51
52
class QPDF;
53
class Pl_Count;
54
class Pl_MD5;
55
56
// This class implements a simple writer for saving QPDF objects to new PDF files.  See comments
57
// through the header file for additional details.
58
class QPDFWriter
59
{
60
  public:
61
    // Construct a QPDFWriter object without specifying output.  You must call one of the output
62
    // setting routines defined below.
63
    QPDF_DLL
64
    QPDFWriter(QPDF& pdf);
65
66
    // Create a QPDFWriter object that writes its output to a file or to stdout.  This is equivalent
67
    // to using the previous constructor and then calling setOutputFilename().  See
68
    // setOutputFilename() for details.
69
    QPDF_DLL
70
    QPDFWriter(QPDF& pdf, char const* filename);
71
72
    // Create a QPDFWriter object that writes its output to an already open FILE*.  This is
73
    // equivalent to calling the first constructor and then calling setOutputFile().  See
74
    // setOutputFile() for details.
75
    QPDF_DLL
76
    QPDFWriter(QPDF& pdf, char const* description, FILE* file, bool close_file);
77
78
8.12k
    ~QPDFWriter() = default;
79
80
    class QPDF_DLL_CLASS ProgressReporter
81
    {
82
      public:
83
        QPDF_DLL
84
        virtual ~ProgressReporter();
85
86
        // This method is called with a value from 0 to 100 to indicate approximate progress through
87
        // the write process. See registerProgressReporter.
88
        virtual void reportProgress(int) = 0;
89
    };
90
91
    // This is a progress reporter that takes a function. It is used by the C APIs, but it is
92
    // available if you want to just register a C function as a handler.
93
    class QPDF_DLL_CLASS FunctionProgressReporter: public ProgressReporter
94
    {
95
      public:
96
        QPDF_DLL
97
        FunctionProgressReporter(std::function<void(int)>);
98
        QPDF_DLL
99
        ~FunctionProgressReporter() override;
100
        QPDF_DLL
101
        void reportProgress(int) override;
102
103
      private:
104
        std::function<void(int)> handler;
105
    };
106
107
    // Setting Output.  Output may be set only one time.  If you don't use the filename version of
108
    // the QPDFWriter constructor, you must call exactly one of these methods.
109
110
    // Passing nullptr as filename means write to stdout.  QPDFWriter will create a zero-length
111
    // output file upon construction.  If write fails, the empty or partially written file will not
112
    // be deleted.  This is by design: sometimes the partial file may be useful for tracking down
113
    // problems.  If your application doesn't want the partially written file to be left behind, you
114
    // should delete it if the eventual call to write fails.
115
    QPDF_DLL
116
    void setOutputFilename(char const* filename);
117
118
    // Write to the given FILE*, which must be opened by the caller. If close_file is true,
119
    // QPDFWriter will close the file. Otherwise, the caller must close the file.  The file does not
120
    // need to be seekable; it will be written to in a single pass. It must be open in binary mode.
121
    QPDF_DLL
122
    void setOutputFile(char const* description, FILE* file, bool close_file);
123
124
    // Indicate that QPDFWriter should create a memory buffer to contain the final PDF file.  Obtain
125
    // the memory by calling getBuffer().
126
    QPDF_DLL
127
    void setOutputMemory();
128
129
    // Return the buffer object containing the PDF file. If setOutputMemory() has been called, this
130
    // method may be called exactly one time after write() has returned. The caller is responsible
131
    // for deleting the buffer when done. See also getBufferSharedPointer().
132
    QPDF_DLL
133
    Buffer* getBuffer();
134
135
    // Return getBuffer() in a shared pointer.
136
    QPDF_DLL
137
    std::shared_ptr<Buffer> getBufferSharedPointer();
138
139
    // Supply your own pipeline object.  Output will be written to this pipeline, and QPDFWriter
140
    // will call finish() on the pipeline.  It is the caller's responsibility to manage the memory
141
    // for the pipeline.  The pipeline is never deleted by QPDFWriter, which makes it possible for
142
    // you to call additional methods on the pipeline after the writing is finished.
143
    QPDF_DLL
144
    void setOutputPipeline(Pipeline*);
145
146
    // Setting Parameters
147
148
    // Set the value of object stream mode.  In disable mode, we never generate any object streams.
149
    // In preserve mode, we preserve object stream structure from the original file.  In generate
150
    // mode, we generate our own object streams.  In all cases, we generate a conventional
151
    // cross-reference table if there are no object streams and a cross-reference stream if there
152
    // are object streams.  The default is o_preserve.
153
    QPDF_DLL
154
    void setObjectStreamMode(qpdf_object_stream_e);
155
156
    // Set value of stream data mode. This is an older interface. Instead of using this, prefer
157
    // setCompressStreams() and setDecodeLevel(). This method is retained for compatibility, but it
158
    // does not cover the full range of available configurations. The mapping between this and the
159
    // new methods is as follows:
160
    //
161
    // qpdf_s_uncompress:
162
    //   setCompressStreams(false)
163
    //   setDecodeLevel(qpdf_dl_generalized)
164
    // qpdf_s_preserve:
165
    //   setCompressStreams(false)
166
    //   setDecodeLevel(qpdf_dl_none)
167
    // qpdf_s_compress:
168
    //   setCompressStreams(true)
169
    //   setDecodeLevel(qpdf_dl_generalized)
170
    //
171
    // The default is qpdf_s_compress.
172
    QPDF_DLL
173
    void setStreamDataMode(qpdf_stream_data_e);
174
175
    // If true, compress any uncompressed streams when writing them. Metadata streams are a special
176
    // case and are not compressed even if this is true. This is true by default for QPDFWriter. If
177
    // you want QPDFWriter to leave uncompressed streams uncompressed, pass false to this method.
178
    QPDF_DLL
179
    void setCompressStreams(bool);
180
181
    // When QPDFWriter encounters streams, this parameter controls the behavior with respect to
182
    // attempting to apply any filters to the streams when copying to the output. The decode levels
183
    // are as follows:
184
    //
185
    // qpdf_dl_none: Do not attempt to apply any filters. Streams remain as they appear in the
186
    // original file. Note that uncompressed streams may still be compressed on output. You can
187
    // disable that by calling setCompressStreams(false).
188
    //
189
    // qpdf_dl_generalized: This is the default. QPDFWriter will apply LZWDecode, ASCII85Decode,
190
    // ASCIIHexDecode, and FlateDecode filters on the input. When combined with
191
    // setCompressStreams(true), which is the default, the effect of this is that streams filtered
192
    // with these older and less efficient filters will be recompressed with the Flate filter. By
193
    // default, as a special case, if a stream is already compressed with FlateDecode and
194
    // setCompressStreams is enabled, the original compressed data will be preserved. This behavior
195
    // can be overridden by calling setRecompressFlate(true).
196
    //
197
    // qpdf_dl_specialized: In addition to uncompressing the generalized compression formats,
198
    // supported non-lossy compression will also be decoded. At present, this includes the
199
    // RunLengthDecode filter.
200
    //
201
    // qpdf_dl_all: In addition to generalized and non-lossy specialized filters, supported lossy
202
    // compression filters will be applied. At present, this includes DCTDecode (JPEG) compression.
203
    // Note that compressing the resulting data with DCTDecode again will accumulate loss, so avoid
204
    // multiple compression and decompression cycles. This is mostly useful for retrieving image
205
    // data.
206
    QPDF_DLL
207
    void setDecodeLevel(qpdf_stream_decode_level_e);
208
209
    // By default, when both the input and output contents of a stream are compressed with Flate,
210
    // qpdf does not uncompress and recompress the stream. Passing true here causes it to do so.
211
    // This can be useful if recompressing all streams with a higher compression level, which can be
212
    // set by calling the static method Pl_Flate::setCompressionLevel.
213
    QPDF_DLL
214
    void setRecompressFlate(bool);
215
216
    // Set value of content stream normalization.  The default is "false".  If true, we attempt to
217
    // normalize newlines inside of content streams.  Some constructs such as inline images may
218
    // thwart our efforts.  There may be some cases where this can damage the content stream.  This
219
    // flag should be used only for debugging and experimenting with PDF content streams.  Never use
220
    // it for production files.
221
    QPDF_DLL
222
    void setContentNormalization(bool);
223
224
    // Set QDF mode.  QDF mode causes special "pretty printing" of PDF objects, adds comments for
225
    // easier perusing of files. Resulting PDF files can be edited in a text editor and then run
226
    // through fix-qdf to update cross reference tables and stream lengths.
227
    QPDF_DLL
228
    void setQDFMode(bool);
229
230
    // Preserve unreferenced objects. The default behavior is to discard any object that is not
231
    // visited during a traversal of the object structure from the trailer.
232
    QPDF_DLL
233
    void setPreserveUnreferencedObjects(bool);
234
235
    // Always write a newline before the endstream keyword. This helps with PDF/A compliance, though
236
    // it is not sufficient for it.
237
    QPDF_DLL
238
    void setNewlineBeforeEndstream(bool);
239
240
    // Set the minimum PDF version.  If the PDF version of the input file (or previously set minimum
241
    // version) is less than the version passed to this method, the PDF version of the output file
242
    // will be set to this value.  If the original PDF file's version or previously set minimum
243
    // version is already this version or later, the original file's version will be used.
244
    // QPDFWriter automatically sets the minimum version to 1.4 when R3 encryption parameters are
245
    // used, and to 1.5 when object streams are used.
246
    QPDF_DLL
247
    void setMinimumPDFVersion(std::string const&, int extension_level = 0);
248
    QPDF_DLL
249
    void setMinimumPDFVersion(PDFVersion const&);
250
251
    // Force the PDF version of the output file to be a given version. Use of this function may
252
    // create PDF files that will not work properly with older PDF viewers.  When a PDF version is
253
    // set using this function, qpdf will use this version even if the file contains features that
254
    // are not supported in that version of PDF.  In other words, you should only use this function
255
    // if you are sure the PDF file in question has no features of newer versions of PDF or if you
256
    // are willing to create files that old viewers may try to open but not be able to properly
257
    // interpret. If any encryption has been applied to the document either explicitly or by
258
    // preserving the encryption of the source document, forcing the PDF version to a value too low
259
    // to support that type of encryption will explicitly disable decryption. Additionally, forcing
260
    // to a version below 1.5 will disable object streams.
261
    QPDF_DLL
262
    void forcePDFVersion(std::string const&, int extension_level = 0);
263
264
    // Provide additional text to insert in the PDF file somewhere near the beginning of the file.
265
    // This can be used to add comments to the beginning of a PDF file, for example, if those
266
    // comments are to be consumed by some other application.  No checks are performed to ensure
267
    // that the text inserted here is valid PDF.  If you want to insert multiline comments, you will
268
    // need to include \n in the string yourself and start each line with %.  An extra newline will
269
    // be appended if one is not already present at the end of your text.
270
    QPDF_DLL
271
    void setExtraHeaderText(std::string const&);
272
273
    // Causes a deterministic /ID value to be generated. When this is set, the current time and
274
    // output file name are not used as part of /ID generation. Instead, a digest of all significant
275
    // parts of the output file's contents is included in the /ID calculation. Use of a
276
    // deterministic /ID can be handy when it is desirable for a repeat of the same qpdf operation
277
    // on the same inputs being written to the same outputs with the same parameters to generate
278
    // exactly the same results. This feature is incompatible with encrypted files because, for
279
    // encrypted files, the /ID is generated before any part of the file is written since it is an
280
    // input to the encryption process.
281
    QPDF_DLL
282
    void setDeterministicID(bool);
283
284
    // Cause a static /ID value to be generated.  Use only in test suites.  See also
285
    // setDeterministicID.
286
    QPDF_DLL
287
    void setStaticID(bool);
288
289
    // Use a fixed initialization vector for AES-CBC encryption.  This is not secure.  It should be
290
    // used only in test suites for creating predictable encrypted output.
291
    QPDF_DLL
292
    void setStaticAesIV(bool);
293
294
    // Suppress inclusion of comments indicating original object IDs when writing QDF files.  This
295
    // can also be useful for testing, particularly when using comparison of two qdf files to
296
    // determine whether two PDF files have identical content.
297
    QPDF_DLL
298
    void setSuppressOriginalObjectIDs(bool);
299
300
    // Preserve encryption.  The default is true unless prefiltering, content normalization, or qdf
301
    // mode has been selected in which case encryption is never preserved.  Encryption is also not
302
    // preserved if we explicitly set encryption parameters.
303
    QPDF_DLL
304
    void setPreserveEncryption(bool);
305
306
    // Copy encryption parameters from another QPDF object.  If you want to copy encryption from the
307
    // object you are writing, call setPreserveEncryption(true) instead.
308
    QPDF_DLL
309
    void copyEncryptionParameters(QPDF&);
310
311
    // Set up for encrypted output.  User and owner password both must be specified.  Either or both
312
    // may be the empty string.  Note that qpdf does not apply any special treatment to the empty
313
    // string, which makes it possible to create encrypted files with empty owner passwords and
314
    // non-empty user passwords or with the same password for both user and owner.  Some PDF reading
315
    // products don't handle such files very well.  Enabling encryption disables stream prefiltering
316
    // and content normalization.  Note that setting R2 encryption parameters sets the PDF version
317
    // to at least 1.3, setting R3 encryption parameters pushes the PDF version number to at
318
    // least 1.4, setting R4 parameters pushes the version to at least 1.5, or if AES is used, 1.6,
319
    // and setting R5 or R6 parameters pushes the version to at least 1.7 with extension level 3.
320
    //
321
    // Note about Unicode passwords: the PDF specification requires passwords to be encoded with PDF
322
    // Doc encoding for R <= 4 and UTF-8 for R >= 5. In all cases, these methods take strings of
323
    // bytes as passwords. It is up to the caller to ensure that passwords are properly encoded. The
324
    // qpdf command-line tool tries to do this, as discussed in the manual. If you are doing this
325
    // from your own application, QUtil contains many transcoding functions that could be useful to
326
    // you, most notably utf8_to_pdf_doc.
327
328
    // R2 uses RC4, which is a weak cryptographic algorithm. Don't use it unless you have to. See
329
    // "Weak Cryptography" in the manual. This encryption format is deprecated in the PDF 2.0
330
    // specification.
331
    QPDF_DLL
332
    void setR2EncryptionParametersInsecure(
333
        char const* user_password,
334
        char const* owner_password,
335
        bool allow_print,
336
        bool allow_modify,
337
        bool allow_extract,
338
        bool allow_annotate);
339
    // R3 uses RC4, which is a weak cryptographic algorithm. Don't use it unless you have to. See
340
    // "Weak Cryptography" in the manual. This encryption format is deprecated in the PDF 2.0
341
    // specification.
342
    QPDF_DLL
343
    void setR3EncryptionParametersInsecure(
344
        char const* user_password,
345
        char const* owner_password,
346
        bool allow_accessibility,
347
        bool allow_extract,
348
        bool allow_assemble,
349
        bool allow_annotate_and_form,
350
        bool allow_form_filling,
351
        bool allow_modify_other,
352
        qpdf_r3_print_e print);
353
    // When use_aes=false, this call enables R4 with RC4, which is a weak cryptographic algorithm.
354
    // Even with use_aes=true, the overall encryption scheme is weak. Don't use it unless you have
355
    // to. See "Weak Cryptography" in the manual. This encryption format is deprecated in the
356
    // PDF 2.0 specification.
357
    QPDF_DLL
358
    void setR4EncryptionParametersInsecure(
359
        char const* user_password,
360
        char const* owner_password,
361
        bool allow_accessibility,
362
        bool allow_extract,
363
        bool allow_assemble,
364
        bool allow_annotate_and_form,
365
        bool allow_form_filling,
366
        bool allow_modify_other,
367
        qpdf_r3_print_e print,
368
        bool encrypt_metadata,
369
        bool use_aes);
370
    // R5 is deprecated.  Do not use it for production use.  Writing R5 is supported by qpdf
371
    // primarily to generate test files for applications that may need to test R5 support.
372
    QPDF_DLL
373
    void setR5EncryptionParameters(
374
        char const* user_password,
375
        char const* owner_password,
376
        bool allow_accessibility,
377
        bool allow_extract,
378
        bool allow_assemble,
379
        bool allow_annotate_and_form,
380
        bool allow_form_filling,
381
        bool allow_modify_other,
382
        qpdf_r3_print_e print,
383
        bool encrypt_metadata);
384
    // This is the only password-based encryption format supported by the PDF specification.
385
    QPDF_DLL
386
    void setR6EncryptionParameters(
387
        char const* user_password,
388
        char const* owner_password,
389
        bool allow_accessibility,
390
        bool allow_extract,
391
        bool allow_assemble,
392
        bool allow_annotate_and_form,
393
        bool allow_form_filling,
394
        bool allow_modify_other,
395
        qpdf_r3_print_e print,
396
        bool encrypt_metadata_aes);
397
398
    // Create linearized output.  Disables qdf mode, content normalization, and stream prefiltering.
399
    QPDF_DLL
400
    void setLinearization(bool);
401
402
    // For debugging QPDF: provide the name of a file to write pass1 of linearization to. The only
403
    // reason to use this is to debug QPDF. To linearize, QPDF writes out the file in two passes.
404
    // Usually the first pass is discarded, but lots of computations are made in pass 1. If a
405
    // linearized file comes out wrong, it can be helpful to look at the first pass.
406
    QPDF_DLL
407
    void setLinearizationPass1Filename(std::string const&);
408
409
    // Create PCLm output. This is only useful for clients that know how to create PCLm files. If a
410
    // file is structured exactly as PCLm requires, this call will tell QPDFWriter to write the PCLm
411
    // header, create certain unreferenced streams required by the standard, and write the objects
412
    // in the required order. Calling this on an ordinary PDF serves no purpose. There is no
413
    // command-line argument that causes this method to be called.
414
    QPDF_DLL
415
    void setPCLm(bool);
416
417
    // If you want to be notified of progress, derive a class from ProgressReporter and override the
418
    // reportProgress method.
419
    QPDF_DLL
420
    void registerProgressReporter(std::shared_ptr<ProgressReporter>);
421
422
    // Return the PDF version that will be written into the header. Calling this method does all the
423
    // preparation for writing, so it is an error to call any methods that may cause a change to the
424
    // version. Adding new objects to the original file after calling this may also cause problems.
425
    // It is safe to update existing objects or stream contents after calling this method, e.g., to
426
    // include the final version number in metadata.
427
    QPDF_DLL
428
    std::string getFinalVersion();
429
430
    // Write the final file. There is no expectation of being able to call write() more than once.
431
    QPDF_DLL
432
    void write();
433
434
    // Return renumbered ObjGen that was written into the final file. This method can be used after
435
    // calling write().
436
    QPDF_DLL
437
    QPDFObjGen getRenumberedObjGen(QPDFObjGen);
438
439
    // Return XRef entry that was written into the final file. This method can be used after calling
440
    // write().
441
    QPDF_DLL
442
    std::map<QPDFObjGen, QPDFXRefEntry> getWrittenXRefTable();
443
444
    // The following structs / classes are not part of the public API.
445
    struct Object;
446
    struct NewObject;
447
    class ObjTable;
448
    class NewObjTable;
449
450
  private:
451
    // flags used by unparseObject
452
    static int const f_stream = 1 << 0;
453
    static int const f_filtered = 1 << 1;
454
    static int const f_in_ostream = 1 << 2;
455
    static int const f_hex_string = 1 << 3;
456
    static int const f_no_encryption = 1 << 4;
457
458
    enum trailer_e { t_normal, t_lin_first, t_lin_second };
459
460
    // An reference to a PipelinePopper instance is passed into activatePipelineStack. When the
461
    // PipelinePopper goes out of scope, the pipeline stack is popped. PipelinePopper's destructor
462
    // calls finish on the current pipeline and pops the pipeline stack until the top of stack is a
463
    // previous active top of stack, and restores the pipeline to that point. It deletes any
464
    // pipelines that it pops. If the bp argument is non-null and any of the stack items are of type
465
    // Pl_Buffer, the buffer is retrieved.
466
    class PipelinePopper
467
    {
468
        friend class QPDFWriter;
469
470
      public:
471
        PipelinePopper(QPDFWriter* qw) :
472
163k
            qw(qw)
473
163k
        {
474
163k
        }
475
        ~PipelinePopper();
476
477
      private:
478
        QPDFWriter* qw{nullptr};
479
        unsigned long stack_id{0};
480
    };
481
482
    unsigned int bytesNeeded(long long n);
483
    void writeBinary(unsigned long long val, unsigned int bytes);
484
    void writeString(std::string_view str);
485
    void writeStringQDF(std::string_view str);
486
    void writeStringNoQDF(std::string_view str);
487
    void writePad(size_t nspaces);
488
    void assignCompressedObjectNumbers(QPDFObjGen og);
489
    void enqueueObject(QPDFObjectHandle object);
490
    void writeObjectStreamOffsets(std::vector<qpdf_offset_t>& offsets, int first_obj);
491
    void writeObjectStream(QPDFObjectHandle object);
492
    void writeObject(QPDFObjectHandle object, int object_stream_index = -1);
493
    void writeTrailer(
494
        trailer_e which, int size, bool xref_stream, qpdf_offset_t prev, int linearization_pass);
495
    bool willFilterStream(
496
        QPDFObjectHandle stream,
497
        bool& compress_stream,
498
        bool& is_metadata,
499
        std::string* stream_data);
500
    void unparseObject(
501
        QPDFObjectHandle object,
502
        int level,
503
        int flags,
504
        // for stream dictionaries
505
        size_t stream_length = 0,
506
        bool compress = false);
507
    void unparseChild(QPDFObjectHandle child, int level, int flags);
508
    void initializeSpecialStreams();
509
    void preserveObjectStreams();
510
    void generateObjectStreams();
511
    std::string getOriginalID1();
512
    void generateID();
513
    void interpretR3EncryptionParameters(
514
        bool allow_accessibility,
515
        bool allow_extract,
516
        bool allow_assemble,
517
        bool allow_annotate_and_form,
518
        bool allow_form_filling,
519
        bool allow_modify_other,
520
        qpdf_r3_print_e print,
521
        qpdf_r3_modify_e modify);
522
    void disableIncompatibleEncryption(int major, int minor, int extension_level);
523
    void parseVersion(std::string const& version, int& major, int& minor) const;
524
    int compareVersions(int major1, int minor1, int major2, int minor2) const;
525
    void setEncryptionParameters(char const* user_password, char const* owner_password);
526
    void setEncryptionMinimumVersion();
527
    void setDataKey(int objid);
528
    int openObject(int objid = 0);
529
    void closeObject(int objid);
530
    QPDFObjectHandle getTrimmedTrailer();
531
    void prepareFileForWrite();
532
    void enqueueObjectsStandard();
533
    void enqueueObjectsPCLm();
534
    void indicateProgress(bool decrement, bool finished);
535
    void writeStandard();
536
    void writeLinearized();
537
    void enqueuePart(std::vector<QPDFObjectHandle>& part);
538
    void writeEncryptionDictionary();
539
    void initializeTables(size_t extra = 0);
540
    void doWriteSetup();
541
    void writeHeader();
542
    void writeHintStream(int hint_id);
543
    qpdf_offset_t writeXRefTable(trailer_e which, int first, int last, int size);
544
    qpdf_offset_t writeXRefTable(
545
        trailer_e which,
546
        int first,
547
        int last,
548
        int size,
549
        // for linearization
550
        qpdf_offset_t prev,
551
        bool suppress_offsets,
552
        int hint_id,
553
        qpdf_offset_t hint_offset,
554
        qpdf_offset_t hint_length,
555
        int linearization_pass);
556
    qpdf_offset_t writeXRefStream(
557
        int objid,
558
        int max_id,
559
        qpdf_offset_t max_offset,
560
        trailer_e which,
561
        int first,
562
        int last,
563
        int size);
564
    qpdf_offset_t writeXRefStream(
565
        int objid,
566
        int max_id,
567
        qpdf_offset_t max_offset,
568
        trailer_e which,
569
        int first,
570
        int last,
571
        int size,
572
        // for linearization
573
        qpdf_offset_t prev,
574
        int hint_id,
575
        qpdf_offset_t hint_offset,
576
        qpdf_offset_t hint_length,
577
        bool skip_compression,
578
        int linearization_pass);
579
    size_t calculateXrefStreamPadding(qpdf_offset_t xref_bytes);
580
581
    // When filtering subsections, push additional pipelines to the stack. When ready to switch,
582
    // activate the pipeline stack. When the passed in PipelinePopper goes out of scope, the stack
583
    // is popped.
584
    Pipeline* pushPipeline(Pipeline*);
585
    void activatePipelineStack(PipelinePopper& pp, std::string& str);
586
    void activatePipelineStack(PipelinePopper& pp, std::unique_ptr<qpdf::pl::Link> link);
587
    void activatePipelineStack(
588
        PipelinePopper& pp,
589
        bool discard = false,
590
        std::string* str = nullptr,
591
        std::unique_ptr<qpdf::pl::Link> link = nullptr);
592
    void initializePipelineStack(Pipeline*);
593
594
    void adjustAESStreamLength(size_t& length);
595
    void pushEncryptionFilter(PipelinePopper&);
596
    void pushMD5Pipeline(PipelinePopper&);
597
    void computeDeterministicIDData();
598
599
    class Members;
600
601
    // Keep all member variables inside the Members object, which we dynamically allocate. This
602
    // makes it possible to add new private members without breaking binary compatibility.
603
    std::shared_ptr<Members> m;
604
};
605
606
#endif // QPDFWRITER_HH