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 | 20 | #ifndef QPDFWRITER_HH |
| 21 | 21 | #define QPDFWRITER_HH |
| 22 | 22 | |
| 23 | +#include <qpdf/Constants.h> | |
| 23 | 24 | #include <qpdf/DLL.h> |
| 24 | 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 | 35 | #include <bitset> |
| 27 | -#include <concepts> | |
| 28 | 36 | #include <cstdio> |
| 29 | 37 | #include <functional> |
| 30 | 38 | #include <list> |
| ... | ... | @@ -35,24 +43,7 @@ |
| 35 | 43 | #include <string_view> |
| 36 | 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 | 46 | class QPDF; |
| 54 | -class Pl_Count; | |
| 55 | -class Pl_MD5; | |
| 56 | 47 | |
| 57 | 48 | // This class implements a simple writer for saving QPDF objects to new PDF files. See comments |
| 58 | 49 | // through the header file for additional details. |
| ... | ... | @@ -449,132 +440,8 @@ class QPDFWriter |
| 449 | 440 | class NewObjTable; |
| 450 | 441 | |
| 451 | 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 | 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 | 445 | std::shared_ptr<Members> m; |
| 579 | 446 | }; |
| 580 | 447 | ... | ... |
libqpdf/NNTree.cc
| ... | ... | @@ -666,7 +666,7 @@ NNTreeImpl::repair() |
| 666 | 666 | NNTreeImpl repl(qpdf, new_node, key_type, value_valid, false); |
| 667 | 667 | std::map<QPDFObjectHandle, QPDFObjectHandle, Cmp> items; |
| 668 | 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 | 670 | items.insert_or_assign(key, value); |
| 671 | 671 | } |
| 672 | 672 | } | ... | ... |
libqpdf/QPDFWriter.cc
| ... | ... | @@ -11,7 +11,6 @@ |
| 11 | 11 | #include <qpdf/Pl_PNGFilter.hh> |
| 12 | 12 | #include <qpdf/Pl_RC4.hh> |
| 13 | 13 | #include <qpdf/Pl_StdioFile.hh> |
| 14 | -#include <qpdf/Pl_String.hh> | |
| 15 | 14 | #include <qpdf/QIntC.hh> |
| 16 | 15 | #include <qpdf/QPDFObjectHandle_private.hh> |
| 17 | 16 | #include <qpdf/QPDFObject_private.hh> |
| ... | ... | @@ -22,6 +21,7 @@ |
| 22 | 21 | #include <qpdf/Util.hh> |
| 23 | 22 | |
| 24 | 23 | #include <algorithm> |
| 24 | +#include <concepts> | |
| 25 | 25 | #include <cstdlib> |
| 26 | 26 | #include <stdexcept> |
| 27 | 27 | |
| ... | ... | @@ -265,12 +265,152 @@ class QPDFWriter::Members |
| 265 | 265 | friend class QPDFWriter; |
| 266 | 266 | |
| 267 | 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 | 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 | 414 | QPDF& pdf; |
| 275 | 415 | QPDFObjGen root_og{-1, 0}; |
| 276 | 416 | char const* filename{"unspecified"}; |
| ... | ... | @@ -341,34 +481,19 @@ class QPDFWriter::Members |
| 341 | 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 | 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 | 489 | QPDFWriter::QPDFWriter(QPDF& pdf, char const* filename) : |
| 365 | - m(new Members(pdf)) | |
| 490 | + m(std::make_shared<Members>(*this, pdf)) | |
| 366 | 491 | { |
| 367 | 492 | setOutputFilename(filename); |
| 368 | 493 | } |
| 369 | 494 | |
| 370 | 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 | 498 | setOutputFile(description, file, close_file); |
| 374 | 499 | } |
| ... | ... | @@ -381,11 +506,9 @@ QPDFWriter::setOutputFilename(char const* filename) |
| 381 | 506 | bool close_file = false; |
| 382 | 507 | if (filename == nullptr) { |
| 383 | 508 | description = "standard output"; |
| 384 | - QTC::TC("qpdf", "QPDFWriter write to stdout"); | |
| 385 | 509 | f = stdout; |
| 386 | 510 | QUtil::binary_stdout(); |
| 387 | 511 | } else { |
| 388 | - QTC::TC("qpdf", "QPDFWriter write to file"); | |
| 389 | 512 | f = QUtil::safe_fopen(filename, "wb+"); |
| 390 | 513 | close_file = true; |
| 391 | 514 | } |
| ... | ... | @@ -508,9 +631,15 @@ QPDFWriter::setNewlineBeforeEndstream(bool val) |
| 508 | 631 | void |
| 509 | 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 | 640 | bool set_version = false; |
| 512 | 641 | bool set_extension_level = false; |
| 513 | - if (m->min_pdf_version.empty()) { | |
| 642 | + if (min_pdf_version.empty()) { | |
| 514 | 643 | set_version = true; |
| 515 | 644 | set_extension_level = true; |
| 516 | 645 | } else { |
| ... | ... | @@ -519,25 +648,24 @@ QPDFWriter::setMinimumPDFVersion(std::string const& version, int extension_level |
| 519 | 648 | int min_major = 0; |
| 520 | 649 | int min_minor = 0; |
| 521 | 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 | 652 | int compare = compareVersions(old_major, old_minor, min_major, min_minor); |
| 524 | 653 | if (compare > 0) { |
| 525 | 654 | QTC::TC("qpdf", "QPDFWriter increasing minimum version", extension_level == 0 ? 0 : 1); |
| 526 | 655 | set_version = true; |
| 527 | 656 | set_extension_level = true; |
| 528 | 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 | 659 | set_extension_level = true; |
| 532 | 660 | } |
| 533 | 661 | } |
| 534 | 662 | } |
| 535 | 663 | |
| 536 | 664 | if (set_version) { |
| 537 | - m->min_pdf_version = version; | |
| 665 | + min_pdf_version = version; | |
| 538 | 666 | } |
| 539 | 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 | 690 | { |
| 563 | 691 | m->extra_header_text = text; |
| 564 | 692 | if (!m->extra_header_text.empty() && *m->extra_header_text.rbegin() != '\n') { |
| 565 | - QTC::TC("qpdf", "QPDFWriter extra header text add newline"); | |
| 566 | 693 | m->extra_header_text += "\n"; |
| 567 | 694 | } else { |
| 568 | 695 | QTC::TC("qpdf", "QPDFWriter extra header text no newline"); |
| ... | ... | @@ -647,7 +774,7 @@ QPDFWriter::setR2EncryptionParametersInsecure( |
| 647 | 774 | if (!allow_annotate) { |
| 648 | 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 | 780 | void |
| ... | ... | @@ -663,7 +790,7 @@ QPDFWriter::setR3EncryptionParametersInsecure( |
| 663 | 790 | qpdf_r3_print_e print) |
| 664 | 791 | { |
| 665 | 792 | m->encryption = std::make_unique<QPDF::EncryptionData>(2, 3, 16, true); |
| 666 | - interpretR3EncryptionParameters( | |
| 793 | + m->interpretR3EncryptionParameters( | |
| 667 | 794 | allow_accessibility, |
| 668 | 795 | allow_extract, |
| 669 | 796 | allow_assemble, |
| ... | ... | @@ -672,7 +799,7 @@ QPDFWriter::setR3EncryptionParametersInsecure( |
| 672 | 799 | allow_modify_other, |
| 673 | 800 | print, |
| 674 | 801 | qpdf_r3m_all); |
| 675 | - setEncryptionParameters(user_password, owner_password); | |
| 802 | + m->setEncryptionParameters(user_password, owner_password); | |
| 676 | 803 | } |
| 677 | 804 | |
| 678 | 805 | void |
| ... | ... | @@ -691,7 +818,7 @@ QPDFWriter::setR4EncryptionParametersInsecure( |
| 691 | 818 | { |
| 692 | 819 | m->encryption = std::make_unique<QPDF::EncryptionData>(4, 4, 16, encrypt_metadata); |
| 693 | 820 | m->encrypt_use_aes = use_aes; |
| 694 | - interpretR3EncryptionParameters( | |
| 821 | + m->interpretR3EncryptionParameters( | |
| 695 | 822 | allow_accessibility, |
| 696 | 823 | allow_extract, |
| 697 | 824 | allow_assemble, |
| ... | ... | @@ -700,7 +827,7 @@ QPDFWriter::setR4EncryptionParametersInsecure( |
| 700 | 827 | allow_modify_other, |
| 701 | 828 | print, |
| 702 | 829 | qpdf_r3m_all); |
| 703 | - setEncryptionParameters(user_password, owner_password); | |
| 830 | + m->setEncryptionParameters(user_password, owner_password); | |
| 704 | 831 | } |
| 705 | 832 | |
| 706 | 833 | void |
| ... | ... | @@ -718,7 +845,7 @@ QPDFWriter::setR5EncryptionParameters( |
| 718 | 845 | { |
| 719 | 846 | m->encryption = std::make_unique<QPDF::EncryptionData>(5, 5, 32, encrypt_metadata); |
| 720 | 847 | m->encrypt_use_aes = true; |
| 721 | - interpretR3EncryptionParameters( | |
| 848 | + m->interpretR3EncryptionParameters( | |
| 722 | 849 | allow_accessibility, |
| 723 | 850 | allow_extract, |
| 724 | 851 | allow_assemble, |
| ... | ... | @@ -727,7 +854,7 @@ QPDFWriter::setR5EncryptionParameters( |
| 727 | 854 | allow_modify_other, |
| 728 | 855 | print, |
| 729 | 856 | qpdf_r3m_all); |
| 730 | - setEncryptionParameters(user_password, owner_password); | |
| 857 | + m->setEncryptionParameters(user_password, owner_password); | |
| 731 | 858 | } |
| 732 | 859 | |
| 733 | 860 | void |
| ... | ... | @@ -744,7 +871,7 @@ QPDFWriter::setR6EncryptionParameters( |
| 744 | 871 | bool encrypt_metadata) |
| 745 | 872 | { |
| 746 | 873 | m->encryption = std::make_unique<QPDF::EncryptionData>(5, 6, 32, encrypt_metadata); |
| 747 | - interpretR3EncryptionParameters( | |
| 874 | + m->interpretR3EncryptionParameters( | |
| 748 | 875 | allow_accessibility, |
| 749 | 876 | allow_extract, |
| 750 | 877 | allow_assemble, |
| ... | ... | @@ -754,11 +881,11 @@ QPDFWriter::setR6EncryptionParameters( |
| 754 | 881 | print, |
| 755 | 882 | qpdf_r3m_all); |
| 756 | 883 | m->encrypt_use_aes = true; |
| 757 | - setEncryptionParameters(user_password, owner_password); | |
| 884 | + m->setEncryptionParameters(user_password, owner_password); | |
| 758 | 885 | } |
| 759 | 886 | |
| 760 | 887 | void |
| 761 | -QPDFWriter::interpretR3EncryptionParameters( | |
| 888 | +QPDFWriter::Members::interpretR3EncryptionParameters( | |
| 762 | 889 | bool allow_accessibility, |
| 763 | 890 | bool allow_extract, |
| 764 | 891 | bool allow_assemble, |
| ... | ... | @@ -797,21 +924,21 @@ QPDFWriter::interpretR3EncryptionParameters( |
| 797 | 924 | // 10: accessibility; ignored by readers, should always be set |
| 798 | 925 | // 11: document assembly even if 4 is clear |
| 799 | 926 | // 12: high-resolution printing |
| 800 | - if (!allow_accessibility && m->encryption->getR() <= 3) { | |
| 927 | + if (!allow_accessibility && encryption->getR() <= 3) { | |
| 801 | 928 | // Bit 10 is deprecated and should always be set. This used to mean accessibility. There |
| 802 | 929 | // is no way to disable accessibility with R > 3. |
| 803 | - m->encryption->setP(10, false); | |
| 930 | + encryption->setP(10, false); | |
| 804 | 931 | } |
| 805 | 932 | if (!allow_extract) { |
| 806 | - m->encryption->setP(5, false); | |
| 933 | + encryption->setP(5, false); | |
| 807 | 934 | } |
| 808 | 935 | |
| 809 | 936 | switch (print) { |
| 810 | 937 | case qpdf_r3p_none: |
| 811 | - m->encryption->setP(3, false); // any printing | |
| 938 | + encryption->setP(3, false); // any printing | |
| 812 | 939 | [[fallthrough]]; |
| 813 | 940 | case qpdf_r3p_low: |
| 814 | - m->encryption->setP(12, false); // high resolution printing | |
| 941 | + encryption->setP(12, false); // high resolution printing | |
| 815 | 942 | [[fallthrough]]; |
| 816 | 943 | case qpdf_r3p_full: |
| 817 | 944 | break; |
| ... | ... | @@ -825,16 +952,16 @@ QPDFWriter::interpretR3EncryptionParameters( |
| 825 | 952 | // NOT EXERCISED IN TEST SUITE |
| 826 | 953 | switch (modify) { |
| 827 | 954 | case qpdf_r3m_none: |
| 828 | - m->encryption->setP(11, false); // document assembly | |
| 955 | + encryption->setP(11, false); // document assembly | |
| 829 | 956 | [[fallthrough]]; |
| 830 | 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 | 959 | [[fallthrough]]; |
| 833 | 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 | 962 | [[fallthrough]]; |
| 836 | 963 | case qpdf_r3m_annotate: |
| 837 | - m->encryption->setP(4, false); // other modifications | |
| 964 | + encryption->setP(4, false); // other modifications | |
| 838 | 965 | [[fallthrough]]; |
| 839 | 966 | case qpdf_r3m_all: |
| 840 | 967 | break; |
| ... | ... | @@ -843,36 +970,42 @@ QPDFWriter::interpretR3EncryptionParameters( |
| 843 | 970 | // END NOT EXERCISED IN TEST SUITE |
| 844 | 971 | |
| 845 | 972 | if (!allow_assemble) { |
| 846 | - m->encryption->setP(11, false); | |
| 973 | + encryption->setP(11, false); | |
| 847 | 974 | } |
| 848 | 975 | if (!allow_annotate_and_form) { |
| 849 | - m->encryption->setP(6, false); | |
| 976 | + encryption->setP(6, false); | |
| 850 | 977 | } |
| 851 | 978 | if (!allow_form_filling) { |
| 852 | - m->encryption->setP(9, false); | |
| 979 | + encryption->setP(9, false); | |
| 853 | 980 | } |
| 854 | 981 | if (!allow_modify_other) { |
| 855 | - m->encryption->setP(4, false); | |
| 982 | + encryption->setP(4, false); | |
| 856 | 983 | } |
| 857 | 984 | } |
| 858 | 985 | |
| 859 | 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 | 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 | 992 | setEncryptionMinimumVersion(); |
| 866 | 993 | } |
| 867 | 994 | |
| 868 | 995 | void |
| 869 | 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 | 1005 | QPDFObjectHandle trailer = qpdf.getTrailer(); |
| 873 | 1006 | if (trailer.hasKey("/Encrypt")) { |
| 874 | 1007 | generateID(true); |
| 875 | - m->id1 = trailer.getKey("/ID").getArrayItem(0).getStringValue(); | |
| 1008 | + id1 = trailer.getKey("/ID").getArrayItem(0).getStringValue(); | |
| 876 | 1009 | QPDFObjectHandle encrypt = trailer.getKey("/Encrypt"); |
| 877 | 1010 | int V = encrypt.getKey("/V").getIntValueAsInt(); |
| 878 | 1011 | int key_len = 5; |
| ... | ... | @@ -888,12 +1021,12 @@ QPDFWriter::copyEncryptionParameters(QPDF& qpdf) |
| 888 | 1021 | // Acrobat doesn't create files with V >= 4 that don't use AES, and the logic of |
| 889 | 1022 | // figuring out whether AES is used or not is complicated with /StmF, /StrF, and /EFF |
| 890 | 1023 | // all potentially having different values. |
| 891 | - m->encrypt_use_aes = true; | |
| 1024 | + encrypt_use_aes = true; | |
| 892 | 1025 | } |
| 893 | 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 | 1030 | V, |
| 898 | 1031 | encrypt.getKey("/R").getIntValueAsInt(), |
| 899 | 1032 | key_len, |
| ... | ... | @@ -903,54 +1036,53 @@ QPDFWriter::copyEncryptionParameters(QPDF& qpdf) |
| 903 | 1036 | V < 5 ? "" : encrypt.getKey("/OE").getStringValue(), |
| 904 | 1037 | V < 5 ? "" : encrypt.getKey("/UE").getStringValue(), |
| 905 | 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 | 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 | 1043 | setEncryptionMinimumVersion(); |
| 912 | 1044 | } |
| 913 | 1045 | } |
| 914 | 1046 | |
| 915 | 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 | 1051 | return; |
| 920 | 1052 | } |
| 921 | 1053 | if (compareVersions(major, minor, 1, 3) < 0) { |
| 922 | - m->encryption = nullptr; | |
| 1054 | + encryption = nullptr; | |
| 923 | 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 | 1059 | if (compareVersions(major, minor, 1, 4) < 0) { |
| 928 | 1060 | if (V > 1 || R > 2) { |
| 929 | - m->encryption = nullptr; | |
| 1061 | + encryption = nullptr; | |
| 930 | 1062 | } |
| 931 | 1063 | } else if (compareVersions(major, minor, 1, 5) < 0) { |
| 932 | 1064 | if (V > 2 || R > 3) { |
| 933 | - m->encryption = nullptr; | |
| 1065 | + encryption = nullptr; | |
| 934 | 1066 | } |
| 935 | 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 | 1071 | } else if ( |
| 940 | 1072 | (compareVersions(major, minor, 1, 7) < 0) || |
| 941 | 1073 | ((compareVersions(major, minor, 1, 7) == 0) && extension_level < 3)) { |
| 942 | 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 | 1080 | QTC::TC("qpdf", "QPDFWriter forced version disabled encryption"); |
| 949 | 1081 | } |
| 950 | 1082 | } |
| 951 | 1083 | |
| 952 | 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 | 1087 | major = QUtil::string_to_int(version.c_str()); |
| 956 | 1088 | minor = 0; |
| ... | ... | @@ -967,54 +1099,48 @@ QPDFWriter::parseVersion(std::string const& version, int& major, int& minor) con |
| 967 | 1099 | } |
| 968 | 1100 | |
| 969 | 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 | 1104 | if (major1 < major2) { |
| 973 | 1105 | return -1; |
| 974 | - } else if (major1 > major2) { | |
| 1106 | + } | |
| 1107 | + if (major1 > major2) { | |
| 975 | 1108 | return 1; |
| 976 | - } else if (minor1 < minor2) { | |
| 1109 | + } | |
| 1110 | + if (minor1 < minor2) { | |
| 977 | 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 | 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 | 1120 | if (R >= 6) { |
| 990 | - setMinimumPDFVersion("1.7", 8); | |
| 1121 | + w.setMinimumPDFVersion("1.7", 8); | |
| 991 | 1122 | } else if (R == 5) { |
| 992 | - setMinimumPDFVersion("1.7", 3); | |
| 1123 | + w.setMinimumPDFVersion("1.7", 3); | |
| 993 | 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 | 1126 | } else if (R == 3) { |
| 996 | - setMinimumPDFVersion("1.4"); | |
| 1127 | + w.setMinimumPDFVersion("1.4"); | |
| 997 | 1128 | } else { |
| 998 | - setMinimumPDFVersion("1.3"); | |
| 1129 | + w.setMinimumPDFVersion("1.3"); | |
| 999 | 1130 | } |
| 1000 | 1131 | } |
| 1001 | 1132 | |
| 1002 | 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 | 1142 | unsigned int |
| 1017 | -QPDFWriter::bytesNeeded(long long n) | |
| 1143 | +QPDFWriter::Members::bytesNeeded(long long n) | |
| 1018 | 1144 | { |
| 1019 | 1145 | unsigned int bytes = 0; |
| 1020 | 1146 | while (n) { |
| ... | ... | @@ -1025,7 +1151,7 @@ QPDFWriter::bytesNeeded(long long n) |
| 1025 | 1151 | } |
| 1026 | 1152 | |
| 1027 | 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 | 1156 | if (bytes > sizeof(unsigned long long)) { |
| 1031 | 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 | 1161 | data[bytes - i - 1] = static_cast<unsigned char>(val & 0xff); |
| 1036 | 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 | 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 | 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 | 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 | 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 | 1199 | return *this; |
| 1074 | 1200 | } |
| 1075 | 1201 | |
| 1076 | 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 | 1209 | return *this; |
| 1084 | 1210 | } |
| 1085 | 1211 | |
| 1086 | 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 | 1219 | return *this; |
| 1094 | 1220 | } |
| 1095 | 1221 | |
| 1096 | 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 | 1226 | // Stream length will be padded with 1 to 16 bytes to end up as a multiple of 16. It will |
| 1101 | 1227 | // also be prepended by 16 bits of random data. |
| 1102 | 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 | 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 | 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 | 1243 | return *this; |
| 1118 | 1244 | } |
| 1119 | 1245 | |
| 1120 | 1246 | void |
| 1121 | -QPDFWriter::computeDeterministicIDData() | |
| 1247 | +QPDFWriter::Members::computeDeterministicIDData() | |
| 1122 | 1248 | { |
| 1123 | - if (!m->id2.empty()) { | |
| 1249 | + if (!id2.empty()) { | |
| 1124 | 1250 | // Can't happen in the code |
| 1125 | 1251 | throw std::logic_error( |
| 1126 | 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 | 1258 | int |
| 1133 | -QPDFWriter::openObject(int objid) | |
| 1259 | +QPDFWriter::Members::openObject(int objid) | |
| 1134 | 1260 | { |
| 1135 | 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 | 1265 | write(objid).write(" 0 obj\n"); |
| 1140 | 1266 | return objid; |
| 1141 | 1267 | } |
| 1142 | 1268 | |
| 1143 | 1269 | void |
| 1144 | -QPDFWriter::closeObject(int objid) | |
| 1270 | +QPDFWriter::Members::closeObject(int objid) | |
| 1145 | 1271 | { |
| 1146 | 1272 | // Write a newline before endobj as it makes the file easier to repair. |
| 1147 | 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 | 1278 | void |
| 1153 | -QPDFWriter::assignCompressedObjectNumbers(QPDFObjGen og) | |
| 1279 | +QPDFWriter::Members::assignCompressedObjectNumbers(QPDFObjGen og) | |
| 1154 | 1280 | { |
| 1155 | 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 | 1283 | // This is not an object stream. |
| 1158 | 1284 | return; |
| 1159 | 1285 | } |
| 1160 | 1286 | |
| 1161 | 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 | 1293 | void |
| 1168 | -QPDFWriter::enqueueObject(QPDFObjectHandle object) | |
| 1294 | +QPDFWriter::Members::enqueueObject(QPDFObjectHandle object) | |
| 1169 | 1295 | { |
| 1170 | 1296 | if (object.isIndirect()) { |
| 1171 | 1297 | // This owner check can only be done for indirect objects. It is possible for a direct |
| 1172 | 1298 | // object to have an owning QPDF that is from another file if a direct QPDFObjectHandle from |
| 1173 | 1299 | // one file was insert into another file without copying. Doing that is safe even if the |
| 1174 | 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 | 1302 | throw std::logic_error( |
| 1178 | 1303 | "QPDFObjectHandle from different QPDF found while writing. Use " |
| 1179 | 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 | 1308 | // As a special case, do not output any extraneous XRef streams in QDF mode. Doing so |
| 1184 | 1309 | // will confuse fix-qdf, which expects to see only one XRef stream at the end of the |
| 1185 | 1310 | // file. This case can occur when creating a QDF from a file with object streams when |
| 1186 | 1311 | // preserving unreferenced objects since the old cross reference streams are not |
| 1187 | 1312 | // actually referenced by object number. |
| 1188 | - QTC::TC("qpdf", "QPDFWriter ignore XRef in qdf mode"); | |
| 1189 | 1313 | return; |
| 1190 | 1314 | } |
| 1191 | 1315 | |
| 1192 | 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 | 1321 | // This is in an object stream. Don't process it here. Instead, enqueue the object |
| 1198 | 1322 | // stream. Object streams always have generation 0. |
| 1199 | 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 | 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 | 1331 | // For linearized files, uncompressed objects go at end, and we take care of |
| 1208 | 1332 | // assigning numbers to them elsewhere. |
| 1209 | - if (!m->linearized) { | |
| 1333 | + if (!linearized) { | |
| 1210 | 1334 | assignCompressedObjectNumbers(og); |
| 1211 | 1335 | } |
| 1212 | - } else if ((!m->direct_stream_lengths) && object.isStream()) { | |
| 1336 | + } else if (!direct_stream_lengths && object.isStream()) { | |
| 1213 | 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 | 1342 | // This can happen if a specially constructed file indicates that an object stream is |
| 1219 | 1343 | // inside itself. |
| 1220 | 1344 | } |
| 1221 | 1345 | return; |
| 1222 | - } else if (!m->linearized) { | |
| 1346 | + } else if (!linearized) { | |
| 1223 | 1347 | if (object.isArray()) { |
| 1224 | 1348 | for (auto& item: object.as_array()) { |
| 1225 | 1349 | enqueueObject(item); |
| ... | ... | @@ -1237,25 +1361,25 @@ QPDFWriter::enqueueObject(QPDFObjectHandle object) |
| 1237 | 1361 | } |
| 1238 | 1362 | |
| 1239 | 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 | 1367 | enqueueObject(child); |
| 1244 | 1368 | } |
| 1245 | 1369 | if (child.isIndirect()) { |
| 1246 | - write(m->obj[child].renumber).write(" 0 R"); | |
| 1370 | + write(obj[child].renumber).write(" 0 R"); | |
| 1247 | 1371 | } else { |
| 1248 | 1372 | unparseObject(child, level, flags); |
| 1249 | 1373 | } |
| 1250 | 1374 | } |
| 1251 | 1375 | |
| 1252 | 1376 | void |
| 1253 | -QPDFWriter::writeTrailer( | |
| 1377 | +QPDFWriter::Members::writeTrailer( | |
| 1254 | 1378 | trailer_e which, int size, bool xref_stream, qpdf_offset_t prev, int linearization_pass) |
| 1255 | 1379 | { |
| 1256 | 1380 | QPDFObjectHandle trailer = getTrimmedTrailer(); |
| 1257 | 1381 | if (xref_stream) { |
| 1258 | - m->cur_data_key.clear(); | |
| 1382 | + cur_data_key.clear(); | |
| 1259 | 1383 | } else { |
| 1260 | 1384 | write("trailer <<"); |
| 1261 | 1385 | } |
| ... | ... | @@ -1272,8 +1396,8 @@ QPDFWriter::writeTrailer( |
| 1272 | 1396 | write(size); |
| 1273 | 1397 | if (which == t_lin_first) { |
| 1274 | 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 | 1402 | } else { |
| 1279 | 1403 | unparseChild(value, 1, 0); |
| ... | ... | @@ -1298,18 +1422,18 @@ QPDFWriter::writeTrailer( |
| 1298 | 1422 | } |
| 1299 | 1423 | write("<00000000000000000000000000000000>"); |
| 1300 | 1424 | } else { |
| 1301 | - if (linearization_pass == 0 && m->deterministic_id) { | |
| 1425 | + if (linearization_pass == 0 && deterministic_id) { | |
| 1302 | 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 | 1431 | write("]"); |
| 1308 | 1432 | |
| 1309 | 1433 | if (which != t_lin_second) { |
| 1310 | 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 | 1441 | } |
| 1318 | 1442 | |
| 1319 | 1443 | bool |
| 1320 | -QPDFWriter::willFilterStream( | |
| 1444 | +QPDFWriter::Members::willFilterStream( | |
| 1321 | 1445 | QPDFObjectHandle stream, |
| 1322 | 1446 | bool& compress_stream, // out only |
| 1323 | 1447 | bool& is_root_metadata, // out only |
| ... | ... | @@ -1332,38 +1456,33 @@ QPDFWriter::willFilterStream( |
| 1332 | 1456 | if (stream.isRootMetadata()) { |
| 1333 | 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 | 1460 | bool filter_on_write = stream.getFilterOnWrite(); |
| 1337 | 1461 | if (!filter_on_write) { |
| 1338 | - QTC::TC("qpdf", "QPDFWriter getFilterOnWrite false"); | |
| 1339 | 1462 | filter = false; |
| 1340 | 1463 | } |
| 1341 | - if (filter_on_write && m->compress_streams) { | |
| 1464 | + if (filter_on_write && compress_streams) { | |
| 1342 | 1465 | // Don't filter if the stream is already compressed with FlateDecode. This way we don't make |
| 1343 | 1466 | // it worse if the original file used a better Flate algorithm, and we don't spend time and |
| 1344 | 1467 | // CPU cycles uncompressing and recompressing stuff. This can be overridden with |
| 1345 | 1468 | // setRecompressFlate(true). |
| 1346 | 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 | 1471 | (filter_obj.getName() == "/FlateDecode" || filter_obj.getName() == "/Fl")) { |
| 1349 | - QTC::TC("qpdf", "QPDFWriter not recompressing /FlateDecode"); | |
| 1350 | 1472 | filter = false; |
| 1351 | 1473 | } |
| 1352 | 1474 | } |
| 1353 | 1475 | bool normalize = false; |
| 1354 | 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 | 1478 | filter = true; |
| 1359 | 1479 | compress_stream = false; |
| 1360 | 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 | 1482 | normalize = true; |
| 1363 | 1483 | filter = true; |
| 1364 | - } else if (filter_on_write && filter && m->compress_streams) { | |
| 1484 | + } else if (filter_on_write && filter && compress_streams) { | |
| 1365 | 1485 | compress_stream = true; |
| 1366 | - QTC::TC("qpdf", "QPDFWriter compressing uncompressed stream"); | |
| 1367 | 1486 | } |
| 1368 | 1487 | |
| 1369 | 1488 | // Disable compression for empty streams to improve compatibility |
| ... | ... | @@ -1375,16 +1494,16 @@ QPDFWriter::willFilterStream( |
| 1375 | 1494 | |
| 1376 | 1495 | bool filtered = false; |
| 1377 | 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 | 1500 | try { |
| 1382 | 1501 | filtered = stream.pipeStreamData( |
| 1383 | - m->pipeline, | |
| 1502 | + pipeline, | |
| 1384 | 1503 | !filter ? 0 |
| 1385 | 1504 | : ((normalize ? qpdf_ef_normalize : 0) | |
| 1386 | 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 | 1507 | false, |
| 1389 | 1508 | first_attempt); |
| 1390 | 1509 | if (filter && !filtered) { |
| ... | ... | @@ -1416,7 +1535,7 @@ QPDFWriter::willFilterStream( |
| 1416 | 1535 | } |
| 1417 | 1536 | |
| 1418 | 1537 | void |
| 1419 | -QPDFWriter::unparseObject( | |
| 1538 | +QPDFWriter::Members::unparseObject( | |
| 1420 | 1539 | QPDFObjectHandle object, size_t level, int flags, size_t stream_length, bool compress) |
| 1421 | 1540 | { |
| 1422 | 1541 | QPDFObjGen old_og = object.getObjGen(); |
| ... | ... | @@ -1424,11 +1543,11 @@ QPDFWriter::unparseObject( |
| 1424 | 1543 | // For non-qdf, "indent" and "indent_large" are a single space between tokens. For qdf, they |
| 1425 | 1544 | // include the preceding newline. |
| 1426 | 1545 | std::string indent_large = " "; |
| 1427 | - if (m->qdf_mode) { | |
| 1546 | + if (qdf_mode) { | |
| 1428 | 1547 | indent_large.append(2 * (level + 1), ' '); |
| 1429 | 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 | 1552 | if (auto const tc = object.getTypeCode(); tc == ::ot_array) { |
| 1434 | 1553 | // Note: PDF spec 1.4 implementation note 121 states that Acrobat requires a space after the |
| ... | ... | @@ -1443,7 +1562,7 @@ QPDFWriter::unparseObject( |
| 1443 | 1562 | } else if (tc == ::ot_dictionary) { |
| 1444 | 1563 | // Handle special cases for specific dictionaries. |
| 1445 | 1564 | |
| 1446 | - if (old_og == m->root_og) { | |
| 1565 | + if (old_og == root_og) { | |
| 1447 | 1566 | // Extensions dictionaries. |
| 1448 | 1567 | |
| 1449 | 1568 | // We have one of several cases: |
| ... | ... | @@ -1464,7 +1583,7 @@ QPDFWriter::unparseObject( |
| 1464 | 1583 | |
| 1465 | 1584 | auto extensions = object.getKey("/Extensions"); |
| 1466 | 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 | 1588 | if (has_extensions || need_extensions_adbe) { |
| 1470 | 1589 | // Make a shallow copy of this object so we can modify it safely without affecting |
| ... | ... | @@ -1484,7 +1603,7 @@ QPDFWriter::unparseObject( |
| 1484 | 1603 | if (need_extensions_adbe) { |
| 1485 | 1604 | if (!(have_extensions_other || have_extensions_adbe)) { |
| 1486 | 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 | 1607 | extensions = object.replaceKeyAndGetNew( |
| 1489 | 1608 | "/Extensions", QPDFObjectHandle::newDictionary()); |
| 1490 | 1609 | } |
| ... | ... | @@ -1501,21 +1620,17 @@ QPDFWriter::unparseObject( |
| 1501 | 1620 | QTC::TC("qpdf", "QPDFWriter preserve Extensions"); |
| 1502 | 1621 | QPDFObjectHandle adbe = extensions.getKey("/ADBE"); |
| 1503 | 1622 | if (adbe.isDictionary() && |
| 1504 | - adbe.getKey("/BaseVersion").isNameAndEquals("/" + m->final_pdf_version) && | |
| 1623 | + adbe.getKey("/BaseVersion").isNameAndEquals("/" + final_pdf_version) && | |
| 1505 | 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 | 1626 | } else { |
| 1510 | 1627 | if (need_extensions_adbe) { |
| 1511 | 1628 | extensions.replaceKey( |
| 1512 | 1629 | "/ADBE", |
| 1513 | 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 | 1633 | } else { |
| 1518 | - QTC::TC("qpdf", "QPDFWriter remove ADBE"); | |
| 1519 | 1634 | extensions.removeKey("/ADBE"); |
| 1520 | 1635 | } |
| 1521 | 1636 | } |
| ... | ... | @@ -1593,10 +1708,10 @@ QPDFWriter::unparseObject( |
| 1593 | 1708 | if (flags & f_stream) { |
| 1594 | 1709 | write(indent_large).write("/Length "); |
| 1595 | 1710 | |
| 1596 | - if (m->direct_stream_lengths) { | |
| 1711 | + if (direct_stream_lengths) { | |
| 1597 | 1712 | write(stream_length); |
| 1598 | 1713 | } else { |
| 1599 | - write(m->cur_stream_length_id).write(" 0 R"); | |
| 1714 | + write(cur_stream_length_id).write(" 0 R"); | |
| 1600 | 1715 | } |
| 1601 | 1716 | if (compress && (flags & f_filtered)) { |
| 1602 | 1717 | write(indent_large).write("/Filter /FlateDecode"); |
| ... | ... | @@ -1606,8 +1721,8 @@ QPDFWriter::unparseObject( |
| 1606 | 1721 | write(indent).write(">>"); |
| 1607 | 1722 | } else if (tc == ::ot_stream) { |
| 1608 | 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 | 1728 | flags |= f_stream; |
| ... | ... | @@ -1619,25 +1734,25 @@ QPDFWriter::unparseObject( |
| 1619 | 1734 | } |
| 1620 | 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 | 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 | 1744 | char last_char = stream_data.empty() ? '\0' : stream_data.back(); |
| 1630 | 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 | 1748 | } else if (tc == ::ot_string) { |
| 1634 | 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 | 1752 | val = object.getStringValue(); |
| 1638 | - if (m->encrypt_use_aes) { | |
| 1753 | + if (encrypt_use_aes) { | |
| 1639 | 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 | 1756 | pl.writeString(val); |
| 1642 | 1757 | pl.finish(); |
| 1643 | 1758 | val = QPDF_String(bufpl.getString()).unparse(true); |
| ... | ... | @@ -1646,8 +1761,8 @@ QPDFWriter::unparseObject( |
| 1646 | 1761 | char* tmp = tmp_ph.get(); |
| 1647 | 1762 | size_t vlen = val.length(); |
| 1648 | 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 | 1766 | auto data = QUtil::unsigned_char_pointer(tmp); |
| 1652 | 1767 | rc4.process(data, vlen, data); |
| 1653 | 1768 | val = QPDF_String(std::string(tmp, vlen)).unparse(); |
| ... | ... | @@ -1664,7 +1779,7 @@ QPDFWriter::unparseObject( |
| 1664 | 1779 | } |
| 1665 | 1780 | |
| 1666 | 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 | 1784 | qpdf_assert_debug(first_obj > 0); |
| 1670 | 1785 | bool is_first = true; |
| ... | ... | @@ -1683,7 +1798,7 @@ QPDFWriter::writeObjectStreamOffsets(std::vector<qpdf_offset_t>& offsets, int fi |
| 1683 | 1798 | } |
| 1684 | 1799 | |
| 1685 | 1800 | void |
| 1686 | -QPDFWriter::writeObjectStream(QPDFObjectHandle object) | |
| 1801 | +QPDFWriter::Members::writeObjectStream(QPDFObjectHandle object) | |
| 1687 | 1802 | { |
| 1688 | 1803 | // Note: object might be null if this is a place-holder for an object stream that we are |
| 1689 | 1804 | // generating from scratch. |
| ... | ... | @@ -1691,7 +1806,7 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) |
| 1691 | 1806 | QPDFObjGen old_og = object.getObjGen(); |
| 1692 | 1807 | qpdf_assert_debug(old_og.getGen() == 0); |
| 1693 | 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 | 1811 | std::vector<qpdf_offset_t> offsets; |
| 1697 | 1812 | qpdf_offset_t first = 0; |
| ... | ... | @@ -1701,39 +1816,38 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) |
| 1701 | 1816 | std::string stream_buffer_pass1; |
| 1702 | 1817 | std::string stream_buffer_pass2; |
| 1703 | 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 | 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 | 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 | 1826 | ++count; |
| 1712 | - int new_obj = m->obj[obj].renumber; | |
| 1827 | + int new_o = obj[og].renumber; | |
| 1713 | 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 | 1835 | // For compatibility, only write the generation if non-zero. While object |
| 1721 | 1836 | // streams only allow objects with generation 0, if we are generating object |
| 1722 | 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 | 1842 | write("\n"); |
| 1729 | 1843 | } |
| 1730 | 1844 | |
| 1731 | - offsets.push_back(m->pipeline->getCount()); | |
| 1845 | + offsets.push_back(pipeline->getCount()); | |
| 1732 | 1846 | // To avoid double-counting objects being written in object streams for progress |
| 1733 | 1847 | // reporting, decrement in pass 1. |
| 1734 | 1848 | indicateProgress(true, false); |
| 1735 | 1849 | |
| 1736 | - QPDFObjectHandle obj_to_write = m->pdf.getObject(obj); | |
| 1850 | + QPDFObjectHandle obj_to_write = pdf.getObject(og); | |
| 1737 | 1851 | if (obj_to_write.isStream()) { |
| 1738 | 1852 | // This condition occurred in a fuzz input. Ideally we should block it at parse |
| 1739 | 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 | 1856 | } |
| 1743 | 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 | 1868 | |
| 1755 | 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 | 1872 | writeObjectStreamOffsets(offsets, first_obj); |
| 1759 | - first += m->pipeline->getCount(); | |
| 1873 | + first += pipeline->getCount(); | |
| 1760 | 1874 | } |
| 1761 | 1875 | |
| 1762 | 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 | 1879 | writeObjectStreamOffsets(offsets, first_obj); |
| 1766 | 1880 | write(stream_buffer_pass1); |
| ... | ... | @@ -1792,65 +1906,65 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) |
| 1792 | 1906 | } |
| 1793 | 1907 | } |
| 1794 | 1908 | write_qdf("\n").write_no_qdf(" ").write(">>\nstream\n").write_encrypted(stream_buffer_pass2); |
| 1795 | - if (m->encryption) { | |
| 1909 | + if (encryption) { | |
| 1796 | 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 | 1914 | closeObject(new_stream_id); |
| 1801 | 1915 | } |
| 1802 | 1916 | |
| 1803 | 1917 | void |
| 1804 | -QPDFWriter::writeObject(QPDFObjectHandle object, int object_stream_index) | |
| 1918 | +QPDFWriter::Members::writeObject(QPDFObjectHandle object, int object_stream_index) | |
| 1805 | 1919 | { |
| 1806 | 1920 | QPDFObjGen old_og = object.getObjGen(); |
| 1807 | 1921 | |
| 1808 | 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 | 1924 | writeObjectStream(object); |
| 1811 | 1925 | return; |
| 1812 | 1926 | } |
| 1813 | 1927 | |
| 1814 | 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 | 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 | 1940 | write("%% Original object ID: ").write(object.getObjGen().unparse(' ')).write("\n"); |
| 1827 | 1941 | } |
| 1828 | 1942 | openObject(new_id); |
| 1829 | 1943 | setDataKey(new_id); |
| 1830 | 1944 | unparseObject(object, 0, 0); |
| 1831 | - m->cur_data_key.clear(); | |
| 1945 | + cur_data_key.clear(); | |
| 1832 | 1946 | closeObject(new_id); |
| 1833 | 1947 | } else { |
| 1834 | 1948 | unparseObject(object, 0, f_in_ostream); |
| 1835 | 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 | 1955 | write("%QDF: ignore_newline\n"); |
| 1842 | 1956 | } |
| 1843 | 1957 | } |
| 1844 | 1958 | openObject(new_id + 1); |
| 1845 | - write(m->cur_stream_length); | |
| 1959 | + write(cur_stream_length); | |
| 1846 | 1960 | closeObject(new_id + 1); |
| 1847 | 1961 | } |
| 1848 | 1962 | } |
| 1849 | 1963 | |
| 1850 | 1964 | std::string |
| 1851 | -QPDFWriter::getOriginalID1() | |
| 1965 | +QPDFWriter::Members::getOriginalID1() | |
| 1852 | 1966 | { |
| 1853 | - QPDFObjectHandle trailer = m->pdf.getTrailer(); | |
| 1967 | + QPDFObjectHandle trailer = pdf.getTrailer(); | |
| 1854 | 1968 | if (trailer.hasKey("/ID")) { |
| 1855 | 1969 | return trailer.getKey("/ID").getArrayItem(0).getStringValue(); |
| 1856 | 1970 | } else { |
| ... | ... | @@ -1859,20 +1973,20 @@ QPDFWriter::getOriginalID1() |
| 1859 | 1973 | } |
| 1860 | 1974 | |
| 1861 | 1975 | void |
| 1862 | -QPDFWriter::generateID(bool encrypted) | |
| 1976 | +QPDFWriter::Members::generateID(bool encrypted) | |
| 1863 | 1977 | { |
| 1864 | 1978 | // Generate the ID lazily so that we can handle the user's preference to use static or |
| 1865 | 1979 | // deterministic ID generation. |
| 1866 | 1980 | |
| 1867 | - if (!m->id2.empty()) { | |
| 1981 | + if (!id2.empty()) { | |
| 1868 | 1982 | return; |
| 1869 | 1983 | } |
| 1870 | 1984 | |
| 1871 | - QPDFObjectHandle trailer = m->pdf.getTrailer(); | |
| 1985 | + QPDFObjectHandle trailer = pdf.getTrailer(); | |
| 1872 | 1986 | |
| 1873 | 1987 | std::string result; |
| 1874 | 1988 | |
| 1875 | - if (m->static_id) { | |
| 1989 | + if (static_id) { | |
| 1876 | 1990 | // For test suite use only... |
| 1877 | 1991 | static unsigned char tmp[] = { |
| 1878 | 1992 | 0x31, |
| ... | ... | @@ -1904,20 +2018,20 @@ QPDFWriter::generateID(bool encrypted) |
| 1904 | 2018 | // that case, would have the same ID regardless of the output file's name. |
| 1905 | 2019 | |
| 1906 | 2020 | std::string seed; |
| 1907 | - if (m->deterministic_id) { | |
| 2021 | + if (deterministic_id) { | |
| 1908 | 2022 | if (encrypted) { |
| 1909 | 2023 | throw std::runtime_error( |
| 1910 | 2024 | "QPDFWriter: unable to generated a deterministic ID because the file to be " |
| 1911 | 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 | 2028 | throw std::logic_error( |
| 1915 | 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 | 2032 | } else { |
| 1919 | 2033 | seed += std::to_string(QUtil::get_current_time()); |
| 1920 | - seed += m->filename; | |
| 2034 | + seed += filename; | |
| 1921 | 2035 | seed += " "; |
| 1922 | 2036 | } |
| 1923 | 2037 | seed += " QPDF "; |
| ... | ... | @@ -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 | 2049 | MD5::Digest digest; |
| 1936 | - m.digest(digest); | |
| 2050 | + md5.digest(digest); | |
| 1937 | 2051 | result = std::string(reinterpret_cast<char*>(digest), sizeof(MD5::Digest)); |
| 1938 | 2052 | } |
| 1939 | 2053 | |
| 1940 | 2054 | // If /ID already exists, follow the spec: use the original first word and generate a new second |
| 1941 | 2055 | // word. Otherwise, we'll use the generated ID for both. |
| 1942 | 2056 | |
| 1943 | - m->id2 = result; | |
| 2057 | + id2 = result; | |
| 1944 | 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 | 2065 | void |
| 1952 | -QPDFWriter::initializeSpecialStreams() | |
| 2066 | +QPDFWriter::Members::initializeSpecialStreams() | |
| 1953 | 2067 | { |
| 1954 | 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 | 2070 | int num = 0; |
| 1957 | 2071 | for (auto& page: pages) { |
| 1958 | - m->page_object_to_seq[page.getObjGen()] = ++num; | |
| 2072 | + page_object_to_seq[page.getObjGen()] = ++num; | |
| 1959 | 2073 | QPDFObjectHandle contents = page.getKey("/Contents"); |
| 1960 | 2074 | std::vector<QPDFObjGen> contents_objects; |
| 1961 | 2075 | if (contents.isArray()) { |
| ... | ... | @@ -1968,16 +2082,16 @@ QPDFWriter::initializeSpecialStreams() |
| 1968 | 2082 | } |
| 1969 | 2083 | |
| 1970 | 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 | 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 | 2095 | // Our object_to_object_stream map has to map ObjGen -> ObjGen since we may be generating object |
| 1982 | 2096 | // streams out of old objects that have generation numbers greater than zero. However in an |
| 1983 | 2097 | // existing PDF, all object stream objects and all objects in them must have generation 0 |
| ... | ... | @@ -1986,14 +2100,13 @@ QPDFWriter::preserveObjectStreams() |
| 1986 | 2100 | // erroneously included in object streams in the source PDF, it also prevents unreferenced |
| 1987 | 2101 | // objects from being included. |
| 1988 | 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 | 2105 | for (auto iter = xref.cbegin(); iter != end; ++iter) { |
| 1992 | 2106 | if (iter->second.getType() == 2) { |
| 1993 | 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 | 2112 | } else { |
| ... | ... | @@ -2002,9 +2115,8 @@ QPDFWriter::preserveObjectStreams() |
| 2002 | 2115 | for (auto iter = xref.cbegin(); iter != end; ++iter) { |
| 2003 | 2116 | if (iter->second.getType() == 2) { |
| 2004 | 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 | 2120 | // The object pointed to by iter may be a previous generation, in which case it is |
| 2009 | 2121 | // removed by getCompressibleObjSet. We need to restart the loop (while the object |
| 2010 | 2122 | // table may contain multiple generations of an object). |
| ... | ... | @@ -2012,7 +2124,7 @@ QPDFWriter::preserveObjectStreams() |
| 2012 | 2124 | if (iter->second.getType() == 2) { |
| 2013 | 2125 | auto id = static_cast<size_t>(iter->first.getObj()); |
| 2014 | 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 | 2128 | } else { |
| 2017 | 2129 | QTC::TC("qpdf", "QPDFWriter exclude from object stream"); |
| 2018 | 2130 | } |
| ... | ... | @@ -2025,7 +2137,7 @@ QPDFWriter::preserveObjectStreams() |
| 2025 | 2137 | } |
| 2026 | 2138 | |
| 2027 | 2139 | void |
| 2028 | -QPDFWriter::generateObjectStreams() | |
| 2140 | +QPDFWriter::Members::generateObjectStreams() | |
| 2029 | 2141 | { |
| 2030 | 2142 | // Basic strategy: make a list of objects that can go into an object stream. Then figure out |
| 2031 | 2143 | // how many object streams are needed so that we can distribute objects approximately evenly |
| ... | ... | @@ -2035,12 +2147,12 @@ QPDFWriter::generateObjectStreams() |
| 2035 | 2147 | |
| 2036 | 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 | 2151 | size_t n_object_streams = (eligible.size() + 99U) / 100U; |
| 2040 | 2152 | |
| 2041 | 2153 | initializeTables(2U * n_object_streams); |
| 2042 | 2154 | if (n_object_streams == 0) { |
| 2043 | - m->obj.streams_empty = true; | |
| 2155 | + obj.streams_empty = true; | |
| 2044 | 2156 | return; |
| 2045 | 2157 | } |
| 2046 | 2158 | size_t n_per = eligible.size() / n_object_streams; |
| ... | ... | @@ -2048,28 +2160,27 @@ QPDFWriter::generateObjectStreams() |
| 2048 | 2160 | ++n_per; |
| 2049 | 2161 | } |
| 2050 | 2162 | unsigned int n = 0; |
| 2051 | - int cur_ostream = m->pdf.newIndirectNull().getObjectID(); | |
| 2163 | + int cur_ostream = pdf.newIndirectNull().getObjectID(); | |
| 2052 | 2164 | for (auto const& item: eligible) { |
| 2053 | 2165 | if (n == n_per) { |
| 2054 | - QTC::TC("qpdf", "QPDFWriter generate >1 ostream"); | |
| 2055 | 2166 | n = 0; |
| 2056 | 2167 | // Construct a new null object as the "original" object stream. The rest of the code |
| 2057 | 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 | 2174 | ++n; |
| 2064 | 2175 | } |
| 2065 | 2176 | } |
| 2066 | 2177 | |
| 2067 | 2178 | QPDFObjectHandle |
| 2068 | -QPDFWriter::getTrimmedTrailer() | |
| 2179 | +QPDFWriter::Members::getTrimmedTrailer() | |
| 2069 | 2180 | { |
| 2070 | 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 | 2185 | // Remove encryption keys |
| 2075 | 2186 | trailer.removeKey("/ID"); |
| ... | ... | @@ -2092,10 +2203,10 @@ QPDFWriter::getTrimmedTrailer() |
| 2092 | 2203 | |
| 2093 | 2204 | // Make document extension level information direct as required by the spec. |
| 2094 | 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 | 2210 | auto oh = root.getKey("/Extensions"); |
| 2100 | 2211 | if (oh.isDictionary()) { |
| 2101 | 2212 | const bool extensions_indirect = oh.isIndirect(); |
| ... | ... | @@ -2115,84 +2226,83 @@ QPDFWriter::prepareFileForWrite() |
| 2115 | 2226 | } |
| 2116 | 2227 | |
| 2117 | 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 | 2236 | void |
| 2126 | -QPDFWriter::doWriteSetup() | |
| 2237 | +QPDFWriter::Members::doWriteSetup() | |
| 2127 | 2238 | { |
| 2128 | - if (m->did_write_setup) { | |
| 2239 | + if (did_write_setup) { | |
| 2129 | 2240 | return; |
| 2130 | 2241 | } |
| 2131 | - m->did_write_setup = true; | |
| 2242 | + did_write_setup = true; | |
| 2132 | 2243 | |
| 2133 | 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 | 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 | 2272 | // Encryption makes looking at contents pretty useless. If the user explicitly encrypted |
| 2162 | 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 | 2282 | int major = 0; |
| 2172 | 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 | 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 | 2292 | initializeSpecialStreams(); |
| 2183 | 2293 | } |
| 2184 | 2294 | |
| 2185 | - if (m->qdf_mode) { | |
| 2295 | + if (qdf_mode) { | |
| 2186 | 2296 | // Generate indirect stream lengths for qdf mode since fix-qdf uses them for storing |
| 2187 | 2297 | // recomputed stream length data. Certain streams such as object streams, xref streams, and |
| 2188 | 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 | 2303 | case qpdf_o_disable: |
| 2194 | 2304 | initializeTables(); |
| 2195 | - m->obj.streams_empty = true; | |
| 2305 | + obj.streams_empty = true; | |
| 2196 | 2306 | break; |
| 2197 | 2307 | |
| 2198 | 2308 | case qpdf_o_preserve: |
| ... | ... | @@ -2207,82 +2317,85 @@ QPDFWriter::doWriteSetup() |
| 2207 | 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 | 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 | 2331 | // The document catalog is not allowed to be compressed in linearized files either. It |
| 2223 | 2332 | // also appears that Adobe Reader 8.0.0 has a bug that prevents it from being able to |
| 2224 | 2333 | // handle encrypted files with compressed document catalogs, so we disable them in that |
| 2225 | 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 | 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 | 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 | 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 | 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 | 2368 | void |
| 2262 | 2369 | QPDFWriter::write() |
| 2263 | 2370 | { |
| 2371 | + m->write(); | |
| 2372 | +} | |
| 2373 | + | |
| 2374 | +void | |
| 2375 | +QPDFWriter::Members::write() | |
| 2376 | +{ | |
| 2264 | 2377 | doWriteSetup(); |
| 2265 | 2378 | |
| 2266 | 2379 | // Set up progress reporting. For linearized files, we write two passes. events_expected is an |
| 2267 | 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 | 2383 | prepareFileForWrite(); |
| 2271 | 2384 | |
| 2272 | - if (m->linearized) { | |
| 2385 | + if (linearized) { | |
| 2273 | 2386 | writeLinearized(); |
| 2274 | 2387 | } else { |
| 2275 | 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 | 2400 | indicateProgress(false, true); |
| 2288 | 2401 | } |
| ... | ... | @@ -2296,10 +2409,16 @@ QPDFWriter::getRenumberedObjGen(QPDFObjGen og) |
| 2296 | 2409 | std::map<QPDFObjGen, QPDFXRefEntry> |
| 2297 | 2410 | QPDFWriter::getWrittenXRefTable() |
| 2298 | 2411 | { |
| 2412 | + return m->getWrittenXRefTable(); | |
| 2413 | +} | |
| 2414 | + | |
| 2415 | +std::map<QPDFObjGen, QPDFXRefEntry> | |
| 2416 | +QPDFWriter::Members::getWrittenXRefTable() | |
| 2417 | +{ | |
| 2299 | 2418 | std::map<QPDFObjGen, QPDFXRefEntry> result; |
| 2300 | 2419 | |
| 2301 | 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 | 2422 | if (item.xref.getType() != 0) { |
| 2304 | 2423 | it = result.emplace_hint(it, QPDFObjGen(id, 0), item.xref); |
| 2305 | 2424 | } |
| ... | ... | @@ -2308,7 +2427,7 @@ QPDFWriter::getWrittenXRefTable() |
| 2308 | 2427 | } |
| 2309 | 2428 | |
| 2310 | 2429 | void |
| 2311 | -QPDFWriter::enqueuePart(std::vector<QPDFObjectHandle>& part) | |
| 2430 | +QPDFWriter::Members::enqueuePart(std::vector<QPDFObjectHandle>& part) | |
| 2312 | 2431 | { |
| 2313 | 2432 | for (auto const& oh: part) { |
| 2314 | 2433 | enqueueObject(oh); |
| ... | ... | @@ -2316,20 +2435,20 @@ QPDFWriter::enqueuePart(std::vector<QPDFObjectHandle>& part) |
| 2316 | 2435 | } |
| 2317 | 2436 | |
| 2318 | 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 | 2442 | auto const V = enc.getV(); |
| 2324 | 2443 | |
| 2325 | 2444 | write("<<"); |
| 2326 | 2445 | if (V >= 4) { |
| 2327 | 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 | 2448 | // The PDF spec says the /Length key is optional, but the PDF previewer on some versions of |
| 2330 | 2449 | // MacOS won't open encrypted files without it. |
| 2331 | 2450 | write((V < 5) ? " /Length 16 >> >>" : " /Length 32 >> >>"); |
| 2332 | - if (!m->encryption->getEncryptMetadata()) { | |
| 2451 | + if (!encryption->getEncryptMetadata()) { | |
| 2333 | 2452 | write(" /EncryptMetadata false"); |
| 2334 | 2453 | } |
| 2335 | 2454 | } |
| ... | ... | @@ -2352,21 +2471,21 @@ QPDFWriter::writeEncryptionDictionary() |
| 2352 | 2471 | write(" /UE ").write_string(enc.getUE(), true); |
| 2353 | 2472 | } |
| 2354 | 2473 | write(" /V ").write(enc.getV()).write(" >>"); |
| 2355 | - closeObject(m->encryption_dict_objid); | |
| 2474 | + closeObject(encryption_dict_objid); | |
| 2356 | 2475 | } |
| 2357 | 2476 | |
| 2358 | 2477 | std::string |
| 2359 | 2478 | QPDFWriter::getFinalVersion() |
| 2360 | 2479 | { |
| 2361 | - doWriteSetup(); | |
| 2480 | + m->doWriteSetup(); | |
| 2362 | 2481 | return m->final_pdf_version; |
| 2363 | 2482 | } |
| 2364 | 2483 | |
| 2365 | 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 | 2489 | // PCLm version |
| 2371 | 2490 | write("\n%PCLm 1.0\n"); |
| 2372 | 2491 | } else { |
| ... | ... | @@ -2383,13 +2502,13 @@ QPDFWriter::writeHeader() |
| 2383 | 2502 | } |
| 2384 | 2503 | |
| 2385 | 2504 | void |
| 2386 | -QPDFWriter::writeHintStream(int hint_id) | |
| 2505 | +QPDFWriter::Members::writeHintStream(int hint_id) | |
| 2387 | 2506 | { |
| 2388 | 2507 | std::string hint_buffer; |
| 2389 | 2508 | int S = 0; |
| 2390 | 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 | 2513 | openObject(hint_id); |
| 2395 | 2514 | setDataKey(hint_id); |
| ... | ... | @@ -2408,7 +2527,7 @@ QPDFWriter::writeHintStream(int hint_id) |
| 2408 | 2527 | write(" /Length ").write(hlen); |
| 2409 | 2528 | write(" >>\nstream\n").write_encrypted(hint_buffer); |
| 2410 | 2529 | |
| 2411 | - if (m->encryption) { | |
| 2530 | + if (encryption) { | |
| 2412 | 2531 | QTC::TC("qpdf", "QPDFWriter encrypted hint stream"); |
| 2413 | 2532 | } |
| 2414 | 2533 | |
| ... | ... | @@ -2417,7 +2536,7 @@ QPDFWriter::writeHintStream(int hint_id) |
| 2417 | 2536 | } |
| 2418 | 2537 | |
| 2419 | 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 | 2541 | // There are too many extra arguments to replace overloaded function with defaults in the header |
| 2423 | 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 | 2544 | } |
| 2426 | 2545 | |
| 2427 | 2546 | qpdf_offset_t |
| 2428 | -QPDFWriter::writeXRefTable( | |
| 2547 | +QPDFWriter::Members::writeXRefTable( | |
| 2429 | 2548 | trailer_e which, |
| 2430 | 2549 | int first, |
| 2431 | 2550 | int last, |
| ... | ... | @@ -2438,7 +2557,7 @@ QPDFWriter::writeXRefTable( |
| 2438 | 2557 | int linearization_pass) |
| 2439 | 2558 | { |
| 2440 | 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 | 2561 | write("\n"); |
| 2443 | 2562 | if (first == 0) { |
| 2444 | 2563 | write("0000000000 65535 f \n"); |
| ... | ... | @@ -2447,7 +2566,7 @@ QPDFWriter::writeXRefTable( |
| 2447 | 2566 | for (int i = first; i <= last; ++i) { |
| 2448 | 2567 | qpdf_offset_t offset = 0; |
| 2449 | 2568 | if (!suppress_offsets) { |
| 2450 | - offset = m->new_obj[i].xref.getOffset(); | |
| 2569 | + offset = new_obj[i].xref.getOffset(); | |
| 2451 | 2570 | if ((hint_id != 0) && (i != hint_id) && (offset >= hint_offset)) { |
| 2452 | 2571 | offset += hint_length; |
| 2453 | 2572 | } |
| ... | ... | @@ -2460,7 +2579,7 @@ QPDFWriter::writeXRefTable( |
| 2460 | 2579 | } |
| 2461 | 2580 | |
| 2462 | 2581 | qpdf_offset_t |
| 2463 | -QPDFWriter::writeXRefStream( | |
| 2582 | +QPDFWriter::Members::writeXRefStream( | |
| 2464 | 2583 | int objid, int max_id, qpdf_offset_t max_offset, trailer_e which, int first, int last, int size) |
| 2465 | 2584 | { |
| 2466 | 2585 | // There are too many extra arguments to replace overloaded function with defaults in the header |
| ... | ... | @@ -2470,7 +2589,7 @@ QPDFWriter::writeXRefStream( |
| 2470 | 2589 | } |
| 2471 | 2590 | |
| 2472 | 2591 | qpdf_offset_t |
| 2473 | -QPDFWriter::writeXRefStream( | |
| 2592 | +QPDFWriter::Members::writeXRefStream( | |
| 2474 | 2593 | int xref_id, |
| 2475 | 2594 | int max_id, |
| 2476 | 2595 | qpdf_offset_t max_offset, |
| ... | ... | @@ -2485,28 +2604,28 @@ QPDFWriter::writeXRefStream( |
| 2485 | 2604 | bool skip_compression, |
| 2486 | 2605 | int linearization_pass) |
| 2487 | 2606 | { |
| 2488 | - qpdf_offset_t xref_offset = m->pipeline->getCount(); | |
| 2607 | + qpdf_offset_t xref_offset = pipeline->getCount(); | |
| 2489 | 2608 | qpdf_offset_t space_before_zero = xref_offset - 1; |
| 2490 | 2609 | |
| 2491 | 2610 | // field 1 contains offsets and object stream identifiers |
| 2492 | 2611 | unsigned int f1_size = std::max(bytesNeeded(max_offset + hint_length), bytesNeeded(max_id)); |
| 2493 | 2612 | |
| 2494 | 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 | 2616 | unsigned int esize = 1 + f1_size + f2_size; |
| 2498 | 2617 | |
| 2499 | 2618 | // Must store in xref table in advance of writing the actual data rather than waiting for |
| 2500 | 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 | 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 | 2627 | for (int i = first; i <= last; ++i) { |
| 2509 | - QPDFXRefEntry& e = m->new_obj[i].xref; | |
| 2628 | + QPDFXRefEntry& e = new_obj[i].xref; | |
| 2510 | 2629 | switch (e.getType()) { |
| 2511 | 2630 | case 0: |
| 2512 | 2631 | writeBinary(0, 1); |
| ... | ... | @@ -2566,7 +2685,7 @@ QPDFWriter::writeXRefStream( |
| 2566 | 2685 | } |
| 2567 | 2686 | |
| 2568 | 2687 | size_t |
| 2569 | -QPDFWriter::calculateXrefStreamPadding(qpdf_offset_t xref_bytes) | |
| 2688 | +QPDFWriter::Members::calculateXrefStreamPadding(qpdf_offset_t xref_bytes) | |
| 2570 | 2689 | { |
| 2571 | 2690 | // This routine is called right after a linearization first pass xref stream has been written |
| 2572 | 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 | 2697 | } |
| 2579 | 2698 | |
| 2580 | 2699 | void |
| 2581 | -QPDFWriter::writeLinearized() | |
| 2700 | +QPDFWriter::Members::writeLinearized() | |
| 2582 | 2701 | { |
| 2583 | 2702 | // Optimize file and enqueue objects in order |
| 2584 | 2703 | |
| ... | ... | @@ -2598,14 +2717,14 @@ QPDFWriter::writeLinearized() |
| 2598 | 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 | 2722 | std::vector<QPDFObjectHandle> part4; |
| 2604 | 2723 | std::vector<QPDFObjectHandle> part6; |
| 2605 | 2724 | std::vector<QPDFObjectHandle> part7; |
| 2606 | 2725 | std::vector<QPDFObjectHandle> part8; |
| 2607 | 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 | 2729 | // Object number sequence: |
| 2611 | 2730 | // |
| ... | ... | @@ -2627,11 +2746,11 @@ QPDFWriter::writeLinearized() |
| 2627 | 2746 | int second_half_uncompressed = QIntC::to_int(part7.size() + part8.size() + part9.size()); |
| 2628 | 2747 | int second_half_first_obj = 1; |
| 2629 | 2748 | int after_second_half = 1 + second_half_uncompressed; |
| 2630 | - m->next_objid = after_second_half; | |
| 2749 | + next_objid = after_second_half; | |
| 2631 | 2750 | int second_half_xref = 0; |
| 2632 | - bool need_xref_stream = !m->obj.streams_empty; | |
| 2751 | + bool need_xref_stream = !obj.streams_empty; | |
| 2633 | 2752 | if (need_xref_stream) { |
| 2634 | - second_half_xref = m->next_objid++; | |
| 2753 | + second_half_xref = next_objid++; | |
| 2635 | 2754 | } |
| 2636 | 2755 | // Assign numbers to all compressed objects in the second half. |
| 2637 | 2756 | std::vector<QPDFObjectHandle>* vecs2[] = {&part7, &part8, &part9}; |
| ... | ... | @@ -2640,26 +2759,26 @@ QPDFWriter::writeLinearized() |
| 2640 | 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 | 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 | 2768 | int first_half_xref = 0; |
| 2650 | 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 | 2782 | // Assign numbers to all compressed objects in the first half |
| 2664 | 2783 | std::vector<QPDFObjectHandle>* vecs1[] = {&part4, &part6}; |
| 2665 | 2784 | for (int i = 0; i < 2; ++i) { |
| ... | ... | @@ -2667,8 +2786,8 @@ QPDFWriter::writeLinearized() |
| 2667 | 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 | 2792 | int part4_end_marker = part4.back().getObjectID(); |
| 2674 | 2793 | int part6_end_marker = part6.back().getObjectID(); |
| ... | ... | @@ -2680,23 +2799,23 @@ QPDFWriter::writeLinearized() |
| 2680 | 2799 | qpdf_offset_t first_xref_end = 0; |
| 2681 | 2800 | qpdf_offset_t second_xref_end = 0; |
| 2682 | 2801 | |
| 2683 | - m->next_objid = part4_first_obj; | |
| 2802 | + next_objid = part4_first_obj; | |
| 2684 | 2803 | enqueuePart(part4); |
| 2685 | - if (m->next_objid != after_part4) { | |
| 2804 | + if (next_objid != after_part4) { | |
| 2686 | 2805 | // This can happen with very botched files as in the fuzzer test. There are likely some |
| 2687 | 2806 | // faulty assumptions in calculateLinearizationData |
| 2688 | 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 | 2810 | enqueuePart(part6); |
| 2692 | - if (m->next_objid != after_part6) { | |
| 2811 | + if (next_objid != after_part6) { | |
| 2693 | 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 | 2815 | enqueuePart(part7); |
| 2697 | 2816 | enqueuePart(part8); |
| 2698 | 2817 | enqueuePart(part9); |
| 2699 | - if (m->next_objid != after_second_half) { | |
| 2818 | + if (next_objid != after_second_half) { | |
| 2700 | 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 | 2825 | // Write file in two passes. Part numbers refer to PDF spec 1.4. |
| 2707 | 2826 | |
| 2708 | 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 | 2830 | for (int pass: {1, 2}) { |
| 2712 | 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 | 2835 | pp_pass1, |
| 2717 | 2836 | std::make_unique<Pl_StdioFile>("linearization pass1", lin_pass1_file)); |
| 2718 | 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 | 2852 | // linearization parameter dictionary must appear within the first 1024 characters of the |
| 2734 | 2853 | // file. |
| 2735 | 2854 | |
| 2736 | - qpdf_offset_t pos = m->pipeline->getCount(); | |
| 2855 | + qpdf_offset_t pos = pipeline->getCount(); | |
| 2737 | 2856 | openObject(lindict_id); |
| 2738 | 2857 | write("<<"); |
| 2739 | 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 | 2862 | write(" /Linearized 1 /L ").write(file_size + hint_length); |
| 2744 | 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 | 2865 | write(hint_length); |
| 2747 | 2866 | write(" ] /O ").write(first_page_object); |
| 2748 | 2867 | write(" /E ").write(part6_end_offset + hint_length); |
| ... | ... | @@ -2752,18 +2871,18 @@ QPDFWriter::writeLinearized() |
| 2752 | 2871 | write(" >>"); |
| 2753 | 2872 | closeObject(lindict_id); |
| 2754 | 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 | 2876 | // If the user supplied any additional header text, write it here after the linearization |
| 2758 | 2877 | // parameter dictionary. |
| 2759 | - write(m->extra_header_text); | |
| 2878 | + write(extra_header_text); | |
| 2760 | 2879 | |
| 2761 | 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 | 2883 | qpdf_offset_t hint_offset = 0; |
| 2765 | 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 | 2887 | if (need_xref_stream) { |
| 2769 | 2888 | // Must pad here too. |
| ... | ... | @@ -2775,7 +2894,7 @@ QPDFWriter::writeLinearized() |
| 2775 | 2894 | // value for this, but it's okay if it's smaller. |
| 2776 | 2895 | first_half_max_obj_offset = 1 << 25; |
| 2777 | 2896 | } |
| 2778 | - pos = m->pipeline->getCount(); | |
| 2897 | + pos = pipeline->getCount(); | |
| 2779 | 2898 | writeXRefStream( |
| 2780 | 2899 | first_half_xref, |
| 2781 | 2900 | first_half_end, |
| ... | ... | @@ -2790,16 +2909,16 @@ QPDFWriter::writeLinearized() |
| 2790 | 2909 | hint_length, |
| 2791 | 2910 | (pass == 1), |
| 2792 | 2911 | pass); |
| 2793 | - qpdf_offset_t endpos = m->pipeline->getCount(); | |
| 2912 | + qpdf_offset_t endpos = pipeline->getCount(); | |
| 2794 | 2913 | if (pass == 1) { |
| 2795 | 2914 | // Pad so we have enough room for the real xref stream. |
| 2796 | 2915 | write(calculateXrefStreamPadding(endpos - pos), ' '); |
| 2797 | - first_xref_end = m->pipeline->getCount(); | |
| 2916 | + first_xref_end = pipeline->getCount(); | |
| 2798 | 2917 | } else { |
| 2799 | 2918 | // Pad so that the next object starts at the same place as in pass 1. |
| 2800 | 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 | 2922 | throw std::logic_error( |
| 2804 | 2923 | "insufficient padding for first pass xref stream; first_xref_end=" + |
| 2805 | 2924 | std::to_string(first_xref_end) + "; endpos=" + std::to_string(endpos)); |
| ... | ... | @@ -2823,24 +2942,24 @@ QPDFWriter::writeLinearized() |
| 2823 | 2942 | |
| 2824 | 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 | 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 | 2949 | writeObject(cur_object); |
| 2831 | 2950 | if (cur_object.getObjectID() == part4_end_marker) { |
| 2832 | - if (m->encryption) { | |
| 2951 | + if (encryption) { | |
| 2833 | 2952 | writeEncryptionDictionary(); |
| 2834 | 2953 | } |
| 2835 | 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 | 2956 | } else { |
| 2838 | 2957 | // Part 5: hint stream |
| 2839 | 2958 | write(hint_buffer); |
| 2840 | 2959 | } |
| 2841 | 2960 | } |
| 2842 | 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 | 2967 | |
| 2849 | 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 | 2971 | if (need_xref_stream) { |
| 2853 | - pos = m->pipeline->getCount(); | |
| 2972 | + pos = pipeline->getCount(); | |
| 2854 | 2973 | space_before_zero = writeXRefStream( |
| 2855 | 2974 | second_half_xref, |
| 2856 | 2975 | second_half_end, |
| ... | ... | @@ -2865,21 +2984,21 @@ QPDFWriter::writeLinearized() |
| 2865 | 2984 | 0, |
| 2866 | 2985 | (pass == 1), |
| 2867 | 2986 | pass); |
| 2868 | - qpdf_offset_t endpos = m->pipeline->getCount(); | |
| 2987 | + qpdf_offset_t endpos = pipeline->getCount(); | |
| 2869 | 2988 | |
| 2870 | 2989 | if (pass == 1) { |
| 2871 | 2990 | // Pad so we have enough room for the real xref stream. See comments for previous |
| 2872 | 2991 | // xref stream on how we calculate the padding. |
| 2873 | 2992 | write(calculateXrefStreamPadding(endpos - pos), ' ').write("\n"); |
| 2874 | - second_xref_end = m->pipeline->getCount(); | |
| 2993 | + second_xref_end = pipeline->getCount(); | |
| 2875 | 2994 | } else { |
| 2876 | 2995 | // Make the file size the same. |
| 2877 | 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 | 2998 | write(padding, ' ').write("\n"); |
| 2880 | 2999 | |
| 2881 | 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 | 3002 | throw std::logic_error( |
| 2884 | 3003 | "count mismatch after xref stream; possible insufficient padding?"); |
| 2885 | 3004 | } |
| ... | ... | @@ -2891,28 +3010,28 @@ QPDFWriter::writeLinearized() |
| 2891 | 3010 | write("startxref\n").write(first_xref_offset).write("\n%%EOF\n"); |
| 2892 | 3011 | |
| 2893 | 3012 | if (pass == 1) { |
| 2894 | - if (m->deterministic_id) { | |
| 3013 | + if (deterministic_id) { | |
| 2895 | 3014 | QTC::TC("qpdf", "QPDFWriter linearized deterministic ID", need_xref_stream ? 0 : 1); |
| 2896 | 3015 | computeDeterministicIDData(); |
| 2897 | 3016 | pp_md5.pop(); |
| 2898 | 3017 | } |
| 2899 | 3018 | |
| 2900 | 3019 | // Close first pass pipeline |
| 2901 | - file_size = m->pipeline->getCount(); | |
| 3020 | + file_size = pipeline->getCount(); | |
| 2902 | 3021 | pp_pass1.pop(); |
| 2903 | 3022 | |
| 2904 | 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 | 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 | 3029 | writeHintStream(hint_id); |
| 2911 | 3030 | } |
| 2912 | 3031 | hint_length = QIntC::to_offset(hint_buffer.size()); |
| 2913 | 3032 | |
| 2914 | 3033 | // Restore hint offset |
| 2915 | - m->new_obj[hint_id].xref = QPDFXRefEntry(hint_offset1); | |
| 3034 | + new_obj[hint_id].xref = QPDFXRefEntry(hint_offset1); | |
| 2916 | 3035 | if (lin_pass1_file) { |
| 2917 | 3036 | // Write some debugging information |
| 2918 | 3037 | fprintf( |
| ... | ... | @@ -2934,11 +3053,10 @@ QPDFWriter::writeLinearized() |
| 2934 | 3053 | } |
| 2935 | 3054 | |
| 2936 | 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 | 3060 | enqueueObject(oh); |
| 2943 | 3061 | } |
| 2944 | 3062 | } |
| ... | ... | @@ -2957,14 +3075,14 @@ QPDFWriter::enqueueObjectsStandard() |
| 2957 | 3075 | } |
| 2958 | 3076 | |
| 2959 | 3077 | void |
| 2960 | -QPDFWriter::enqueueObjectsPCLm() | |
| 3078 | +QPDFWriter::Members::enqueueObjectsPCLm() | |
| 2961 | 3079 | { |
| 2962 | 3080 | // Image transform stream content for page strip images. Each of this new stream has to come |
| 2963 | 3081 | // after every page image strip written in the pclm file. |
| 2964 | 3082 | std::string image_transform_content = "q /image Do Q\n"; |
| 2965 | 3083 | |
| 2966 | 3084 | // enqueue all pages first |
| 2967 | - std::vector<QPDFObjectHandle> all = m->pdf.getAllPages(); | |
| 3085 | + std::vector<QPDFObjectHandle> all = pdf.getAllPages(); | |
| 2968 | 3086 | for (auto& page: all) { |
| 2969 | 3087 | // enqueue page |
| 2970 | 3088 | enqueueObject(page); |
| ... | ... | @@ -2977,7 +3095,7 @@ QPDFWriter::enqueueObjectsPCLm() |
| 2977 | 3095 | for (auto& image: strips.as_dictionary()) { |
| 2978 | 3096 | if (!image.second.null()) { |
| 2979 | 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 | 3106 | } |
| 2989 | 3107 | |
| 2990 | 3108 | void |
| 2991 | -QPDFWriter::indicateProgress(bool decrement, bool finished) | |
| 3109 | +QPDFWriter::Members::indicateProgress(bool decrement, bool finished) | |
| 2992 | 3110 | { |
| 2993 | 3111 | if (decrement) { |
| 2994 | - --m->events_seen; | |
| 3112 | + --events_seen; | |
| 2995 | 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 | 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 | 3123 | int percentage = |
| 3006 | 3124 | (finished ? 100 |
| 3007 | - : m->next_progress_report == 0 | |
| 3125 | + : next_progress_report == 0 | |
| 3008 | 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 | 3140 | } |
| 3023 | 3141 | |
| 3024 | 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 | 3150 | // Start writing |
| 3033 | 3151 | |
| 3034 | 3152 | writeHeader(); |
| 3035 | - write(m->extra_header_text); | |
| 3153 | + write(extra_header_text); | |
| 3036 | 3154 | |
| 3037 | - if (m->pclm) { | |
| 3155 | + if (pclm) { | |
| 3038 | 3156 | enqueueObjectsPCLm(); |
| 3039 | 3157 | } else { |
| 3040 | 3158 | enqueueObjectsStandard(); |
| 3041 | 3159 | } |
| 3042 | 3160 | |
| 3043 | 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 | 3165 | writeObject(cur_object); |
| 3048 | 3166 | } |
| 3049 | 3167 | |
| 3050 | 3168 | // Write out the encryption dictionary, if any |
| 3051 | - if (m->encryption) { | |
| 3169 | + if (encryption) { | |
| 3052 | 3170 | writeEncryptionDictionary(); |
| 3053 | 3171 | } |
| 3054 | 3172 | |
| 3055 | 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 | 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 | 3178 | } else { |
| 3061 | 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 | 3183 | write("startxref\n").write(xref_offset).write("\n%%EOF\n"); |
| 3067 | 3184 | |
| 3068 | - if (m->deterministic_id) { | |
| 3185 | + if (deterministic_id) { | |
| 3069 | 3186 | QTC::TC( |
| 3070 | 3187 | "qpdf", |
| 3071 | 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 | 40 | main QTest dictionary 0 |
| 41 | 41 | main QTest dictionary indirect 1 |
| 42 | 42 | main QTest stream 0 |
| 43 | -QPDFWriter write to stdout 0 | |
| 44 | -QPDFWriter write to file 0 | |
| 45 | 43 | QPDF lin write nshared_total > nshared_first_page 1 |
| 46 | 44 | QPDFWriter encrypted hint stream 0 |
| 47 | 45 | QPDF opt inherited scalar 0 |
| ... | ... | @@ -83,11 +81,7 @@ QPDF xref deleted object 0 |
| 83 | 81 | SF_FlateLzwDecode PNG filter 0 |
| 84 | 82 | QPDF xref /Index is array 1 |
| 85 | 83 | QPDFWriter encrypt object stream 0 |
| 86 | -QPDFWriter uncompressing page dictionary 0 | |
| 87 | -QPDFWriter uncompressing root 0 | |
| 88 | -QPDFWriter compressing uncompressed stream 0 | |
| 89 | 84 | QPDF exclude indirect length 0 |
| 90 | -QPDFWriter generate >1 ostream 0 | |
| 91 | 85 | QPDF exclude encryption dictionary 0 |
| 92 | 86 | QPDF loop detected traversing objects 0 |
| 93 | 87 | QPDF reconstructed xref table 0 |
| ... | ... | @@ -95,7 +89,6 @@ QPDF recovered in readObjectAtOffset 0 |
| 95 | 89 | QPDF recovered stream length 0 |
| 96 | 90 | QPDF found wrong endstream in recovery 0 |
| 97 | 91 | QPDF_Stream pipeStreamData with null pipeline 0 |
| 98 | -QPDFWriter not recompressing /FlateDecode 0 | |
| 99 | 92 | QPDFJob unable to filter 0 |
| 100 | 93 | QUtil non-trivial UTF-16 0 |
| 101 | 94 | QPDF xref overwrite invalid objgen 0 |
| ... | ... | @@ -135,14 +128,11 @@ qpdf-c called qpdf_allow_modify_annotation 0 |
| 135 | 128 | qpdf-c called qpdf_allow_modify_other 0 |
| 136 | 129 | qpdf-c called qpdf_allow_modify_all 0 |
| 137 | 130 | QPDFWriter increasing minimum version 1 |
| 138 | -QPDFWriter using forced PDF version 0 | |
| 139 | 131 | qpdf-c called qpdf_set_minimum_pdf_version 0 |
| 140 | 132 | qpdf-c called qpdf_force_pdf_version 0 |
| 141 | 133 | qpdf-c called qpdf_init_write multiple times 0 |
| 142 | 134 | QPDF_encryption rc4 decode string 0 |
| 143 | -QPDFWriter not compressing metadata 0 | |
| 144 | 135 | QPDF_encryption aes decode string 0 |
| 145 | -QPDFWriter forcing object stream disable 0 | |
| 146 | 136 | QPDFWriter forced version disabled encryption 0 |
| 147 | 137 | qpdf-c called qpdf_set_r4_encryption_parameters_insecure 0 |
| 148 | 138 | qpdf-c called qpdf_set_static_aes_IV 0 |
| ... | ... | @@ -195,7 +185,6 @@ QPDF replace dictionary 0 |
| 195 | 185 | QPDF replace stream 0 |
| 196 | 186 | QPDF replace foreign indirect with null 0 |
| 197 | 187 | QPDF insert foreign page 0 |
| 198 | -QPDFWriter foreign object 0 | |
| 199 | 188 | QPDFWriter copy use_aes 1 |
| 200 | 189 | QPDFParser indirect without context 0 |
| 201 | 190 | QPDFObjectHandle trailing data in parse 0 |
| ... | ... | @@ -203,17 +192,13 @@ QPDFJob pages encryption password 0 |
| 203 | 192 | QPDFTokenizer EOF reading token 0 |
| 204 | 193 | QPDFTokenizer EOF reading appendable token 0 |
| 205 | 194 | QPDFWriter extra header text no newline 0 |
| 206 | -QPDFWriter extra header text add newline 0 | |
| 207 | 195 | QPDF bogus 0 offset 0 |
| 208 | 196 | QPDF global offset 0 |
| 209 | -QPDFWriter increasing extension level 0 | |
| 210 | 197 | QPDFWriter make Extensions direct 0 |
| 211 | 198 | QPDFWriter make ADBE direct 1 |
| 212 | 199 | QPDFWriter preserve Extensions 0 |
| 213 | 200 | QPDFWriter create Extensions 1 |
| 214 | -QPDFWriter remove ADBE 0 | |
| 215 | 201 | QPDFWriter remove existing Extensions 0 |
| 216 | -QPDFWriter preserve ADBE 0 | |
| 217 | 202 | QPDF_encryption skip 0x28 0 |
| 218 | 203 | qpdf-c called qpdf_get_pdf_extension_level 0 |
| 219 | 204 | qpdf-c called qpdf_set_r5_encryption_parameters 0 |
| ... | ... | @@ -221,7 +206,6 @@ qpdf-c called qpdf_set_r6_encryption_parameters 0 |
| 221 | 206 | QPDFObjectHandle EOF in inline image 0 |
| 222 | 207 | QPDFObjectHandle inline image token 0 |
| 223 | 208 | QPDF not caching overridden objstm object 0 |
| 224 | -QPDFWriter original obj non-zero gen 0 | |
| 225 | 209 | QPDF_optimization indirect outlines 0 |
| 226 | 210 | QPDF xref space 2 |
| 227 | 211 | QPDFJob pages range omitted in middle 0 |
| ... | ... | @@ -237,7 +221,6 @@ QPDFParser treat word as string in parseRemainder 0 |
| 237 | 221 | QPDFParser found fake 1 |
| 238 | 222 | QPDFParser no val for last key 0 |
| 239 | 223 | QPDF resolve failure to null 0 |
| 240 | -QPDFWriter preserve unreferenced standard 0 | |
| 241 | 224 | QPDFObjectHandle errors in parsecontent 0 |
| 242 | 225 | QPDFJob same file error 0 |
| 243 | 226 | QPDFJob split-pages %d 0 |
| ... | ... | @@ -374,7 +357,6 @@ QPDF_encryption same password 1 |
| 374 | 357 | QPDFParser duplicate dict key 0 |
| 375 | 358 | QPDFWriter no encryption sig contents 0 |
| 376 | 359 | QPDFPageObjectHelper colorspace lookup 0 |
| 377 | -QPDFWriter ignore XRef in qdf mode 0 | |
| 378 | 360 | QPDFPageObjectHelper filter form xobject 0 |
| 379 | 361 | QPDFJob found resources in non-leaf 0 |
| 380 | 362 | QPDFJob found shared resources in leaf 0 |
| ... | ... | @@ -463,7 +445,6 @@ qpdf-c called qpdf_oh_get_generation 0 |
| 463 | 445 | qpdf-c called qpdf_oh_unparse 0 |
| 464 | 446 | qpdf-c called qpdf_oh_unparse_resolved 0 |
| 465 | 447 | qpdf-c called qpdf_oh_unparse_binary 0 |
| 466 | -QPDFWriter getFilterOnWrite false 0 | |
| 467 | 448 | QPDFPageObjectHelper::forEachXObject 3 |
| 468 | 449 | NNTree erased last kid/item in tree 1 |
| 469 | 450 | QPDFPageObjectHelper unresolved names 0 |
| ... | ... | @@ -481,8 +462,6 @@ QPDFAcroFormDocumentHelper AP parse error 1 |
| 481 | 462 | QPDFJob copy fields not this file 0 |
| 482 | 463 | QPDFJob copy fields non-first from orig 0 |
| 483 | 464 | QPDF resolve duplicated page in insert 0 |
| 484 | -QPDFWriter preserve object streams 0 | |
| 485 | -QPDFWriter preserve object streams preserve unreferenced 0 | |
| 486 | 465 | QPDFWriter exclude from object stream 0 |
| 487 | 466 | QPDF_pages findPage not found 0 |
| 488 | 467 | QPDFJob weak crypto error 0 | ... | ... |
qpdf/test_driver.cc
| ... | ... | @@ -2624,7 +2624,7 @@ test_76(QPDF& pdf, char const* arg2) |
| 2624 | 2624 | { |
| 2625 | 2625 | // Embedded files. arg2 is a file to attach. Hard-code the |
| 2626 | 2626 | // mime type and file name for test purposes. |
| 2627 | - auto &efdh = QPDFEmbeddedFileDocumentHelper::get(pdf); | |
| 2627 | + auto& efdh = QPDFEmbeddedFileDocumentHelper::get(pdf); | |
| 2628 | 2628 | auto fs1 = QPDFFileSpecObjectHelper::createFileSpec(pdf, "att1.txt", arg2); |
| 2629 | 2629 | fs1.setDescription("some text"); |
| 2630 | 2630 | auto efs1 = QPDFEFStreamObjectHelper(fs1.getEmbeddedFileStream()); | ... | ... |