Commit 05cb757df564e4196c89fbf88c00489b23b65102
Committed by
GitHub
Merge pull request #1544 from m-holger/writer
Remove implementation detail from QPDFWriter.hh
Showing
5 changed files
with
640 additions
and
677 deletions
include/qpdf/QPDFWriter.hh
| @@ -20,11 +20,19 @@ | @@ -20,11 +20,19 @@ | ||
| 20 | #ifndef QPDFWRITER_HH | 20 | #ifndef QPDFWRITER_HH |
| 21 | #define QPDFWRITER_HH | 21 | #define QPDFWRITER_HH |
| 22 | 22 | ||
| 23 | +#include <qpdf/Constants.h> | ||
| 23 | #include <qpdf/DLL.h> | 24 | #include <qpdf/DLL.h> |
| 24 | #include <qpdf/Types.h> | 25 | #include <qpdf/Types.h> |
| 25 | 26 | ||
| 27 | +#include <qpdf/Buffer.hh> | ||
| 28 | +#include <qpdf/PDFVersion.hh> | ||
| 29 | +#include <qpdf/Pipeline.hh> | ||
| 30 | +#include <qpdf/Pl_Buffer.hh> | ||
| 31 | +#include <qpdf/QPDFObjGen.hh> | ||
| 32 | +#include <qpdf/QPDFObjectHandle.hh> | ||
| 33 | +#include <qpdf/QPDFXRefEntry.hh> | ||
| 34 | + | ||
| 26 | #include <bitset> | 35 | #include <bitset> |
| 27 | -#include <concepts> | ||
| 28 | #include <cstdio> | 36 | #include <cstdio> |
| 29 | #include <functional> | 37 | #include <functional> |
| 30 | #include <list> | 38 | #include <list> |
| @@ -35,24 +43,7 @@ | @@ -35,24 +43,7 @@ | ||
| 35 | #include <string_view> | 43 | #include <string_view> |
| 36 | #include <vector> | 44 | #include <vector> |
| 37 | 45 | ||
| 38 | -#include <qpdf/Constants.h> | ||
| 39 | - | ||
| 40 | -#include <qpdf/Buffer.hh> | ||
| 41 | -#include <qpdf/PDFVersion.hh> | ||
| 42 | -#include <qpdf/Pipeline.hh> | ||
| 43 | -#include <qpdf/Pl_Buffer.hh> | ||
| 44 | -#include <qpdf/QPDFObjGen.hh> | ||
| 45 | -#include <qpdf/QPDFObjectHandle.hh> | ||
| 46 | -#include <qpdf/QPDFXRefEntry.hh> | ||
| 47 | - | ||
| 48 | -namespace qpdf::pl | ||
| 49 | -{ | ||
| 50 | - struct Link; | ||
| 51 | -} | ||
| 52 | - | ||
| 53 | class QPDF; | 46 | class QPDF; |
| 54 | -class Pl_Count; | ||
| 55 | -class Pl_MD5; | ||
| 56 | 47 | ||
| 57 | // This class implements a simple writer for saving QPDF objects to new PDF files. See comments | 48 | // This class implements a simple writer for saving QPDF objects to new PDF files. See comments |
| 58 | // through the header file for additional details. | 49 | // through the header file for additional details. |
| @@ -449,132 +440,8 @@ class QPDFWriter | @@ -449,132 +440,8 @@ class QPDFWriter | ||
| 449 | class NewObjTable; | 440 | class NewObjTable; |
| 450 | 441 | ||
| 451 | private: | 442 | private: |
| 452 | - // flags used by unparseObject | ||
| 453 | - static int const f_stream = 1 << 0; | ||
| 454 | - static int const f_filtered = 1 << 1; | ||
| 455 | - static int const f_in_ostream = 1 << 2; | ||
| 456 | - static int const f_hex_string = 1 << 3; | ||
| 457 | - static int const f_no_encryption = 1 << 4; | ||
| 458 | - | ||
| 459 | - enum trailer_e { t_normal, t_lin_first, t_lin_second }; | ||
| 460 | - | ||
| 461 | - unsigned int bytesNeeded(long long n); | ||
| 462 | - void writeBinary(unsigned long long val, unsigned int bytes); | ||
| 463 | - QPDFWriter& write(std::string_view str); | ||
| 464 | - QPDFWriter& write(size_t count, char c); | ||
| 465 | - QPDFWriter& write(std::integral auto val); | ||
| 466 | - QPDFWriter& write_name(std::string const& str); | ||
| 467 | - QPDFWriter& write_string(std::string const& str, bool force_binary = false); | ||
| 468 | - QPDFWriter& write_encrypted(std::string_view str); | ||
| 469 | - | ||
| 470 | - template <typename... Args> | ||
| 471 | - QPDFWriter& write_qdf(Args&&... args); | ||
| 472 | - template <typename... Args> | ||
| 473 | - QPDFWriter& write_no_qdf(Args&&... args); | ||
| 474 | - void assignCompressedObjectNumbers(QPDFObjGen og); | ||
| 475 | - void enqueueObject(QPDFObjectHandle object); | ||
| 476 | - void writeObjectStreamOffsets(std::vector<qpdf_offset_t>& offsets, int first_obj); | ||
| 477 | - void writeObjectStream(QPDFObjectHandle object); | ||
| 478 | - void writeObject(QPDFObjectHandle object, int object_stream_index = -1); | ||
| 479 | - void writeTrailer( | ||
| 480 | - trailer_e which, int size, bool xref_stream, qpdf_offset_t prev, int linearization_pass); | ||
| 481 | - bool willFilterStream( | ||
| 482 | - QPDFObjectHandle stream, | ||
| 483 | - bool& compress_stream, | ||
| 484 | - bool& is_metadata, | ||
| 485 | - std::string* stream_data); | ||
| 486 | - void unparseObject( | ||
| 487 | - QPDFObjectHandle object, | ||
| 488 | - size_t level, | ||
| 489 | - int flags, | ||
| 490 | - // for stream dictionaries | ||
| 491 | - size_t stream_length = 0, | ||
| 492 | - bool compress = false); | ||
| 493 | - void unparseChild(QPDFObjectHandle const& child, size_t level, int flags); | ||
| 494 | - void initializeSpecialStreams(); | ||
| 495 | - void preserveObjectStreams(); | ||
| 496 | - void generateObjectStreams(); | ||
| 497 | - std::string getOriginalID1(); | ||
| 498 | - void generateID(bool encrypted); | ||
| 499 | - void interpretR3EncryptionParameters( | ||
| 500 | - bool allow_accessibility, | ||
| 501 | - bool allow_extract, | ||
| 502 | - bool allow_assemble, | ||
| 503 | - bool allow_annotate_and_form, | ||
| 504 | - bool allow_form_filling, | ||
| 505 | - bool allow_modify_other, | ||
| 506 | - qpdf_r3_print_e print, | ||
| 507 | - qpdf_r3_modify_e modify); | ||
| 508 | - void disableIncompatibleEncryption(int major, int minor, int extension_level); | ||
| 509 | - void parseVersion(std::string const& version, int& major, int& minor) const; | ||
| 510 | - int compareVersions(int major1, int minor1, int major2, int minor2) const; | ||
| 511 | - void setEncryptionParameters(char const* user_password, char const* owner_password); | ||
| 512 | - void setEncryptionMinimumVersion(); | ||
| 513 | - void setDataKey(int objid); | ||
| 514 | - int openObject(int objid = 0); | ||
| 515 | - void closeObject(int objid); | ||
| 516 | - QPDFObjectHandle getTrimmedTrailer(); | ||
| 517 | - void prepareFileForWrite(); | ||
| 518 | - void enqueueObjectsStandard(); | ||
| 519 | - void enqueueObjectsPCLm(); | ||
| 520 | - void indicateProgress(bool decrement, bool finished); | ||
| 521 | - void writeStandard(); | ||
| 522 | - void writeLinearized(); | ||
| 523 | - void enqueuePart(std::vector<QPDFObjectHandle>& part); | ||
| 524 | - void writeEncryptionDictionary(); | ||
| 525 | - void initializeTables(size_t extra = 0); | ||
| 526 | - void doWriteSetup(); | ||
| 527 | - void writeHeader(); | ||
| 528 | - void writeHintStream(int hint_id); | ||
| 529 | - qpdf_offset_t writeXRefTable(trailer_e which, int first, int last, int size); | ||
| 530 | - qpdf_offset_t writeXRefTable( | ||
| 531 | - trailer_e which, | ||
| 532 | - int first, | ||
| 533 | - int last, | ||
| 534 | - int size, | ||
| 535 | - // for linearization | ||
| 536 | - qpdf_offset_t prev, | ||
| 537 | - bool suppress_offsets, | ||
| 538 | - int hint_id, | ||
| 539 | - qpdf_offset_t hint_offset, | ||
| 540 | - qpdf_offset_t hint_length, | ||
| 541 | - int linearization_pass); | ||
| 542 | - qpdf_offset_t writeXRefStream( | ||
| 543 | - int objid, | ||
| 544 | - int max_id, | ||
| 545 | - qpdf_offset_t max_offset, | ||
| 546 | - trailer_e which, | ||
| 547 | - int first, | ||
| 548 | - int last, | ||
| 549 | - int size); | ||
| 550 | - qpdf_offset_t writeXRefStream( | ||
| 551 | - int objid, | ||
| 552 | - int max_id, | ||
| 553 | - qpdf_offset_t max_offset, | ||
| 554 | - trailer_e which, | ||
| 555 | - int first, | ||
| 556 | - int last, | ||
| 557 | - int size, | ||
| 558 | - // for linearization | ||
| 559 | - qpdf_offset_t prev, | ||
| 560 | - int hint_id, | ||
| 561 | - qpdf_offset_t hint_offset, | ||
| 562 | - qpdf_offset_t hint_length, | ||
| 563 | - bool skip_compression, | ||
| 564 | - int linearization_pass); | ||
| 565 | - size_t calculateXrefStreamPadding(qpdf_offset_t xref_bytes); | ||
| 566 | - | ||
| 567 | - // When filtering subsections, push additional pipelines to the stack. When ready to switch, | ||
| 568 | - // activate the pipeline stack. When the passed in PipelinePopper goes out of scope, the stack | ||
| 569 | - // is popped. | ||
| 570 | - | ||
| 571 | - void adjustAESStreamLength(size_t& length); | ||
| 572 | - void computeDeterministicIDData(); | ||
| 573 | - | ||
| 574 | class Members; | 443 | class Members; |
| 575 | 444 | ||
| 576 | - // Keep all member variables inside the Members object, which we dynamically allocate. This | ||
| 577 | - // makes it possible to add new private members without breaking binary compatibility. | ||
| 578 | std::shared_ptr<Members> m; | 445 | std::shared_ptr<Members> m; |
| 579 | }; | 446 | }; |
| 580 | 447 |
libqpdf/NNTree.cc
| @@ -666,7 +666,7 @@ NNTreeImpl::repair() | @@ -666,7 +666,7 @@ NNTreeImpl::repair() | ||
| 666 | NNTreeImpl repl(qpdf, new_node, key_type, value_valid, false); | 666 | NNTreeImpl repl(qpdf, new_node, key_type, value_valid, false); |
| 667 | std::map<QPDFObjectHandle, QPDFObjectHandle, Cmp> items; | 667 | std::map<QPDFObjectHandle, QPDFObjectHandle, Cmp> items; |
| 668 | for (auto const& [key, value]: *this) { | 668 | for (auto const& [key, value]: *this) { |
| 669 | - if (key && value && repl.keyValid(key) && repl.value_valid(value) ) { | 669 | + if (key && value && repl.keyValid(key) && repl.value_valid(value)) { |
| 670 | items.insert_or_assign(key, value); | 670 | items.insert_or_assign(key, value); |
| 671 | } | 671 | } |
| 672 | } | 672 | } |
libqpdf/QPDFWriter.cc
| @@ -11,7 +11,6 @@ | @@ -11,7 +11,6 @@ | ||
| 11 | #include <qpdf/Pl_PNGFilter.hh> | 11 | #include <qpdf/Pl_PNGFilter.hh> |
| 12 | #include <qpdf/Pl_RC4.hh> | 12 | #include <qpdf/Pl_RC4.hh> |
| 13 | #include <qpdf/Pl_StdioFile.hh> | 13 | #include <qpdf/Pl_StdioFile.hh> |
| 14 | -#include <qpdf/Pl_String.hh> | ||
| 15 | #include <qpdf/QIntC.hh> | 14 | #include <qpdf/QIntC.hh> |
| 16 | #include <qpdf/QPDFObjectHandle_private.hh> | 15 | #include <qpdf/QPDFObjectHandle_private.hh> |
| 17 | #include <qpdf/QPDFObject_private.hh> | 16 | #include <qpdf/QPDFObject_private.hh> |
| @@ -22,6 +21,7 @@ | @@ -22,6 +21,7 @@ | ||
| 22 | #include <qpdf/Util.hh> | 21 | #include <qpdf/Util.hh> |
| 23 | 22 | ||
| 24 | #include <algorithm> | 23 | #include <algorithm> |
| 24 | +#include <concepts> | ||
| 25 | #include <cstdlib> | 25 | #include <cstdlib> |
| 26 | #include <stdexcept> | 26 | #include <stdexcept> |
| 27 | 27 | ||
| @@ -265,12 +265,152 @@ class QPDFWriter::Members | @@ -265,12 +265,152 @@ class QPDFWriter::Members | ||
| 265 | friend class QPDFWriter; | 265 | friend class QPDFWriter; |
| 266 | 266 | ||
| 267 | public: | 267 | public: |
| 268 | - ~Members(); | 268 | + // flags used by unparseObject |
| 269 | + static int const f_stream = 1 << 0; | ||
| 270 | + static int const f_filtered = 1 << 1; | ||
| 271 | + static int const f_in_ostream = 1 << 2; | ||
| 272 | + static int const f_hex_string = 1 << 3; | ||
| 273 | + static int const f_no_encryption = 1 << 4; | ||
| 274 | + | ||
| 275 | + enum trailer_e { t_normal, t_lin_first, t_lin_second }; | ||
| 276 | + | ||
| 277 | + Members(QPDFWriter& w, QPDF& pdf) : | ||
| 278 | + w(w), | ||
| 279 | + pdf(pdf), | ||
| 280 | + root_og( | ||
| 281 | + pdf.getRoot().getObjGen().isIndirect() ? pdf.getRoot().getObjGen() : QPDFObjGen(-1, 0)), | ||
| 282 | + pipeline_stack(pipeline) | ||
| 283 | + { | ||
| 284 | + } | ||
| 269 | 285 | ||
| 270 | - private: | ||
| 271 | - Members(QPDF& pdf); | ||
| 272 | Members(Members const&) = delete; | 286 | Members(Members const&) = delete; |
| 273 | 287 | ||
| 288 | + ~Members() | ||
| 289 | + { | ||
| 290 | + if (file && close_file) { | ||
| 291 | + fclose(file); | ||
| 292 | + } | ||
| 293 | + delete output_buffer; | ||
| 294 | + } | ||
| 295 | + | ||
| 296 | + void write(); | ||
| 297 | + std::map<QPDFObjGen, QPDFXRefEntry> getWrittenXRefTable(); | ||
| 298 | + void setMinimumPDFVersion(std::string const& version, int extension_level); | ||
| 299 | + void copyEncryptionParameters(QPDF&); | ||
| 300 | + void doWriteSetup(); | ||
| 301 | + void prepareFileForWrite(); | ||
| 302 | + | ||
| 303 | + void disableIncompatibleEncryption(int major, int minor, int extension_level); | ||
| 304 | + void interpretR3EncryptionParameters( | ||
| 305 | + bool allow_accessibility, | ||
| 306 | + bool allow_extract, | ||
| 307 | + bool allow_assemble, | ||
| 308 | + bool allow_annotate_and_form, | ||
| 309 | + bool allow_form_filling, | ||
| 310 | + bool allow_modify_other, | ||
| 311 | + qpdf_r3_print_e print, | ||
| 312 | + qpdf_r3_modify_e modify); | ||
| 313 | + void setEncryptionParameters(char const* user_password, char const* owner_password); | ||
| 314 | + void setEncryptionMinimumVersion(); | ||
| 315 | + void parseVersion(std::string const& version, int& major, int& minor) const; | ||
| 316 | + int compareVersions(int major1, int minor1, int major2, int minor2) const; | ||
| 317 | + void generateID(bool encrypted); | ||
| 318 | + std::string getOriginalID1(); | ||
| 319 | + void initializeTables(size_t extra = 0); | ||
| 320 | + void preserveObjectStreams(); | ||
| 321 | + void generateObjectStreams(); | ||
| 322 | + void initializeSpecialStreams(); | ||
| 323 | + void enqueueObject(QPDFObjectHandle object); | ||
| 324 | + void enqueueObjectsStandard(); | ||
| 325 | + void enqueueObjectsPCLm(); | ||
| 326 | + void enqueuePart(std::vector<QPDFObjectHandle>& part); | ||
| 327 | + void assignCompressedObjectNumbers(QPDFObjGen og); | ||
| 328 | + QPDFObjectHandle getTrimmedTrailer(); | ||
| 329 | + | ||
| 330 | + bool willFilterStream( | ||
| 331 | + QPDFObjectHandle stream, | ||
| 332 | + bool& compress_stream, | ||
| 333 | + bool& is_metadata, | ||
| 334 | + std::string* stream_data); | ||
| 335 | + unsigned int bytesNeeded(long long n); | ||
| 336 | + void writeBinary(unsigned long long val, unsigned int bytes); | ||
| 337 | + Members& write(std::string_view str); | ||
| 338 | + Members& write(size_t count, char c); | ||
| 339 | + Members& write(std::integral auto val); | ||
| 340 | + Members& write_name(std::string const& str); | ||
| 341 | + Members& write_string(std::string const& str, bool force_binary = false); | ||
| 342 | + Members& write_encrypted(std::string_view str); | ||
| 343 | + | ||
| 344 | + template <typename... Args> | ||
| 345 | + Members& write_qdf(Args&&... args); | ||
| 346 | + template <typename... Args> | ||
| 347 | + Members& write_no_qdf(Args&&... args); | ||
| 348 | + void writeObjectStreamOffsets(std::vector<qpdf_offset_t>& offsets, int first_obj); | ||
| 349 | + void writeObjectStream(QPDFObjectHandle object); | ||
| 350 | + void writeObject(QPDFObjectHandle object, int object_stream_index = -1); | ||
| 351 | + void writeTrailer( | ||
| 352 | + trailer_e which, int size, bool xref_stream, qpdf_offset_t prev, int linearization_pass); | ||
| 353 | + void unparseObject( | ||
| 354 | + QPDFObjectHandle object, | ||
| 355 | + size_t level, | ||
| 356 | + int flags, | ||
| 357 | + // for stream dictionaries | ||
| 358 | + size_t stream_length = 0, | ||
| 359 | + bool compress = false); | ||
| 360 | + void unparseChild(QPDFObjectHandle const& child, size_t level, int flags); | ||
| 361 | + int openObject(int objid = 0); | ||
| 362 | + void closeObject(int objid); | ||
| 363 | + void writeStandard(); | ||
| 364 | + void writeLinearized(); | ||
| 365 | + void writeEncryptionDictionary(); | ||
| 366 | + void writeHeader(); | ||
| 367 | + void writeHintStream(int hint_id); | ||
| 368 | + qpdf_offset_t writeXRefTable(trailer_e which, int first, int last, int size); | ||
| 369 | + qpdf_offset_t writeXRefTable( | ||
| 370 | + trailer_e which, | ||
| 371 | + int first, | ||
| 372 | + int last, | ||
| 373 | + int size, | ||
| 374 | + // for linearization | ||
| 375 | + qpdf_offset_t prev, | ||
| 376 | + bool suppress_offsets, | ||
| 377 | + int hint_id, | ||
| 378 | + qpdf_offset_t hint_offset, | ||
| 379 | + qpdf_offset_t hint_length, | ||
| 380 | + int linearization_pass); | ||
| 381 | + qpdf_offset_t writeXRefStream( | ||
| 382 | + int objid, | ||
| 383 | + int max_id, | ||
| 384 | + qpdf_offset_t max_offset, | ||
| 385 | + trailer_e which, | ||
| 386 | + int first, | ||
| 387 | + int last, | ||
| 388 | + int size); | ||
| 389 | + qpdf_offset_t writeXRefStream( | ||
| 390 | + int objid, | ||
| 391 | + int max_id, | ||
| 392 | + qpdf_offset_t max_offset, | ||
| 393 | + trailer_e which, | ||
| 394 | + int first, | ||
| 395 | + int last, | ||
| 396 | + int size, | ||
| 397 | + // for linearization | ||
| 398 | + qpdf_offset_t prev, | ||
| 399 | + int hint_id, | ||
| 400 | + qpdf_offset_t hint_offset, | ||
| 401 | + qpdf_offset_t hint_length, | ||
| 402 | + bool skip_compression, | ||
| 403 | + int linearization_pass); | ||
| 404 | + | ||
| 405 | + void setDataKey(int objid); | ||
| 406 | + void indicateProgress(bool decrement, bool finished); | ||
| 407 | + size_t calculateXrefStreamPadding(qpdf_offset_t xref_bytes); | ||
| 408 | + | ||
| 409 | + void adjustAESStreamLength(size_t& length); | ||
| 410 | + void computeDeterministicIDData(); | ||
| 411 | + | ||
| 412 | + private: | ||
| 413 | + QPDFWriter& w; | ||
| 274 | QPDF& pdf; | 414 | QPDF& pdf; |
| 275 | QPDFObjGen root_og{-1, 0}; | 415 | QPDFObjGen root_og{-1, 0}; |
| 276 | char const* filename{"unspecified"}; | 416 | char const* filename{"unspecified"}; |
| @@ -341,34 +481,19 @@ class QPDFWriter::Members | @@ -341,34 +481,19 @@ class QPDFWriter::Members | ||
| 341 | int next_progress_report{0}; | 481 | int next_progress_report{0}; |
| 342 | }; | 482 | }; |
| 343 | 483 | ||
| 344 | -QPDFWriter::Members::Members(QPDF& pdf) : | ||
| 345 | - pdf(pdf), | ||
| 346 | - root_og(pdf.getRoot().getObjGen().isIndirect() ? pdf.getRoot().getObjGen() : QPDFObjGen(-1, 0)), | ||
| 347 | - pipeline_stack(pipeline) | ||
| 348 | -{ | ||
| 349 | -} | ||
| 350 | - | ||
| 351 | -QPDFWriter::Members::~Members() | ||
| 352 | -{ | ||
| 353 | - if (file && close_file) { | ||
| 354 | - fclose(file); | ||
| 355 | - } | ||
| 356 | - delete output_buffer; | ||
| 357 | -} | ||
| 358 | - | ||
| 359 | QPDFWriter::QPDFWriter(QPDF& pdf) : | 484 | QPDFWriter::QPDFWriter(QPDF& pdf) : |
| 360 | - m(new Members(pdf)) | 485 | + m(std::make_shared<Members>(*this, pdf)) |
| 361 | { | 486 | { |
| 362 | } | 487 | } |
| 363 | 488 | ||
| 364 | QPDFWriter::QPDFWriter(QPDF& pdf, char const* filename) : | 489 | QPDFWriter::QPDFWriter(QPDF& pdf, char const* filename) : |
| 365 | - m(new Members(pdf)) | 490 | + m(std::make_shared<Members>(*this, pdf)) |
| 366 | { | 491 | { |
| 367 | setOutputFilename(filename); | 492 | setOutputFilename(filename); |
| 368 | } | 493 | } |
| 369 | 494 | ||
| 370 | QPDFWriter::QPDFWriter(QPDF& pdf, char const* description, FILE* file, bool close_file) : | 495 | QPDFWriter::QPDFWriter(QPDF& pdf, char const* description, FILE* file, bool close_file) : |
| 371 | - m(new Members(pdf)) | 496 | + m(std::make_shared<Members>(*this, pdf)) |
| 372 | { | 497 | { |
| 373 | setOutputFile(description, file, close_file); | 498 | setOutputFile(description, file, close_file); |
| 374 | } | 499 | } |
| @@ -381,11 +506,9 @@ QPDFWriter::setOutputFilename(char const* filename) | @@ -381,11 +506,9 @@ QPDFWriter::setOutputFilename(char const* filename) | ||
| 381 | bool close_file = false; | 506 | bool close_file = false; |
| 382 | if (filename == nullptr) { | 507 | if (filename == nullptr) { |
| 383 | description = "standard output"; | 508 | description = "standard output"; |
| 384 | - QTC::TC("qpdf", "QPDFWriter write to stdout"); | ||
| 385 | f = stdout; | 509 | f = stdout; |
| 386 | QUtil::binary_stdout(); | 510 | QUtil::binary_stdout(); |
| 387 | } else { | 511 | } else { |
| 388 | - QTC::TC("qpdf", "QPDFWriter write to file"); | ||
| 389 | f = QUtil::safe_fopen(filename, "wb+"); | 512 | f = QUtil::safe_fopen(filename, "wb+"); |
| 390 | close_file = true; | 513 | close_file = true; |
| 391 | } | 514 | } |
| @@ -508,9 +631,15 @@ QPDFWriter::setNewlineBeforeEndstream(bool val) | @@ -508,9 +631,15 @@ QPDFWriter::setNewlineBeforeEndstream(bool val) | ||
| 508 | void | 631 | void |
| 509 | QPDFWriter::setMinimumPDFVersion(std::string const& version, int extension_level) | 632 | QPDFWriter::setMinimumPDFVersion(std::string const& version, int extension_level) |
| 510 | { | 633 | { |
| 634 | + m->setMinimumPDFVersion(version, extension_level); | ||
| 635 | +} | ||
| 636 | + | ||
| 637 | +void | ||
| 638 | +QPDFWriter::Members::setMinimumPDFVersion(std::string const& version, int extension_level) | ||
| 639 | +{ | ||
| 511 | bool set_version = false; | 640 | bool set_version = false; |
| 512 | bool set_extension_level = false; | 641 | bool set_extension_level = false; |
| 513 | - if (m->min_pdf_version.empty()) { | 642 | + if (min_pdf_version.empty()) { |
| 514 | set_version = true; | 643 | set_version = true; |
| 515 | set_extension_level = true; | 644 | set_extension_level = true; |
| 516 | } else { | 645 | } else { |
| @@ -519,25 +648,24 @@ QPDFWriter::setMinimumPDFVersion(std::string const& version, int extension_level | @@ -519,25 +648,24 @@ QPDFWriter::setMinimumPDFVersion(std::string const& version, int extension_level | ||
| 519 | int min_major = 0; | 648 | int min_major = 0; |
| 520 | int min_minor = 0; | 649 | int min_minor = 0; |
| 521 | parseVersion(version, old_major, old_minor); | 650 | parseVersion(version, old_major, old_minor); |
| 522 | - parseVersion(m->min_pdf_version, min_major, min_minor); | 651 | + parseVersion(min_pdf_version, min_major, min_minor); |
| 523 | int compare = compareVersions(old_major, old_minor, min_major, min_minor); | 652 | int compare = compareVersions(old_major, old_minor, min_major, min_minor); |
| 524 | if (compare > 0) { | 653 | if (compare > 0) { |
| 525 | QTC::TC("qpdf", "QPDFWriter increasing minimum version", extension_level == 0 ? 0 : 1); | 654 | QTC::TC("qpdf", "QPDFWriter increasing minimum version", extension_level == 0 ? 0 : 1); |
| 526 | set_version = true; | 655 | set_version = true; |
| 527 | set_extension_level = true; | 656 | set_extension_level = true; |
| 528 | } else if (compare == 0) { | 657 | } else if (compare == 0) { |
| 529 | - if (extension_level > m->min_extension_level) { | ||
| 530 | - QTC::TC("qpdf", "QPDFWriter increasing extension level"); | 658 | + if (extension_level > min_extension_level) { |
| 531 | set_extension_level = true; | 659 | set_extension_level = true; |
| 532 | } | 660 | } |
| 533 | } | 661 | } |
| 534 | } | 662 | } |
| 535 | 663 | ||
| 536 | if (set_version) { | 664 | if (set_version) { |
| 537 | - m->min_pdf_version = version; | 665 | + min_pdf_version = version; |
| 538 | } | 666 | } |
| 539 | if (set_extension_level) { | 667 | if (set_extension_level) { |
| 540 | - m->min_extension_level = extension_level; | 668 | + min_extension_level = extension_level; |
| 541 | } | 669 | } |
| 542 | } | 670 | } |
| 543 | 671 | ||
| @@ -562,7 +690,6 @@ QPDFWriter::setExtraHeaderText(std::string const& text) | @@ -562,7 +690,6 @@ QPDFWriter::setExtraHeaderText(std::string const& text) | ||
| 562 | { | 690 | { |
| 563 | m->extra_header_text = text; | 691 | m->extra_header_text = text; |
| 564 | if (!m->extra_header_text.empty() && *m->extra_header_text.rbegin() != '\n') { | 692 | if (!m->extra_header_text.empty() && *m->extra_header_text.rbegin() != '\n') { |
| 565 | - QTC::TC("qpdf", "QPDFWriter extra header text add newline"); | ||
| 566 | m->extra_header_text += "\n"; | 693 | m->extra_header_text += "\n"; |
| 567 | } else { | 694 | } else { |
| 568 | QTC::TC("qpdf", "QPDFWriter extra header text no newline"); | 695 | QTC::TC("qpdf", "QPDFWriter extra header text no newline"); |
| @@ -647,7 +774,7 @@ QPDFWriter::setR2EncryptionParametersInsecure( | @@ -647,7 +774,7 @@ QPDFWriter::setR2EncryptionParametersInsecure( | ||
| 647 | if (!allow_annotate) { | 774 | if (!allow_annotate) { |
| 648 | m->encryption->setP(6, false); | 775 | m->encryption->setP(6, false); |
| 649 | } | 776 | } |
| 650 | - setEncryptionParameters(user_password, owner_password); | 777 | + m->setEncryptionParameters(user_password, owner_password); |
| 651 | } | 778 | } |
| 652 | 779 | ||
| 653 | void | 780 | void |
| @@ -663,7 +790,7 @@ QPDFWriter::setR3EncryptionParametersInsecure( | @@ -663,7 +790,7 @@ QPDFWriter::setR3EncryptionParametersInsecure( | ||
| 663 | qpdf_r3_print_e print) | 790 | qpdf_r3_print_e print) |
| 664 | { | 791 | { |
| 665 | m->encryption = std::make_unique<QPDF::EncryptionData>(2, 3, 16, true); | 792 | m->encryption = std::make_unique<QPDF::EncryptionData>(2, 3, 16, true); |
| 666 | - interpretR3EncryptionParameters( | 793 | + m->interpretR3EncryptionParameters( |
| 667 | allow_accessibility, | 794 | allow_accessibility, |
| 668 | allow_extract, | 795 | allow_extract, |
| 669 | allow_assemble, | 796 | allow_assemble, |
| @@ -672,7 +799,7 @@ QPDFWriter::setR3EncryptionParametersInsecure( | @@ -672,7 +799,7 @@ QPDFWriter::setR3EncryptionParametersInsecure( | ||
| 672 | allow_modify_other, | 799 | allow_modify_other, |
| 673 | print, | 800 | print, |
| 674 | qpdf_r3m_all); | 801 | qpdf_r3m_all); |
| 675 | - setEncryptionParameters(user_password, owner_password); | 802 | + m->setEncryptionParameters(user_password, owner_password); |
| 676 | } | 803 | } |
| 677 | 804 | ||
| 678 | void | 805 | void |
| @@ -691,7 +818,7 @@ QPDFWriter::setR4EncryptionParametersInsecure( | @@ -691,7 +818,7 @@ QPDFWriter::setR4EncryptionParametersInsecure( | ||
| 691 | { | 818 | { |
| 692 | m->encryption = std::make_unique<QPDF::EncryptionData>(4, 4, 16, encrypt_metadata); | 819 | m->encryption = std::make_unique<QPDF::EncryptionData>(4, 4, 16, encrypt_metadata); |
| 693 | m->encrypt_use_aes = use_aes; | 820 | m->encrypt_use_aes = use_aes; |
| 694 | - interpretR3EncryptionParameters( | 821 | + m->interpretR3EncryptionParameters( |
| 695 | allow_accessibility, | 822 | allow_accessibility, |
| 696 | allow_extract, | 823 | allow_extract, |
| 697 | allow_assemble, | 824 | allow_assemble, |
| @@ -700,7 +827,7 @@ QPDFWriter::setR4EncryptionParametersInsecure( | @@ -700,7 +827,7 @@ QPDFWriter::setR4EncryptionParametersInsecure( | ||
| 700 | allow_modify_other, | 827 | allow_modify_other, |
| 701 | print, | 828 | print, |
| 702 | qpdf_r3m_all); | 829 | qpdf_r3m_all); |
| 703 | - setEncryptionParameters(user_password, owner_password); | 830 | + m->setEncryptionParameters(user_password, owner_password); |
| 704 | } | 831 | } |
| 705 | 832 | ||
| 706 | void | 833 | void |
| @@ -718,7 +845,7 @@ QPDFWriter::setR5EncryptionParameters( | @@ -718,7 +845,7 @@ QPDFWriter::setR5EncryptionParameters( | ||
| 718 | { | 845 | { |
| 719 | m->encryption = std::make_unique<QPDF::EncryptionData>(5, 5, 32, encrypt_metadata); | 846 | m->encryption = std::make_unique<QPDF::EncryptionData>(5, 5, 32, encrypt_metadata); |
| 720 | m->encrypt_use_aes = true; | 847 | m->encrypt_use_aes = true; |
| 721 | - interpretR3EncryptionParameters( | 848 | + m->interpretR3EncryptionParameters( |
| 722 | allow_accessibility, | 849 | allow_accessibility, |
| 723 | allow_extract, | 850 | allow_extract, |
| 724 | allow_assemble, | 851 | allow_assemble, |
| @@ -727,7 +854,7 @@ QPDFWriter::setR5EncryptionParameters( | @@ -727,7 +854,7 @@ QPDFWriter::setR5EncryptionParameters( | ||
| 727 | allow_modify_other, | 854 | allow_modify_other, |
| 728 | print, | 855 | print, |
| 729 | qpdf_r3m_all); | 856 | qpdf_r3m_all); |
| 730 | - setEncryptionParameters(user_password, owner_password); | 857 | + m->setEncryptionParameters(user_password, owner_password); |
| 731 | } | 858 | } |
| 732 | 859 | ||
| 733 | void | 860 | void |
| @@ -744,7 +871,7 @@ QPDFWriter::setR6EncryptionParameters( | @@ -744,7 +871,7 @@ QPDFWriter::setR6EncryptionParameters( | ||
| 744 | bool encrypt_metadata) | 871 | bool encrypt_metadata) |
| 745 | { | 872 | { |
| 746 | m->encryption = std::make_unique<QPDF::EncryptionData>(5, 6, 32, encrypt_metadata); | 873 | m->encryption = std::make_unique<QPDF::EncryptionData>(5, 6, 32, encrypt_metadata); |
| 747 | - interpretR3EncryptionParameters( | 874 | + m->interpretR3EncryptionParameters( |
| 748 | allow_accessibility, | 875 | allow_accessibility, |
| 749 | allow_extract, | 876 | allow_extract, |
| 750 | allow_assemble, | 877 | allow_assemble, |
| @@ -754,11 +881,11 @@ QPDFWriter::setR6EncryptionParameters( | @@ -754,11 +881,11 @@ QPDFWriter::setR6EncryptionParameters( | ||
| 754 | print, | 881 | print, |
| 755 | qpdf_r3m_all); | 882 | qpdf_r3m_all); |
| 756 | m->encrypt_use_aes = true; | 883 | m->encrypt_use_aes = true; |
| 757 | - setEncryptionParameters(user_password, owner_password); | 884 | + m->setEncryptionParameters(user_password, owner_password); |
| 758 | } | 885 | } |
| 759 | 886 | ||
| 760 | void | 887 | void |
| 761 | -QPDFWriter::interpretR3EncryptionParameters( | 888 | +QPDFWriter::Members::interpretR3EncryptionParameters( |
| 762 | bool allow_accessibility, | 889 | bool allow_accessibility, |
| 763 | bool allow_extract, | 890 | bool allow_extract, |
| 764 | bool allow_assemble, | 891 | bool allow_assemble, |
| @@ -797,21 +924,21 @@ QPDFWriter::interpretR3EncryptionParameters( | @@ -797,21 +924,21 @@ QPDFWriter::interpretR3EncryptionParameters( | ||
| 797 | // 10: accessibility; ignored by readers, should always be set | 924 | // 10: accessibility; ignored by readers, should always be set |
| 798 | // 11: document assembly even if 4 is clear | 925 | // 11: document assembly even if 4 is clear |
| 799 | // 12: high-resolution printing | 926 | // 12: high-resolution printing |
| 800 | - if (!allow_accessibility && m->encryption->getR() <= 3) { | 927 | + if (!allow_accessibility && encryption->getR() <= 3) { |
| 801 | // Bit 10 is deprecated and should always be set. This used to mean accessibility. There | 928 | // Bit 10 is deprecated and should always be set. This used to mean accessibility. There |
| 802 | // is no way to disable accessibility with R > 3. | 929 | // is no way to disable accessibility with R > 3. |
| 803 | - m->encryption->setP(10, false); | 930 | + encryption->setP(10, false); |
| 804 | } | 931 | } |
| 805 | if (!allow_extract) { | 932 | if (!allow_extract) { |
| 806 | - m->encryption->setP(5, false); | 933 | + encryption->setP(5, false); |
| 807 | } | 934 | } |
| 808 | 935 | ||
| 809 | switch (print) { | 936 | switch (print) { |
| 810 | case qpdf_r3p_none: | 937 | case qpdf_r3p_none: |
| 811 | - m->encryption->setP(3, false); // any printing | 938 | + encryption->setP(3, false); // any printing |
| 812 | [[fallthrough]]; | 939 | [[fallthrough]]; |
| 813 | case qpdf_r3p_low: | 940 | case qpdf_r3p_low: |
| 814 | - m->encryption->setP(12, false); // high resolution printing | 941 | + encryption->setP(12, false); // high resolution printing |
| 815 | [[fallthrough]]; | 942 | [[fallthrough]]; |
| 816 | case qpdf_r3p_full: | 943 | case qpdf_r3p_full: |
| 817 | break; | 944 | break; |
| @@ -825,16 +952,16 @@ QPDFWriter::interpretR3EncryptionParameters( | @@ -825,16 +952,16 @@ QPDFWriter::interpretR3EncryptionParameters( | ||
| 825 | // NOT EXERCISED IN TEST SUITE | 952 | // NOT EXERCISED IN TEST SUITE |
| 826 | switch (modify) { | 953 | switch (modify) { |
| 827 | case qpdf_r3m_none: | 954 | case qpdf_r3m_none: |
| 828 | - m->encryption->setP(11, false); // document assembly | 955 | + encryption->setP(11, false); // document assembly |
| 829 | [[fallthrough]]; | 956 | [[fallthrough]]; |
| 830 | case qpdf_r3m_assembly: | 957 | case qpdf_r3m_assembly: |
| 831 | - m->encryption->setP(9, false); // filling in form fields | 958 | + encryption->setP(9, false); // filling in form fields |
| 832 | [[fallthrough]]; | 959 | [[fallthrough]]; |
| 833 | case qpdf_r3m_form: | 960 | case qpdf_r3m_form: |
| 834 | - m->encryption->setP(6, false); // modify annotations, fill in form fields | 961 | + encryption->setP(6, false); // modify annotations, fill in form fields |
| 835 | [[fallthrough]]; | 962 | [[fallthrough]]; |
| 836 | case qpdf_r3m_annotate: | 963 | case qpdf_r3m_annotate: |
| 837 | - m->encryption->setP(4, false); // other modifications | 964 | + encryption->setP(4, false); // other modifications |
| 838 | [[fallthrough]]; | 965 | [[fallthrough]]; |
| 839 | case qpdf_r3m_all: | 966 | case qpdf_r3m_all: |
| 840 | break; | 967 | break; |
| @@ -843,36 +970,42 @@ QPDFWriter::interpretR3EncryptionParameters( | @@ -843,36 +970,42 @@ QPDFWriter::interpretR3EncryptionParameters( | ||
| 843 | // END NOT EXERCISED IN TEST SUITE | 970 | // END NOT EXERCISED IN TEST SUITE |
| 844 | 971 | ||
| 845 | if (!allow_assemble) { | 972 | if (!allow_assemble) { |
| 846 | - m->encryption->setP(11, false); | 973 | + encryption->setP(11, false); |
| 847 | } | 974 | } |
| 848 | if (!allow_annotate_and_form) { | 975 | if (!allow_annotate_and_form) { |
| 849 | - m->encryption->setP(6, false); | 976 | + encryption->setP(6, false); |
| 850 | } | 977 | } |
| 851 | if (!allow_form_filling) { | 978 | if (!allow_form_filling) { |
| 852 | - m->encryption->setP(9, false); | 979 | + encryption->setP(9, false); |
| 853 | } | 980 | } |
| 854 | if (!allow_modify_other) { | 981 | if (!allow_modify_other) { |
| 855 | - m->encryption->setP(4, false); | 982 | + encryption->setP(4, false); |
| 856 | } | 983 | } |
| 857 | } | 984 | } |
| 858 | 985 | ||
| 859 | void | 986 | void |
| 860 | -QPDFWriter::setEncryptionParameters(char const* user_password, char const* owner_password) | 987 | +QPDFWriter::Members::setEncryptionParameters(char const* user_password, char const* owner_password) |
| 861 | { | 988 | { |
| 862 | generateID(true); | 989 | generateID(true); |
| 863 | - m->encryption->setId1(m->id1); | ||
| 864 | - m->encryption_key = m->encryption->compute_parameters(user_password, owner_password); | 990 | + encryption->setId1(id1); |
| 991 | + encryption_key = encryption->compute_parameters(user_password, owner_password); | ||
| 865 | setEncryptionMinimumVersion(); | 992 | setEncryptionMinimumVersion(); |
| 866 | } | 993 | } |
| 867 | 994 | ||
| 868 | void | 995 | void |
| 869 | QPDFWriter::copyEncryptionParameters(QPDF& qpdf) | 996 | QPDFWriter::copyEncryptionParameters(QPDF& qpdf) |
| 870 | { | 997 | { |
| 871 | - m->preserve_encryption = false; | 998 | + m->copyEncryptionParameters(qpdf); |
| 999 | +} | ||
| 1000 | + | ||
| 1001 | +void | ||
| 1002 | +QPDFWriter::Members::copyEncryptionParameters(QPDF& qpdf) | ||
| 1003 | +{ | ||
| 1004 | + preserve_encryption = false; | ||
| 872 | QPDFObjectHandle trailer = qpdf.getTrailer(); | 1005 | QPDFObjectHandle trailer = qpdf.getTrailer(); |
| 873 | if (trailer.hasKey("/Encrypt")) { | 1006 | if (trailer.hasKey("/Encrypt")) { |
| 874 | generateID(true); | 1007 | generateID(true); |
| 875 | - m->id1 = trailer.getKey("/ID").getArrayItem(0).getStringValue(); | 1008 | + id1 = trailer.getKey("/ID").getArrayItem(0).getStringValue(); |
| 876 | QPDFObjectHandle encrypt = trailer.getKey("/Encrypt"); | 1009 | QPDFObjectHandle encrypt = trailer.getKey("/Encrypt"); |
| 877 | int V = encrypt.getKey("/V").getIntValueAsInt(); | 1010 | int V = encrypt.getKey("/V").getIntValueAsInt(); |
| 878 | int key_len = 5; | 1011 | int key_len = 5; |
| @@ -888,12 +1021,12 @@ QPDFWriter::copyEncryptionParameters(QPDF& qpdf) | @@ -888,12 +1021,12 @@ QPDFWriter::copyEncryptionParameters(QPDF& qpdf) | ||
| 888 | // Acrobat doesn't create files with V >= 4 that don't use AES, and the logic of | 1021 | // Acrobat doesn't create files with V >= 4 that don't use AES, and the logic of |
| 889 | // figuring out whether AES is used or not is complicated with /StmF, /StrF, and /EFF | 1022 | // figuring out whether AES is used or not is complicated with /StmF, /StrF, and /EFF |
| 890 | // all potentially having different values. | 1023 | // all potentially having different values. |
| 891 | - m->encrypt_use_aes = true; | 1024 | + encrypt_use_aes = true; |
| 892 | } | 1025 | } |
| 893 | QTC::TC("qpdf", "QPDFWriter copy encrypt metadata", encrypt_metadata ? 0 : 1); | 1026 | QTC::TC("qpdf", "QPDFWriter copy encrypt metadata", encrypt_metadata ? 0 : 1); |
| 894 | - QTC::TC("qpdf", "QPDFWriter copy use_aes", m->encrypt_use_aes ? 0 : 1); | 1027 | + QTC::TC("qpdf", "QPDFWriter copy use_aes", encrypt_use_aes ? 0 : 1); |
| 895 | 1028 | ||
| 896 | - m->encryption = std::make_unique<QPDF::EncryptionData>( | 1029 | + encryption = std::make_unique<QPDF::EncryptionData>( |
| 897 | V, | 1030 | V, |
| 898 | encrypt.getKey("/R").getIntValueAsInt(), | 1031 | encrypt.getKey("/R").getIntValueAsInt(), |
| 899 | key_len, | 1032 | key_len, |
| @@ -903,54 +1036,53 @@ QPDFWriter::copyEncryptionParameters(QPDF& qpdf) | @@ -903,54 +1036,53 @@ QPDFWriter::copyEncryptionParameters(QPDF& qpdf) | ||
| 903 | V < 5 ? "" : encrypt.getKey("/OE").getStringValue(), | 1036 | V < 5 ? "" : encrypt.getKey("/OE").getStringValue(), |
| 904 | V < 5 ? "" : encrypt.getKey("/UE").getStringValue(), | 1037 | V < 5 ? "" : encrypt.getKey("/UE").getStringValue(), |
| 905 | V < 5 ? "" : encrypt.getKey("/Perms").getStringValue(), | 1038 | V < 5 ? "" : encrypt.getKey("/Perms").getStringValue(), |
| 906 | - m->id1, // m->id1 == the other file's id1 | 1039 | + id1, // id1 == the other file's id1 |
| 907 | encrypt_metadata); | 1040 | encrypt_metadata); |
| 908 | - m->encryption_key = V >= 5 | ||
| 909 | - ? qpdf.getEncryptionKey() | ||
| 910 | - : m->encryption->compute_encryption_key(qpdf.getPaddedUserPassword()); | 1041 | + encryption_key = V >= 5 ? qpdf.getEncryptionKey() |
| 1042 | + : encryption->compute_encryption_key(qpdf.getPaddedUserPassword()); | ||
| 911 | setEncryptionMinimumVersion(); | 1043 | setEncryptionMinimumVersion(); |
| 912 | } | 1044 | } |
| 913 | } | 1045 | } |
| 914 | 1046 | ||
| 915 | void | 1047 | void |
| 916 | -QPDFWriter::disableIncompatibleEncryption(int major, int minor, int extension_level) | 1048 | +QPDFWriter::Members::disableIncompatibleEncryption(int major, int minor, int extension_level) |
| 917 | { | 1049 | { |
| 918 | - if (!m->encryption) { | 1050 | + if (!encryption) { |
| 919 | return; | 1051 | return; |
| 920 | } | 1052 | } |
| 921 | if (compareVersions(major, minor, 1, 3) < 0) { | 1053 | if (compareVersions(major, minor, 1, 3) < 0) { |
| 922 | - m->encryption = nullptr; | 1054 | + encryption = nullptr; |
| 923 | return; | 1055 | return; |
| 924 | } | 1056 | } |
| 925 | - int V = m->encryption->getV(); | ||
| 926 | - int R = m->encryption->getR(); | 1057 | + int V = encryption->getV(); |
| 1058 | + int R = encryption->getR(); | ||
| 927 | if (compareVersions(major, minor, 1, 4) < 0) { | 1059 | if (compareVersions(major, minor, 1, 4) < 0) { |
| 928 | if (V > 1 || R > 2) { | 1060 | if (V > 1 || R > 2) { |
| 929 | - m->encryption = nullptr; | 1061 | + encryption = nullptr; |
| 930 | } | 1062 | } |
| 931 | } else if (compareVersions(major, minor, 1, 5) < 0) { | 1063 | } else if (compareVersions(major, minor, 1, 5) < 0) { |
| 932 | if (V > 2 || R > 3) { | 1064 | if (V > 2 || R > 3) { |
| 933 | - m->encryption = nullptr; | 1065 | + encryption = nullptr; |
| 934 | } | 1066 | } |
| 935 | } else if (compareVersions(major, minor, 1, 6) < 0) { | 1067 | } else if (compareVersions(major, minor, 1, 6) < 0) { |
| 936 | - if (m->encrypt_use_aes) { | ||
| 937 | - m->encryption = nullptr; | 1068 | + if (encrypt_use_aes) { |
| 1069 | + encryption = nullptr; | ||
| 938 | } | 1070 | } |
| 939 | } else if ( | 1071 | } else if ( |
| 940 | (compareVersions(major, minor, 1, 7) < 0) || | 1072 | (compareVersions(major, minor, 1, 7) < 0) || |
| 941 | ((compareVersions(major, minor, 1, 7) == 0) && extension_level < 3)) { | 1073 | ((compareVersions(major, minor, 1, 7) == 0) && extension_level < 3)) { |
| 942 | if (V >= 5 || R >= 5) { | 1074 | if (V >= 5 || R >= 5) { |
| 943 | - m->encryption = nullptr; | 1075 | + encryption = nullptr; |
| 944 | } | 1076 | } |
| 945 | } | 1077 | } |
| 946 | 1078 | ||
| 947 | - if (!m->encryption) { | 1079 | + if (!encryption) { |
| 948 | QTC::TC("qpdf", "QPDFWriter forced version disabled encryption"); | 1080 | QTC::TC("qpdf", "QPDFWriter forced version disabled encryption"); |
| 949 | } | 1081 | } |
| 950 | } | 1082 | } |
| 951 | 1083 | ||
| 952 | void | 1084 | void |
| 953 | -QPDFWriter::parseVersion(std::string const& version, int& major, int& minor) const | 1085 | +QPDFWriter::Members::parseVersion(std::string const& version, int& major, int& minor) const |
| 954 | { | 1086 | { |
| 955 | major = QUtil::string_to_int(version.c_str()); | 1087 | major = QUtil::string_to_int(version.c_str()); |
| 956 | minor = 0; | 1088 | minor = 0; |
| @@ -967,54 +1099,48 @@ QPDFWriter::parseVersion(std::string const& version, int& major, int& minor) con | @@ -967,54 +1099,48 @@ QPDFWriter::parseVersion(std::string const& version, int& major, int& minor) con | ||
| 967 | } | 1099 | } |
| 968 | 1100 | ||
| 969 | int | 1101 | int |
| 970 | -QPDFWriter::compareVersions(int major1, int minor1, int major2, int minor2) const | 1102 | +QPDFWriter::Members::compareVersions(int major1, int minor1, int major2, int minor2) const |
| 971 | { | 1103 | { |
| 972 | if (major1 < major2) { | 1104 | if (major1 < major2) { |
| 973 | return -1; | 1105 | return -1; |
| 974 | - } else if (major1 > major2) { | 1106 | + } |
| 1107 | + if (major1 > major2) { | ||
| 975 | return 1; | 1108 | return 1; |
| 976 | - } else if (minor1 < minor2) { | 1109 | + } |
| 1110 | + if (minor1 < minor2) { | ||
| 977 | return -1; | 1111 | return -1; |
| 978 | - } else if (minor1 > minor2) { | ||
| 979 | - return 1; | ||
| 980 | - } else { | ||
| 981 | - return 0; | ||
| 982 | } | 1112 | } |
| 1113 | + return minor1 > minor2 ? 1 : 0; | ||
| 983 | } | 1114 | } |
| 984 | 1115 | ||
| 985 | void | 1116 | void |
| 986 | -QPDFWriter::setEncryptionMinimumVersion() | 1117 | +QPDFWriter::Members::setEncryptionMinimumVersion() |
| 987 | { | 1118 | { |
| 988 | - auto const R = m->encryption->getR(); | 1119 | + auto const R = encryption->getR(); |
| 989 | if (R >= 6) { | 1120 | if (R >= 6) { |
| 990 | - setMinimumPDFVersion("1.7", 8); | 1121 | + w.setMinimumPDFVersion("1.7", 8); |
| 991 | } else if (R == 5) { | 1122 | } else if (R == 5) { |
| 992 | - setMinimumPDFVersion("1.7", 3); | 1123 | + w.setMinimumPDFVersion("1.7", 3); |
| 993 | } else if (R == 4) { | 1124 | } else if (R == 4) { |
| 994 | - setMinimumPDFVersion(m->encrypt_use_aes ? "1.6" : "1.5"); | 1125 | + w.setMinimumPDFVersion(encrypt_use_aes ? "1.6" : "1.5"); |
| 995 | } else if (R == 3) { | 1126 | } else if (R == 3) { |
| 996 | - setMinimumPDFVersion("1.4"); | 1127 | + w.setMinimumPDFVersion("1.4"); |
| 997 | } else { | 1128 | } else { |
| 998 | - setMinimumPDFVersion("1.3"); | 1129 | + w.setMinimumPDFVersion("1.3"); |
| 999 | } | 1130 | } |
| 1000 | } | 1131 | } |
| 1001 | 1132 | ||
| 1002 | void | 1133 | void |
| 1003 | -QPDFWriter::setDataKey(int objid) | 1134 | +QPDFWriter::Members::setDataKey(int objid) |
| 1004 | { | 1135 | { |
| 1005 | - if (m->encryption) { | ||
| 1006 | - m->cur_data_key = QPDF::compute_data_key( | ||
| 1007 | - m->encryption_key, | ||
| 1008 | - objid, | ||
| 1009 | - 0, | ||
| 1010 | - m->encrypt_use_aes, | ||
| 1011 | - m->encryption->getV(), | ||
| 1012 | - m->encryption->getR()); | 1136 | + if (encryption) { |
| 1137 | + cur_data_key = QPDF::compute_data_key( | ||
| 1138 | + encryption_key, objid, 0, encrypt_use_aes, encryption->getV(), encryption->getR()); | ||
| 1013 | } | 1139 | } |
| 1014 | } | 1140 | } |
| 1015 | 1141 | ||
| 1016 | unsigned int | 1142 | unsigned int |
| 1017 | -QPDFWriter::bytesNeeded(long long n) | 1143 | +QPDFWriter::Members::bytesNeeded(long long n) |
| 1018 | { | 1144 | { |
| 1019 | unsigned int bytes = 0; | 1145 | unsigned int bytes = 0; |
| 1020 | while (n) { | 1146 | while (n) { |
| @@ -1025,7 +1151,7 @@ QPDFWriter::bytesNeeded(long long n) | @@ -1025,7 +1151,7 @@ QPDFWriter::bytesNeeded(long long n) | ||
| 1025 | } | 1151 | } |
| 1026 | 1152 | ||
| 1027 | void | 1153 | void |
| 1028 | -QPDFWriter::writeBinary(unsigned long long val, unsigned int bytes) | 1154 | +QPDFWriter::Members::writeBinary(unsigned long long val, unsigned int bytes) |
| 1029 | { | 1155 | { |
| 1030 | if (bytes > sizeof(unsigned long long)) { | 1156 | if (bytes > sizeof(unsigned long long)) { |
| 1031 | throw std::logic_error("QPDFWriter::writeBinary called with too many bytes"); | 1157 | throw std::logic_error("QPDFWriter::writeBinary called with too many bytes"); |
| @@ -1035,191 +1161,189 @@ QPDFWriter::writeBinary(unsigned long long val, unsigned int bytes) | @@ -1035,191 +1161,189 @@ QPDFWriter::writeBinary(unsigned long long val, unsigned int bytes) | ||
| 1035 | data[bytes - i - 1] = static_cast<unsigned char>(val & 0xff); | 1161 | data[bytes - i - 1] = static_cast<unsigned char>(val & 0xff); |
| 1036 | val >>= 8; | 1162 | val >>= 8; |
| 1037 | } | 1163 | } |
| 1038 | - m->pipeline->write(data, bytes); | 1164 | + pipeline->write(data, bytes); |
| 1039 | } | 1165 | } |
| 1040 | 1166 | ||
| 1041 | -QPDFWriter& | ||
| 1042 | -QPDFWriter::write(std::string_view str) | 1167 | +QPDFWriter::Members& |
| 1168 | +QPDFWriter::Members::write(std::string_view str) | ||
| 1043 | { | 1169 | { |
| 1044 | - m->pipeline->write(str); | 1170 | + pipeline->write(str); |
| 1045 | return *this; | 1171 | return *this; |
| 1046 | } | 1172 | } |
| 1047 | 1173 | ||
| 1048 | -QPDFWriter& | ||
| 1049 | -QPDFWriter::write(std::integral auto val) | 1174 | +QPDFWriter::Members& |
| 1175 | +QPDFWriter::Members::write(std::integral auto val) | ||
| 1050 | { | 1176 | { |
| 1051 | - m->pipeline->write(std::to_string(val)); | 1177 | + pipeline->write(std::to_string(val)); |
| 1052 | return *this; | 1178 | return *this; |
| 1053 | } | 1179 | } |
| 1054 | 1180 | ||
| 1055 | -QPDFWriter& | ||
| 1056 | -QPDFWriter::write(size_t count, char c) | 1181 | +QPDFWriter::Members& |
| 1182 | +QPDFWriter::Members::write(size_t count, char c) | ||
| 1057 | { | 1183 | { |
| 1058 | - m->pipeline->write(count, c); | 1184 | + pipeline->write(count, c); |
| 1059 | return *this; | 1185 | return *this; |
| 1060 | } | 1186 | } |
| 1061 | 1187 | ||
| 1062 | -QPDFWriter& | ||
| 1063 | -QPDFWriter::write_name(std::string const& str) | 1188 | +QPDFWriter::Members& |
| 1189 | +QPDFWriter::Members::write_name(std::string const& str) | ||
| 1064 | { | 1190 | { |
| 1065 | - m->pipeline->write(Name::normalize(str)); | 1191 | + pipeline->write(Name::normalize(str)); |
| 1066 | return *this; | 1192 | return *this; |
| 1067 | } | 1193 | } |
| 1068 | 1194 | ||
| 1069 | -QPDFWriter& | ||
| 1070 | -QPDFWriter::write_string(std::string const& str, bool force_binary) | 1195 | +QPDFWriter::Members& |
| 1196 | +QPDFWriter::Members::write_string(std::string const& str, bool force_binary) | ||
| 1071 | { | 1197 | { |
| 1072 | - m->pipeline->write(QPDF_String(str).unparse(force_binary)); | 1198 | + pipeline->write(QPDF_String(str).unparse(force_binary)); |
| 1073 | return *this; | 1199 | return *this; |
| 1074 | } | 1200 | } |
| 1075 | 1201 | ||
| 1076 | template <typename... Args> | 1202 | template <typename... Args> |
| 1077 | -QPDFWriter& | ||
| 1078 | -QPDFWriter::write_qdf(Args&&... args) | 1203 | +QPDFWriter::Members& |
| 1204 | +QPDFWriter::Members::write_qdf(Args&&... args) | ||
| 1079 | { | 1205 | { |
| 1080 | - if (m->qdf_mode) { | ||
| 1081 | - m->pipeline->write(std::forward<Args>(args)...); | 1206 | + if (qdf_mode) { |
| 1207 | + pipeline->write(std::forward<Args>(args)...); | ||
| 1082 | } | 1208 | } |
| 1083 | return *this; | 1209 | return *this; |
| 1084 | } | 1210 | } |
| 1085 | 1211 | ||
| 1086 | template <typename... Args> | 1212 | template <typename... Args> |
| 1087 | -QPDFWriter& | ||
| 1088 | -QPDFWriter::write_no_qdf(Args&&... args) | 1213 | +QPDFWriter::Members& |
| 1214 | +QPDFWriter::Members::write_no_qdf(Args&&... args) | ||
| 1089 | { | 1215 | { |
| 1090 | - if (!m->qdf_mode) { | ||
| 1091 | - m->pipeline->write(std::forward<Args>(args)...); | 1216 | + if (!qdf_mode) { |
| 1217 | + pipeline->write(std::forward<Args>(args)...); | ||
| 1092 | } | 1218 | } |
| 1093 | return *this; | 1219 | return *this; |
| 1094 | } | 1220 | } |
| 1095 | 1221 | ||
| 1096 | void | 1222 | void |
| 1097 | -QPDFWriter::adjustAESStreamLength(size_t& length) | 1223 | +QPDFWriter::Members::adjustAESStreamLength(size_t& length) |
| 1098 | { | 1224 | { |
| 1099 | - if (m->encryption && !m->cur_data_key.empty() && m->encrypt_use_aes) { | 1225 | + if (encryption && !cur_data_key.empty() && encrypt_use_aes) { |
| 1100 | // Stream length will be padded with 1 to 16 bytes to end up as a multiple of 16. It will | 1226 | // Stream length will be padded with 1 to 16 bytes to end up as a multiple of 16. It will |
| 1101 | // also be prepended by 16 bits of random data. | 1227 | // also be prepended by 16 bits of random data. |
| 1102 | length += 32 - (length & 0xf); | 1228 | length += 32 - (length & 0xf); |
| 1103 | } | 1229 | } |
| 1104 | } | 1230 | } |
| 1105 | 1231 | ||
| 1106 | -QPDFWriter& | ||
| 1107 | -QPDFWriter::write_encrypted(std::string_view str) | 1232 | +QPDFWriter::Members& |
| 1233 | +QPDFWriter::Members::write_encrypted(std::string_view str) | ||
| 1108 | { | 1234 | { |
| 1109 | - if (!(m->encryption && !m->cur_data_key.empty())) { | 1235 | + if (!(encryption && !cur_data_key.empty())) { |
| 1110 | write(str); | 1236 | write(str); |
| 1111 | - } else if (m->encrypt_use_aes) { | ||
| 1112 | - write(pl::pipe<Pl_AES_PDF>(str, true, m->cur_data_key)); | 1237 | + } else if (encrypt_use_aes) { |
| 1238 | + write(pl::pipe<Pl_AES_PDF>(str, true, cur_data_key)); | ||
| 1113 | } else { | 1239 | } else { |
| 1114 | - write(pl::pipe<Pl_RC4>(str, m->cur_data_key)); | 1240 | + write(pl::pipe<Pl_RC4>(str, cur_data_key)); |
| 1115 | } | 1241 | } |
| 1116 | 1242 | ||
| 1117 | return *this; | 1243 | return *this; |
| 1118 | } | 1244 | } |
| 1119 | 1245 | ||
| 1120 | void | 1246 | void |
| 1121 | -QPDFWriter::computeDeterministicIDData() | 1247 | +QPDFWriter::Members::computeDeterministicIDData() |
| 1122 | { | 1248 | { |
| 1123 | - if (!m->id2.empty()) { | 1249 | + if (!id2.empty()) { |
| 1124 | // Can't happen in the code | 1250 | // Can't happen in the code |
| 1125 | throw std::logic_error( | 1251 | throw std::logic_error( |
| 1126 | "Deterministic ID computation enabled after ID generation has already occurred."); | 1252 | "Deterministic ID computation enabled after ID generation has already occurred."); |
| 1127 | } | 1253 | } |
| 1128 | - qpdf_assert_debug(m->deterministic_id_data.empty()); | ||
| 1129 | - m->deterministic_id_data = m->pipeline_stack.hex_digest(); | 1254 | + qpdf_assert_debug(deterministic_id_data.empty()); |
| 1255 | + deterministic_id_data = pipeline_stack.hex_digest(); | ||
| 1130 | } | 1256 | } |
| 1131 | 1257 | ||
| 1132 | int | 1258 | int |
| 1133 | -QPDFWriter::openObject(int objid) | 1259 | +QPDFWriter::Members::openObject(int objid) |
| 1134 | { | 1260 | { |
| 1135 | if (objid == 0) { | 1261 | if (objid == 0) { |
| 1136 | - objid = m->next_objid++; | 1262 | + objid = next_objid++; |
| 1137 | } | 1263 | } |
| 1138 | - m->new_obj[objid].xref = QPDFXRefEntry(m->pipeline->getCount()); | 1264 | + new_obj[objid].xref = QPDFXRefEntry(pipeline->getCount()); |
| 1139 | write(objid).write(" 0 obj\n"); | 1265 | write(objid).write(" 0 obj\n"); |
| 1140 | return objid; | 1266 | return objid; |
| 1141 | } | 1267 | } |
| 1142 | 1268 | ||
| 1143 | void | 1269 | void |
| 1144 | -QPDFWriter::closeObject(int objid) | 1270 | +QPDFWriter::Members::closeObject(int objid) |
| 1145 | { | 1271 | { |
| 1146 | // Write a newline before endobj as it makes the file easier to repair. | 1272 | // Write a newline before endobj as it makes the file easier to repair. |
| 1147 | write("\nendobj\n").write_qdf("\n"); | 1273 | write("\nendobj\n").write_qdf("\n"); |
| 1148 | - auto& new_obj = m->new_obj[objid]; | ||
| 1149 | - new_obj.length = m->pipeline->getCount() - new_obj.xref.getOffset(); | 1274 | + auto& no = new_obj[objid]; |
| 1275 | + no.length = pipeline->getCount() - no.xref.getOffset(); | ||
| 1150 | } | 1276 | } |
| 1151 | 1277 | ||
| 1152 | void | 1278 | void |
| 1153 | -QPDFWriter::assignCompressedObjectNumbers(QPDFObjGen og) | 1279 | +QPDFWriter::Members::assignCompressedObjectNumbers(QPDFObjGen og) |
| 1154 | { | 1280 | { |
| 1155 | int objid = og.getObj(); | 1281 | int objid = og.getObj(); |
| 1156 | - if ((og.getGen() != 0) || (!m->object_stream_to_objects.contains(objid))) { | 1282 | + if (og.getGen() != 0 || !object_stream_to_objects.contains(objid)) { |
| 1157 | // This is not an object stream. | 1283 | // This is not an object stream. |
| 1158 | return; | 1284 | return; |
| 1159 | } | 1285 | } |
| 1160 | 1286 | ||
| 1161 | // Reserve numbers for the objects that belong to this object stream. | 1287 | // Reserve numbers for the objects that belong to this object stream. |
| 1162 | - for (auto const& iter: m->object_stream_to_objects[objid]) { | ||
| 1163 | - m->obj[iter].renumber = m->next_objid++; | 1288 | + for (auto const& iter: object_stream_to_objects[objid]) { |
| 1289 | + obj[iter].renumber = next_objid++; | ||
| 1164 | } | 1290 | } |
| 1165 | } | 1291 | } |
| 1166 | 1292 | ||
| 1167 | void | 1293 | void |
| 1168 | -QPDFWriter::enqueueObject(QPDFObjectHandle object) | 1294 | +QPDFWriter::Members::enqueueObject(QPDFObjectHandle object) |
| 1169 | { | 1295 | { |
| 1170 | if (object.isIndirect()) { | 1296 | if (object.isIndirect()) { |
| 1171 | // This owner check can only be done for indirect objects. It is possible for a direct | 1297 | // This owner check can only be done for indirect objects. It is possible for a direct |
| 1172 | // object to have an owning QPDF that is from another file if a direct QPDFObjectHandle from | 1298 | // object to have an owning QPDF that is from another file if a direct QPDFObjectHandle from |
| 1173 | // one file was insert into another file without copying. Doing that is safe even if the | 1299 | // one file was insert into another file without copying. Doing that is safe even if the |
| 1174 | // original QPDF gets destroyed, which just disconnects the QPDFObjectHandle from its owner. | 1300 | // original QPDF gets destroyed, which just disconnects the QPDFObjectHandle from its owner. |
| 1175 | - if (object.getOwningQPDF() != &(m->pdf)) { | ||
| 1176 | - QTC::TC("qpdf", "QPDFWriter foreign object"); | 1301 | + if (object.getOwningQPDF() != &pdf) { |
| 1177 | throw std::logic_error( | 1302 | throw std::logic_error( |
| 1178 | "QPDFObjectHandle from different QPDF found while writing. Use " | 1303 | "QPDFObjectHandle from different QPDF found while writing. Use " |
| 1179 | "QPDF::copyForeignObject to add objects from another file."); | 1304 | "QPDF::copyForeignObject to add objects from another file."); |
| 1180 | } | 1305 | } |
| 1181 | 1306 | ||
| 1182 | - if (m->qdf_mode && object.isStreamOfType("/XRef")) { | 1307 | + if (qdf_mode && object.isStreamOfType("/XRef")) { |
| 1183 | // As a special case, do not output any extraneous XRef streams in QDF mode. Doing so | 1308 | // As a special case, do not output any extraneous XRef streams in QDF mode. Doing so |
| 1184 | // will confuse fix-qdf, which expects to see only one XRef stream at the end of the | 1309 | // will confuse fix-qdf, which expects to see only one XRef stream at the end of the |
| 1185 | // file. This case can occur when creating a QDF from a file with object streams when | 1310 | // file. This case can occur when creating a QDF from a file with object streams when |
| 1186 | // preserving unreferenced objects since the old cross reference streams are not | 1311 | // preserving unreferenced objects since the old cross reference streams are not |
| 1187 | // actually referenced by object number. | 1312 | // actually referenced by object number. |
| 1188 | - QTC::TC("qpdf", "QPDFWriter ignore XRef in qdf mode"); | ||
| 1189 | return; | 1313 | return; |
| 1190 | } | 1314 | } |
| 1191 | 1315 | ||
| 1192 | QPDFObjGen og = object.getObjGen(); | 1316 | QPDFObjGen og = object.getObjGen(); |
| 1193 | - auto& obj = m->obj[og]; | 1317 | + auto& o = obj[og]; |
| 1194 | 1318 | ||
| 1195 | - if (obj.renumber == 0) { | ||
| 1196 | - if (obj.object_stream > 0) { | 1319 | + if (o.renumber == 0) { |
| 1320 | + if (o.object_stream > 0) { | ||
| 1197 | // This is in an object stream. Don't process it here. Instead, enqueue the object | 1321 | // This is in an object stream. Don't process it here. Instead, enqueue the object |
| 1198 | // stream. Object streams always have generation 0. | 1322 | // stream. Object streams always have generation 0. |
| 1199 | // Detect loops by storing invalid object ID -1, which will get overwritten later. | 1323 | // Detect loops by storing invalid object ID -1, which will get overwritten later. |
| 1200 | - obj.renumber = -1; | ||
| 1201 | - enqueueObject(m->pdf.getObject(obj.object_stream, 0)); | 1324 | + o.renumber = -1; |
| 1325 | + enqueueObject(pdf.getObject(o.object_stream, 0)); | ||
| 1202 | } else { | 1326 | } else { |
| 1203 | - m->object_queue.push_back(object); | ||
| 1204 | - obj.renumber = m->next_objid++; | 1327 | + object_queue.emplace_back(object); |
| 1328 | + o.renumber = next_objid++; | ||
| 1205 | 1329 | ||
| 1206 | - if ((og.getGen() == 0) && m->object_stream_to_objects.contains(og.getObj())) { | 1330 | + if (og.getGen() == 0 && object_stream_to_objects.contains(og.getObj())) { |
| 1207 | // For linearized files, uncompressed objects go at end, and we take care of | 1331 | // For linearized files, uncompressed objects go at end, and we take care of |
| 1208 | // assigning numbers to them elsewhere. | 1332 | // assigning numbers to them elsewhere. |
| 1209 | - if (!m->linearized) { | 1333 | + if (!linearized) { |
| 1210 | assignCompressedObjectNumbers(og); | 1334 | assignCompressedObjectNumbers(og); |
| 1211 | } | 1335 | } |
| 1212 | - } else if ((!m->direct_stream_lengths) && object.isStream()) { | 1336 | + } else if (!direct_stream_lengths && object.isStream()) { |
| 1213 | // reserve next object ID for length | 1337 | // reserve next object ID for length |
| 1214 | - ++m->next_objid; | 1338 | + ++next_objid; |
| 1215 | } | 1339 | } |
| 1216 | } | 1340 | } |
| 1217 | - } else if (obj.renumber == -1) { | 1341 | + } else if (o.renumber == -1) { |
| 1218 | // This can happen if a specially constructed file indicates that an object stream is | 1342 | // This can happen if a specially constructed file indicates that an object stream is |
| 1219 | // inside itself. | 1343 | // inside itself. |
| 1220 | } | 1344 | } |
| 1221 | return; | 1345 | return; |
| 1222 | - } else if (!m->linearized) { | 1346 | + } else if (!linearized) { |
| 1223 | if (object.isArray()) { | 1347 | if (object.isArray()) { |
| 1224 | for (auto& item: object.as_array()) { | 1348 | for (auto& item: object.as_array()) { |
| 1225 | enqueueObject(item); | 1349 | enqueueObject(item); |
| @@ -1237,25 +1361,25 @@ QPDFWriter::enqueueObject(QPDFObjectHandle object) | @@ -1237,25 +1361,25 @@ QPDFWriter::enqueueObject(QPDFObjectHandle object) | ||
| 1237 | } | 1361 | } |
| 1238 | 1362 | ||
| 1239 | void | 1363 | void |
| 1240 | -QPDFWriter::unparseChild(QPDFObjectHandle const& child, size_t level, int flags) | 1364 | +QPDFWriter::Members::unparseChild(QPDFObjectHandle const& child, size_t level, int flags) |
| 1241 | { | 1365 | { |
| 1242 | - if (!m->linearized) { | 1366 | + if (!linearized) { |
| 1243 | enqueueObject(child); | 1367 | enqueueObject(child); |
| 1244 | } | 1368 | } |
| 1245 | if (child.isIndirect()) { | 1369 | if (child.isIndirect()) { |
| 1246 | - write(m->obj[child].renumber).write(" 0 R"); | 1370 | + write(obj[child].renumber).write(" 0 R"); |
| 1247 | } else { | 1371 | } else { |
| 1248 | unparseObject(child, level, flags); | 1372 | unparseObject(child, level, flags); |
| 1249 | } | 1373 | } |
| 1250 | } | 1374 | } |
| 1251 | 1375 | ||
| 1252 | void | 1376 | void |
| 1253 | -QPDFWriter::writeTrailer( | 1377 | +QPDFWriter::Members::writeTrailer( |
| 1254 | trailer_e which, int size, bool xref_stream, qpdf_offset_t prev, int linearization_pass) | 1378 | trailer_e which, int size, bool xref_stream, qpdf_offset_t prev, int linearization_pass) |
| 1255 | { | 1379 | { |
| 1256 | QPDFObjectHandle trailer = getTrimmedTrailer(); | 1380 | QPDFObjectHandle trailer = getTrimmedTrailer(); |
| 1257 | if (xref_stream) { | 1381 | if (xref_stream) { |
| 1258 | - m->cur_data_key.clear(); | 1382 | + cur_data_key.clear(); |
| 1259 | } else { | 1383 | } else { |
| 1260 | write("trailer <<"); | 1384 | write("trailer <<"); |
| 1261 | } | 1385 | } |
| @@ -1272,8 +1396,8 @@ QPDFWriter::writeTrailer( | @@ -1272,8 +1396,8 @@ QPDFWriter::writeTrailer( | ||
| 1272 | write(size); | 1396 | write(size); |
| 1273 | if (which == t_lin_first) { | 1397 | if (which == t_lin_first) { |
| 1274 | write(" /Prev "); | 1398 | write(" /Prev "); |
| 1275 | - qpdf_offset_t pos = m->pipeline->getCount(); | ||
| 1276 | - write(prev).write(QIntC::to_size(pos - m->pipeline->getCount() + 21), ' '); | 1399 | + qpdf_offset_t pos = pipeline->getCount(); |
| 1400 | + write(prev).write(QIntC::to_size(pos - pipeline->getCount() + 21), ' '); | ||
| 1277 | } | 1401 | } |
| 1278 | } else { | 1402 | } else { |
| 1279 | unparseChild(value, 1, 0); | 1403 | unparseChild(value, 1, 0); |
| @@ -1298,18 +1422,18 @@ QPDFWriter::writeTrailer( | @@ -1298,18 +1422,18 @@ QPDFWriter::writeTrailer( | ||
| 1298 | } | 1422 | } |
| 1299 | write("<00000000000000000000000000000000>"); | 1423 | write("<00000000000000000000000000000000>"); |
| 1300 | } else { | 1424 | } else { |
| 1301 | - if (linearization_pass == 0 && m->deterministic_id) { | 1425 | + if (linearization_pass == 0 && deterministic_id) { |
| 1302 | computeDeterministicIDData(); | 1426 | computeDeterministicIDData(); |
| 1303 | } | 1427 | } |
| 1304 | - generateID(m->encryption.get()); | ||
| 1305 | - write_string(m->id1, true).write_string(m->id2, true); | 1428 | + generateID(encryption.get()); |
| 1429 | + write_string(id1, true).write_string(id2, true); | ||
| 1306 | } | 1430 | } |
| 1307 | write("]"); | 1431 | write("]"); |
| 1308 | 1432 | ||
| 1309 | if (which != t_lin_second) { | 1433 | if (which != t_lin_second) { |
| 1310 | // Write reference to encryption dictionary | 1434 | // Write reference to encryption dictionary |
| 1311 | - if (m->encryption) { | ||
| 1312 | - write(" /Encrypt ").write(m->encryption_dict_objid).write(" 0 R"); | 1435 | + if (encryption) { |
| 1436 | + write(" /Encrypt ").write(encryption_dict_objid).write(" 0 R"); | ||
| 1313 | } | 1437 | } |
| 1314 | } | 1438 | } |
| 1315 | 1439 | ||
| @@ -1317,7 +1441,7 @@ QPDFWriter::writeTrailer( | @@ -1317,7 +1441,7 @@ QPDFWriter::writeTrailer( | ||
| 1317 | } | 1441 | } |
| 1318 | 1442 | ||
| 1319 | bool | 1443 | bool |
| 1320 | -QPDFWriter::willFilterStream( | 1444 | +QPDFWriter::Members::willFilterStream( |
| 1321 | QPDFObjectHandle stream, | 1445 | QPDFObjectHandle stream, |
| 1322 | bool& compress_stream, // out only | 1446 | bool& compress_stream, // out only |
| 1323 | bool& is_root_metadata, // out only | 1447 | bool& is_root_metadata, // out only |
| @@ -1332,38 +1456,33 @@ QPDFWriter::willFilterStream( | @@ -1332,38 +1456,33 @@ QPDFWriter::willFilterStream( | ||
| 1332 | if (stream.isRootMetadata()) { | 1456 | if (stream.isRootMetadata()) { |
| 1333 | is_root_metadata = true; | 1457 | is_root_metadata = true; |
| 1334 | } | 1458 | } |
| 1335 | - bool filter = stream.isDataModified() || m->compress_streams || m->stream_decode_level; | 1459 | + bool filter = stream.isDataModified() || compress_streams || stream_decode_level; |
| 1336 | bool filter_on_write = stream.getFilterOnWrite(); | 1460 | bool filter_on_write = stream.getFilterOnWrite(); |
| 1337 | if (!filter_on_write) { | 1461 | if (!filter_on_write) { |
| 1338 | - QTC::TC("qpdf", "QPDFWriter getFilterOnWrite false"); | ||
| 1339 | filter = false; | 1462 | filter = false; |
| 1340 | } | 1463 | } |
| 1341 | - if (filter_on_write && m->compress_streams) { | 1464 | + if (filter_on_write && compress_streams) { |
| 1342 | // Don't filter if the stream is already compressed with FlateDecode. This way we don't make | 1465 | // Don't filter if the stream is already compressed with FlateDecode. This way we don't make |
| 1343 | // it worse if the original file used a better Flate algorithm, and we don't spend time and | 1466 | // it worse if the original file used a better Flate algorithm, and we don't spend time and |
| 1344 | // CPU cycles uncompressing and recompressing stuff. This can be overridden with | 1467 | // CPU cycles uncompressing and recompressing stuff. This can be overridden with |
| 1345 | // setRecompressFlate(true). | 1468 | // setRecompressFlate(true). |
| 1346 | QPDFObjectHandle filter_obj = stream_dict.getKey("/Filter"); | 1469 | QPDFObjectHandle filter_obj = stream_dict.getKey("/Filter"); |
| 1347 | - if (!m->recompress_flate && !stream.isDataModified() && filter_obj.isName() && | 1470 | + if (!recompress_flate && !stream.isDataModified() && filter_obj.isName() && |
| 1348 | (filter_obj.getName() == "/FlateDecode" || filter_obj.getName() == "/Fl")) { | 1471 | (filter_obj.getName() == "/FlateDecode" || filter_obj.getName() == "/Fl")) { |
| 1349 | - QTC::TC("qpdf", "QPDFWriter not recompressing /FlateDecode"); | ||
| 1350 | filter = false; | 1472 | filter = false; |
| 1351 | } | 1473 | } |
| 1352 | } | 1474 | } |
| 1353 | bool normalize = false; | 1475 | bool normalize = false; |
| 1354 | bool uncompress = false; | 1476 | bool uncompress = false; |
| 1355 | - if (filter_on_write && is_root_metadata && | ||
| 1356 | - (!m->encryption || !m->encryption->getEncryptMetadata())) { | ||
| 1357 | - QTC::TC("qpdf", "QPDFWriter not compressing metadata"); | 1477 | + if (filter_on_write && is_root_metadata && (!encryption || !encryption->getEncryptMetadata())) { |
| 1358 | filter = true; | 1478 | filter = true; |
| 1359 | compress_stream = false; | 1479 | compress_stream = false; |
| 1360 | uncompress = true; | 1480 | uncompress = true; |
| 1361 | - } else if (filter_on_write && m->normalize_content && m->normalized_streams.contains(old_og)) { | 1481 | + } else if (filter_on_write && normalize_content && normalized_streams.contains(old_og)) { |
| 1362 | normalize = true; | 1482 | normalize = true; |
| 1363 | filter = true; | 1483 | filter = true; |
| 1364 | - } else if (filter_on_write && filter && m->compress_streams) { | 1484 | + } else if (filter_on_write && filter && compress_streams) { |
| 1365 | compress_stream = true; | 1485 | compress_stream = true; |
| 1366 | - QTC::TC("qpdf", "QPDFWriter compressing uncompressed stream"); | ||
| 1367 | } | 1486 | } |
| 1368 | 1487 | ||
| 1369 | // Disable compression for empty streams to improve compatibility | 1488 | // Disable compression for empty streams to improve compatibility |
| @@ -1375,16 +1494,16 @@ QPDFWriter::willFilterStream( | @@ -1375,16 +1494,16 @@ QPDFWriter::willFilterStream( | ||
| 1375 | 1494 | ||
| 1376 | bool filtered = false; | 1495 | bool filtered = false; |
| 1377 | for (bool first_attempt: {true, false}) { | 1496 | for (bool first_attempt: {true, false}) { |
| 1378 | - auto pp_stream_data = stream_data ? m->pipeline_stack.activate(*stream_data) | ||
| 1379 | - : m->pipeline_stack.activate(true); | 1497 | + auto pp_stream_data = |
| 1498 | + stream_data ? pipeline_stack.activate(*stream_data) : pipeline_stack.activate(true); | ||
| 1380 | 1499 | ||
| 1381 | try { | 1500 | try { |
| 1382 | filtered = stream.pipeStreamData( | 1501 | filtered = stream.pipeStreamData( |
| 1383 | - m->pipeline, | 1502 | + pipeline, |
| 1384 | !filter ? 0 | 1503 | !filter ? 0 |
| 1385 | : ((normalize ? qpdf_ef_normalize : 0) | | 1504 | : ((normalize ? qpdf_ef_normalize : 0) | |
| 1386 | (compress_stream ? qpdf_ef_compress : 0)), | 1505 | (compress_stream ? qpdf_ef_compress : 0)), |
| 1387 | - !filter ? qpdf_dl_none : (uncompress ? qpdf_dl_all : m->stream_decode_level), | 1506 | + !filter ? qpdf_dl_none : (uncompress ? qpdf_dl_all : stream_decode_level), |
| 1388 | false, | 1507 | false, |
| 1389 | first_attempt); | 1508 | first_attempt); |
| 1390 | if (filter && !filtered) { | 1509 | if (filter && !filtered) { |
| @@ -1416,7 +1535,7 @@ QPDFWriter::willFilterStream( | @@ -1416,7 +1535,7 @@ QPDFWriter::willFilterStream( | ||
| 1416 | } | 1535 | } |
| 1417 | 1536 | ||
| 1418 | void | 1537 | void |
| 1419 | -QPDFWriter::unparseObject( | 1538 | +QPDFWriter::Members::unparseObject( |
| 1420 | QPDFObjectHandle object, size_t level, int flags, size_t stream_length, bool compress) | 1539 | QPDFObjectHandle object, size_t level, int flags, size_t stream_length, bool compress) |
| 1421 | { | 1540 | { |
| 1422 | QPDFObjGen old_og = object.getObjGen(); | 1541 | QPDFObjGen old_og = object.getObjGen(); |
| @@ -1424,11 +1543,11 @@ QPDFWriter::unparseObject( | @@ -1424,11 +1543,11 @@ QPDFWriter::unparseObject( | ||
| 1424 | // For non-qdf, "indent" and "indent_large" are a single space between tokens. For qdf, they | 1543 | // For non-qdf, "indent" and "indent_large" are a single space between tokens. For qdf, they |
| 1425 | // include the preceding newline. | 1544 | // include the preceding newline. |
| 1426 | std::string indent_large = " "; | 1545 | std::string indent_large = " "; |
| 1427 | - if (m->qdf_mode) { | 1546 | + if (qdf_mode) { |
| 1428 | indent_large.append(2 * (level + 1), ' '); | 1547 | indent_large.append(2 * (level + 1), ' '); |
| 1429 | indent_large[0] = '\n'; | 1548 | indent_large[0] = '\n'; |
| 1430 | } | 1549 | } |
| 1431 | - std::string_view indent{indent_large.data(), m->qdf_mode ? indent_large.size() - 2 : 1}; | 1550 | + std::string_view indent{indent_large.data(), qdf_mode ? indent_large.size() - 2 : 1}; |
| 1432 | 1551 | ||
| 1433 | if (auto const tc = object.getTypeCode(); tc == ::ot_array) { | 1552 | if (auto const tc = object.getTypeCode(); tc == ::ot_array) { |
| 1434 | // Note: PDF spec 1.4 implementation note 121 states that Acrobat requires a space after the | 1553 | // Note: PDF spec 1.4 implementation note 121 states that Acrobat requires a space after the |
| @@ -1443,7 +1562,7 @@ QPDFWriter::unparseObject( | @@ -1443,7 +1562,7 @@ QPDFWriter::unparseObject( | ||
| 1443 | } else if (tc == ::ot_dictionary) { | 1562 | } else if (tc == ::ot_dictionary) { |
| 1444 | // Handle special cases for specific dictionaries. | 1563 | // Handle special cases for specific dictionaries. |
| 1445 | 1564 | ||
| 1446 | - if (old_og == m->root_og) { | 1565 | + if (old_og == root_og) { |
| 1447 | // Extensions dictionaries. | 1566 | // Extensions dictionaries. |
| 1448 | 1567 | ||
| 1449 | // We have one of several cases: | 1568 | // We have one of several cases: |
| @@ -1464,7 +1583,7 @@ QPDFWriter::unparseObject( | @@ -1464,7 +1583,7 @@ QPDFWriter::unparseObject( | ||
| 1464 | 1583 | ||
| 1465 | auto extensions = object.getKey("/Extensions"); | 1584 | auto extensions = object.getKey("/Extensions"); |
| 1466 | const bool has_extensions = extensions.isDictionary(); | 1585 | const bool has_extensions = extensions.isDictionary(); |
| 1467 | - const bool need_extensions_adbe = m->final_extension_level > 0; | 1586 | + const bool need_extensions_adbe = final_extension_level > 0; |
| 1468 | 1587 | ||
| 1469 | if (has_extensions || need_extensions_adbe) { | 1588 | if (has_extensions || need_extensions_adbe) { |
| 1470 | // Make a shallow copy of this object so we can modify it safely without affecting | 1589 | // Make a shallow copy of this object so we can modify it safely without affecting |
| @@ -1484,7 +1603,7 @@ QPDFWriter::unparseObject( | @@ -1484,7 +1603,7 @@ QPDFWriter::unparseObject( | ||
| 1484 | if (need_extensions_adbe) { | 1603 | if (need_extensions_adbe) { |
| 1485 | if (!(have_extensions_other || have_extensions_adbe)) { | 1604 | if (!(have_extensions_other || have_extensions_adbe)) { |
| 1486 | // We need Extensions and don't have it. Create it here. | 1605 | // We need Extensions and don't have it. Create it here. |
| 1487 | - QTC::TC("qpdf", "QPDFWriter create Extensions", m->qdf_mode ? 0 : 1); | 1606 | + QTC::TC("qpdf", "QPDFWriter create Extensions", qdf_mode ? 0 : 1); |
| 1488 | extensions = object.replaceKeyAndGetNew( | 1607 | extensions = object.replaceKeyAndGetNew( |
| 1489 | "/Extensions", QPDFObjectHandle::newDictionary()); | 1608 | "/Extensions", QPDFObjectHandle::newDictionary()); |
| 1490 | } | 1609 | } |
| @@ -1501,21 +1620,17 @@ QPDFWriter::unparseObject( | @@ -1501,21 +1620,17 @@ QPDFWriter::unparseObject( | ||
| 1501 | QTC::TC("qpdf", "QPDFWriter preserve Extensions"); | 1620 | QTC::TC("qpdf", "QPDFWriter preserve Extensions"); |
| 1502 | QPDFObjectHandle adbe = extensions.getKey("/ADBE"); | 1621 | QPDFObjectHandle adbe = extensions.getKey("/ADBE"); |
| 1503 | if (adbe.isDictionary() && | 1622 | if (adbe.isDictionary() && |
| 1504 | - adbe.getKey("/BaseVersion").isNameAndEquals("/" + m->final_pdf_version) && | 1623 | + adbe.getKey("/BaseVersion").isNameAndEquals("/" + final_pdf_version) && |
| 1505 | adbe.getKey("/ExtensionLevel").isInteger() && | 1624 | adbe.getKey("/ExtensionLevel").isInteger() && |
| 1506 | - (adbe.getKey("/ExtensionLevel").getIntValue() == | ||
| 1507 | - m->final_extension_level)) { | ||
| 1508 | - QTC::TC("qpdf", "QPDFWriter preserve ADBE"); | 1625 | + (adbe.getKey("/ExtensionLevel").getIntValue() == final_extension_level)) { |
| 1509 | } else { | 1626 | } else { |
| 1510 | if (need_extensions_adbe) { | 1627 | if (need_extensions_adbe) { |
| 1511 | extensions.replaceKey( | 1628 | extensions.replaceKey( |
| 1512 | "/ADBE", | 1629 | "/ADBE", |
| 1513 | QPDFObjectHandle::parse( | 1630 | QPDFObjectHandle::parse( |
| 1514 | - "<< /BaseVersion /" + m->final_pdf_version + | ||
| 1515 | - " /ExtensionLevel " + std::to_string(m->final_extension_level) + | ||
| 1516 | - " >>")); | 1631 | + "<< /BaseVersion /" + final_pdf_version + " /ExtensionLevel " + |
| 1632 | + std::to_string(final_extension_level) + " >>")); | ||
| 1517 | } else { | 1633 | } else { |
| 1518 | - QTC::TC("qpdf", "QPDFWriter remove ADBE"); | ||
| 1519 | extensions.removeKey("/ADBE"); | 1634 | extensions.removeKey("/ADBE"); |
| 1520 | } | 1635 | } |
| 1521 | } | 1636 | } |
| @@ -1593,10 +1708,10 @@ QPDFWriter::unparseObject( | @@ -1593,10 +1708,10 @@ QPDFWriter::unparseObject( | ||
| 1593 | if (flags & f_stream) { | 1708 | if (flags & f_stream) { |
| 1594 | write(indent_large).write("/Length "); | 1709 | write(indent_large).write("/Length "); |
| 1595 | 1710 | ||
| 1596 | - if (m->direct_stream_lengths) { | 1711 | + if (direct_stream_lengths) { |
| 1597 | write(stream_length); | 1712 | write(stream_length); |
| 1598 | } else { | 1713 | } else { |
| 1599 | - write(m->cur_stream_length_id).write(" 0 R"); | 1714 | + write(cur_stream_length_id).write(" 0 R"); |
| 1600 | } | 1715 | } |
| 1601 | if (compress && (flags & f_filtered)) { | 1716 | if (compress && (flags & f_filtered)) { |
| 1602 | write(indent_large).write("/Filter /FlateDecode"); | 1717 | write(indent_large).write("/Filter /FlateDecode"); |
| @@ -1606,8 +1721,8 @@ QPDFWriter::unparseObject( | @@ -1606,8 +1721,8 @@ QPDFWriter::unparseObject( | ||
| 1606 | write(indent).write(">>"); | 1721 | write(indent).write(">>"); |
| 1607 | } else if (tc == ::ot_stream) { | 1722 | } else if (tc == ::ot_stream) { |
| 1608 | // Write stream data to a buffer. | 1723 | // Write stream data to a buffer. |
| 1609 | - if (!m->direct_stream_lengths) { | ||
| 1610 | - m->cur_stream_length_id = m->obj[old_og].renumber + 1; | 1724 | + if (!direct_stream_lengths) { |
| 1725 | + cur_stream_length_id = obj[old_og].renumber + 1; | ||
| 1611 | } | 1726 | } |
| 1612 | 1727 | ||
| 1613 | flags |= f_stream; | 1728 | flags |= f_stream; |
| @@ -1619,25 +1734,25 @@ QPDFWriter::unparseObject( | @@ -1619,25 +1734,25 @@ QPDFWriter::unparseObject( | ||
| 1619 | } | 1734 | } |
| 1620 | QPDFObjectHandle stream_dict = object.getDict(); | 1735 | QPDFObjectHandle stream_dict = object.getDict(); |
| 1621 | 1736 | ||
| 1622 | - m->cur_stream_length = stream_data.size(); | ||
| 1623 | - if (is_metadata && m->encryption && !m->encryption->getEncryptMetadata()) { | 1737 | + cur_stream_length = stream_data.size(); |
| 1738 | + if (is_metadata && encryption && !encryption->getEncryptMetadata()) { | ||
| 1624 | // Don't encrypt stream data for the metadata stream | 1739 | // Don't encrypt stream data for the metadata stream |
| 1625 | - m->cur_data_key.clear(); | 1740 | + cur_data_key.clear(); |
| 1626 | } | 1741 | } |
| 1627 | - adjustAESStreamLength(m->cur_stream_length); | ||
| 1628 | - unparseObject(stream_dict, 0, flags, m->cur_stream_length, compress_stream); | 1742 | + adjustAESStreamLength(cur_stream_length); |
| 1743 | + unparseObject(stream_dict, 0, flags, cur_stream_length, compress_stream); | ||
| 1629 | char last_char = stream_data.empty() ? '\0' : stream_data.back(); | 1744 | char last_char = stream_data.empty() ? '\0' : stream_data.back(); |
| 1630 | write("\nstream\n").write_encrypted(stream_data); | 1745 | write("\nstream\n").write_encrypted(stream_data); |
| 1631 | - m->added_newline = m->newline_before_endstream || (m->qdf_mode && last_char != '\n'); | ||
| 1632 | - write(m->added_newline ? "\nendstream" : "endstream"); | 1746 | + added_newline = newline_before_endstream || (qdf_mode && last_char != '\n'); |
| 1747 | + write(added_newline ? "\nendstream" : "endstream"); | ||
| 1633 | } else if (tc == ::ot_string) { | 1748 | } else if (tc == ::ot_string) { |
| 1634 | std::string val; | 1749 | std::string val; |
| 1635 | - if (m->encryption && !(flags & f_in_ostream) && !(flags & f_no_encryption) && | ||
| 1636 | - !m->cur_data_key.empty()) { | 1750 | + if (encryption && !(flags & f_in_ostream) && !(flags & f_no_encryption) && |
| 1751 | + !cur_data_key.empty()) { | ||
| 1637 | val = object.getStringValue(); | 1752 | val = object.getStringValue(); |
| 1638 | - if (m->encrypt_use_aes) { | 1753 | + if (encrypt_use_aes) { |
| 1639 | Pl_Buffer bufpl("encrypted string"); | 1754 | Pl_Buffer bufpl("encrypted string"); |
| 1640 | - Pl_AES_PDF pl("aes encrypt string", &bufpl, true, m->cur_data_key); | 1755 | + Pl_AES_PDF pl("aes encrypt string", &bufpl, true, cur_data_key); |
| 1641 | pl.writeString(val); | 1756 | pl.writeString(val); |
| 1642 | pl.finish(); | 1757 | pl.finish(); |
| 1643 | val = QPDF_String(bufpl.getString()).unparse(true); | 1758 | val = QPDF_String(bufpl.getString()).unparse(true); |
| @@ -1646,8 +1761,8 @@ QPDFWriter::unparseObject( | @@ -1646,8 +1761,8 @@ QPDFWriter::unparseObject( | ||
| 1646 | char* tmp = tmp_ph.get(); | 1761 | char* tmp = tmp_ph.get(); |
| 1647 | size_t vlen = val.length(); | 1762 | size_t vlen = val.length(); |
| 1648 | RC4 rc4( | 1763 | RC4 rc4( |
| 1649 | - QUtil::unsigned_char_pointer(m->cur_data_key), | ||
| 1650 | - QIntC::to_int(m->cur_data_key.length())); | 1764 | + QUtil::unsigned_char_pointer(cur_data_key), |
| 1765 | + QIntC::to_int(cur_data_key.length())); | ||
| 1651 | auto data = QUtil::unsigned_char_pointer(tmp); | 1766 | auto data = QUtil::unsigned_char_pointer(tmp); |
| 1652 | rc4.process(data, vlen, data); | 1767 | rc4.process(data, vlen, data); |
| 1653 | val = QPDF_String(std::string(tmp, vlen)).unparse(); | 1768 | val = QPDF_String(std::string(tmp, vlen)).unparse(); |
| @@ -1664,7 +1779,7 @@ QPDFWriter::unparseObject( | @@ -1664,7 +1779,7 @@ QPDFWriter::unparseObject( | ||
| 1664 | } | 1779 | } |
| 1665 | 1780 | ||
| 1666 | void | 1781 | void |
| 1667 | -QPDFWriter::writeObjectStreamOffsets(std::vector<qpdf_offset_t>& offsets, int first_obj) | 1782 | +QPDFWriter::Members::writeObjectStreamOffsets(std::vector<qpdf_offset_t>& offsets, int first_obj) |
| 1668 | { | 1783 | { |
| 1669 | qpdf_assert_debug(first_obj > 0); | 1784 | qpdf_assert_debug(first_obj > 0); |
| 1670 | bool is_first = true; | 1785 | bool is_first = true; |
| @@ -1683,7 +1798,7 @@ QPDFWriter::writeObjectStreamOffsets(std::vector<qpdf_offset_t>& offsets, int fi | @@ -1683,7 +1798,7 @@ QPDFWriter::writeObjectStreamOffsets(std::vector<qpdf_offset_t>& offsets, int fi | ||
| 1683 | } | 1798 | } |
| 1684 | 1799 | ||
| 1685 | void | 1800 | void |
| 1686 | -QPDFWriter::writeObjectStream(QPDFObjectHandle object) | 1801 | +QPDFWriter::Members::writeObjectStream(QPDFObjectHandle object) |
| 1687 | { | 1802 | { |
| 1688 | // Note: object might be null if this is a place-holder for an object stream that we are | 1803 | // Note: object might be null if this is a place-holder for an object stream that we are |
| 1689 | // generating from scratch. | 1804 | // generating from scratch. |
| @@ -1691,7 +1806,7 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) | @@ -1691,7 +1806,7 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) | ||
| 1691 | QPDFObjGen old_og = object.getObjGen(); | 1806 | QPDFObjGen old_og = object.getObjGen(); |
| 1692 | qpdf_assert_debug(old_og.getGen() == 0); | 1807 | qpdf_assert_debug(old_og.getGen() == 0); |
| 1693 | int old_id = old_og.getObj(); | 1808 | int old_id = old_og.getObj(); |
| 1694 | - int new_stream_id = m->obj[old_og].renumber; | 1809 | + int new_stream_id = obj[old_og].renumber; |
| 1695 | 1810 | ||
| 1696 | std::vector<qpdf_offset_t> offsets; | 1811 | std::vector<qpdf_offset_t> offsets; |
| 1697 | qpdf_offset_t first = 0; | 1812 | qpdf_offset_t first = 0; |
| @@ -1701,39 +1816,38 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) | @@ -1701,39 +1816,38 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) | ||
| 1701 | std::string stream_buffer_pass1; | 1816 | std::string stream_buffer_pass1; |
| 1702 | std::string stream_buffer_pass2; | 1817 | std::string stream_buffer_pass2; |
| 1703 | int first_obj = -1; | 1818 | int first_obj = -1; |
| 1704 | - const bool compressed = m->compress_streams && !m->qdf_mode; | 1819 | + const bool compressed = compress_streams && !qdf_mode; |
| 1705 | { | 1820 | { |
| 1706 | // Pass 1 | 1821 | // Pass 1 |
| 1707 | - auto pp_ostream_pass1 = m->pipeline_stack.activate(stream_buffer_pass1); | 1822 | + auto pp_ostream_pass1 = pipeline_stack.activate(stream_buffer_pass1); |
| 1708 | 1823 | ||
| 1709 | int count = -1; | 1824 | int count = -1; |
| 1710 | - for (auto const& obj: m->object_stream_to_objects[old_id]) { | 1825 | + for (auto const& og: object_stream_to_objects[old_id]) { |
| 1711 | ++count; | 1826 | ++count; |
| 1712 | - int new_obj = m->obj[obj].renumber; | 1827 | + int new_o = obj[og].renumber; |
| 1713 | if (first_obj == -1) { | 1828 | if (first_obj == -1) { |
| 1714 | - first_obj = new_obj; | 1829 | + first_obj = new_o; |
| 1715 | } | 1830 | } |
| 1716 | - if (m->qdf_mode) { | ||
| 1717 | - write("%% Object stream: object ").write(new_obj).write(", index ").write(count); | ||
| 1718 | - if (!m->suppress_original_object_ids) { | ||
| 1719 | - write("; original object ID: ").write(obj.getObj()); | 1831 | + if (qdf_mode) { |
| 1832 | + write("%% Object stream: object ").write(new_o).write(", index ").write(count); | ||
| 1833 | + if (!suppress_original_object_ids) { | ||
| 1834 | + write("; original object ID: ").write(og.getObj()); | ||
| 1720 | // For compatibility, only write the generation if non-zero. While object | 1835 | // For compatibility, only write the generation if non-zero. While object |
| 1721 | // streams only allow objects with generation 0, if we are generating object | 1836 | // streams only allow objects with generation 0, if we are generating object |
| 1722 | // streams, the old object could have a non-zero generation. | 1837 | // streams, the old object could have a non-zero generation. |
| 1723 | - if (obj.getGen() != 0) { | ||
| 1724 | - QTC::TC("qpdf", "QPDFWriter original obj non-zero gen"); | ||
| 1725 | - write(" ").write(obj.getGen()); | 1838 | + if (og.getGen() != 0) { |
| 1839 | + write(" ").write(og.getGen()); | ||
| 1726 | } | 1840 | } |
| 1727 | } | 1841 | } |
| 1728 | write("\n"); | 1842 | write("\n"); |
| 1729 | } | 1843 | } |
| 1730 | 1844 | ||
| 1731 | - offsets.push_back(m->pipeline->getCount()); | 1845 | + offsets.push_back(pipeline->getCount()); |
| 1732 | // To avoid double-counting objects being written in object streams for progress | 1846 | // To avoid double-counting objects being written in object streams for progress |
| 1733 | // reporting, decrement in pass 1. | 1847 | // reporting, decrement in pass 1. |
| 1734 | indicateProgress(true, false); | 1848 | indicateProgress(true, false); |
| 1735 | 1849 | ||
| 1736 | - QPDFObjectHandle obj_to_write = m->pdf.getObject(obj); | 1850 | + QPDFObjectHandle obj_to_write = pdf.getObject(og); |
| 1737 | if (obj_to_write.isStream()) { | 1851 | if (obj_to_write.isStream()) { |
| 1738 | // This condition occurred in a fuzz input. Ideally we should block it at parse | 1852 | // This condition occurred in a fuzz input. Ideally we should block it at parse |
| 1739 | // time, but it's not clear to me how to construct a case for this. | 1853 | // time, but it's not clear to me how to construct a case for this. |
| @@ -1742,7 +1856,7 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) | @@ -1742,7 +1856,7 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) | ||
| 1742 | } | 1856 | } |
| 1743 | writeObject(obj_to_write, count); | 1857 | writeObject(obj_to_write, count); |
| 1744 | 1858 | ||
| 1745 | - m->new_obj[new_obj].xref = QPDFXRefEntry(new_stream_id, count); | 1859 | + new_obj[new_o].xref = QPDFXRefEntry(new_stream_id, count); |
| 1746 | } | 1860 | } |
| 1747 | } | 1861 | } |
| 1748 | { | 1862 | { |
| @@ -1754,13 +1868,13 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) | @@ -1754,13 +1868,13 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) | ||
| 1754 | 1868 | ||
| 1755 | // Take one pass at writing pairs of numbers so we can get their size information | 1869 | // Take one pass at writing pairs of numbers so we can get their size information |
| 1756 | { | 1870 | { |
| 1757 | - auto pp_discard = m->pipeline_stack.activate(true); | 1871 | + auto pp_discard = pipeline_stack.activate(true); |
| 1758 | writeObjectStreamOffsets(offsets, first_obj); | 1872 | writeObjectStreamOffsets(offsets, first_obj); |
| 1759 | - first += m->pipeline->getCount(); | 1873 | + first += pipeline->getCount(); |
| 1760 | } | 1874 | } |
| 1761 | 1875 | ||
| 1762 | // Set up a stream to write the stream data into a buffer. | 1876 | // Set up a stream to write the stream data into a buffer. |
| 1763 | - auto pp_ostream = m->pipeline_stack.activate(stream_buffer_pass2); | 1877 | + auto pp_ostream = pipeline_stack.activate(stream_buffer_pass2); |
| 1764 | 1878 | ||
| 1765 | writeObjectStreamOffsets(offsets, first_obj); | 1879 | writeObjectStreamOffsets(offsets, first_obj); |
| 1766 | write(stream_buffer_pass1); | 1880 | write(stream_buffer_pass1); |
| @@ -1792,65 +1906,65 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) | @@ -1792,65 +1906,65 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) | ||
| 1792 | } | 1906 | } |
| 1793 | } | 1907 | } |
| 1794 | write_qdf("\n").write_no_qdf(" ").write(">>\nstream\n").write_encrypted(stream_buffer_pass2); | 1908 | write_qdf("\n").write_no_qdf(" ").write(">>\nstream\n").write_encrypted(stream_buffer_pass2); |
| 1795 | - if (m->encryption) { | 1909 | + if (encryption) { |
| 1796 | QTC::TC("qpdf", "QPDFWriter encrypt object stream"); | 1910 | QTC::TC("qpdf", "QPDFWriter encrypt object stream"); |
| 1797 | } | 1911 | } |
| 1798 | - write(m->newline_before_endstream ? "\nendstream" : "endstream"); | ||
| 1799 | - m->cur_data_key.clear(); | 1912 | + write(newline_before_endstream ? "\nendstream" : "endstream"); |
| 1913 | + cur_data_key.clear(); | ||
| 1800 | closeObject(new_stream_id); | 1914 | closeObject(new_stream_id); |
| 1801 | } | 1915 | } |
| 1802 | 1916 | ||
| 1803 | void | 1917 | void |
| 1804 | -QPDFWriter::writeObject(QPDFObjectHandle object, int object_stream_index) | 1918 | +QPDFWriter::Members::writeObject(QPDFObjectHandle object, int object_stream_index) |
| 1805 | { | 1919 | { |
| 1806 | QPDFObjGen old_og = object.getObjGen(); | 1920 | QPDFObjGen old_og = object.getObjGen(); |
| 1807 | 1921 | ||
| 1808 | if (object_stream_index == -1 && old_og.getGen() == 0 && | 1922 | if (object_stream_index == -1 && old_og.getGen() == 0 && |
| 1809 | - m->object_stream_to_objects.contains(old_og.getObj())) { | 1923 | + object_stream_to_objects.contains(old_og.getObj())) { |
| 1810 | writeObjectStream(object); | 1924 | writeObjectStream(object); |
| 1811 | return; | 1925 | return; |
| 1812 | } | 1926 | } |
| 1813 | 1927 | ||
| 1814 | indicateProgress(false, false); | 1928 | indicateProgress(false, false); |
| 1815 | - auto new_id = m->obj[old_og].renumber; | ||
| 1816 | - if (m->qdf_mode) { | ||
| 1817 | - if (m->page_object_to_seq.contains(old_og)) { | ||
| 1818 | - write("%% Page ").write(m->page_object_to_seq[old_og]).write("\n"); | 1929 | + auto new_id = obj[old_og].renumber; |
| 1930 | + if (qdf_mode) { | ||
| 1931 | + if (page_object_to_seq.contains(old_og)) { | ||
| 1932 | + write("%% Page ").write(page_object_to_seq[old_og]).write("\n"); | ||
| 1819 | } | 1933 | } |
| 1820 | - if (m->contents_to_page_seq.contains(old_og)) { | ||
| 1821 | - write("%% Contents for page ").write(m->contents_to_page_seq[old_og]).write("\n"); | 1934 | + if (contents_to_page_seq.contains(old_og)) { |
| 1935 | + write("%% Contents for page ").write(contents_to_page_seq[old_og]).write("\n"); | ||
| 1822 | } | 1936 | } |
| 1823 | } | 1937 | } |
| 1824 | if (object_stream_index == -1) { | 1938 | if (object_stream_index == -1) { |
| 1825 | - if (m->qdf_mode && (!m->suppress_original_object_ids)) { | 1939 | + if (qdf_mode && !suppress_original_object_ids) { |
| 1826 | write("%% Original object ID: ").write(object.getObjGen().unparse(' ')).write("\n"); | 1940 | write("%% Original object ID: ").write(object.getObjGen().unparse(' ')).write("\n"); |
| 1827 | } | 1941 | } |
| 1828 | openObject(new_id); | 1942 | openObject(new_id); |
| 1829 | setDataKey(new_id); | 1943 | setDataKey(new_id); |
| 1830 | unparseObject(object, 0, 0); | 1944 | unparseObject(object, 0, 0); |
| 1831 | - m->cur_data_key.clear(); | 1945 | + cur_data_key.clear(); |
| 1832 | closeObject(new_id); | 1946 | closeObject(new_id); |
| 1833 | } else { | 1947 | } else { |
| 1834 | unparseObject(object, 0, f_in_ostream); | 1948 | unparseObject(object, 0, f_in_ostream); |
| 1835 | write("\n"); | 1949 | write("\n"); |
| 1836 | } | 1950 | } |
| 1837 | 1951 | ||
| 1838 | - if (!m->direct_stream_lengths && object.isStream()) { | ||
| 1839 | - if (m->qdf_mode) { | ||
| 1840 | - if (m->added_newline) { | 1952 | + if (!direct_stream_lengths && object.isStream()) { |
| 1953 | + if (qdf_mode) { | ||
| 1954 | + if (added_newline) { | ||
| 1841 | write("%QDF: ignore_newline\n"); | 1955 | write("%QDF: ignore_newline\n"); |
| 1842 | } | 1956 | } |
| 1843 | } | 1957 | } |
| 1844 | openObject(new_id + 1); | 1958 | openObject(new_id + 1); |
| 1845 | - write(m->cur_stream_length); | 1959 | + write(cur_stream_length); |
| 1846 | closeObject(new_id + 1); | 1960 | closeObject(new_id + 1); |
| 1847 | } | 1961 | } |
| 1848 | } | 1962 | } |
| 1849 | 1963 | ||
| 1850 | std::string | 1964 | std::string |
| 1851 | -QPDFWriter::getOriginalID1() | 1965 | +QPDFWriter::Members::getOriginalID1() |
| 1852 | { | 1966 | { |
| 1853 | - QPDFObjectHandle trailer = m->pdf.getTrailer(); | 1967 | + QPDFObjectHandle trailer = pdf.getTrailer(); |
| 1854 | if (trailer.hasKey("/ID")) { | 1968 | if (trailer.hasKey("/ID")) { |
| 1855 | return trailer.getKey("/ID").getArrayItem(0).getStringValue(); | 1969 | return trailer.getKey("/ID").getArrayItem(0).getStringValue(); |
| 1856 | } else { | 1970 | } else { |
| @@ -1859,20 +1973,20 @@ QPDFWriter::getOriginalID1() | @@ -1859,20 +1973,20 @@ QPDFWriter::getOriginalID1() | ||
| 1859 | } | 1973 | } |
| 1860 | 1974 | ||
| 1861 | void | 1975 | void |
| 1862 | -QPDFWriter::generateID(bool encrypted) | 1976 | +QPDFWriter::Members::generateID(bool encrypted) |
| 1863 | { | 1977 | { |
| 1864 | // Generate the ID lazily so that we can handle the user's preference to use static or | 1978 | // Generate the ID lazily so that we can handle the user's preference to use static or |
| 1865 | // deterministic ID generation. | 1979 | // deterministic ID generation. |
| 1866 | 1980 | ||
| 1867 | - if (!m->id2.empty()) { | 1981 | + if (!id2.empty()) { |
| 1868 | return; | 1982 | return; |
| 1869 | } | 1983 | } |
| 1870 | 1984 | ||
| 1871 | - QPDFObjectHandle trailer = m->pdf.getTrailer(); | 1985 | + QPDFObjectHandle trailer = pdf.getTrailer(); |
| 1872 | 1986 | ||
| 1873 | std::string result; | 1987 | std::string result; |
| 1874 | 1988 | ||
| 1875 | - if (m->static_id) { | 1989 | + if (static_id) { |
| 1876 | // For test suite use only... | 1990 | // For test suite use only... |
| 1877 | static unsigned char tmp[] = { | 1991 | static unsigned char tmp[] = { |
| 1878 | 0x31, | 1992 | 0x31, |
| @@ -1904,20 +2018,20 @@ QPDFWriter::generateID(bool encrypted) | @@ -1904,20 +2018,20 @@ QPDFWriter::generateID(bool encrypted) | ||
| 1904 | // that case, would have the same ID regardless of the output file's name. | 2018 | // that case, would have the same ID regardless of the output file's name. |
| 1905 | 2019 | ||
| 1906 | std::string seed; | 2020 | std::string seed; |
| 1907 | - if (m->deterministic_id) { | 2021 | + if (deterministic_id) { |
| 1908 | if (encrypted) { | 2022 | if (encrypted) { |
| 1909 | throw std::runtime_error( | 2023 | throw std::runtime_error( |
| 1910 | "QPDFWriter: unable to generated a deterministic ID because the file to be " | 2024 | "QPDFWriter: unable to generated a deterministic ID because the file to be " |
| 1911 | "written is encrypted (even though the file may not require a password)"); | 2025 | "written is encrypted (even though the file may not require a password)"); |
| 1912 | } | 2026 | } |
| 1913 | - if (m->deterministic_id_data.empty()) { | 2027 | + if (deterministic_id_data.empty()) { |
| 1914 | throw std::logic_error( | 2028 | throw std::logic_error( |
| 1915 | "INTERNAL ERROR: QPDFWriter::generateID has no data for deterministic ID"); | 2029 | "INTERNAL ERROR: QPDFWriter::generateID has no data for deterministic ID"); |
| 1916 | } | 2030 | } |
| 1917 | - seed += m->deterministic_id_data; | 2031 | + seed += deterministic_id_data; |
| 1918 | } else { | 2032 | } else { |
| 1919 | seed += std::to_string(QUtil::get_current_time()); | 2033 | seed += std::to_string(QUtil::get_current_time()); |
| 1920 | - seed += m->filename; | 2034 | + seed += filename; |
| 1921 | seed += " "; | 2035 | seed += " "; |
| 1922 | } | 2036 | } |
| 1923 | seed += " QPDF "; | 2037 | seed += " QPDF "; |
| @@ -1930,32 +2044,32 @@ QPDFWriter::generateID(bool encrypted) | @@ -1930,32 +2044,32 @@ QPDFWriter::generateID(bool encrypted) | ||
| 1930 | } | 2044 | } |
| 1931 | } | 2045 | } |
| 1932 | 2046 | ||
| 1933 | - MD5 m; | ||
| 1934 | - m.encodeString(seed.c_str()); | 2047 | + MD5 md5; |
| 2048 | + md5.encodeString(seed.c_str()); | ||
| 1935 | MD5::Digest digest; | 2049 | MD5::Digest digest; |
| 1936 | - m.digest(digest); | 2050 | + md5.digest(digest); |
| 1937 | result = std::string(reinterpret_cast<char*>(digest), sizeof(MD5::Digest)); | 2051 | result = std::string(reinterpret_cast<char*>(digest), sizeof(MD5::Digest)); |
| 1938 | } | 2052 | } |
| 1939 | 2053 | ||
| 1940 | // If /ID already exists, follow the spec: use the original first word and generate a new second | 2054 | // If /ID already exists, follow the spec: use the original first word and generate a new second |
| 1941 | // word. Otherwise, we'll use the generated ID for both. | 2055 | // word. Otherwise, we'll use the generated ID for both. |
| 1942 | 2056 | ||
| 1943 | - m->id2 = result; | 2057 | + id2 = result; |
| 1944 | // Note: keep /ID from old file even if --static-id was given. | 2058 | // Note: keep /ID from old file even if --static-id was given. |
| 1945 | - m->id1 = getOriginalID1(); | ||
| 1946 | - if (m->id1.empty()) { | ||
| 1947 | - m->id1 = m->id2; | 2059 | + id1 = getOriginalID1(); |
| 2060 | + if (id1.empty()) { | ||
| 2061 | + id1 = id2; | ||
| 1948 | } | 2062 | } |
| 1949 | } | 2063 | } |
| 1950 | 2064 | ||
| 1951 | void | 2065 | void |
| 1952 | -QPDFWriter::initializeSpecialStreams() | 2066 | +QPDFWriter::Members::initializeSpecialStreams() |
| 1953 | { | 2067 | { |
| 1954 | // Mark all page content streams in case we are filtering or normalizing. | 2068 | // Mark all page content streams in case we are filtering or normalizing. |
| 1955 | - std::vector<QPDFObjectHandle> pages = m->pdf.getAllPages(); | 2069 | + std::vector<QPDFObjectHandle> pages = pdf.getAllPages(); |
| 1956 | int num = 0; | 2070 | int num = 0; |
| 1957 | for (auto& page: pages) { | 2071 | for (auto& page: pages) { |
| 1958 | - m->page_object_to_seq[page.getObjGen()] = ++num; | 2072 | + page_object_to_seq[page.getObjGen()] = ++num; |
| 1959 | QPDFObjectHandle contents = page.getKey("/Contents"); | 2073 | QPDFObjectHandle contents = page.getKey("/Contents"); |
| 1960 | std::vector<QPDFObjGen> contents_objects; | 2074 | std::vector<QPDFObjGen> contents_objects; |
| 1961 | if (contents.isArray()) { | 2075 | if (contents.isArray()) { |
| @@ -1968,16 +2082,16 @@ QPDFWriter::initializeSpecialStreams() | @@ -1968,16 +2082,16 @@ QPDFWriter::initializeSpecialStreams() | ||
| 1968 | } | 2082 | } |
| 1969 | 2083 | ||
| 1970 | for (auto const& c: contents_objects) { | 2084 | for (auto const& c: contents_objects) { |
| 1971 | - m->contents_to_page_seq[c] = num; | ||
| 1972 | - m->normalized_streams.insert(c); | 2085 | + contents_to_page_seq[c] = num; |
| 2086 | + normalized_streams.insert(c); | ||
| 1973 | } | 2087 | } |
| 1974 | } | 2088 | } |
| 1975 | } | 2089 | } |
| 1976 | 2090 | ||
| 1977 | void | 2091 | void |
| 1978 | -QPDFWriter::preserveObjectStreams() | 2092 | +QPDFWriter::Members::preserveObjectStreams() |
| 1979 | { | 2093 | { |
| 1980 | - auto const& xref = QPDF::Writer::getXRefTable(m->pdf); | 2094 | + auto const& xref = QPDF::Writer::getXRefTable(pdf); |
| 1981 | // Our object_to_object_stream map has to map ObjGen -> ObjGen since we may be generating object | 2095 | // Our object_to_object_stream map has to map ObjGen -> ObjGen since we may be generating object |
| 1982 | // streams out of old objects that have generation numbers greater than zero. However in an | 2096 | // streams out of old objects that have generation numbers greater than zero. However in an |
| 1983 | // existing PDF, all object stream objects and all objects in them must have generation 0 | 2097 | // existing PDF, all object stream objects and all objects in them must have generation 0 |
| @@ -1986,14 +2100,13 @@ QPDFWriter::preserveObjectStreams() | @@ -1986,14 +2100,13 @@ QPDFWriter::preserveObjectStreams() | ||
| 1986 | // erroneously included in object streams in the source PDF, it also prevents unreferenced | 2100 | // erroneously included in object streams in the source PDF, it also prevents unreferenced |
| 1987 | // objects from being included. | 2101 | // objects from being included. |
| 1988 | auto end = xref.cend(); | 2102 | auto end = xref.cend(); |
| 1989 | - m->obj.streams_empty = true; | ||
| 1990 | - if (m->preserve_unreferenced_objects) { | 2103 | + obj.streams_empty = true; |
| 2104 | + if (preserve_unreferenced_objects) { | ||
| 1991 | for (auto iter = xref.cbegin(); iter != end; ++iter) { | 2105 | for (auto iter = xref.cbegin(); iter != end; ++iter) { |
| 1992 | if (iter->second.getType() == 2) { | 2106 | if (iter->second.getType() == 2) { |
| 1993 | // Pdf contains object streams. | 2107 | // Pdf contains object streams. |
| 1994 | - QTC::TC("qpdf", "QPDFWriter preserve object streams preserve unreferenced"); | ||
| 1995 | - m->obj.streams_empty = false; | ||
| 1996 | - m->obj[iter->first].object_stream = iter->second.getObjStreamNumber(); | 2108 | + obj.streams_empty = false; |
| 2109 | + obj[iter->first].object_stream = iter->second.getObjStreamNumber(); | ||
| 1997 | } | 2110 | } |
| 1998 | } | 2111 | } |
| 1999 | } else { | 2112 | } else { |
| @@ -2002,9 +2115,8 @@ QPDFWriter::preserveObjectStreams() | @@ -2002,9 +2115,8 @@ QPDFWriter::preserveObjectStreams() | ||
| 2002 | for (auto iter = xref.cbegin(); iter != end; ++iter) { | 2115 | for (auto iter = xref.cbegin(); iter != end; ++iter) { |
| 2003 | if (iter->second.getType() == 2) { | 2116 | if (iter->second.getType() == 2) { |
| 2004 | // Pdf contains object streams. | 2117 | // Pdf contains object streams. |
| 2005 | - QTC::TC("qpdf", "QPDFWriter preserve object streams"); | ||
| 2006 | - m->obj.streams_empty = false; | ||
| 2007 | - auto eligible = QPDF::Writer::getCompressibleObjSet(m->pdf); | 2118 | + obj.streams_empty = false; |
| 2119 | + auto eligible = QPDF::Writer::getCompressibleObjSet(pdf); | ||
| 2008 | // The object pointed to by iter may be a previous generation, in which case it is | 2120 | // The object pointed to by iter may be a previous generation, in which case it is |
| 2009 | // removed by getCompressibleObjSet. We need to restart the loop (while the object | 2121 | // removed by getCompressibleObjSet. We need to restart the loop (while the object |
| 2010 | // table may contain multiple generations of an object). | 2122 | // table may contain multiple generations of an object). |
| @@ -2012,7 +2124,7 @@ QPDFWriter::preserveObjectStreams() | @@ -2012,7 +2124,7 @@ QPDFWriter::preserveObjectStreams() | ||
| 2012 | if (iter->second.getType() == 2) { | 2124 | if (iter->second.getType() == 2) { |
| 2013 | auto id = static_cast<size_t>(iter->first.getObj()); | 2125 | auto id = static_cast<size_t>(iter->first.getObj()); |
| 2014 | if (id < eligible.size() && eligible[id]) { | 2126 | if (id < eligible.size() && eligible[id]) { |
| 2015 | - m->obj[iter->first].object_stream = iter->second.getObjStreamNumber(); | 2127 | + obj[iter->first].object_stream = iter->second.getObjStreamNumber(); |
| 2016 | } else { | 2128 | } else { |
| 2017 | QTC::TC("qpdf", "QPDFWriter exclude from object stream"); | 2129 | QTC::TC("qpdf", "QPDFWriter exclude from object stream"); |
| 2018 | } | 2130 | } |
| @@ -2025,7 +2137,7 @@ QPDFWriter::preserveObjectStreams() | @@ -2025,7 +2137,7 @@ QPDFWriter::preserveObjectStreams() | ||
| 2025 | } | 2137 | } |
| 2026 | 2138 | ||
| 2027 | void | 2139 | void |
| 2028 | -QPDFWriter::generateObjectStreams() | 2140 | +QPDFWriter::Members::generateObjectStreams() |
| 2029 | { | 2141 | { |
| 2030 | // Basic strategy: make a list of objects that can go into an object stream. Then figure out | 2142 | // Basic strategy: make a list of objects that can go into an object stream. Then figure out |
| 2031 | // how many object streams are needed so that we can distribute objects approximately evenly | 2143 | // how many object streams are needed so that we can distribute objects approximately evenly |
| @@ -2035,12 +2147,12 @@ QPDFWriter::generateObjectStreams() | @@ -2035,12 +2147,12 @@ QPDFWriter::generateObjectStreams() | ||
| 2035 | 2147 | ||
| 2036 | // This code doesn't do anything with /Extends. | 2148 | // This code doesn't do anything with /Extends. |
| 2037 | 2149 | ||
| 2038 | - std::vector<QPDFObjGen> eligible = QPDF::Writer::getCompressibleObjGens(m->pdf); | 2150 | + std::vector<QPDFObjGen> eligible = QPDF::Writer::getCompressibleObjGens(pdf); |
| 2039 | size_t n_object_streams = (eligible.size() + 99U) / 100U; | 2151 | size_t n_object_streams = (eligible.size() + 99U) / 100U; |
| 2040 | 2152 | ||
| 2041 | initializeTables(2U * n_object_streams); | 2153 | initializeTables(2U * n_object_streams); |
| 2042 | if (n_object_streams == 0) { | 2154 | if (n_object_streams == 0) { |
| 2043 | - m->obj.streams_empty = true; | 2155 | + obj.streams_empty = true; |
| 2044 | return; | 2156 | return; |
| 2045 | } | 2157 | } |
| 2046 | size_t n_per = eligible.size() / n_object_streams; | 2158 | size_t n_per = eligible.size() / n_object_streams; |
| @@ -2048,28 +2160,27 @@ QPDFWriter::generateObjectStreams() | @@ -2048,28 +2160,27 @@ QPDFWriter::generateObjectStreams() | ||
| 2048 | ++n_per; | 2160 | ++n_per; |
| 2049 | } | 2161 | } |
| 2050 | unsigned int n = 0; | 2162 | unsigned int n = 0; |
| 2051 | - int cur_ostream = m->pdf.newIndirectNull().getObjectID(); | 2163 | + int cur_ostream = pdf.newIndirectNull().getObjectID(); |
| 2052 | for (auto const& item: eligible) { | 2164 | for (auto const& item: eligible) { |
| 2053 | if (n == n_per) { | 2165 | if (n == n_per) { |
| 2054 | - QTC::TC("qpdf", "QPDFWriter generate >1 ostream"); | ||
| 2055 | n = 0; | 2166 | n = 0; |
| 2056 | // Construct a new null object as the "original" object stream. The rest of the code | 2167 | // Construct a new null object as the "original" object stream. The rest of the code |
| 2057 | // knows that this means we're creating the object stream from scratch. | 2168 | // knows that this means we're creating the object stream from scratch. |
| 2058 | - cur_ostream = m->pdf.newIndirectNull().getObjectID(); | 2169 | + cur_ostream = pdf.newIndirectNull().getObjectID(); |
| 2059 | } | 2170 | } |
| 2060 | - auto& obj = m->obj[item]; | ||
| 2061 | - obj.object_stream = cur_ostream; | ||
| 2062 | - obj.gen = item.getGen(); | 2171 | + auto& o = obj[item]; |
| 2172 | + o.object_stream = cur_ostream; | ||
| 2173 | + o.gen = item.getGen(); | ||
| 2063 | ++n; | 2174 | ++n; |
| 2064 | } | 2175 | } |
| 2065 | } | 2176 | } |
| 2066 | 2177 | ||
| 2067 | QPDFObjectHandle | 2178 | QPDFObjectHandle |
| 2068 | -QPDFWriter::getTrimmedTrailer() | 2179 | +QPDFWriter::Members::getTrimmedTrailer() |
| 2069 | { | 2180 | { |
| 2070 | // Remove keys from the trailer that necessarily have to be replaced when writing the file. | 2181 | // Remove keys from the trailer that necessarily have to be replaced when writing the file. |
| 2071 | 2182 | ||
| 2072 | - QPDFObjectHandle trailer = m->pdf.getTrailer().unsafeShallowCopy(); | 2183 | + QPDFObjectHandle trailer = pdf.getTrailer().unsafeShallowCopy(); |
| 2073 | 2184 | ||
| 2074 | // Remove encryption keys | 2185 | // Remove encryption keys |
| 2075 | trailer.removeKey("/ID"); | 2186 | trailer.removeKey("/ID"); |
| @@ -2092,10 +2203,10 @@ QPDFWriter::getTrimmedTrailer() | @@ -2092,10 +2203,10 @@ QPDFWriter::getTrimmedTrailer() | ||
| 2092 | 2203 | ||
| 2093 | // Make document extension level information direct as required by the spec. | 2204 | // Make document extension level information direct as required by the spec. |
| 2094 | void | 2205 | void |
| 2095 | -QPDFWriter::prepareFileForWrite() | 2206 | +QPDFWriter::Members::prepareFileForWrite() |
| 2096 | { | 2207 | { |
| 2097 | - m->pdf.fixDanglingReferences(); | ||
| 2098 | - auto root = m->pdf.getRoot(); | 2208 | + pdf.fixDanglingReferences(); |
| 2209 | + auto root = pdf.getRoot(); | ||
| 2099 | auto oh = root.getKey("/Extensions"); | 2210 | auto oh = root.getKey("/Extensions"); |
| 2100 | if (oh.isDictionary()) { | 2211 | if (oh.isDictionary()) { |
| 2101 | const bool extensions_indirect = oh.isIndirect(); | 2212 | const bool extensions_indirect = oh.isIndirect(); |
| @@ -2115,84 +2226,83 @@ QPDFWriter::prepareFileForWrite() | @@ -2115,84 +2226,83 @@ QPDFWriter::prepareFileForWrite() | ||
| 2115 | } | 2226 | } |
| 2116 | 2227 | ||
| 2117 | void | 2228 | void |
| 2118 | -QPDFWriter::initializeTables(size_t extra) | 2229 | +QPDFWriter::Members::initializeTables(size_t extra) |
| 2119 | { | 2230 | { |
| 2120 | - auto size = QIntC::to_size(QPDF::Writer::tableSize(m->pdf) + 100) + extra; | ||
| 2121 | - m->obj.resize(size); | ||
| 2122 | - m->new_obj.resize(size); | 2231 | + auto size = QIntC::to_size(QPDF::Writer::tableSize(pdf) + 100) + extra; |
| 2232 | + obj.resize(size); | ||
| 2233 | + new_obj.resize(size); | ||
| 2123 | } | 2234 | } |
| 2124 | 2235 | ||
| 2125 | void | 2236 | void |
| 2126 | -QPDFWriter::doWriteSetup() | 2237 | +QPDFWriter::Members::doWriteSetup() |
| 2127 | { | 2238 | { |
| 2128 | - if (m->did_write_setup) { | 2239 | + if (did_write_setup) { |
| 2129 | return; | 2240 | return; |
| 2130 | } | 2241 | } |
| 2131 | - m->did_write_setup = true; | 2242 | + did_write_setup = true; |
| 2132 | 2243 | ||
| 2133 | // Do preliminary setup | 2244 | // Do preliminary setup |
| 2134 | 2245 | ||
| 2135 | - if (m->linearized) { | ||
| 2136 | - m->qdf_mode = false; | 2246 | + if (linearized) { |
| 2247 | + qdf_mode = false; | ||
| 2137 | } | 2248 | } |
| 2138 | 2249 | ||
| 2139 | - if (m->pclm) { | ||
| 2140 | - m->stream_decode_level = qpdf_dl_none; | ||
| 2141 | - m->compress_streams = false; | ||
| 2142 | - m->encryption = nullptr; | 2250 | + if (pclm) { |
| 2251 | + stream_decode_level = qpdf_dl_none; | ||
| 2252 | + compress_streams = false; | ||
| 2253 | + encryption = nullptr; | ||
| 2143 | } | 2254 | } |
| 2144 | 2255 | ||
| 2145 | - if (m->qdf_mode) { | ||
| 2146 | - if (!m->normalize_content_set) { | ||
| 2147 | - m->normalize_content = true; | 2256 | + if (qdf_mode) { |
| 2257 | + if (!normalize_content_set) { | ||
| 2258 | + normalize_content = true; | ||
| 2148 | } | 2259 | } |
| 2149 | - if (!m->compress_streams_set) { | ||
| 2150 | - m->compress_streams = false; | 2260 | + if (!compress_streams_set) { |
| 2261 | + compress_streams = false; | ||
| 2151 | } | 2262 | } |
| 2152 | - if (!m->stream_decode_level_set) { | ||
| 2153 | - m->stream_decode_level = qpdf_dl_generalized; | 2263 | + if (!stream_decode_level_set) { |
| 2264 | + stream_decode_level = qpdf_dl_generalized; | ||
| 2154 | } | 2265 | } |
| 2155 | } | 2266 | } |
| 2156 | 2267 | ||
| 2157 | - if (m->encryption) { | 2268 | + if (encryption) { |
| 2158 | // Encryption has been explicitly set | 2269 | // Encryption has been explicitly set |
| 2159 | - m->preserve_encryption = false; | ||
| 2160 | - } else if (m->normalize_content || !m->compress_streams || m->pclm || m->qdf_mode) { | 2270 | + preserve_encryption = false; |
| 2271 | + } else if (normalize_content || !compress_streams || pclm || qdf_mode) { | ||
| 2161 | // Encryption makes looking at contents pretty useless. If the user explicitly encrypted | 2272 | // Encryption makes looking at contents pretty useless. If the user explicitly encrypted |
| 2162 | // though, we still obey that. | 2273 | // though, we still obey that. |
| 2163 | - m->preserve_encryption = false; | 2274 | + preserve_encryption = false; |
| 2164 | } | 2275 | } |
| 2165 | 2276 | ||
| 2166 | - if (m->preserve_encryption) { | ||
| 2167 | - copyEncryptionParameters(m->pdf); | 2277 | + if (preserve_encryption) { |
| 2278 | + copyEncryptionParameters(pdf); | ||
| 2168 | } | 2279 | } |
| 2169 | 2280 | ||
| 2170 | - if (!m->forced_pdf_version.empty()) { | 2281 | + if (!forced_pdf_version.empty()) { |
| 2171 | int major = 0; | 2282 | int major = 0; |
| 2172 | int minor = 0; | 2283 | int minor = 0; |
| 2173 | - parseVersion(m->forced_pdf_version, major, minor); | ||
| 2174 | - disableIncompatibleEncryption(major, minor, m->forced_extension_level); | 2284 | + parseVersion(forced_pdf_version, major, minor); |
| 2285 | + disableIncompatibleEncryption(major, minor, forced_extension_level); | ||
| 2175 | if (compareVersions(major, minor, 1, 5) < 0) { | 2286 | if (compareVersions(major, minor, 1, 5) < 0) { |
| 2176 | - QTC::TC("qpdf", "QPDFWriter forcing object stream disable"); | ||
| 2177 | - m->object_stream_mode = qpdf_o_disable; | 2287 | + object_stream_mode = qpdf_o_disable; |
| 2178 | } | 2288 | } |
| 2179 | } | 2289 | } |
| 2180 | 2290 | ||
| 2181 | - if (m->qdf_mode || m->normalize_content) { | 2291 | + if (qdf_mode || normalize_content) { |
| 2182 | initializeSpecialStreams(); | 2292 | initializeSpecialStreams(); |
| 2183 | } | 2293 | } |
| 2184 | 2294 | ||
| 2185 | - if (m->qdf_mode) { | 2295 | + if (qdf_mode) { |
| 2186 | // Generate indirect stream lengths for qdf mode since fix-qdf uses them for storing | 2296 | // Generate indirect stream lengths for qdf mode since fix-qdf uses them for storing |
| 2187 | // recomputed stream length data. Certain streams such as object streams, xref streams, and | 2297 | // recomputed stream length data. Certain streams such as object streams, xref streams, and |
| 2188 | // hint streams always get direct stream lengths. | 2298 | // hint streams always get direct stream lengths. |
| 2189 | - m->direct_stream_lengths = false; | 2299 | + direct_stream_lengths = false; |
| 2190 | } | 2300 | } |
| 2191 | 2301 | ||
| 2192 | - switch (m->object_stream_mode) { | 2302 | + switch (object_stream_mode) { |
| 2193 | case qpdf_o_disable: | 2303 | case qpdf_o_disable: |
| 2194 | initializeTables(); | 2304 | initializeTables(); |
| 2195 | - m->obj.streams_empty = true; | 2305 | + obj.streams_empty = true; |
| 2196 | break; | 2306 | break; |
| 2197 | 2307 | ||
| 2198 | case qpdf_o_preserve: | 2308 | case qpdf_o_preserve: |
| @@ -2207,82 +2317,85 @@ QPDFWriter::doWriteSetup() | @@ -2207,82 +2317,85 @@ QPDFWriter::doWriteSetup() | ||
| 2207 | // no default so gcc will warn for missing case tag | 2317 | // no default so gcc will warn for missing case tag |
| 2208 | } | 2318 | } |
| 2209 | 2319 | ||
| 2210 | - if (!m->obj.streams_empty) { | ||
| 2211 | - if (m->linearized) { | 2320 | + if (!obj.streams_empty) { |
| 2321 | + if (linearized) { | ||
| 2212 | // Page dictionaries are not allowed to be compressed objects. | 2322 | // Page dictionaries are not allowed to be compressed objects. |
| 2213 | - for (auto& page: m->pdf.getAllPages()) { | ||
| 2214 | - if (m->obj[page].object_stream > 0) { | ||
| 2215 | - QTC::TC("qpdf", "QPDFWriter uncompressing page dictionary"); | ||
| 2216 | - m->obj[page].object_stream = 0; | 2323 | + for (auto& page: pdf.getAllPages()) { |
| 2324 | + if (obj[page].object_stream > 0) { | ||
| 2325 | + obj[page].object_stream = 0; | ||
| 2217 | } | 2326 | } |
| 2218 | } | 2327 | } |
| 2219 | } | 2328 | } |
| 2220 | 2329 | ||
| 2221 | - if (m->linearized || m->encryption) { | 2330 | + if (linearized || encryption) { |
| 2222 | // The document catalog is not allowed to be compressed in linearized files either. It | 2331 | // The document catalog is not allowed to be compressed in linearized files either. It |
| 2223 | // also appears that Adobe Reader 8.0.0 has a bug that prevents it from being able to | 2332 | // also appears that Adobe Reader 8.0.0 has a bug that prevents it from being able to |
| 2224 | // handle encrypted files with compressed document catalogs, so we disable them in that | 2333 | // handle encrypted files with compressed document catalogs, so we disable them in that |
| 2225 | // case as well. | 2334 | // case as well. |
| 2226 | - if (m->obj[m->root_og].object_stream > 0) { | ||
| 2227 | - QTC::TC("qpdf", "QPDFWriter uncompressing root"); | ||
| 2228 | - m->obj[m->root_og].object_stream = 0; | 2335 | + if (obj[root_og].object_stream > 0) { |
| 2336 | + obj[root_og].object_stream = 0; | ||
| 2229 | } | 2337 | } |
| 2230 | } | 2338 | } |
| 2231 | 2339 | ||
| 2232 | // Generate reverse mapping from object stream to objects | 2340 | // Generate reverse mapping from object stream to objects |
| 2233 | - m->obj.forEach([this](auto id, auto const& item) -> void { | 2341 | + obj.forEach([this](auto id, auto const& item) -> void { |
| 2234 | if (item.object_stream > 0) { | 2342 | if (item.object_stream > 0) { |
| 2235 | - auto& vec = m->object_stream_to_objects[item.object_stream]; | 2343 | + auto& vec = object_stream_to_objects[item.object_stream]; |
| 2236 | vec.emplace_back(id, item.gen); | 2344 | vec.emplace_back(id, item.gen); |
| 2237 | - if (m->max_ostream_index < vec.size()) { | ||
| 2238 | - ++m->max_ostream_index; | 2345 | + if (max_ostream_index < vec.size()) { |
| 2346 | + ++max_ostream_index; | ||
| 2239 | } | 2347 | } |
| 2240 | } | 2348 | } |
| 2241 | }); | 2349 | }); |
| 2242 | - --m->max_ostream_index; | 2350 | + --max_ostream_index; |
| 2243 | 2351 | ||
| 2244 | - if (m->object_stream_to_objects.empty()) { | ||
| 2245 | - m->obj.streams_empty = true; | 2352 | + if (object_stream_to_objects.empty()) { |
| 2353 | + obj.streams_empty = true; | ||
| 2246 | } else { | 2354 | } else { |
| 2247 | - setMinimumPDFVersion("1.5"); | 2355 | + w.setMinimumPDFVersion("1.5"); |
| 2248 | } | 2356 | } |
| 2249 | } | 2357 | } |
| 2250 | 2358 | ||
| 2251 | - setMinimumPDFVersion(m->pdf.getPDFVersion(), m->pdf.getExtensionLevel()); | ||
| 2252 | - m->final_pdf_version = m->min_pdf_version; | ||
| 2253 | - m->final_extension_level = m->min_extension_level; | ||
| 2254 | - if (!m->forced_pdf_version.empty()) { | ||
| 2255 | - QTC::TC("qpdf", "QPDFWriter using forced PDF version"); | ||
| 2256 | - m->final_pdf_version = m->forced_pdf_version; | ||
| 2257 | - m->final_extension_level = m->forced_extension_level; | 2359 | + setMinimumPDFVersion(pdf.getPDFVersion(), pdf.getExtensionLevel()); |
| 2360 | + final_pdf_version = min_pdf_version; | ||
| 2361 | + final_extension_level = min_extension_level; | ||
| 2362 | + if (!forced_pdf_version.empty()) { | ||
| 2363 | + final_pdf_version = forced_pdf_version; | ||
| 2364 | + final_extension_level = forced_extension_level; | ||
| 2258 | } | 2365 | } |
| 2259 | } | 2366 | } |
| 2260 | 2367 | ||
| 2261 | void | 2368 | void |
| 2262 | QPDFWriter::write() | 2369 | QPDFWriter::write() |
| 2263 | { | 2370 | { |
| 2371 | + m->write(); | ||
| 2372 | +} | ||
| 2373 | + | ||
| 2374 | +void | ||
| 2375 | +QPDFWriter::Members::write() | ||
| 2376 | +{ | ||
| 2264 | doWriteSetup(); | 2377 | doWriteSetup(); |
| 2265 | 2378 | ||
| 2266 | // Set up progress reporting. For linearized files, we write two passes. events_expected is an | 2379 | // Set up progress reporting. For linearized files, we write two passes. events_expected is an |
| 2267 | // approximation, but it's good enough for progress reporting, which is mostly a guess anyway. | 2380 | // approximation, but it's good enough for progress reporting, which is mostly a guess anyway. |
| 2268 | - m->events_expected = QIntC::to_int(m->pdf.getObjectCount() * (m->linearized ? 2 : 1)); | 2381 | + events_expected = QIntC::to_int(pdf.getObjectCount() * (linearized ? 2 : 1)); |
| 2269 | 2382 | ||
| 2270 | prepareFileForWrite(); | 2383 | prepareFileForWrite(); |
| 2271 | 2384 | ||
| 2272 | - if (m->linearized) { | 2385 | + if (linearized) { |
| 2273 | writeLinearized(); | 2386 | writeLinearized(); |
| 2274 | } else { | 2387 | } else { |
| 2275 | writeStandard(); | 2388 | writeStandard(); |
| 2276 | } | 2389 | } |
| 2277 | 2390 | ||
| 2278 | - m->pipeline->finish(); | ||
| 2279 | - if (m->close_file) { | ||
| 2280 | - fclose(m->file); | 2391 | + pipeline->finish(); |
| 2392 | + if (close_file) { | ||
| 2393 | + fclose(file); | ||
| 2281 | } | 2394 | } |
| 2282 | - m->file = nullptr; | ||
| 2283 | - if (m->buffer_pipeline) { | ||
| 2284 | - m->output_buffer = m->buffer_pipeline->getBuffer(); | ||
| 2285 | - m->buffer_pipeline = nullptr; | 2395 | + file = nullptr; |
| 2396 | + if (buffer_pipeline) { | ||
| 2397 | + output_buffer = buffer_pipeline->getBuffer(); | ||
| 2398 | + buffer_pipeline = nullptr; | ||
| 2286 | } | 2399 | } |
| 2287 | indicateProgress(false, true); | 2400 | indicateProgress(false, true); |
| 2288 | } | 2401 | } |
| @@ -2296,10 +2409,16 @@ QPDFWriter::getRenumberedObjGen(QPDFObjGen og) | @@ -2296,10 +2409,16 @@ QPDFWriter::getRenumberedObjGen(QPDFObjGen og) | ||
| 2296 | std::map<QPDFObjGen, QPDFXRefEntry> | 2409 | std::map<QPDFObjGen, QPDFXRefEntry> |
| 2297 | QPDFWriter::getWrittenXRefTable() | 2410 | QPDFWriter::getWrittenXRefTable() |
| 2298 | { | 2411 | { |
| 2412 | + return m->getWrittenXRefTable(); | ||
| 2413 | +} | ||
| 2414 | + | ||
| 2415 | +std::map<QPDFObjGen, QPDFXRefEntry> | ||
| 2416 | +QPDFWriter::Members::getWrittenXRefTable() | ||
| 2417 | +{ | ||
| 2299 | std::map<QPDFObjGen, QPDFXRefEntry> result; | 2418 | std::map<QPDFObjGen, QPDFXRefEntry> result; |
| 2300 | 2419 | ||
| 2301 | auto it = result.begin(); | 2420 | auto it = result.begin(); |
| 2302 | - m->new_obj.forEach([&it, &result](auto id, auto const& item) -> void { | 2421 | + new_obj.forEach([&it, &result](auto id, auto const& item) -> void { |
| 2303 | if (item.xref.getType() != 0) { | 2422 | if (item.xref.getType() != 0) { |
| 2304 | it = result.emplace_hint(it, QPDFObjGen(id, 0), item.xref); | 2423 | it = result.emplace_hint(it, QPDFObjGen(id, 0), item.xref); |
| 2305 | } | 2424 | } |
| @@ -2308,7 +2427,7 @@ QPDFWriter::getWrittenXRefTable() | @@ -2308,7 +2427,7 @@ QPDFWriter::getWrittenXRefTable() | ||
| 2308 | } | 2427 | } |
| 2309 | 2428 | ||
| 2310 | void | 2429 | void |
| 2311 | -QPDFWriter::enqueuePart(std::vector<QPDFObjectHandle>& part) | 2430 | +QPDFWriter::Members::enqueuePart(std::vector<QPDFObjectHandle>& part) |
| 2312 | { | 2431 | { |
| 2313 | for (auto const& oh: part) { | 2432 | for (auto const& oh: part) { |
| 2314 | enqueueObject(oh); | 2433 | enqueueObject(oh); |
| @@ -2316,20 +2435,20 @@ QPDFWriter::enqueuePart(std::vector<QPDFObjectHandle>& part) | @@ -2316,20 +2435,20 @@ QPDFWriter::enqueuePart(std::vector<QPDFObjectHandle>& part) | ||
| 2316 | } | 2435 | } |
| 2317 | 2436 | ||
| 2318 | void | 2437 | void |
| 2319 | -QPDFWriter::writeEncryptionDictionary() | 2438 | +QPDFWriter::Members::writeEncryptionDictionary() |
| 2320 | { | 2439 | { |
| 2321 | - m->encryption_dict_objid = openObject(m->encryption_dict_objid); | ||
| 2322 | - auto& enc = *m->encryption; | 2440 | + encryption_dict_objid = openObject(encryption_dict_objid); |
| 2441 | + auto& enc = *encryption; | ||
| 2323 | auto const V = enc.getV(); | 2442 | auto const V = enc.getV(); |
| 2324 | 2443 | ||
| 2325 | write("<<"); | 2444 | write("<<"); |
| 2326 | if (V >= 4) { | 2445 | if (V >= 4) { |
| 2327 | write(" /CF << /StdCF << /AuthEvent /DocOpen /CFM "); | 2446 | write(" /CF << /StdCF << /AuthEvent /DocOpen /CFM "); |
| 2328 | - write(m->encrypt_use_aes ? ((V < 5) ? "/AESV2" : "/AESV3") : "/V2"); | 2447 | + write(encrypt_use_aes ? ((V < 5) ? "/AESV2" : "/AESV3") : "/V2"); |
| 2329 | // The PDF spec says the /Length key is optional, but the PDF previewer on some versions of | 2448 | // The PDF spec says the /Length key is optional, but the PDF previewer on some versions of |
| 2330 | // MacOS won't open encrypted files without it. | 2449 | // MacOS won't open encrypted files without it. |
| 2331 | write((V < 5) ? " /Length 16 >> >>" : " /Length 32 >> >>"); | 2450 | write((V < 5) ? " /Length 16 >> >>" : " /Length 32 >> >>"); |
| 2332 | - if (!m->encryption->getEncryptMetadata()) { | 2451 | + if (!encryption->getEncryptMetadata()) { |
| 2333 | write(" /EncryptMetadata false"); | 2452 | write(" /EncryptMetadata false"); |
| 2334 | } | 2453 | } |
| 2335 | } | 2454 | } |
| @@ -2352,21 +2471,21 @@ QPDFWriter::writeEncryptionDictionary() | @@ -2352,21 +2471,21 @@ QPDFWriter::writeEncryptionDictionary() | ||
| 2352 | write(" /UE ").write_string(enc.getUE(), true); | 2471 | write(" /UE ").write_string(enc.getUE(), true); |
| 2353 | } | 2472 | } |
| 2354 | write(" /V ").write(enc.getV()).write(" >>"); | 2473 | write(" /V ").write(enc.getV()).write(" >>"); |
| 2355 | - closeObject(m->encryption_dict_objid); | 2474 | + closeObject(encryption_dict_objid); |
| 2356 | } | 2475 | } |
| 2357 | 2476 | ||
| 2358 | std::string | 2477 | std::string |
| 2359 | QPDFWriter::getFinalVersion() | 2478 | QPDFWriter::getFinalVersion() |
| 2360 | { | 2479 | { |
| 2361 | - doWriteSetup(); | 2480 | + m->doWriteSetup(); |
| 2362 | return m->final_pdf_version; | 2481 | return m->final_pdf_version; |
| 2363 | } | 2482 | } |
| 2364 | 2483 | ||
| 2365 | void | 2484 | void |
| 2366 | -QPDFWriter::writeHeader() | 2485 | +QPDFWriter::Members::writeHeader() |
| 2367 | { | 2486 | { |
| 2368 | - write("%PDF-").write(m->final_pdf_version); | ||
| 2369 | - if (m->pclm) { | 2487 | + write("%PDF-").write(final_pdf_version); |
| 2488 | + if (pclm) { | ||
| 2370 | // PCLm version | 2489 | // PCLm version |
| 2371 | write("\n%PCLm 1.0\n"); | 2490 | write("\n%PCLm 1.0\n"); |
| 2372 | } else { | 2491 | } else { |
| @@ -2383,13 +2502,13 @@ QPDFWriter::writeHeader() | @@ -2383,13 +2502,13 @@ QPDFWriter::writeHeader() | ||
| 2383 | } | 2502 | } |
| 2384 | 2503 | ||
| 2385 | void | 2504 | void |
| 2386 | -QPDFWriter::writeHintStream(int hint_id) | 2505 | +QPDFWriter::Members::writeHintStream(int hint_id) |
| 2387 | { | 2506 | { |
| 2388 | std::string hint_buffer; | 2507 | std::string hint_buffer; |
| 2389 | int S = 0; | 2508 | int S = 0; |
| 2390 | int O = 0; | 2509 | int O = 0; |
| 2391 | - bool compressed = m->compress_streams && !m->qdf_mode; | ||
| 2392 | - QPDF::Writer::generateHintStream(m->pdf, m->new_obj, m->obj, hint_buffer, S, O, compressed); | 2510 | + bool compressed = compress_streams && !qdf_mode; |
| 2511 | + QPDF::Writer::generateHintStream(pdf, new_obj, obj, hint_buffer, S, O, compressed); | ||
| 2393 | 2512 | ||
| 2394 | openObject(hint_id); | 2513 | openObject(hint_id); |
| 2395 | setDataKey(hint_id); | 2514 | setDataKey(hint_id); |
| @@ -2408,7 +2527,7 @@ QPDFWriter::writeHintStream(int hint_id) | @@ -2408,7 +2527,7 @@ QPDFWriter::writeHintStream(int hint_id) | ||
| 2408 | write(" /Length ").write(hlen); | 2527 | write(" /Length ").write(hlen); |
| 2409 | write(" >>\nstream\n").write_encrypted(hint_buffer); | 2528 | write(" >>\nstream\n").write_encrypted(hint_buffer); |
| 2410 | 2529 | ||
| 2411 | - if (m->encryption) { | 2530 | + if (encryption) { |
| 2412 | QTC::TC("qpdf", "QPDFWriter encrypted hint stream"); | 2531 | QTC::TC("qpdf", "QPDFWriter encrypted hint stream"); |
| 2413 | } | 2532 | } |
| 2414 | 2533 | ||
| @@ -2417,7 +2536,7 @@ QPDFWriter::writeHintStream(int hint_id) | @@ -2417,7 +2536,7 @@ QPDFWriter::writeHintStream(int hint_id) | ||
| 2417 | } | 2536 | } |
| 2418 | 2537 | ||
| 2419 | qpdf_offset_t | 2538 | qpdf_offset_t |
| 2420 | -QPDFWriter::writeXRefTable(trailer_e which, int first, int last, int size) | 2539 | +QPDFWriter::Members::writeXRefTable(trailer_e which, int first, int last, int size) |
| 2421 | { | 2540 | { |
| 2422 | // There are too many extra arguments to replace overloaded function with defaults in the header | 2541 | // There are too many extra arguments to replace overloaded function with defaults in the header |
| 2423 | // file...too much risk of leaving something off. | 2542 | // file...too much risk of leaving something off. |
| @@ -2425,7 +2544,7 @@ QPDFWriter::writeXRefTable(trailer_e which, int first, int last, int size) | @@ -2425,7 +2544,7 @@ QPDFWriter::writeXRefTable(trailer_e which, int first, int last, int size) | ||
| 2425 | } | 2544 | } |
| 2426 | 2545 | ||
| 2427 | qpdf_offset_t | 2546 | qpdf_offset_t |
| 2428 | -QPDFWriter::writeXRefTable( | 2547 | +QPDFWriter::Members::writeXRefTable( |
| 2429 | trailer_e which, | 2548 | trailer_e which, |
| 2430 | int first, | 2549 | int first, |
| 2431 | int last, | 2550 | int last, |
| @@ -2438,7 +2557,7 @@ QPDFWriter::writeXRefTable( | @@ -2438,7 +2557,7 @@ QPDFWriter::writeXRefTable( | ||
| 2438 | int linearization_pass) | 2557 | int linearization_pass) |
| 2439 | { | 2558 | { |
| 2440 | write("xref\n").write(first).write(" ").write(last - first + 1); | 2559 | write("xref\n").write(first).write(" ").write(last - first + 1); |
| 2441 | - qpdf_offset_t space_before_zero = m->pipeline->getCount(); | 2560 | + qpdf_offset_t space_before_zero = pipeline->getCount(); |
| 2442 | write("\n"); | 2561 | write("\n"); |
| 2443 | if (first == 0) { | 2562 | if (first == 0) { |
| 2444 | write("0000000000 65535 f \n"); | 2563 | write("0000000000 65535 f \n"); |
| @@ -2447,7 +2566,7 @@ QPDFWriter::writeXRefTable( | @@ -2447,7 +2566,7 @@ QPDFWriter::writeXRefTable( | ||
| 2447 | for (int i = first; i <= last; ++i) { | 2566 | for (int i = first; i <= last; ++i) { |
| 2448 | qpdf_offset_t offset = 0; | 2567 | qpdf_offset_t offset = 0; |
| 2449 | if (!suppress_offsets) { | 2568 | if (!suppress_offsets) { |
| 2450 | - offset = m->new_obj[i].xref.getOffset(); | 2569 | + offset = new_obj[i].xref.getOffset(); |
| 2451 | if ((hint_id != 0) && (i != hint_id) && (offset >= hint_offset)) { | 2570 | if ((hint_id != 0) && (i != hint_id) && (offset >= hint_offset)) { |
| 2452 | offset += hint_length; | 2571 | offset += hint_length; |
| 2453 | } | 2572 | } |
| @@ -2460,7 +2579,7 @@ QPDFWriter::writeXRefTable( | @@ -2460,7 +2579,7 @@ QPDFWriter::writeXRefTable( | ||
| 2460 | } | 2579 | } |
| 2461 | 2580 | ||
| 2462 | qpdf_offset_t | 2581 | qpdf_offset_t |
| 2463 | -QPDFWriter::writeXRefStream( | 2582 | +QPDFWriter::Members::writeXRefStream( |
| 2464 | int objid, int max_id, qpdf_offset_t max_offset, trailer_e which, int first, int last, int size) | 2583 | int objid, int max_id, qpdf_offset_t max_offset, trailer_e which, int first, int last, int size) |
| 2465 | { | 2584 | { |
| 2466 | // There are too many extra arguments to replace overloaded function with defaults in the header | 2585 | // There are too many extra arguments to replace overloaded function with defaults in the header |
| @@ -2470,7 +2589,7 @@ QPDFWriter::writeXRefStream( | @@ -2470,7 +2589,7 @@ QPDFWriter::writeXRefStream( | ||
| 2470 | } | 2589 | } |
| 2471 | 2590 | ||
| 2472 | qpdf_offset_t | 2591 | qpdf_offset_t |
| 2473 | -QPDFWriter::writeXRefStream( | 2592 | +QPDFWriter::Members::writeXRefStream( |
| 2474 | int xref_id, | 2593 | int xref_id, |
| 2475 | int max_id, | 2594 | int max_id, |
| 2476 | qpdf_offset_t max_offset, | 2595 | qpdf_offset_t max_offset, |
| @@ -2485,28 +2604,28 @@ QPDFWriter::writeXRefStream( | @@ -2485,28 +2604,28 @@ QPDFWriter::writeXRefStream( | ||
| 2485 | bool skip_compression, | 2604 | bool skip_compression, |
| 2486 | int linearization_pass) | 2605 | int linearization_pass) |
| 2487 | { | 2606 | { |
| 2488 | - qpdf_offset_t xref_offset = m->pipeline->getCount(); | 2607 | + qpdf_offset_t xref_offset = pipeline->getCount(); |
| 2489 | qpdf_offset_t space_before_zero = xref_offset - 1; | 2608 | qpdf_offset_t space_before_zero = xref_offset - 1; |
| 2490 | 2609 | ||
| 2491 | // field 1 contains offsets and object stream identifiers | 2610 | // field 1 contains offsets and object stream identifiers |
| 2492 | unsigned int f1_size = std::max(bytesNeeded(max_offset + hint_length), bytesNeeded(max_id)); | 2611 | unsigned int f1_size = std::max(bytesNeeded(max_offset + hint_length), bytesNeeded(max_id)); |
| 2493 | 2612 | ||
| 2494 | // field 2 contains object stream indices | 2613 | // field 2 contains object stream indices |
| 2495 | - unsigned int f2_size = bytesNeeded(QIntC::to_longlong(m->max_ostream_index)); | 2614 | + unsigned int f2_size = bytesNeeded(QIntC::to_longlong(max_ostream_index)); |
| 2496 | 2615 | ||
| 2497 | unsigned int esize = 1 + f1_size + f2_size; | 2616 | unsigned int esize = 1 + f1_size + f2_size; |
| 2498 | 2617 | ||
| 2499 | // Must store in xref table in advance of writing the actual data rather than waiting for | 2618 | // Must store in xref table in advance of writing the actual data rather than waiting for |
| 2500 | // openObject to do it. | 2619 | // openObject to do it. |
| 2501 | - m->new_obj[xref_id].xref = QPDFXRefEntry(m->pipeline->getCount()); | 2620 | + new_obj[xref_id].xref = QPDFXRefEntry(pipeline->getCount()); |
| 2502 | 2621 | ||
| 2503 | std::string xref_data; | 2622 | std::string xref_data; |
| 2504 | - const bool compressed = m->compress_streams && !m->qdf_mode; | 2623 | + const bool compressed = compress_streams && !qdf_mode; |
| 2505 | { | 2624 | { |
| 2506 | - auto pp_xref = m->pipeline_stack.activate(xref_data); | 2625 | + auto pp_xref = pipeline_stack.activate(xref_data); |
| 2507 | 2626 | ||
| 2508 | for (int i = first; i <= last; ++i) { | 2627 | for (int i = first; i <= last; ++i) { |
| 2509 | - QPDFXRefEntry& e = m->new_obj[i].xref; | 2628 | + QPDFXRefEntry& e = new_obj[i].xref; |
| 2510 | switch (e.getType()) { | 2629 | switch (e.getType()) { |
| 2511 | case 0: | 2630 | case 0: |
| 2512 | writeBinary(0, 1); | 2631 | writeBinary(0, 1); |
| @@ -2566,7 +2685,7 @@ QPDFWriter::writeXRefStream( | @@ -2566,7 +2685,7 @@ QPDFWriter::writeXRefStream( | ||
| 2566 | } | 2685 | } |
| 2567 | 2686 | ||
| 2568 | size_t | 2687 | size_t |
| 2569 | -QPDFWriter::calculateXrefStreamPadding(qpdf_offset_t xref_bytes) | 2688 | +QPDFWriter::Members::calculateXrefStreamPadding(qpdf_offset_t xref_bytes) |
| 2570 | { | 2689 | { |
| 2571 | // This routine is called right after a linearization first pass xref stream has been written | 2690 | // This routine is called right after a linearization first pass xref stream has been written |
| 2572 | // without compression. Calculate the amount of padding that would be required in the worst | 2691 | // without compression. Calculate the amount of padding that would be required in the worst |
| @@ -2578,7 +2697,7 @@ QPDFWriter::calculateXrefStreamPadding(qpdf_offset_t xref_bytes) | @@ -2578,7 +2697,7 @@ QPDFWriter::calculateXrefStreamPadding(qpdf_offset_t xref_bytes) | ||
| 2578 | } | 2697 | } |
| 2579 | 2698 | ||
| 2580 | void | 2699 | void |
| 2581 | -QPDFWriter::writeLinearized() | 2700 | +QPDFWriter::Members::writeLinearized() |
| 2582 | { | 2701 | { |
| 2583 | // Optimize file and enqueue objects in order | 2702 | // Optimize file and enqueue objects in order |
| 2584 | 2703 | ||
| @@ -2598,14 +2717,14 @@ QPDFWriter::writeLinearized() | @@ -2598,14 +2717,14 @@ QPDFWriter::writeLinearized() | ||
| 2598 | return result; | 2717 | return result; |
| 2599 | }; | 2718 | }; |
| 2600 | 2719 | ||
| 2601 | - QPDF::Writer::optimize(m->pdf, m->obj, skip_stream_parameters); | 2720 | + QPDF::Writer::optimize(pdf, obj, skip_stream_parameters); |
| 2602 | 2721 | ||
| 2603 | std::vector<QPDFObjectHandle> part4; | 2722 | std::vector<QPDFObjectHandle> part4; |
| 2604 | std::vector<QPDFObjectHandle> part6; | 2723 | std::vector<QPDFObjectHandle> part6; |
| 2605 | std::vector<QPDFObjectHandle> part7; | 2724 | std::vector<QPDFObjectHandle> part7; |
| 2606 | std::vector<QPDFObjectHandle> part8; | 2725 | std::vector<QPDFObjectHandle> part8; |
| 2607 | std::vector<QPDFObjectHandle> part9; | 2726 | std::vector<QPDFObjectHandle> part9; |
| 2608 | - QPDF::Writer::getLinearizedParts(m->pdf, m->obj, part4, part6, part7, part8, part9); | 2727 | + QPDF::Writer::getLinearizedParts(pdf, obj, part4, part6, part7, part8, part9); |
| 2609 | 2728 | ||
| 2610 | // Object number sequence: | 2729 | // Object number sequence: |
| 2611 | // | 2730 | // |
| @@ -2627,11 +2746,11 @@ QPDFWriter::writeLinearized() | @@ -2627,11 +2746,11 @@ QPDFWriter::writeLinearized() | ||
| 2627 | int second_half_uncompressed = QIntC::to_int(part7.size() + part8.size() + part9.size()); | 2746 | int second_half_uncompressed = QIntC::to_int(part7.size() + part8.size() + part9.size()); |
| 2628 | int second_half_first_obj = 1; | 2747 | int second_half_first_obj = 1; |
| 2629 | int after_second_half = 1 + second_half_uncompressed; | 2748 | int after_second_half = 1 + second_half_uncompressed; |
| 2630 | - m->next_objid = after_second_half; | 2749 | + next_objid = after_second_half; |
| 2631 | int second_half_xref = 0; | 2750 | int second_half_xref = 0; |
| 2632 | - bool need_xref_stream = !m->obj.streams_empty; | 2751 | + bool need_xref_stream = !obj.streams_empty; |
| 2633 | if (need_xref_stream) { | 2752 | if (need_xref_stream) { |
| 2634 | - second_half_xref = m->next_objid++; | 2753 | + second_half_xref = next_objid++; |
| 2635 | } | 2754 | } |
| 2636 | // Assign numbers to all compressed objects in the second half. | 2755 | // Assign numbers to all compressed objects in the second half. |
| 2637 | std::vector<QPDFObjectHandle>* vecs2[] = {&part7, &part8, &part9}; | 2756 | std::vector<QPDFObjectHandle>* vecs2[] = {&part7, &part8, &part9}; |
| @@ -2640,26 +2759,26 @@ QPDFWriter::writeLinearized() | @@ -2640,26 +2759,26 @@ QPDFWriter::writeLinearized() | ||
| 2640 | assignCompressedObjectNumbers(oh.getObjGen()); | 2759 | assignCompressedObjectNumbers(oh.getObjGen()); |
| 2641 | } | 2760 | } |
| 2642 | } | 2761 | } |
| 2643 | - int second_half_end = m->next_objid - 1; | ||
| 2644 | - int second_trailer_size = m->next_objid; | 2762 | + int second_half_end = next_objid - 1; |
| 2763 | + int second_trailer_size = next_objid; | ||
| 2645 | 2764 | ||
| 2646 | // First half objects | 2765 | // First half objects |
| 2647 | - int first_half_start = m->next_objid; | ||
| 2648 | - int lindict_id = m->next_objid++; | 2766 | + int first_half_start = next_objid; |
| 2767 | + int lindict_id = next_objid++; | ||
| 2649 | int first_half_xref = 0; | 2768 | int first_half_xref = 0; |
| 2650 | if (need_xref_stream) { | 2769 | if (need_xref_stream) { |
| 2651 | - first_half_xref = m->next_objid++; | ||
| 2652 | - } | ||
| 2653 | - int part4_first_obj = m->next_objid; | ||
| 2654 | - m->next_objid += QIntC::to_int(part4.size()); | ||
| 2655 | - int after_part4 = m->next_objid; | ||
| 2656 | - if (m->encryption) { | ||
| 2657 | - m->encryption_dict_objid = m->next_objid++; | ||
| 2658 | - } | ||
| 2659 | - int hint_id = m->next_objid++; | ||
| 2660 | - int part6_first_obj = m->next_objid; | ||
| 2661 | - m->next_objid += QIntC::to_int(part6.size()); | ||
| 2662 | - int after_part6 = m->next_objid; | 2770 | + first_half_xref = next_objid++; |
| 2771 | + } | ||
| 2772 | + int part4_first_obj = next_objid; | ||
| 2773 | + next_objid += QIntC::to_int(part4.size()); | ||
| 2774 | + int after_part4 = next_objid; | ||
| 2775 | + if (encryption) { | ||
| 2776 | + encryption_dict_objid = next_objid++; | ||
| 2777 | + } | ||
| 2778 | + int hint_id = next_objid++; | ||
| 2779 | + int part6_first_obj = next_objid; | ||
| 2780 | + next_objid += QIntC::to_int(part6.size()); | ||
| 2781 | + int after_part6 = next_objid; | ||
| 2663 | // Assign numbers to all compressed objects in the first half | 2782 | // Assign numbers to all compressed objects in the first half |
| 2664 | std::vector<QPDFObjectHandle>* vecs1[] = {&part4, &part6}; | 2783 | std::vector<QPDFObjectHandle>* vecs1[] = {&part4, &part6}; |
| 2665 | for (int i = 0; i < 2; ++i) { | 2784 | for (int i = 0; i < 2; ++i) { |
| @@ -2667,8 +2786,8 @@ QPDFWriter::writeLinearized() | @@ -2667,8 +2786,8 @@ QPDFWriter::writeLinearized() | ||
| 2667 | assignCompressedObjectNumbers(oh.getObjGen()); | 2786 | assignCompressedObjectNumbers(oh.getObjGen()); |
| 2668 | } | 2787 | } |
| 2669 | } | 2788 | } |
| 2670 | - int first_half_end = m->next_objid - 1; | ||
| 2671 | - int first_trailer_size = m->next_objid; | 2789 | + int first_half_end = next_objid - 1; |
| 2790 | + int first_trailer_size = next_objid; | ||
| 2672 | 2791 | ||
| 2673 | int part4_end_marker = part4.back().getObjectID(); | 2792 | int part4_end_marker = part4.back().getObjectID(); |
| 2674 | int part6_end_marker = part6.back().getObjectID(); | 2793 | int part6_end_marker = part6.back().getObjectID(); |
| @@ -2680,23 +2799,23 @@ QPDFWriter::writeLinearized() | @@ -2680,23 +2799,23 @@ QPDFWriter::writeLinearized() | ||
| 2680 | qpdf_offset_t first_xref_end = 0; | 2799 | qpdf_offset_t first_xref_end = 0; |
| 2681 | qpdf_offset_t second_xref_end = 0; | 2800 | qpdf_offset_t second_xref_end = 0; |
| 2682 | 2801 | ||
| 2683 | - m->next_objid = part4_first_obj; | 2802 | + next_objid = part4_first_obj; |
| 2684 | enqueuePart(part4); | 2803 | enqueuePart(part4); |
| 2685 | - if (m->next_objid != after_part4) { | 2804 | + if (next_objid != after_part4) { |
| 2686 | // This can happen with very botched files as in the fuzzer test. There are likely some | 2805 | // This can happen with very botched files as in the fuzzer test. There are likely some |
| 2687 | // faulty assumptions in calculateLinearizationData | 2806 | // faulty assumptions in calculateLinearizationData |
| 2688 | throw std::runtime_error("error encountered after writing part 4 of linearized data"); | 2807 | throw std::runtime_error("error encountered after writing part 4 of linearized data"); |
| 2689 | } | 2808 | } |
| 2690 | - m->next_objid = part6_first_obj; | 2809 | + next_objid = part6_first_obj; |
| 2691 | enqueuePart(part6); | 2810 | enqueuePart(part6); |
| 2692 | - if (m->next_objid != after_part6) { | 2811 | + if (next_objid != after_part6) { |
| 2693 | throw std::runtime_error("error encountered after writing part 6 of linearized data"); | 2812 | throw std::runtime_error("error encountered after writing part 6 of linearized data"); |
| 2694 | } | 2813 | } |
| 2695 | - m->next_objid = second_half_first_obj; | 2814 | + next_objid = second_half_first_obj; |
| 2696 | enqueuePart(part7); | 2815 | enqueuePart(part7); |
| 2697 | enqueuePart(part8); | 2816 | enqueuePart(part8); |
| 2698 | enqueuePart(part9); | 2817 | enqueuePart(part9); |
| 2699 | - if (m->next_objid != after_second_half) { | 2818 | + if (next_objid != after_second_half) { |
| 2700 | throw std::runtime_error("error encountered after writing part 9 of linearized data"); | 2819 | throw std::runtime_error("error encountered after writing part 9 of linearized data"); |
| 2701 | } | 2820 | } |
| 2702 | 2821 | ||
| @@ -2706,20 +2825,20 @@ QPDFWriter::writeLinearized() | @@ -2706,20 +2825,20 @@ QPDFWriter::writeLinearized() | ||
| 2706 | // Write file in two passes. Part numbers refer to PDF spec 1.4. | 2825 | // Write file in two passes. Part numbers refer to PDF spec 1.4. |
| 2707 | 2826 | ||
| 2708 | FILE* lin_pass1_file = nullptr; | 2827 | FILE* lin_pass1_file = nullptr; |
| 2709 | - auto pp_pass1 = m->pipeline_stack.popper(); | ||
| 2710 | - auto pp_md5 = m->pipeline_stack.popper(); | 2828 | + auto pp_pass1 = pipeline_stack.popper(); |
| 2829 | + auto pp_md5 = pipeline_stack.popper(); | ||
| 2711 | for (int pass: {1, 2}) { | 2830 | for (int pass: {1, 2}) { |
| 2712 | if (pass == 1) { | 2831 | if (pass == 1) { |
| 2713 | - if (!m->lin_pass1_filename.empty()) { | ||
| 2714 | - lin_pass1_file = QUtil::safe_fopen(m->lin_pass1_filename.c_str(), "wb"); | ||
| 2715 | - m->pipeline_stack.activate( | 2832 | + if (!lin_pass1_filename.empty()) { |
| 2833 | + lin_pass1_file = QUtil::safe_fopen(lin_pass1_filename.c_str(), "wb"); | ||
| 2834 | + pipeline_stack.activate( | ||
| 2716 | pp_pass1, | 2835 | pp_pass1, |
| 2717 | std::make_unique<Pl_StdioFile>("linearization pass1", lin_pass1_file)); | 2836 | std::make_unique<Pl_StdioFile>("linearization pass1", lin_pass1_file)); |
| 2718 | } else { | 2837 | } else { |
| 2719 | - m->pipeline_stack.activate(pp_pass1, true); | 2838 | + pipeline_stack.activate(pp_pass1, true); |
| 2720 | } | 2839 | } |
| 2721 | - if (m->deterministic_id) { | ||
| 2722 | - m->pipeline_stack.activate_md5(pp_md5); | 2840 | + if (deterministic_id) { |
| 2841 | + pipeline_stack.activate_md5(pp_md5); | ||
| 2723 | } | 2842 | } |
| 2724 | } | 2843 | } |
| 2725 | 2844 | ||
| @@ -2733,16 +2852,16 @@ QPDFWriter::writeLinearized() | @@ -2733,16 +2852,16 @@ QPDFWriter::writeLinearized() | ||
| 2733 | // linearization parameter dictionary must appear within the first 1024 characters of the | 2852 | // linearization parameter dictionary must appear within the first 1024 characters of the |
| 2734 | // file. | 2853 | // file. |
| 2735 | 2854 | ||
| 2736 | - qpdf_offset_t pos = m->pipeline->getCount(); | 2855 | + qpdf_offset_t pos = pipeline->getCount(); |
| 2737 | openObject(lindict_id); | 2856 | openObject(lindict_id); |
| 2738 | write("<<"); | 2857 | write("<<"); |
| 2739 | if (pass == 2) { | 2858 | if (pass == 2) { |
| 2740 | - std::vector<QPDFObjectHandle> const& pages = m->pdf.getAllPages(); | ||
| 2741 | - int first_page_object = m->obj[pages.at(0)].renumber; | 2859 | + std::vector<QPDFObjectHandle> const& pages = pdf.getAllPages(); |
| 2860 | + int first_page_object = obj[pages.at(0)].renumber; | ||
| 2742 | 2861 | ||
| 2743 | write(" /Linearized 1 /L ").write(file_size + hint_length); | 2862 | write(" /Linearized 1 /L ").write(file_size + hint_length); |
| 2744 | // Implementation note 121 states that a space is mandatory after this open bracket. | 2863 | // Implementation note 121 states that a space is mandatory after this open bracket. |
| 2745 | - write(" /H [ ").write(m->new_obj[hint_id].xref.getOffset()).write(" "); | 2864 | + write(" /H [ ").write(new_obj[hint_id].xref.getOffset()).write(" "); |
| 2746 | write(hint_length); | 2865 | write(hint_length); |
| 2747 | write(" ] /O ").write(first_page_object); | 2866 | write(" ] /O ").write(first_page_object); |
| 2748 | write(" /E ").write(part6_end_offset + hint_length); | 2867 | write(" /E ").write(part6_end_offset + hint_length); |
| @@ -2752,18 +2871,18 @@ QPDFWriter::writeLinearized() | @@ -2752,18 +2871,18 @@ QPDFWriter::writeLinearized() | ||
| 2752 | write(" >>"); | 2871 | write(" >>"); |
| 2753 | closeObject(lindict_id); | 2872 | closeObject(lindict_id); |
| 2754 | static int const pad = 200; | 2873 | static int const pad = 200; |
| 2755 | - write(QIntC::to_size(pos - m->pipeline->getCount() + pad), ' ').write("\n"); | 2874 | + write(QIntC::to_size(pos - pipeline->getCount() + pad), ' ').write("\n"); |
| 2756 | 2875 | ||
| 2757 | // If the user supplied any additional header text, write it here after the linearization | 2876 | // If the user supplied any additional header text, write it here after the linearization |
| 2758 | // parameter dictionary. | 2877 | // parameter dictionary. |
| 2759 | - write(m->extra_header_text); | 2878 | + write(extra_header_text); |
| 2760 | 2879 | ||
| 2761 | // Part 3: first page cross reference table and trailer. | 2880 | // Part 3: first page cross reference table and trailer. |
| 2762 | 2881 | ||
| 2763 | - qpdf_offset_t first_xref_offset = m->pipeline->getCount(); | 2882 | + qpdf_offset_t first_xref_offset = pipeline->getCount(); |
| 2764 | qpdf_offset_t hint_offset = 0; | 2883 | qpdf_offset_t hint_offset = 0; |
| 2765 | if (pass == 2) { | 2884 | if (pass == 2) { |
| 2766 | - hint_offset = m->new_obj[hint_id].xref.getOffset(); | 2885 | + hint_offset = new_obj[hint_id].xref.getOffset(); |
| 2767 | } | 2886 | } |
| 2768 | if (need_xref_stream) { | 2887 | if (need_xref_stream) { |
| 2769 | // Must pad here too. | 2888 | // Must pad here too. |
| @@ -2775,7 +2894,7 @@ QPDFWriter::writeLinearized() | @@ -2775,7 +2894,7 @@ QPDFWriter::writeLinearized() | ||
| 2775 | // value for this, but it's okay if it's smaller. | 2894 | // value for this, but it's okay if it's smaller. |
| 2776 | first_half_max_obj_offset = 1 << 25; | 2895 | first_half_max_obj_offset = 1 << 25; |
| 2777 | } | 2896 | } |
| 2778 | - pos = m->pipeline->getCount(); | 2897 | + pos = pipeline->getCount(); |
| 2779 | writeXRefStream( | 2898 | writeXRefStream( |
| 2780 | first_half_xref, | 2899 | first_half_xref, |
| 2781 | first_half_end, | 2900 | first_half_end, |
| @@ -2790,16 +2909,16 @@ QPDFWriter::writeLinearized() | @@ -2790,16 +2909,16 @@ QPDFWriter::writeLinearized() | ||
| 2790 | hint_length, | 2909 | hint_length, |
| 2791 | (pass == 1), | 2910 | (pass == 1), |
| 2792 | pass); | 2911 | pass); |
| 2793 | - qpdf_offset_t endpos = m->pipeline->getCount(); | 2912 | + qpdf_offset_t endpos = pipeline->getCount(); |
| 2794 | if (pass == 1) { | 2913 | if (pass == 1) { |
| 2795 | // Pad so we have enough room for the real xref stream. | 2914 | // Pad so we have enough room for the real xref stream. |
| 2796 | write(calculateXrefStreamPadding(endpos - pos), ' '); | 2915 | write(calculateXrefStreamPadding(endpos - pos), ' '); |
| 2797 | - first_xref_end = m->pipeline->getCount(); | 2916 | + first_xref_end = pipeline->getCount(); |
| 2798 | } else { | 2917 | } else { |
| 2799 | // Pad so that the next object starts at the same place as in pass 1. | 2918 | // Pad so that the next object starts at the same place as in pass 1. |
| 2800 | write(QIntC::to_size(first_xref_end - endpos), ' '); | 2919 | write(QIntC::to_size(first_xref_end - endpos), ' '); |
| 2801 | 2920 | ||
| 2802 | - if (m->pipeline->getCount() != first_xref_end) { | 2921 | + if (pipeline->getCount() != first_xref_end) { |
| 2803 | throw std::logic_error( | 2922 | throw std::logic_error( |
| 2804 | "insufficient padding for first pass xref stream; first_xref_end=" + | 2923 | "insufficient padding for first pass xref stream; first_xref_end=" + |
| 2805 | std::to_string(first_xref_end) + "; endpos=" + std::to_string(endpos)); | 2924 | std::to_string(first_xref_end) + "; endpos=" + std::to_string(endpos)); |
| @@ -2823,24 +2942,24 @@ QPDFWriter::writeLinearized() | @@ -2823,24 +2942,24 @@ QPDFWriter::writeLinearized() | ||
| 2823 | 2942 | ||
| 2824 | // Parts 4 through 9 | 2943 | // Parts 4 through 9 |
| 2825 | 2944 | ||
| 2826 | - for (auto const& cur_object: m->object_queue) { | 2945 | + for (auto const& cur_object: object_queue) { |
| 2827 | if (cur_object.getObjectID() == part6_end_marker) { | 2946 | if (cur_object.getObjectID() == part6_end_marker) { |
| 2828 | - first_half_max_obj_offset = m->pipeline->getCount(); | 2947 | + first_half_max_obj_offset = pipeline->getCount(); |
| 2829 | } | 2948 | } |
| 2830 | writeObject(cur_object); | 2949 | writeObject(cur_object); |
| 2831 | if (cur_object.getObjectID() == part4_end_marker) { | 2950 | if (cur_object.getObjectID() == part4_end_marker) { |
| 2832 | - if (m->encryption) { | 2951 | + if (encryption) { |
| 2833 | writeEncryptionDictionary(); | 2952 | writeEncryptionDictionary(); |
| 2834 | } | 2953 | } |
| 2835 | if (pass == 1) { | 2954 | if (pass == 1) { |
| 2836 | - m->new_obj[hint_id].xref = QPDFXRefEntry(m->pipeline->getCount()); | 2955 | + new_obj[hint_id].xref = QPDFXRefEntry(pipeline->getCount()); |
| 2837 | } else { | 2956 | } else { |
| 2838 | // Part 5: hint stream | 2957 | // Part 5: hint stream |
| 2839 | write(hint_buffer); | 2958 | write(hint_buffer); |
| 2840 | } | 2959 | } |
| 2841 | } | 2960 | } |
| 2842 | if (cur_object.getObjectID() == part6_end_marker) { | 2961 | if (cur_object.getObjectID() == part6_end_marker) { |
| 2843 | - part6_end_offset = m->pipeline->getCount(); | 2962 | + part6_end_offset = pipeline->getCount(); |
| 2844 | } | 2963 | } |
| 2845 | } | 2964 | } |
| 2846 | 2965 | ||
| @@ -2848,9 +2967,9 @@ QPDFWriter::writeLinearized() | @@ -2848,9 +2967,9 @@ QPDFWriter::writeLinearized() | ||
| 2848 | 2967 | ||
| 2849 | // Part 11: main cross reference table and trailer | 2968 | // Part 11: main cross reference table and trailer |
| 2850 | 2969 | ||
| 2851 | - second_xref_offset = m->pipeline->getCount(); | 2970 | + second_xref_offset = pipeline->getCount(); |
| 2852 | if (need_xref_stream) { | 2971 | if (need_xref_stream) { |
| 2853 | - pos = m->pipeline->getCount(); | 2972 | + pos = pipeline->getCount(); |
| 2854 | space_before_zero = writeXRefStream( | 2973 | space_before_zero = writeXRefStream( |
| 2855 | second_half_xref, | 2974 | second_half_xref, |
| 2856 | second_half_end, | 2975 | second_half_end, |
| @@ -2865,21 +2984,21 @@ QPDFWriter::writeLinearized() | @@ -2865,21 +2984,21 @@ QPDFWriter::writeLinearized() | ||
| 2865 | 0, | 2984 | 0, |
| 2866 | (pass == 1), | 2985 | (pass == 1), |
| 2867 | pass); | 2986 | pass); |
| 2868 | - qpdf_offset_t endpos = m->pipeline->getCount(); | 2987 | + qpdf_offset_t endpos = pipeline->getCount(); |
| 2869 | 2988 | ||
| 2870 | if (pass == 1) { | 2989 | if (pass == 1) { |
| 2871 | // Pad so we have enough room for the real xref stream. See comments for previous | 2990 | // Pad so we have enough room for the real xref stream. See comments for previous |
| 2872 | // xref stream on how we calculate the padding. | 2991 | // xref stream on how we calculate the padding. |
| 2873 | write(calculateXrefStreamPadding(endpos - pos), ' ').write("\n"); | 2992 | write(calculateXrefStreamPadding(endpos - pos), ' ').write("\n"); |
| 2874 | - second_xref_end = m->pipeline->getCount(); | 2993 | + second_xref_end = pipeline->getCount(); |
| 2875 | } else { | 2994 | } else { |
| 2876 | // Make the file size the same. | 2995 | // Make the file size the same. |
| 2877 | auto padding = | 2996 | auto padding = |
| 2878 | - QIntC::to_size(second_xref_end + hint_length - 1 - m->pipeline->getCount()); | 2997 | + QIntC::to_size(second_xref_end + hint_length - 1 - pipeline->getCount()); |
| 2879 | write(padding, ' ').write("\n"); | 2998 | write(padding, ' ').write("\n"); |
| 2880 | 2999 | ||
| 2881 | // If this assertion fails, maybe we didn't have enough padding above. | 3000 | // If this assertion fails, maybe we didn't have enough padding above. |
| 2882 | - if (m->pipeline->getCount() != second_xref_end + hint_length) { | 3001 | + if (pipeline->getCount() != second_xref_end + hint_length) { |
| 2883 | throw std::logic_error( | 3002 | throw std::logic_error( |
| 2884 | "count mismatch after xref stream; possible insufficient padding?"); | 3003 | "count mismatch after xref stream; possible insufficient padding?"); |
| 2885 | } | 3004 | } |
| @@ -2891,28 +3010,28 @@ QPDFWriter::writeLinearized() | @@ -2891,28 +3010,28 @@ QPDFWriter::writeLinearized() | ||
| 2891 | write("startxref\n").write(first_xref_offset).write("\n%%EOF\n"); | 3010 | write("startxref\n").write(first_xref_offset).write("\n%%EOF\n"); |
| 2892 | 3011 | ||
| 2893 | if (pass == 1) { | 3012 | if (pass == 1) { |
| 2894 | - if (m->deterministic_id) { | 3013 | + if (deterministic_id) { |
| 2895 | QTC::TC("qpdf", "QPDFWriter linearized deterministic ID", need_xref_stream ? 0 : 1); | 3014 | QTC::TC("qpdf", "QPDFWriter linearized deterministic ID", need_xref_stream ? 0 : 1); |
| 2896 | computeDeterministicIDData(); | 3015 | computeDeterministicIDData(); |
| 2897 | pp_md5.pop(); | 3016 | pp_md5.pop(); |
| 2898 | } | 3017 | } |
| 2899 | 3018 | ||
| 2900 | // Close first pass pipeline | 3019 | // Close first pass pipeline |
| 2901 | - file_size = m->pipeline->getCount(); | 3020 | + file_size = pipeline->getCount(); |
| 2902 | pp_pass1.pop(); | 3021 | pp_pass1.pop(); |
| 2903 | 3022 | ||
| 2904 | // Save hint offset since it will be set to zero by calling openObject. | 3023 | // Save hint offset since it will be set to zero by calling openObject. |
| 2905 | - qpdf_offset_t hint_offset1 = m->new_obj[hint_id].xref.getOffset(); | 3024 | + qpdf_offset_t hint_offset1 = new_obj[hint_id].xref.getOffset(); |
| 2906 | 3025 | ||
| 2907 | // Write hint stream to a buffer | 3026 | // Write hint stream to a buffer |
| 2908 | { | 3027 | { |
| 2909 | - auto pp_hint = m->pipeline_stack.activate(hint_buffer); | 3028 | + auto pp_hint = pipeline_stack.activate(hint_buffer); |
| 2910 | writeHintStream(hint_id); | 3029 | writeHintStream(hint_id); |
| 2911 | } | 3030 | } |
| 2912 | hint_length = QIntC::to_offset(hint_buffer.size()); | 3031 | hint_length = QIntC::to_offset(hint_buffer.size()); |
| 2913 | 3032 | ||
| 2914 | // Restore hint offset | 3033 | // Restore hint offset |
| 2915 | - m->new_obj[hint_id].xref = QPDFXRefEntry(hint_offset1); | 3034 | + new_obj[hint_id].xref = QPDFXRefEntry(hint_offset1); |
| 2916 | if (lin_pass1_file) { | 3035 | if (lin_pass1_file) { |
| 2917 | // Write some debugging information | 3036 | // Write some debugging information |
| 2918 | fprintf( | 3037 | fprintf( |
| @@ -2934,11 +3053,10 @@ QPDFWriter::writeLinearized() | @@ -2934,11 +3053,10 @@ QPDFWriter::writeLinearized() | ||
| 2934 | } | 3053 | } |
| 2935 | 3054 | ||
| 2936 | void | 3055 | void |
| 2937 | -QPDFWriter::enqueueObjectsStandard() | 3056 | +QPDFWriter::Members::enqueueObjectsStandard() |
| 2938 | { | 3057 | { |
| 2939 | - if (m->preserve_unreferenced_objects) { | ||
| 2940 | - QTC::TC("qpdf", "QPDFWriter preserve unreferenced standard"); | ||
| 2941 | - for (auto const& oh: m->pdf.getAllObjects()) { | 3058 | + if (preserve_unreferenced_objects) { |
| 3059 | + for (auto const& oh: pdf.getAllObjects()) { | ||
| 2942 | enqueueObject(oh); | 3060 | enqueueObject(oh); |
| 2943 | } | 3061 | } |
| 2944 | } | 3062 | } |
| @@ -2957,14 +3075,14 @@ QPDFWriter::enqueueObjectsStandard() | @@ -2957,14 +3075,14 @@ QPDFWriter::enqueueObjectsStandard() | ||
| 2957 | } | 3075 | } |
| 2958 | 3076 | ||
| 2959 | void | 3077 | void |
| 2960 | -QPDFWriter::enqueueObjectsPCLm() | 3078 | +QPDFWriter::Members::enqueueObjectsPCLm() |
| 2961 | { | 3079 | { |
| 2962 | // Image transform stream content for page strip images. Each of this new stream has to come | 3080 | // Image transform stream content for page strip images. Each of this new stream has to come |
| 2963 | // after every page image strip written in the pclm file. | 3081 | // after every page image strip written in the pclm file. |
| 2964 | std::string image_transform_content = "q /image Do Q\n"; | 3082 | std::string image_transform_content = "q /image Do Q\n"; |
| 2965 | 3083 | ||
| 2966 | // enqueue all pages first | 3084 | // enqueue all pages first |
| 2967 | - std::vector<QPDFObjectHandle> all = m->pdf.getAllPages(); | 3085 | + std::vector<QPDFObjectHandle> all = pdf.getAllPages(); |
| 2968 | for (auto& page: all) { | 3086 | for (auto& page: all) { |
| 2969 | // enqueue page | 3087 | // enqueue page |
| 2970 | enqueueObject(page); | 3088 | enqueueObject(page); |
| @@ -2977,7 +3095,7 @@ QPDFWriter::enqueueObjectsPCLm() | @@ -2977,7 +3095,7 @@ QPDFWriter::enqueueObjectsPCLm() | ||
| 2977 | for (auto& image: strips.as_dictionary()) { | 3095 | for (auto& image: strips.as_dictionary()) { |
| 2978 | if (!image.second.null()) { | 3096 | if (!image.second.null()) { |
| 2979 | enqueueObject(image.second); | 3097 | enqueueObject(image.second); |
| 2980 | - enqueueObject(QPDFObjectHandle::newStream(&m->pdf, image_transform_content)); | 3098 | + enqueueObject(QPDFObjectHandle::newStream(&pdf, image_transform_content)); |
| 2981 | } | 3099 | } |
| 2982 | } | 3100 | } |
| 2983 | } | 3101 | } |
| @@ -2988,30 +3106,30 @@ QPDFWriter::enqueueObjectsPCLm() | @@ -2988,30 +3106,30 @@ QPDFWriter::enqueueObjectsPCLm() | ||
| 2988 | } | 3106 | } |
| 2989 | 3107 | ||
| 2990 | void | 3108 | void |
| 2991 | -QPDFWriter::indicateProgress(bool decrement, bool finished) | 3109 | +QPDFWriter::Members::indicateProgress(bool decrement, bool finished) |
| 2992 | { | 3110 | { |
| 2993 | if (decrement) { | 3111 | if (decrement) { |
| 2994 | - --m->events_seen; | 3112 | + --events_seen; |
| 2995 | return; | 3113 | return; |
| 2996 | } | 3114 | } |
| 2997 | 3115 | ||
| 2998 | - ++m->events_seen; | 3116 | + ++events_seen; |
| 2999 | 3117 | ||
| 3000 | - if (!m->progress_reporter.get()) { | 3118 | + if (!progress_reporter.get()) { |
| 3001 | return; | 3119 | return; |
| 3002 | } | 3120 | } |
| 3003 | 3121 | ||
| 3004 | - if (finished || (m->events_seen >= m->next_progress_report)) { | 3122 | + if (finished || events_seen >= next_progress_report) { |
| 3005 | int percentage = | 3123 | int percentage = |
| 3006 | (finished ? 100 | 3124 | (finished ? 100 |
| 3007 | - : m->next_progress_report == 0 | 3125 | + : next_progress_report == 0 |
| 3008 | ? 0 | 3126 | ? 0 |
| 3009 | - : std::min(99, 1 + ((100 * m->events_seen) / m->events_expected))); | ||
| 3010 | - m->progress_reporter->reportProgress(percentage); | 3127 | + : std::min(99, 1 + ((100 * events_seen) / events_expected))); |
| 3128 | + progress_reporter->reportProgress(percentage); | ||
| 3011 | } | 3129 | } |
| 3012 | - int increment = std::max(1, (m->events_expected / 100)); | ||
| 3013 | - while (m->events_seen >= m->next_progress_report) { | ||
| 3014 | - m->next_progress_report += increment; | 3130 | + int increment = std::max(1, (events_expected / 100)); |
| 3131 | + while (events_seen >= next_progress_report) { | ||
| 3132 | + next_progress_report += increment; | ||
| 3015 | } | 3133 | } |
| 3016 | } | 3134 | } |
| 3017 | 3135 | ||
| @@ -3022,53 +3140,52 @@ QPDFWriter::registerProgressReporter(std::shared_ptr<ProgressReporter> pr) | @@ -3022,53 +3140,52 @@ QPDFWriter::registerProgressReporter(std::shared_ptr<ProgressReporter> pr) | ||
| 3022 | } | 3140 | } |
| 3023 | 3141 | ||
| 3024 | void | 3142 | void |
| 3025 | -QPDFWriter::writeStandard() | 3143 | +QPDFWriter::Members::writeStandard() |
| 3026 | { | 3144 | { |
| 3027 | - auto pp_md5 = m->pipeline_stack.popper(); | ||
| 3028 | - if (m->deterministic_id) { | ||
| 3029 | - m->pipeline_stack.activate_md5(pp_md5); | 3145 | + auto pp_md5 = pipeline_stack.popper(); |
| 3146 | + if (deterministic_id) { | ||
| 3147 | + pipeline_stack.activate_md5(pp_md5); | ||
| 3030 | } | 3148 | } |
| 3031 | 3149 | ||
| 3032 | // Start writing | 3150 | // Start writing |
| 3033 | 3151 | ||
| 3034 | writeHeader(); | 3152 | writeHeader(); |
| 3035 | - write(m->extra_header_text); | 3153 | + write(extra_header_text); |
| 3036 | 3154 | ||
| 3037 | - if (m->pclm) { | 3155 | + if (pclm) { |
| 3038 | enqueueObjectsPCLm(); | 3156 | enqueueObjectsPCLm(); |
| 3039 | } else { | 3157 | } else { |
| 3040 | enqueueObjectsStandard(); | 3158 | enqueueObjectsStandard(); |
| 3041 | } | 3159 | } |
| 3042 | 3160 | ||
| 3043 | // Now start walking queue, outputting each object. | 3161 | // Now start walking queue, outputting each object. |
| 3044 | - while (m->object_queue_front < m->object_queue.size()) { | ||
| 3045 | - QPDFObjectHandle cur_object = m->object_queue.at(m->object_queue_front); | ||
| 3046 | - ++m->object_queue_front; | 3162 | + while (object_queue_front < object_queue.size()) { |
| 3163 | + QPDFObjectHandle cur_object = object_queue.at(object_queue_front); | ||
| 3164 | + ++object_queue_front; | ||
| 3047 | writeObject(cur_object); | 3165 | writeObject(cur_object); |
| 3048 | } | 3166 | } |
| 3049 | 3167 | ||
| 3050 | // Write out the encryption dictionary, if any | 3168 | // Write out the encryption dictionary, if any |
| 3051 | - if (m->encryption) { | 3169 | + if (encryption) { |
| 3052 | writeEncryptionDictionary(); | 3170 | writeEncryptionDictionary(); |
| 3053 | } | 3171 | } |
| 3054 | 3172 | ||
| 3055 | // Now write out xref. next_objid is now the number of objects. | 3173 | // Now write out xref. next_objid is now the number of objects. |
| 3056 | - qpdf_offset_t xref_offset = m->pipeline->getCount(); | ||
| 3057 | - if (m->object_stream_to_objects.empty()) { | 3174 | + qpdf_offset_t xref_offset = pipeline->getCount(); |
| 3175 | + if (object_stream_to_objects.empty()) { | ||
| 3058 | // Write regular cross-reference table | 3176 | // Write regular cross-reference table |
| 3059 | - writeXRefTable(t_normal, 0, m->next_objid - 1, m->next_objid); | 3177 | + writeXRefTable(t_normal, 0, next_objid - 1, next_objid); |
| 3060 | } else { | 3178 | } else { |
| 3061 | // Write cross-reference stream. | 3179 | // Write cross-reference stream. |
| 3062 | - int xref_id = m->next_objid++; | ||
| 3063 | - writeXRefStream( | ||
| 3064 | - xref_id, xref_id, xref_offset, t_normal, 0, m->next_objid - 1, m->next_objid); | 3180 | + int xref_id = next_objid++; |
| 3181 | + writeXRefStream(xref_id, xref_id, xref_offset, t_normal, 0, next_objid - 1, next_objid); | ||
| 3065 | } | 3182 | } |
| 3066 | write("startxref\n").write(xref_offset).write("\n%%EOF\n"); | 3183 | write("startxref\n").write(xref_offset).write("\n%%EOF\n"); |
| 3067 | 3184 | ||
| 3068 | - if (m->deterministic_id) { | 3185 | + if (deterministic_id) { |
| 3069 | QTC::TC( | 3186 | QTC::TC( |
| 3070 | "qpdf", | 3187 | "qpdf", |
| 3071 | "QPDFWriter standard deterministic ID", | 3188 | "QPDFWriter standard deterministic ID", |
| 3072 | - m->object_stream_to_objects.empty() ? 0 : 1); | 3189 | + object_stream_to_objects.empty() ? 0 : 1); |
| 3073 | } | 3190 | } |
| 3074 | } | 3191 | } |
qpdf/qpdf.testcov
| @@ -40,8 +40,6 @@ main QTest array indirect 1 | @@ -40,8 +40,6 @@ main QTest array indirect 1 | ||
| 40 | main QTest dictionary 0 | 40 | main QTest dictionary 0 |
| 41 | main QTest dictionary indirect 1 | 41 | main QTest dictionary indirect 1 |
| 42 | main QTest stream 0 | 42 | main QTest stream 0 |
| 43 | -QPDFWriter write to stdout 0 | ||
| 44 | -QPDFWriter write to file 0 | ||
| 45 | QPDF lin write nshared_total > nshared_first_page 1 | 43 | QPDF lin write nshared_total > nshared_first_page 1 |
| 46 | QPDFWriter encrypted hint stream 0 | 44 | QPDFWriter encrypted hint stream 0 |
| 47 | QPDF opt inherited scalar 0 | 45 | QPDF opt inherited scalar 0 |
| @@ -83,11 +81,7 @@ QPDF xref deleted object 0 | @@ -83,11 +81,7 @@ QPDF xref deleted object 0 | ||
| 83 | SF_FlateLzwDecode PNG filter 0 | 81 | SF_FlateLzwDecode PNG filter 0 |
| 84 | QPDF xref /Index is array 1 | 82 | QPDF xref /Index is array 1 |
| 85 | QPDFWriter encrypt object stream 0 | 83 | QPDFWriter encrypt object stream 0 |
| 86 | -QPDFWriter uncompressing page dictionary 0 | ||
| 87 | -QPDFWriter uncompressing root 0 | ||
| 88 | -QPDFWriter compressing uncompressed stream 0 | ||
| 89 | QPDF exclude indirect length 0 | 84 | QPDF exclude indirect length 0 |
| 90 | -QPDFWriter generate >1 ostream 0 | ||
| 91 | QPDF exclude encryption dictionary 0 | 85 | QPDF exclude encryption dictionary 0 |
| 92 | QPDF loop detected traversing objects 0 | 86 | QPDF loop detected traversing objects 0 |
| 93 | QPDF reconstructed xref table 0 | 87 | QPDF reconstructed xref table 0 |
| @@ -95,7 +89,6 @@ QPDF recovered in readObjectAtOffset 0 | @@ -95,7 +89,6 @@ QPDF recovered in readObjectAtOffset 0 | ||
| 95 | QPDF recovered stream length 0 | 89 | QPDF recovered stream length 0 |
| 96 | QPDF found wrong endstream in recovery 0 | 90 | QPDF found wrong endstream in recovery 0 |
| 97 | QPDF_Stream pipeStreamData with null pipeline 0 | 91 | QPDF_Stream pipeStreamData with null pipeline 0 |
| 98 | -QPDFWriter not recompressing /FlateDecode 0 | ||
| 99 | QPDFJob unable to filter 0 | 92 | QPDFJob unable to filter 0 |
| 100 | QUtil non-trivial UTF-16 0 | 93 | QUtil non-trivial UTF-16 0 |
| 101 | QPDF xref overwrite invalid objgen 0 | 94 | QPDF xref overwrite invalid objgen 0 |
| @@ -135,14 +128,11 @@ qpdf-c called qpdf_allow_modify_annotation 0 | @@ -135,14 +128,11 @@ qpdf-c called qpdf_allow_modify_annotation 0 | ||
| 135 | qpdf-c called qpdf_allow_modify_other 0 | 128 | qpdf-c called qpdf_allow_modify_other 0 |
| 136 | qpdf-c called qpdf_allow_modify_all 0 | 129 | qpdf-c called qpdf_allow_modify_all 0 |
| 137 | QPDFWriter increasing minimum version 1 | 130 | QPDFWriter increasing minimum version 1 |
| 138 | -QPDFWriter using forced PDF version 0 | ||
| 139 | qpdf-c called qpdf_set_minimum_pdf_version 0 | 131 | qpdf-c called qpdf_set_minimum_pdf_version 0 |
| 140 | qpdf-c called qpdf_force_pdf_version 0 | 132 | qpdf-c called qpdf_force_pdf_version 0 |
| 141 | qpdf-c called qpdf_init_write multiple times 0 | 133 | qpdf-c called qpdf_init_write multiple times 0 |
| 142 | QPDF_encryption rc4 decode string 0 | 134 | QPDF_encryption rc4 decode string 0 |
| 143 | -QPDFWriter not compressing metadata 0 | ||
| 144 | QPDF_encryption aes decode string 0 | 135 | QPDF_encryption aes decode string 0 |
| 145 | -QPDFWriter forcing object stream disable 0 | ||
| 146 | QPDFWriter forced version disabled encryption 0 | 136 | QPDFWriter forced version disabled encryption 0 |
| 147 | qpdf-c called qpdf_set_r4_encryption_parameters_insecure 0 | 137 | qpdf-c called qpdf_set_r4_encryption_parameters_insecure 0 |
| 148 | qpdf-c called qpdf_set_static_aes_IV 0 | 138 | qpdf-c called qpdf_set_static_aes_IV 0 |
| @@ -195,7 +185,6 @@ QPDF replace dictionary 0 | @@ -195,7 +185,6 @@ QPDF replace dictionary 0 | ||
| 195 | QPDF replace stream 0 | 185 | QPDF replace stream 0 |
| 196 | QPDF replace foreign indirect with null 0 | 186 | QPDF replace foreign indirect with null 0 |
| 197 | QPDF insert foreign page 0 | 187 | QPDF insert foreign page 0 |
| 198 | -QPDFWriter foreign object 0 | ||
| 199 | QPDFWriter copy use_aes 1 | 188 | QPDFWriter copy use_aes 1 |
| 200 | QPDFParser indirect without context 0 | 189 | QPDFParser indirect without context 0 |
| 201 | QPDFObjectHandle trailing data in parse 0 | 190 | QPDFObjectHandle trailing data in parse 0 |
| @@ -203,17 +192,13 @@ QPDFJob pages encryption password 0 | @@ -203,17 +192,13 @@ QPDFJob pages encryption password 0 | ||
| 203 | QPDFTokenizer EOF reading token 0 | 192 | QPDFTokenizer EOF reading token 0 |
| 204 | QPDFTokenizer EOF reading appendable token 0 | 193 | QPDFTokenizer EOF reading appendable token 0 |
| 205 | QPDFWriter extra header text no newline 0 | 194 | QPDFWriter extra header text no newline 0 |
| 206 | -QPDFWriter extra header text add newline 0 | ||
| 207 | QPDF bogus 0 offset 0 | 195 | QPDF bogus 0 offset 0 |
| 208 | QPDF global offset 0 | 196 | QPDF global offset 0 |
| 209 | -QPDFWriter increasing extension level 0 | ||
| 210 | QPDFWriter make Extensions direct 0 | 197 | QPDFWriter make Extensions direct 0 |
| 211 | QPDFWriter make ADBE direct 1 | 198 | QPDFWriter make ADBE direct 1 |
| 212 | QPDFWriter preserve Extensions 0 | 199 | QPDFWriter preserve Extensions 0 |
| 213 | QPDFWriter create Extensions 1 | 200 | QPDFWriter create Extensions 1 |
| 214 | -QPDFWriter remove ADBE 0 | ||
| 215 | QPDFWriter remove existing Extensions 0 | 201 | QPDFWriter remove existing Extensions 0 |
| 216 | -QPDFWriter preserve ADBE 0 | ||
| 217 | QPDF_encryption skip 0x28 0 | 202 | QPDF_encryption skip 0x28 0 |
| 218 | qpdf-c called qpdf_get_pdf_extension_level 0 | 203 | qpdf-c called qpdf_get_pdf_extension_level 0 |
| 219 | qpdf-c called qpdf_set_r5_encryption_parameters 0 | 204 | qpdf-c called qpdf_set_r5_encryption_parameters 0 |
| @@ -221,7 +206,6 @@ qpdf-c called qpdf_set_r6_encryption_parameters 0 | @@ -221,7 +206,6 @@ qpdf-c called qpdf_set_r6_encryption_parameters 0 | ||
| 221 | QPDFObjectHandle EOF in inline image 0 | 206 | QPDFObjectHandle EOF in inline image 0 |
| 222 | QPDFObjectHandle inline image token 0 | 207 | QPDFObjectHandle inline image token 0 |
| 223 | QPDF not caching overridden objstm object 0 | 208 | QPDF not caching overridden objstm object 0 |
| 224 | -QPDFWriter original obj non-zero gen 0 | ||
| 225 | QPDF_optimization indirect outlines 0 | 209 | QPDF_optimization indirect outlines 0 |
| 226 | QPDF xref space 2 | 210 | QPDF xref space 2 |
| 227 | QPDFJob pages range omitted in middle 0 | 211 | QPDFJob pages range omitted in middle 0 |
| @@ -237,7 +221,6 @@ QPDFParser treat word as string in parseRemainder 0 | @@ -237,7 +221,6 @@ QPDFParser treat word as string in parseRemainder 0 | ||
| 237 | QPDFParser found fake 1 | 221 | QPDFParser found fake 1 |
| 238 | QPDFParser no val for last key 0 | 222 | QPDFParser no val for last key 0 |
| 239 | QPDF resolve failure to null 0 | 223 | QPDF resolve failure to null 0 |
| 240 | -QPDFWriter preserve unreferenced standard 0 | ||
| 241 | QPDFObjectHandle errors in parsecontent 0 | 224 | QPDFObjectHandle errors in parsecontent 0 |
| 242 | QPDFJob same file error 0 | 225 | QPDFJob same file error 0 |
| 243 | QPDFJob split-pages %d 0 | 226 | QPDFJob split-pages %d 0 |
| @@ -374,7 +357,6 @@ QPDF_encryption same password 1 | @@ -374,7 +357,6 @@ QPDF_encryption same password 1 | ||
| 374 | QPDFParser duplicate dict key 0 | 357 | QPDFParser duplicate dict key 0 |
| 375 | QPDFWriter no encryption sig contents 0 | 358 | QPDFWriter no encryption sig contents 0 |
| 376 | QPDFPageObjectHelper colorspace lookup 0 | 359 | QPDFPageObjectHelper colorspace lookup 0 |
| 377 | -QPDFWriter ignore XRef in qdf mode 0 | ||
| 378 | QPDFPageObjectHelper filter form xobject 0 | 360 | QPDFPageObjectHelper filter form xobject 0 |
| 379 | QPDFJob found resources in non-leaf 0 | 361 | QPDFJob found resources in non-leaf 0 |
| 380 | QPDFJob found shared resources in leaf 0 | 362 | QPDFJob found shared resources in leaf 0 |
| @@ -463,7 +445,6 @@ qpdf-c called qpdf_oh_get_generation 0 | @@ -463,7 +445,6 @@ qpdf-c called qpdf_oh_get_generation 0 | ||
| 463 | qpdf-c called qpdf_oh_unparse 0 | 445 | qpdf-c called qpdf_oh_unparse 0 |
| 464 | qpdf-c called qpdf_oh_unparse_resolved 0 | 446 | qpdf-c called qpdf_oh_unparse_resolved 0 |
| 465 | qpdf-c called qpdf_oh_unparse_binary 0 | 447 | qpdf-c called qpdf_oh_unparse_binary 0 |
| 466 | -QPDFWriter getFilterOnWrite false 0 | ||
| 467 | QPDFPageObjectHelper::forEachXObject 3 | 448 | QPDFPageObjectHelper::forEachXObject 3 |
| 468 | NNTree erased last kid/item in tree 1 | 449 | NNTree erased last kid/item in tree 1 |
| 469 | QPDFPageObjectHelper unresolved names 0 | 450 | QPDFPageObjectHelper unresolved names 0 |
| @@ -481,8 +462,6 @@ QPDFAcroFormDocumentHelper AP parse error 1 | @@ -481,8 +462,6 @@ QPDFAcroFormDocumentHelper AP parse error 1 | ||
| 481 | QPDFJob copy fields not this file 0 | 462 | QPDFJob copy fields not this file 0 |
| 482 | QPDFJob copy fields non-first from orig 0 | 463 | QPDFJob copy fields non-first from orig 0 |
| 483 | QPDF resolve duplicated page in insert 0 | 464 | QPDF resolve duplicated page in insert 0 |
| 484 | -QPDFWriter preserve object streams 0 | ||
| 485 | -QPDFWriter preserve object streams preserve unreferenced 0 | ||
| 486 | QPDFWriter exclude from object stream 0 | 465 | QPDFWriter exclude from object stream 0 |
| 487 | QPDF_pages findPage not found 0 | 466 | QPDF_pages findPage not found 0 |
| 488 | QPDFJob weak crypto error 0 | 467 | QPDFJob weak crypto error 0 |
qpdf/test_driver.cc
| @@ -2624,7 +2624,7 @@ test_76(QPDF& pdf, char const* arg2) | @@ -2624,7 +2624,7 @@ test_76(QPDF& pdf, char const* arg2) | ||
| 2624 | { | 2624 | { |
| 2625 | // Embedded files. arg2 is a file to attach. Hard-code the | 2625 | // Embedded files. arg2 is a file to attach. Hard-code the |
| 2626 | // mime type and file name for test purposes. | 2626 | // mime type and file name for test purposes. |
| 2627 | - auto &efdh = QPDFEmbeddedFileDocumentHelper::get(pdf); | 2627 | + auto& efdh = QPDFEmbeddedFileDocumentHelper::get(pdf); |
| 2628 | auto fs1 = QPDFFileSpecObjectHelper::createFileSpec(pdf, "att1.txt", arg2); | 2628 | auto fs1 = QPDFFileSpecObjectHelper::createFileSpec(pdf, "att1.txt", arg2); |
| 2629 | fs1.setDescription("some text"); | 2629 | fs1.setDescription("some text"); |
| 2630 | auto efs1 = QPDFEFStreamObjectHelper(fs1.getEmbeddedFileStream()); | 2630 | auto efs1 = QPDFEFStreamObjectHelper(fs1.getEmbeddedFileStream()); |