From 09c3dc5f92e1512ba1e3fdf221bd3be08f6654fa Mon Sep 17 00:00:00 2001 From: m-holger Date: Sun, 22 Sep 2024 20:24:40 +0100 Subject: [PATCH] Refactor QPDF_Stream --- include/qpdf/ObjectHandle.hh | 3 ++- include/qpdf/QPDF.hh | 1 + include/qpdf/QPDFObjectHandle.hh | 1 + libqpdf/QPDF.cc | 24 +++++++++++------------- libqpdf/QPDFObjectHandle.cc | 33 ++++++++++++++++----------------- libqpdf/QPDF_Stream.cc | 208 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------------------------------------------------------------------------------------------------- libqpdf/QPDF_json.cc | 9 +++++---- libqpdf/qpdf/QPDFObjectHandle_private.hh | 133 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- libqpdf/qpdf/QPDF_Stream.hh | 59 +++-------------------------------------------------------- 9 files changed, 258 insertions(+), 213 deletions(-) diff --git a/include/qpdf/ObjectHandle.hh b/include/qpdf/ObjectHandle.hh index 1f4d052..781cf59 100644 --- a/include/qpdf/ObjectHandle.hh +++ b/include/qpdf/ObjectHandle.hh @@ -35,8 +35,9 @@ class QPDFObjectHandle; namespace qpdf { class Array; - class Dictionary; class BaseDictionary; + class Dictionary; + class Stream; enum typed : std::uint8_t { strict = 0, any_flag = 1, optional = 2, any = 3, error = 4}; diff --git a/include/qpdf/QPDF.hh b/include/qpdf/QPDF.hh index 0e79967..9721d63 100644 --- a/include/qpdf/QPDF.hh +++ b/include/qpdf/QPDF.hh @@ -854,6 +854,7 @@ class QPDF class Pipe { friend class QPDF_Stream; + friend class qpdf::Stream; private: static bool diff --git a/include/qpdf/QPDFObjectHandle.hh b/include/qpdf/QPDFObjectHandle.hh index 40df43f..068083f 100644 --- a/include/qpdf/QPDFObjectHandle.hh +++ b/include/qpdf/QPDFObjectHandle.hh @@ -1357,6 +1357,7 @@ class QPDFObjectHandle final: public qpdf::BaseHandle inline qpdf::Array as_array(qpdf::typed options = qpdf::typed::any) const; inline qpdf::Dictionary as_dictionary(qpdf::typed options = qpdf::typed::any) const; + inline qpdf::Stream as_stream(qpdf::typed options = qpdf::typed::strict) const; private: QPDF_Array* asArray() const; diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index 60303d1..6602fa1 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -17,9 +17,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -298,7 +298,7 @@ void QPDF::registerStreamFilter( std::string const& filter_name, std::function()> factory) { - QPDF_Stream::registerStreamFilter(filter_name, factory); + qpdf::Stream::registerStreamFilter(filter_name, factory); } void @@ -2442,13 +2442,11 @@ QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign) QPDF& foreign_stream_qpdf = foreign.getQPDF("unable to retrieve owning qpdf from foreign stream"); - auto stream = foreign.getObjectPtr()->as(); - if (stream == nullptr) { - throw std::logic_error( - "unable to retrieve underlying" - " stream object from foreign stream"); + auto stream = foreign.as_stream(); + if (!stream) { + throw std::logic_error("unable to retrieve underlying stream object from foreign stream"); } - std::shared_ptr stream_buffer = stream->getStreamDataBuffer(); + std::shared_ptr stream_buffer = stream.getStreamDataBuffer(); if ((foreign_stream_qpdf.m->immediate_copy_from) && (stream_buffer == nullptr)) { // Pull the stream data into a buffer before attempting the copy operation. Do it on the // source stream so that if the source stream is copied multiple times, we don't have to @@ -2458,10 +2456,10 @@ QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign) foreign.getRawStreamData(), old_dict.getKey("/Filter"), old_dict.getKey("/DecodeParms")); - stream_buffer = stream->getStreamDataBuffer(); + stream_buffer = stream.getStreamDataBuffer(); } std::shared_ptr stream_provider = - stream->getStreamDataProvider(); + stream.getStreamDataProvider(); if (stream_buffer.get()) { QTC::TC("qpdf", "QPDF copy foreign stream with buffer"); result.replaceStreamData( @@ -2476,9 +2474,9 @@ QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign) auto foreign_stream_data = std::make_shared( foreign_stream_qpdf.m->encp, foreign_stream_qpdf.m->file, - foreign.getObjGen(), - stream->getParsedOffset(), - stream->getLength(), + foreign, + foreign.getParsedOffset(), + stream.getLength(), dict); m->copied_stream_data_provider->registerForeignStream(local_og, foreign_stream_data); result.replaceStreamData( diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc index 38bdad7..2e8ebf2 100644 --- a/libqpdf/QPDFObjectHandle.cc +++ b/libqpdf/QPDFObjectHandle.cc @@ -962,43 +962,43 @@ QPDFObjectHandle::getUniqueResourceName( QPDFObjectHandle QPDFObjectHandle::getDict() const { - return asStreamWithAssert()->getDict(); + return as_stream(error).getDict(); } void QPDFObjectHandle::setFilterOnWrite(bool val) { - asStreamWithAssert()->setFilterOnWrite(val); + as_stream(error).setFilterOnWrite(val); } bool QPDFObjectHandle::getFilterOnWrite() { - return asStreamWithAssert()->getFilterOnWrite(); + return as_stream(error).getFilterOnWrite(); } bool QPDFObjectHandle::isDataModified() { - return asStreamWithAssert()->isDataModified(); + return as_stream(error).isDataModified(); } void QPDFObjectHandle::replaceDict(QPDFObjectHandle const& new_dict) { - asStreamWithAssert()->replaceDict(new_dict); + as_stream(error).replaceDict(new_dict); } std::shared_ptr QPDFObjectHandle::getStreamData(qpdf_stream_decode_level_e level) { - return asStreamWithAssert()->getStreamData(level); + return as_stream(error).getStreamData(level); } std::shared_ptr QPDFObjectHandle::getRawStreamData() { - return asStreamWithAssert()->getRawStreamData(); + return as_stream(error).getRawStreamData(); } bool @@ -1010,7 +1010,7 @@ QPDFObjectHandle::pipeStreamData( bool suppress_warnings, bool will_retry) { - return asStreamWithAssert()->pipeStreamData( + return as_stream(error).pipeStreamData( p, filtering_attempted, encode_flags, decode_level, suppress_warnings, will_retry); } @@ -1023,7 +1023,7 @@ QPDFObjectHandle::pipeStreamData( bool will_retry) { bool filtering_attempted; - asStreamWithAssert()->pipeStreamData( + as_stream(error).pipeStreamData( p, &filtering_attempted, encode_flags, decode_level, suppress_warnings, will_retry); return filtering_attempted; } @@ -1051,7 +1051,7 @@ QPDFObjectHandle::replaceStreamData( QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms) { - asStreamWithAssert()->replaceStreamData(data, filter, decode_parms); + as_stream(error).replaceStreamData(data, filter, decode_parms); } void @@ -1063,7 +1063,7 @@ QPDFObjectHandle::replaceStreamData( if (bp) { memcpy(bp, data.c_str(), data.length()); } - asStreamWithAssert()->replaceStreamData(b, filter, decode_parms); + as_stream(error).replaceStreamData(b, filter, decode_parms); } void @@ -1072,7 +1072,7 @@ QPDFObjectHandle::replaceStreamData( QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms) { - asStreamWithAssert()->replaceStreamData(provider, filter, decode_parms); + as_stream(error).replaceStreamData(provider, filter, decode_parms); } namespace @@ -1119,7 +1119,7 @@ QPDFObjectHandle::replaceStreamData( QPDFObjectHandle const& decode_parms) { auto sdp = std::shared_ptr(new FunctionProvider(provider)); - asStreamWithAssert()->replaceStreamData(sdp, filter, decode_parms); + as_stream(error).replaceStreamData(sdp, filter, decode_parms); } void @@ -1129,7 +1129,7 @@ QPDFObjectHandle::replaceStreamData( QPDFObjectHandle const& decode_parms) { auto sdp = std::shared_ptr(new FunctionProvider(provider)); - asStreamWithAssert()->replaceStreamData(sdp, filter, decode_parms); + as_stream(error).replaceStreamData(sdp, filter, decode_parms); } std::map @@ -1348,8 +1348,7 @@ QPDFObjectHandle::getStreamJSON( Pipeline* p, std::string const& data_filename) { - return asStreamWithAssert()->getStreamJSON( - json_version, json_data, decode_level, p, data_filename); + return as_stream(error).getStreamJSON(json_version, json_data, decode_level, p, data_filename); } QPDFObjectHandle @@ -1552,7 +1551,7 @@ QPDFObjectHandle::addContentTokenFilter(std::shared_ptr filter) void QPDFObjectHandle::addTokenFilter(std::shared_ptr filter) { - return asStreamWithAssert()->addTokenFilter(filter); + return as_stream(error).addTokenFilter(filter); } QPDFObjectHandle diff --git a/libqpdf/QPDF_Stream.cc b/libqpdf/QPDF_Stream.cc index 3e1defa..d041a65 100644 --- a/libqpdf/QPDF_Stream.cc +++ b/libqpdf/QPDF_Stream.cc @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -22,6 +23,9 @@ #include +using namespace std::literals; +using namespace qpdf; + namespace { class SF_Crypt: public QPDFStreamFilter @@ -60,16 +64,24 @@ namespace class StreamBlobProvider { public: - StreamBlobProvider(QPDF_Stream* stream, qpdf_stream_decode_level_e decode_level); - void operator()(Pipeline*); + StreamBlobProvider(Stream stream, qpdf_stream_decode_level_e decode_level) : + stream(stream), + decode_level(decode_level) + { + } + void + operator()(Pipeline* p) + { + stream.pipeStreamData(p, nullptr, 0, decode_level, false, false); + } private: - QPDF_Stream* stream; + Stream stream; qpdf_stream_decode_level_e decode_level; }; } // namespace -std::map QPDF_Stream::filter_abbreviations = { +std::map Stream::filter_abbreviations = { // The PDF specification provides these filter abbreviations for use in inline images, but // according to table H.1 in the pre-ISO versions of the PDF specification, Adobe Reader also // accepts them for stream filters. @@ -82,8 +94,8 @@ std::map QPDF_Stream::filter_abbreviations = { {"/DCT", "/DCTDecode"}, }; -std::map()>> - QPDF_Stream::filter_factories = { +std::map()>> Stream::filter_factories = + { {"/Crypt", []() { return std::make_shared(); }}, {"/FlateDecode", SF_FlateLzwDecode::flate_factory}, {"/LZWDecode", SF_FlateLzwDecode::lzw_factory}, @@ -93,19 +105,6 @@ std::map()>> {"/ASCIIHexDecode", SF_ASCIIHexDecode::factory}, }; -StreamBlobProvider::StreamBlobProvider( - QPDF_Stream* stream, qpdf_stream_decode_level_e decode_level) : - stream(stream), - decode_level(decode_level) -{ -} - -void -StreamBlobProvider::operator()(Pipeline* p) -{ - this->stream->pipeStreamData(p, nullptr, 0, decode_level, false, false); -} - QPDF_Stream::QPDF_Stream( QPDF* qpdf, QPDFObjGen og, QPDFObjectHandle stream_dict, qpdf_offset_t offset, size_t length) : QPDFValue(::ot_stream, qpdf, og), @@ -137,25 +136,13 @@ QPDF_Stream::copy(bool shallow) } void -QPDF_Stream::registerStreamFilter( +Stream::registerStreamFilter( std::string const& filter_name, std::function()> factory) { filter_factories[filter_name] = factory; } void -QPDF_Stream::setFilterOnWrite(bool val) -{ - this->filter_on_write = val; -} - -bool -QPDF_Stream::getFilterOnWrite() const -{ - return this->filter_on_write; -} - -void QPDF_Stream::disconnect() { this->stream_provider = nullptr; @@ -175,8 +162,20 @@ QPDF_Stream::writeJSON(int json_version, JSON::Writer& jw) stream_dict.writeJSON(json_version, jw); } +QPDF_Stream* +Stream::stream() const +{ + if (obj) { + if (auto s = obj->as()) { + return s; + } + } + throw std::runtime_error("operation for stream attempted on object of type dictionary"); + return nullptr; // unreachable +} + JSON -QPDF_Stream::getStreamJSON( +Stream::getStreamJSON( int json_version, qpdf_json_stream_data_e json_data, qpdf_stream_decode_level_e decode_level, @@ -190,13 +189,13 @@ QPDF_Stream::getStreamJSON( pb.finish(); auto result = JSON::parse(pb.getString()); if (json_data == qpdf_sj_inline) { - result.addDictionaryMember("data", JSON::makeBlob(StreamBlobProvider(this, decode_level))); + result.addDictionaryMember("data", JSON::makeBlob(StreamBlobProvider(*this, decode_level))); } return result; } qpdf_stream_decode_level_e -QPDF_Stream::writeStreamJSON( +Stream::writeStreamJSON( int json_version, JSON::Writer& jw, qpdf_json_stream_data_e json_data, @@ -205,6 +204,7 @@ QPDF_Stream::writeStreamJSON( std::string const& data_filename, bool no_data_key) { + auto s = stream(); switch (json_data) { case qpdf_sj_none: case qpdf_sj_inline: @@ -232,7 +232,7 @@ QPDF_Stream::writeStreamJSON( if (json_data == qpdf_sj_none) { jw.writeNext(); jw << R"("dict": )"; - stream_dict.writeJSON(json_version, jw); + s->stream_dict.writeJSON(json_version, jw); jw.writeEnd('}'); return decode_level; } @@ -264,7 +264,7 @@ QPDF_Stream::writeStreamJSON( throw std::logic_error("QPDF_Stream: failed to get stream data"); } // We can use unsafeShallowCopy because we are only touching top-level keys. - auto dict = stream_dict.unsafeShallowCopy(); + auto dict = s->stream_dict.unsafeShallowCopy(); dict.removeKey("/Length"); if (filter && filtered) { dict.removeKey("/Filter"); @@ -305,48 +305,19 @@ QPDF_Stream::setDictDescription() } } -QPDFObjectHandle -QPDF_Stream::getDict() const -{ - return this->stream_dict; -} - -bool -QPDF_Stream::isDataModified() const -{ - return (!this->token_filters.empty()); -} - -size_t -QPDF_Stream::getLength() const -{ - return this->length; -} - -std::shared_ptr -QPDF_Stream::getStreamDataBuffer() const -{ - return this->stream_data; -} - -std::shared_ptr -QPDF_Stream::getStreamDataProvider() const -{ - return this->stream_provider; -} - std::shared_ptr -QPDF_Stream::getStreamData(qpdf_stream_decode_level_e decode_level) +Stream::getStreamData(qpdf_stream_decode_level_e decode_level) { + auto s = stream(); Pl_Buffer buf("stream data buffer"); bool filtered; pipeStreamData(&buf, &filtered, 0, decode_level, false, false); if (!filtered) { throw QPDFExc( qpdf_e_unsupported, - qpdf->getFilename(), + s->qpdf->getFilename(), "", - this->parsed_offset, + s->parsed_offset, "getStreamData called on unfilterable stream"); } QTC::TC("qpdf", "QPDF_Stream getStreamData"); @@ -354,15 +325,16 @@ QPDF_Stream::getStreamData(qpdf_stream_decode_level_e decode_level) } std::shared_ptr -QPDF_Stream::getRawStreamData() +Stream::getRawStreamData() { + auto s = stream(); Pl_Buffer buf("stream data buffer"); if (!pipeStreamData(&buf, nullptr, 0, qpdf_dl_none, false, false)) { throw QPDFExc( qpdf_e_unsupported, - qpdf->getFilename(), + s->qpdf->getFilename(), "", - this->parsed_offset, + s->parsed_offset, "error getting raw stream data"); } QTC::TC("qpdf", "QPDF_Stream getRawStreamData"); @@ -370,14 +342,15 @@ QPDF_Stream::getRawStreamData() } bool -QPDF_Stream::filterable( +Stream::filterable( std::vector>& filters, bool& specialized_compression, bool& lossy_compression) { + auto s = stream(); // Check filters - QPDFObjectHandle filter_obj = this->stream_dict.getKey("/Filter"); + QPDFObjectHandle filter_obj = s->stream_dict.getKey("/Filter"); bool filters_okay = true; std::vector filter_names; @@ -432,7 +405,7 @@ QPDF_Stream::filterable( // See if we can support any decode parameters that are specified. - QPDFObjectHandle decode_obj = this->stream_dict.getKey("/DecodeParms"); + QPDFObjectHandle decode_obj = s->stream_dict.getKey("/DecodeParms"); std::vector decode_parms; if (decode_obj.isArray() && (decode_obj.getArrayNItems() == 0)) { decode_obj = QPDFObjectHandle::newNull(); @@ -479,7 +452,7 @@ QPDF_Stream::filterable( } bool -QPDF_Stream::pipeStreamData( +Stream::pipeStreamData( Pipeline* pipeline, bool* filterp, int encode_flags, @@ -487,6 +460,7 @@ QPDF_Stream::pipeStreamData( bool suppress_warnings, bool will_retry) { + auto s = stream(); std::vector> filters; bool specialized_compression = false; bool lossy_compression = false; @@ -543,7 +517,7 @@ QPDF_Stream::pipeStreamData( pipeline = new_pipeline.get(); } - for (auto iter = this->token_filters.rbegin(); iter != this->token_filters.rend(); ++iter) { + for (auto iter = s->token_filters.rbegin(); iter != s->token_filters.rend(); ++iter) { new_pipeline = std::make_shared("token filter", (*iter).get(), pipeline); to_delete.push_back(new_pipeline); @@ -562,25 +536,25 @@ QPDF_Stream::pipeStreamData( } } - if (this->stream_data.get()) { + if (s->stream_data.get()) { QTC::TC("qpdf", "QPDF_Stream pipe replaced stream data"); - pipeline->write(this->stream_data->getBuffer(), this->stream_data->getSize()); + pipeline->write(s->stream_data->getBuffer(), s->stream_data->getSize()); pipeline->finish(); - } else if (this->stream_provider.get()) { + } else if (s->stream_provider.get()) { Pl_Count count("stream provider count", pipeline); - if (this->stream_provider->supportsRetry()) { - if (!this->stream_provider->provideStreamData( - og, &count, suppress_warnings, will_retry)) { + if (s->stream_provider->supportsRetry()) { + if (!s->stream_provider->provideStreamData( + s->og, &count, suppress_warnings, will_retry)) { filter = false; success = false; } } else { - this->stream_provider->provideStreamData(og, &count); + s->stream_provider->provideStreamData(s->og, &count); } qpdf_offset_t actual_length = count.getCount(); qpdf_offset_t desired_length = 0; - if (success && this->stream_dict.hasKey("/Length")) { - desired_length = this->stream_dict.getKey("/Length").getIntValue(); + if (success && s->stream_dict.hasKey("/Length")) { + desired_length = s->stream_dict.getKey("/Length").getIntValue(); if (actual_length == desired_length) { QTC::TC("qpdf", "QPDF_Stream pipe use stream provider"); } else { @@ -588,25 +562,25 @@ QPDF_Stream::pipeStreamData( // This would be caused by programmer error on the part of a library user, not by // invalid input data. throw std::runtime_error( - "stream data provider for " + og.unparse(' ') + " provided " + + "stream data provider for " + s->og.unparse(' ') + " provided " + std::to_string(actual_length) + " bytes instead of expected " + std::to_string(desired_length) + " bytes"); } } else if (success) { QTC::TC("qpdf", "QPDF_Stream provider length not provided"); - this->stream_dict.replaceKey("/Length", QPDFObjectHandle::newInteger(actual_length)); + s->stream_dict.replaceKey("/Length", QPDFObjectHandle::newInteger(actual_length)); } - } else if (this->parsed_offset == 0) { + } else if (s->parsed_offset == 0) { QTC::TC("qpdf", "QPDF_Stream pipe no stream data"); throw std::logic_error("pipeStreamData called for stream with no data"); } else { QTC::TC("qpdf", "QPDF_Stream pipe original stream data"); if (!QPDF::Pipe::pipeStreamData( - this->qpdf, - og, - this->parsed_offset, - this->length, - this->stream_dict, + s->qpdf, + s->og, + s->parsed_offset, + s->length, + s->stream_dict, pipeline, suppress_warnings, will_retry)) { @@ -634,60 +608,52 @@ QPDF_Stream::pipeStreamData( } void -QPDF_Stream::replaceStreamData( +Stream::replaceStreamData( std::shared_ptr data, QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms) { - this->stream_data = data; - this->stream_provider = nullptr; + auto s = stream(); + s->stream_data = data; + s->stream_provider = nullptr; replaceFilterData(filter, decode_parms, data->getSize()); } void -QPDF_Stream::replaceStreamData( +Stream::replaceStreamData( std::shared_ptr provider, QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms) { - this->stream_provider = provider; - this->stream_data = nullptr; + auto s = stream(); + s->stream_provider = provider; + s->stream_data = nullptr; replaceFilterData(filter, decode_parms, 0); } void -QPDF_Stream::addTokenFilter(std::shared_ptr token_filter) -{ - this->token_filters.push_back(token_filter); -} - -void -QPDF_Stream::replaceFilterData( +Stream::replaceFilterData( QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms, size_t length) { + auto s = stream(); if (filter) { - stream_dict.replaceKey("/Filter", filter); + s->stream_dict.replaceKey("/Filter", filter); } if (decode_parms) { - stream_dict.replaceKey("/DecodeParms", decode_parms); + s->stream_dict.replaceKey("/DecodeParms", decode_parms); } if (length == 0) { QTC::TC("qpdf", "QPDF_Stream unknown stream length"); - stream_dict.removeKey("/Length"); + s->stream_dict.removeKey("/Length"); } else { - stream_dict.replaceKey("/Length", QPDFObjectHandle::newInteger(QIntC::to_longlong(length))); + s->stream_dict.replaceKey( + "/Length", QPDFObjectHandle::newInteger(QIntC::to_longlong(length))); } } void -QPDF_Stream::replaceDict(QPDFObjectHandle const& new_dict) -{ - this->stream_dict = new_dict; - setDictDescription(); -} - -void -QPDF_Stream::warn(std::string const& message) +Stream::warn(std::string const& message) { - this->qpdf->warn(qpdf_e_damaged_pdf, "", this->parsed_offset, message); + auto s = stream(); + s->qpdf->warn(qpdf_e_damaged_pdf, "", s->parsed_offset, message); } diff --git a/libqpdf/QPDF_json.cc b/libqpdf/QPDF_json.cc index f1a9f25..1b9318d 100644 --- a/libqpdf/QPDF_json.cc +++ b/libqpdf/QPDF_json.cc @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -821,7 +822,7 @@ void writeJSONStreamFile( int version, JSON::Writer& jw, - QPDF_Stream& stream, + qpdf::Stream& stream, int id, qpdf_stream_decode_level_e decode_level, std::string const& file_prefix) @@ -894,13 +895,13 @@ QPDF::writeJSON( } else { jw << "\n },\n \"" << key; } - if (auto* stream = obj.getObjectPtr()->as()) { + if (auto stream = obj.as_stream()) { jw << "\": {\n \"stream\": "; if (json_stream_data == qpdf_sj_file) { writeJSONStreamFile( - version, jw, *stream, og.getObj(), decode_level, file_prefix); + version, jw, stream, og.getObj(), decode_level, file_prefix); } else { - stream->writeStreamJSON( + stream.writeStreamJSON( version, jw, json_stream_data, decode_level, nullptr, ""); } } else { diff --git a/libqpdf/qpdf/QPDFObjectHandle_private.hh b/libqpdf/qpdf/QPDFObjectHandle_private.hh index d6ec3ee..afd4118 100644 --- a/libqpdf/qpdf/QPDFObjectHandle_private.hh +++ b/libqpdf/qpdf/QPDFObjectHandle_private.hh @@ -6,6 +6,7 @@ #include #include #include +#include namespace qpdf { @@ -80,6 +81,123 @@ namespace qpdf } }; + class Stream final: public BaseHandle + { + public: + explicit Stream(std::shared_ptr const& obj) : + BaseHandle(obj) + { + } + + explicit Stream(std::shared_ptr&& obj) : + BaseHandle(std::move(obj)) + { + } + + QPDFObjectHandle + getDict() const + { + return stream()->stream_dict; + } + bool + isDataModified() const + { + return !stream()->token_filters.empty(); + } + void + setFilterOnWrite(bool val) + { + stream()->filter_on_write = val; + } + bool + getFilterOnWrite() const + { + return stream()->filter_on_write; + } + + // Methods to help QPDF copy foreign streams + size_t + getLength() const + { + return stream()->length; + } + std::shared_ptr + getStreamDataBuffer() const + { + return stream()->stream_data; + } + std::shared_ptr + getStreamDataProvider() const + { + return stream()->stream_provider; + } + + // See comments in QPDFObjectHandle.hh for these methods. + bool pipeStreamData( + Pipeline* p, + bool* tried_filtering, + int encode_flags, + qpdf_stream_decode_level_e decode_level, + bool suppress_warnings, + bool will_retry); + std::shared_ptr getStreamData(qpdf_stream_decode_level_e level); + std::shared_ptr getRawStreamData(); + void replaceStreamData( + std::shared_ptr data, + QPDFObjectHandle const& filter, + QPDFObjectHandle const& decode_parms); + void replaceStreamData( + std::shared_ptr provider, + QPDFObjectHandle const& filter, + QPDFObjectHandle const& decode_parms); + void + addTokenFilter(std::shared_ptr token_filter) + { + stream()->token_filters.emplace_back(token_filter); + } + JSON getStreamJSON( + int json_version, + qpdf_json_stream_data_e json_data, + qpdf_stream_decode_level_e decode_level, + Pipeline* p, + std::string const& data_filename); + qpdf_stream_decode_level_e writeStreamJSON( + int json_version, + JSON::Writer& jw, + qpdf_json_stream_data_e json_data, + qpdf_stream_decode_level_e decode_level, + Pipeline* p, + std::string const& data_filename, + bool no_data_key = false); + void + replaceDict(QPDFObjectHandle const& new_dict) + { + auto s = stream(); + s->stream_dict = new_dict; + s->setDictDescription(); + } + + static void registerStreamFilter( + std::string const& filter_name, + std::function()> factory); + + private: + QPDF_Stream* stream() const; + + bool filterable( + std::vector>& filters, + bool& specialized_compression, + bool& lossy_compression); + void replaceFilterData( + QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms, size_t length); + + void warn(std::string const& message); + + static std::map filter_abbreviations; + static std::map()>> + filter_factories; + }; + inline qpdf_object_type_e BaseHandle::type_code() const { @@ -98,7 +216,7 @@ QPDFObjectHandle::as_array(qpdf::typed options) const (options & qpdf::optional && type_code() == ::ot_null)) { return qpdf::Array(obj); } - return qpdf::Array({}); + return qpdf::Array(std::shared_ptr()); } inline qpdf::Dictionary @@ -114,4 +232,17 @@ QPDFObjectHandle::as_dictionary(qpdf::typed options) const return qpdf::Dictionary(std::shared_ptr()); } +inline qpdf::Stream +QPDFObjectHandle::as_stream(qpdf::typed options) const +{ + if (options & qpdf::any_flag || type_code() == ::ot_stream || + (options & qpdf::optional && type_code() == ::ot_null)) { + return qpdf::Stream(obj); + } + if (options & qpdf::error) { + assertType("stream", false); + } + return qpdf::Stream(std::shared_ptr()); +} + #endif // OBJECTHANDLE_PRIVATE_HH diff --git a/libqpdf/qpdf/QPDF_Stream.hh b/libqpdf/qpdf/QPDF_Stream.hh index 0acdf71..7d44262 100644 --- a/libqpdf/qpdf/QPDF_Stream.hh +++ b/libqpdf/qpdf/QPDF_Stream.hh @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -25,69 +26,15 @@ class QPDF_Stream final: public QPDFValue void setDescription( QPDF*, std::shared_ptr& description, qpdf_offset_t offset) final; void disconnect() final; - QPDFObjectHandle getDict() const; - bool isDataModified() const; - void setFilterOnWrite(bool); - bool getFilterOnWrite() const; - - // Methods to help QPDF copy foreign streams - size_t getLength() const; - std::shared_ptr getStreamDataBuffer() const; - std::shared_ptr getStreamDataProvider() const; - - // See comments in QPDFObjectHandle.hh for these methods. - bool pipeStreamData( - Pipeline*, - bool* tried_filtering, - int encode_flags, - qpdf_stream_decode_level_e decode_level, - bool suppress_warnings, - bool will_retry); - std::shared_ptr getStreamData(qpdf_stream_decode_level_e); - std::shared_ptr getRawStreamData(); - void replaceStreamData( - std::shared_ptr data, - QPDFObjectHandle const& filter, - QPDFObjectHandle const& decode_parms); - void replaceStreamData( - std::shared_ptr provider, - QPDFObjectHandle const& filter, - QPDFObjectHandle const& decode_parms); - void addTokenFilter(std::shared_ptr token_filter); - JSON getStreamJSON( - int json_version, - qpdf_json_stream_data_e json_data, - qpdf_stream_decode_level_e decode_level, - Pipeline* p, - std::string const& data_filename); - qpdf_stream_decode_level_e writeStreamJSON( - int json_version, - JSON::Writer& jw, - qpdf_json_stream_data_e json_data, - qpdf_stream_decode_level_e decode_level, - Pipeline* p, - std::string const& data_filename, - bool no_data_key = false); - - void replaceDict(QPDFObjectHandle const& new_dict); - - static void registerStreamFilter( - std::string const& filter_name, std::function()> factory); private: + friend class qpdf::Stream; + QPDF_Stream( QPDF*, QPDFObjGen og, QPDFObjectHandle stream_dict, qpdf_offset_t offset, size_t length); - static std::map filter_abbreviations; - static std::map()>> - filter_factories; void replaceFilterData( QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms, size_t length); - bool filterable( - std::vector>& filters, - bool& specialized_compression, - bool& lossy_compression); - void warn(std::string const& message); void setDictDescription(); bool filter_on_write; -- libgit2 0.21.4