Commit eadfa25bd449e01460a7746ffb167e8fc57d2bde
1 parent
e10932f3
Refactor `CopiedStreamDataProvider`: move functionality to `Streams::Copier`, im…
…prove encapsulation, and streamline stream data handling.
Showing
3 changed files
with
87 additions
and
42 deletions
include/qpdf/QPDF.hh
libqpdf/QPDF.cc
| ... | ... | @@ -28,6 +28,8 @@ using namespace qpdf; |
| 28 | 28 | using namespace std::literals; |
| 29 | 29 | |
| 30 | 30 | using Objects = QPDF::Doc::Objects; |
| 31 | +using Foreign = Objects::Foreign; | |
| 32 | +using Streams = Objects::Streams; | |
| 31 | 33 | |
| 32 | 34 | // This must be a fixed value. This API returns a const reference to it, and the C API relies on its |
| 33 | 35 | // being static as well. |
| ... | ... | @@ -122,24 +124,24 @@ QPDF::ForeignStreamData::ForeignStreamData( |
| 122 | 124 | { |
| 123 | 125 | } |
| 124 | 126 | |
| 125 | -QPDF::CopiedStreamDataProvider::CopiedStreamDataProvider(QPDF& destination_qpdf) : | |
| 127 | +Streams::Copier::Copier(QPDF& qpdf) : | |
| 126 | 128 | QPDFObjectHandle::StreamDataProvider(true), |
| 127 | - destination_qpdf(destination_qpdf) | |
| 129 | + qpdf(qpdf) | |
| 128 | 130 | { |
| 129 | 131 | } |
| 130 | 132 | |
| 131 | 133 | bool |
| 132 | -QPDF::CopiedStreamDataProvider::provideStreamData( | |
| 134 | +Streams::Copier::provideStreamData( | |
| 133 | 135 | QPDFObjGen const& og, Pipeline* pipeline, bool suppress_warnings, bool will_retry) |
| 134 | 136 | { |
| 135 | - auto foreign_data = foreign_stream_data.find(og); | |
| 137 | + auto foreign_data = copied_data.find(og); | |
| 136 | 138 | bool result = false; |
| 137 | - if (foreign_data != foreign_stream_data.end()) { | |
| 138 | - result = destination_qpdf.pipeForeignStreamData( | |
| 139 | + if (foreign_data != copied_data.end()) { | |
| 140 | + result = qpdf.pipeForeignStreamData( | |
| 139 | 141 | foreign_data->second, pipeline, suppress_warnings, will_retry); |
| 140 | 142 | QTC::TC("qpdf", "QPDF copy foreign with data", result ? 0 : 1); |
| 141 | 143 | } else { |
| 142 | - auto foreign_stream = foreign_streams[og]; | |
| 144 | + auto foreign_stream = copied_streams[og]; | |
| 143 | 145 | result = foreign_stream.pipeStreamData( |
| 144 | 146 | pipeline, nullptr, 0, qpdf_dl_none, suppress_warnings, will_retry); |
| 145 | 147 | QTC::TC("qpdf", "QPDF copy foreign with foreign_stream", result ? 0 : 1); |
| ... | ... | @@ -669,9 +671,6 @@ QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign_oh) |
| 669 | 671 | |
| 670 | 672 | Dictionary dict = result.getDict(); |
| 671 | 673 | Dictionary old_dict = foreign_oh.getDict(); |
| 672 | - if (!m->copied_stream_data_provider) { | |
| 673 | - m->copied_stream_data_provider = std::make_shared<CopiedStreamDataProvider>(*this); | |
| 674 | - } | |
| 675 | 674 | QPDFObjGen local_og(result.getObjGen()); |
| 676 | 675 | // Copy information from the foreign stream so we can pipe its data later without keeping the |
| 677 | 676 | // original QPDF object around. |
| ... | ... | @@ -697,14 +696,14 @@ QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign_oh) |
| 697 | 696 | result.replaceStreamData(stream_buffer, dict["/Filter"], dict["/DecodeParms"]); |
| 698 | 697 | } else if (stream_provider) { |
| 699 | 698 | // In this case, the remote stream's QPDF must stay in scope. |
| 700 | - m->copied_stream_data_provider->registerForeignStream(local_og, foreign_oh); | |
| 699 | + m->objects.streams().copier()->register_copy(local_og, foreign_oh); | |
| 701 | 700 | result.replaceStreamData( |
| 702 | - m->copied_stream_data_provider, dict["/Filter"], dict["/DecodeParms"]); | |
| 701 | + m->objects.streams().copier(), dict["/Filter"], dict["/DecodeParms"]); | |
| 703 | 702 | } else { |
| 704 | 703 | auto foreign_stream_data = ForeignStreamData(foreign, foreign_oh.offset(), dict); |
| 705 | - m->copied_stream_data_provider->registerForeignStream(local_og, foreign_stream_data); | |
| 704 | + m->objects.streams().copier()->register_copy(local_og, foreign_stream_data); | |
| 706 | 705 | result.replaceStreamData( |
| 707 | - m->copied_stream_data_provider, dict["/Filter"], dict["/DecodeParms"]); | |
| 706 | + m->objects.streams().copier(), dict["/Filter"], dict["/DecodeParms"]); | |
| 708 | 707 | } |
| 709 | 708 | } |
| 710 | 709 | ... | ... |
libqpdf/qpdf/QPDF_private.hh
| ... | ... | @@ -106,31 +106,6 @@ class QPDF::ForeignStreamData |
| 106 | 106 | bool is_root_metadata{false}; |
| 107 | 107 | }; |
| 108 | 108 | |
| 109 | -class QPDF::CopiedStreamDataProvider final: public QPDFObjectHandle::StreamDataProvider | |
| 110 | -{ | |
| 111 | - public: | |
| 112 | - CopiedStreamDataProvider(QPDF& destination_qpdf); | |
| 113 | - ~CopiedStreamDataProvider() final = default; | |
| 114 | - bool provideStreamData( | |
| 115 | - QPDFObjGen const& og, Pipeline* pipeline, bool suppress_warnings, bool will_retry) final; | |
| 116 | - void | |
| 117 | - registerForeignStream(QPDFObjGen const& local_og, QPDFObjectHandle foreign_stream) | |
| 118 | - { | |
| 119 | - foreign_streams.insert_or_assign(local_og, foreign_stream); | |
| 120 | - } | |
| 121 | - | |
| 122 | - void | |
| 123 | - registerForeignStream(QPDFObjGen local_og, ForeignStreamData foreign_stream) | |
| 124 | - { | |
| 125 | - foreign_stream_data.insert_or_assign(local_og, foreign_stream); | |
| 126 | - } | |
| 127 | - | |
| 128 | - private: | |
| 129 | - QPDF& destination_qpdf; | |
| 130 | - std::map<QPDFObjGen, QPDFObjectHandle> foreign_streams; | |
| 131 | - std::map<QPDFObjGen, ForeignStreamData> foreign_stream_data; | |
| 132 | -}; | |
| 133 | - | |
| 134 | 109 | class QPDF::StringDecrypter final: public QPDFObjectHandle::StringDecrypter |
| 135 | 110 | { |
| 136 | 111 | friend class QPDF; |
| ... | ... | @@ -620,6 +595,57 @@ class QPDF::Doc |
| 620 | 595 | |
| 621 | 596 | class Streams |
| 622 | 597 | { |
| 598 | + // Copier manages the copying of streams into this PDF. It is used both for copying | |
| 599 | + // local and foreign streams. | |
| 600 | + class Copier final: public QPDFObjectHandle::StreamDataProvider | |
| 601 | + { | |
| 602 | + public: | |
| 603 | + Copier() = delete; | |
| 604 | + Copier(StreamDataProvider const&) = delete; | |
| 605 | + Copier(StreamDataProvider&&) = delete; | |
| 606 | + Copier& operator=(StreamDataProvider const&) = delete; | |
| 607 | + Copier& operator=(StreamDataProvider&&) = delete; | |
| 608 | + | |
| 609 | + Copier(QPDF& qpdf); | |
| 610 | + ~Copier() final = default; | |
| 611 | + | |
| 612 | + bool provideStreamData( | |
| 613 | + QPDFObjGen const& og, | |
| 614 | + Pipeline* pipeline, | |
| 615 | + bool suppress_warnings, | |
| 616 | + bool will_retry) final; | |
| 617 | + | |
| 618 | + void | |
| 619 | + register_copy(QPDFObjGen local_og, QPDFObjectHandle foreign_stream) | |
| 620 | + { | |
| 621 | + copied_streams.insert_or_assign(local_og, foreign_stream); | |
| 622 | + } | |
| 623 | + | |
| 624 | + void | |
| 625 | + register_copy(QPDFObjGen local_og, ForeignStreamData foreign_stream) | |
| 626 | + { | |
| 627 | + copied_data.insert_or_assign(local_og, foreign_stream); | |
| 628 | + } | |
| 629 | + | |
| 630 | + private: | |
| 631 | + QPDF& qpdf; | |
| 632 | + std::map<QPDFObjGen, QPDFObjectHandle> copied_streams; | |
| 633 | + std::map<QPDFObjGen, ForeignStreamData> copied_data; | |
| 634 | + }; | |
| 635 | + | |
| 636 | + public: | |
| 637 | + Streams(QPDF& qpdf) : | |
| 638 | + qpdf(qpdf) | |
| 639 | + { | |
| 640 | + } | |
| 641 | + | |
| 642 | + Streams() = delete; | |
| 643 | + Streams(Streams const&) = delete; | |
| 644 | + Streams(Streams&&) = delete; | |
| 645 | + Streams& operator=(Streams const&) = delete; | |
| 646 | + Streams& operator=(Streams&&) = delete; | |
| 647 | + ~Streams() = default; | |
| 648 | + | |
| 623 | 649 | public: |
| 624 | 650 | static bool |
| 625 | 651 | pipeStreamData( |
| ... | ... | @@ -649,6 +675,20 @@ class QPDF::Doc |
| 649 | 675 | { |
| 650 | 676 | qpdf->copyStreamData(dest, src); |
| 651 | 677 | } |
| 678 | + | |
| 679 | + std::shared_ptr<Copier>& | |
| 680 | + copier() | |
| 681 | + { | |
| 682 | + if (!copier_) { | |
| 683 | + copier_ = std::make_shared<Copier>(qpdf); | |
| 684 | + } | |
| 685 | + return copier_; | |
| 686 | + } | |
| 687 | + | |
| 688 | + private: | |
| 689 | + QPDF& qpdf; | |
| 690 | + | |
| 691 | + std::shared_ptr<Copier> copier_; | |
| 652 | 692 | }; |
| 653 | 693 | |
| 654 | 694 | public: |
| ... | ... | @@ -662,7 +702,8 @@ class QPDF::Doc |
| 662 | 702 | Objects(QPDF& qpdf, QPDF::Members* m) : |
| 663 | 703 | qpdf(qpdf), |
| 664 | 704 | m(m), |
| 665 | - foreign_(qpdf) | |
| 705 | + foreign_(qpdf), | |
| 706 | + streams_(qpdf) | |
| 666 | 707 | { |
| 667 | 708 | } |
| 668 | 709 | |
| ... | ... | @@ -672,6 +713,12 @@ class QPDF::Doc |
| 672 | 713 | return foreign_; |
| 673 | 714 | } |
| 674 | 715 | |
| 716 | + Streams& | |
| 717 | + streams() | |
| 718 | + { | |
| 719 | + return streams_; | |
| 720 | + } | |
| 721 | + | |
| 675 | 722 | void parse(char const* password); |
| 676 | 723 | std::shared_ptr<QPDFObject> const& resolve(QPDFObjGen og); |
| 677 | 724 | void inParse(bool); |
| ... | ... | @@ -748,6 +795,7 @@ class QPDF::Doc |
| 748 | 795 | QPDF::Members* m; |
| 749 | 796 | |
| 750 | 797 | Foreign foreign_; |
| 798 | + Streams streams_; | |
| 751 | 799 | }; // class QPDF::Doc::Objects |
| 752 | 800 | |
| 753 | 801 | // This class is used to represent a PDF Pages tree. |
| ... | ... | @@ -929,7 +977,6 @@ class QPDF::Members |
| 929 | 977 | bool ever_pushed_inherited_attributes_to_pages{false}; |
| 930 | 978 | bool ever_called_get_all_pages{false}; |
| 931 | 979 | std::vector<QPDFExc> warnings; |
| 932 | - std::shared_ptr<CopiedStreamDataProvider> copied_stream_data_provider; | |
| 933 | 980 | bool reconstructed_xref{false}; |
| 934 | 981 | bool in_read_xref_stream{false}; |
| 935 | 982 | bool fixed_dangling_refs{false}; | ... | ... |