Commit 09c3dc5f92e1512ba1e3fdf221bd3be08f6654fa

Authored by m-holger
1 parent 796913e9

Refactor QPDF_Stream

Move all stream-specific methods to new class qpdf::Stream
include/qpdf/ObjectHandle.hh
@@ -35,8 +35,9 @@ class QPDFObjectHandle; @@ -35,8 +35,9 @@ class QPDFObjectHandle;
35 namespace qpdf 35 namespace qpdf
36 { 36 {
37 class Array; 37 class Array;
38 - class Dictionary;  
39 class BaseDictionary; 38 class BaseDictionary;
  39 + class Dictionary;
  40 + class Stream;
40 41
41 enum typed : std::uint8_t { strict = 0, any_flag = 1, optional = 2, any = 3, error = 4}; 42 enum typed : std::uint8_t { strict = 0, any_flag = 1, optional = 2, any = 3, error = 4};
42 43
include/qpdf/QPDF.hh
@@ -854,6 +854,7 @@ class QPDF @@ -854,6 +854,7 @@ class QPDF
854 class Pipe 854 class Pipe
855 { 855 {
856 friend class QPDF_Stream; 856 friend class QPDF_Stream;
  857 + friend class qpdf::Stream;
857 858
858 private: 859 private:
859 static bool 860 static bool
include/qpdf/QPDFObjectHandle.hh
@@ -1357,6 +1357,7 @@ class QPDFObjectHandle final: public qpdf::BaseHandle @@ -1357,6 +1357,7 @@ class QPDFObjectHandle final: public qpdf::BaseHandle
1357 1357
1358 inline qpdf::Array as_array(qpdf::typed options = qpdf::typed::any) const; 1358 inline qpdf::Array as_array(qpdf::typed options = qpdf::typed::any) const;
1359 inline qpdf::Dictionary as_dictionary(qpdf::typed options = qpdf::typed::any) const; 1359 inline qpdf::Dictionary as_dictionary(qpdf::typed options = qpdf::typed::any) const;
  1360 + inline qpdf::Stream as_stream(qpdf::typed options = qpdf::typed::strict) const;
1360 1361
1361 private: 1362 private:
1362 QPDF_Array* asArray() const; 1363 QPDF_Array* asArray() const;
libqpdf/QPDF.cc
@@ -17,9 +17,9 @@ @@ -17,9 +17,9 @@
17 #include <qpdf/Pipeline.hh> 17 #include <qpdf/Pipeline.hh>
18 #include <qpdf/QPDFExc.hh> 18 #include <qpdf/QPDFExc.hh>
19 #include <qpdf/QPDFLogger.hh> 19 #include <qpdf/QPDFLogger.hh>
  20 +#include <qpdf/QPDFObjectHandle_private.hh>
20 #include <qpdf/QPDFObject_private.hh> 21 #include <qpdf/QPDFObject_private.hh>
21 #include <qpdf/QPDFParser.hh> 22 #include <qpdf/QPDFParser.hh>
22 -#include <qpdf/QPDF_Array.hh>  
23 #include <qpdf/QPDF_Dictionary.hh> 23 #include <qpdf/QPDF_Dictionary.hh>
24 #include <qpdf/QPDF_Null.hh> 24 #include <qpdf/QPDF_Null.hh>
25 #include <qpdf/QPDF_Reserved.hh> 25 #include <qpdf/QPDF_Reserved.hh>
@@ -298,7 +298,7 @@ void @@ -298,7 +298,7 @@ void
298 QPDF::registerStreamFilter( 298 QPDF::registerStreamFilter(
299 std::string const& filter_name, std::function<std::shared_ptr<QPDFStreamFilter>()> factory) 299 std::string const& filter_name, std::function<std::shared_ptr<QPDFStreamFilter>()> factory)
300 { 300 {
301 - QPDF_Stream::registerStreamFilter(filter_name, factory); 301 + qpdf::Stream::registerStreamFilter(filter_name, factory);
302 } 302 }
303 303
304 void 304 void
@@ -2442,13 +2442,11 @@ QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign) @@ -2442,13 +2442,11 @@ QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign)
2442 QPDF& foreign_stream_qpdf = 2442 QPDF& foreign_stream_qpdf =
2443 foreign.getQPDF("unable to retrieve owning qpdf from foreign stream"); 2443 foreign.getQPDF("unable to retrieve owning qpdf from foreign stream");
2444 2444
2445 - auto stream = foreign.getObjectPtr()->as<QPDF_Stream>();  
2446 - if (stream == nullptr) {  
2447 - throw std::logic_error(  
2448 - "unable to retrieve underlying"  
2449 - " stream object from foreign stream"); 2445 + auto stream = foreign.as_stream();
  2446 + if (!stream) {
  2447 + throw std::logic_error("unable to retrieve underlying stream object from foreign stream");
2450 } 2448 }
2451 - std::shared_ptr<Buffer> stream_buffer = stream->getStreamDataBuffer(); 2449 + std::shared_ptr<Buffer> stream_buffer = stream.getStreamDataBuffer();
2452 if ((foreign_stream_qpdf.m->immediate_copy_from) && (stream_buffer == nullptr)) { 2450 if ((foreign_stream_qpdf.m->immediate_copy_from) && (stream_buffer == nullptr)) {
2453 // Pull the stream data into a buffer before attempting the copy operation. Do it on the 2451 // Pull the stream data into a buffer before attempting the copy operation. Do it on the
2454 // source stream so that if the source stream is copied multiple times, we don't have to 2452 // 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) @@ -2458,10 +2456,10 @@ QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign)
2458 foreign.getRawStreamData(), 2456 foreign.getRawStreamData(),
2459 old_dict.getKey("/Filter"), 2457 old_dict.getKey("/Filter"),
2460 old_dict.getKey("/DecodeParms")); 2458 old_dict.getKey("/DecodeParms"));
2461 - stream_buffer = stream->getStreamDataBuffer(); 2459 + stream_buffer = stream.getStreamDataBuffer();
2462 } 2460 }
2463 std::shared_ptr<QPDFObjectHandle::StreamDataProvider> stream_provider = 2461 std::shared_ptr<QPDFObjectHandle::StreamDataProvider> stream_provider =
2464 - stream->getStreamDataProvider(); 2462 + stream.getStreamDataProvider();
2465 if (stream_buffer.get()) { 2463 if (stream_buffer.get()) {
2466 QTC::TC("qpdf", "QPDF copy foreign stream with buffer"); 2464 QTC::TC("qpdf", "QPDF copy foreign stream with buffer");
2467 result.replaceStreamData( 2465 result.replaceStreamData(
@@ -2476,9 +2474,9 @@ QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign) @@ -2476,9 +2474,9 @@ QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign)
2476 auto foreign_stream_data = std::make_shared<ForeignStreamData>( 2474 auto foreign_stream_data = std::make_shared<ForeignStreamData>(
2477 foreign_stream_qpdf.m->encp, 2475 foreign_stream_qpdf.m->encp,
2478 foreign_stream_qpdf.m->file, 2476 foreign_stream_qpdf.m->file,
2479 - foreign.getObjGen(),  
2480 - stream->getParsedOffset(),  
2481 - stream->getLength(), 2477 + foreign,
  2478 + foreign.getParsedOffset(),
  2479 + stream.getLength(),
2482 dict); 2480 dict);
2483 m->copied_stream_data_provider->registerForeignStream(local_og, foreign_stream_data); 2481 m->copied_stream_data_provider->registerForeignStream(local_og, foreign_stream_data);
2484 result.replaceStreamData( 2482 result.replaceStreamData(
libqpdf/QPDFObjectHandle.cc
@@ -962,43 +962,43 @@ QPDFObjectHandle::getUniqueResourceName( @@ -962,43 +962,43 @@ QPDFObjectHandle::getUniqueResourceName(
962 QPDFObjectHandle 962 QPDFObjectHandle
963 QPDFObjectHandle::getDict() const 963 QPDFObjectHandle::getDict() const
964 { 964 {
965 - return asStreamWithAssert()->getDict(); 965 + return as_stream(error).getDict();
966 } 966 }
967 967
968 void 968 void
969 QPDFObjectHandle::setFilterOnWrite(bool val) 969 QPDFObjectHandle::setFilterOnWrite(bool val)
970 { 970 {
971 - asStreamWithAssert()->setFilterOnWrite(val); 971 + as_stream(error).setFilterOnWrite(val);
972 } 972 }
973 973
974 bool 974 bool
975 QPDFObjectHandle::getFilterOnWrite() 975 QPDFObjectHandle::getFilterOnWrite()
976 { 976 {
977 - return asStreamWithAssert()->getFilterOnWrite(); 977 + return as_stream(error).getFilterOnWrite();
978 } 978 }
979 979
980 bool 980 bool
981 QPDFObjectHandle::isDataModified() 981 QPDFObjectHandle::isDataModified()
982 { 982 {
983 - return asStreamWithAssert()->isDataModified(); 983 + return as_stream(error).isDataModified();
984 } 984 }
985 985
986 void 986 void
987 QPDFObjectHandle::replaceDict(QPDFObjectHandle const& new_dict) 987 QPDFObjectHandle::replaceDict(QPDFObjectHandle const& new_dict)
988 { 988 {
989 - asStreamWithAssert()->replaceDict(new_dict); 989 + as_stream(error).replaceDict(new_dict);
990 } 990 }
991 991
992 std::shared_ptr<Buffer> 992 std::shared_ptr<Buffer>
993 QPDFObjectHandle::getStreamData(qpdf_stream_decode_level_e level) 993 QPDFObjectHandle::getStreamData(qpdf_stream_decode_level_e level)
994 { 994 {
995 - return asStreamWithAssert()->getStreamData(level); 995 + return as_stream(error).getStreamData(level);
996 } 996 }
997 997
998 std::shared_ptr<Buffer> 998 std::shared_ptr<Buffer>
999 QPDFObjectHandle::getRawStreamData() 999 QPDFObjectHandle::getRawStreamData()
1000 { 1000 {
1001 - return asStreamWithAssert()->getRawStreamData(); 1001 + return as_stream(error).getRawStreamData();
1002 } 1002 }
1003 1003
1004 bool 1004 bool
@@ -1010,7 +1010,7 @@ QPDFObjectHandle::pipeStreamData( @@ -1010,7 +1010,7 @@ QPDFObjectHandle::pipeStreamData(
1010 bool suppress_warnings, 1010 bool suppress_warnings,
1011 bool will_retry) 1011 bool will_retry)
1012 { 1012 {
1013 - return asStreamWithAssert()->pipeStreamData( 1013 + return as_stream(error).pipeStreamData(
1014 p, filtering_attempted, encode_flags, decode_level, suppress_warnings, will_retry); 1014 p, filtering_attempted, encode_flags, decode_level, suppress_warnings, will_retry);
1015 } 1015 }
1016 1016
@@ -1023,7 +1023,7 @@ QPDFObjectHandle::pipeStreamData( @@ -1023,7 +1023,7 @@ QPDFObjectHandle::pipeStreamData(
1023 bool will_retry) 1023 bool will_retry)
1024 { 1024 {
1025 bool filtering_attempted; 1025 bool filtering_attempted;
1026 - asStreamWithAssert()->pipeStreamData( 1026 + as_stream(error).pipeStreamData(
1027 p, &filtering_attempted, encode_flags, decode_level, suppress_warnings, will_retry); 1027 p, &filtering_attempted, encode_flags, decode_level, suppress_warnings, will_retry);
1028 return filtering_attempted; 1028 return filtering_attempted;
1029 } 1029 }
@@ -1051,7 +1051,7 @@ QPDFObjectHandle::replaceStreamData( @@ -1051,7 +1051,7 @@ QPDFObjectHandle::replaceStreamData(
1051 QPDFObjectHandle const& filter, 1051 QPDFObjectHandle const& filter,
1052 QPDFObjectHandle const& decode_parms) 1052 QPDFObjectHandle const& decode_parms)
1053 { 1053 {
1054 - asStreamWithAssert()->replaceStreamData(data, filter, decode_parms); 1054 + as_stream(error).replaceStreamData(data, filter, decode_parms);
1055 } 1055 }
1056 1056
1057 void 1057 void
@@ -1063,7 +1063,7 @@ QPDFObjectHandle::replaceStreamData( @@ -1063,7 +1063,7 @@ QPDFObjectHandle::replaceStreamData(
1063 if (bp) { 1063 if (bp) {
1064 memcpy(bp, data.c_str(), data.length()); 1064 memcpy(bp, data.c_str(), data.length());
1065 } 1065 }
1066 - asStreamWithAssert()->replaceStreamData(b, filter, decode_parms); 1066 + as_stream(error).replaceStreamData(b, filter, decode_parms);
1067 } 1067 }
1068 1068
1069 void 1069 void
@@ -1072,7 +1072,7 @@ QPDFObjectHandle::replaceStreamData( @@ -1072,7 +1072,7 @@ QPDFObjectHandle::replaceStreamData(
1072 QPDFObjectHandle const& filter, 1072 QPDFObjectHandle const& filter,
1073 QPDFObjectHandle const& decode_parms) 1073 QPDFObjectHandle const& decode_parms)
1074 { 1074 {
1075 - asStreamWithAssert()->replaceStreamData(provider, filter, decode_parms); 1075 + as_stream(error).replaceStreamData(provider, filter, decode_parms);
1076 } 1076 }
1077 1077
1078 namespace 1078 namespace
@@ -1119,7 +1119,7 @@ QPDFObjectHandle::replaceStreamData( @@ -1119,7 +1119,7 @@ QPDFObjectHandle::replaceStreamData(
1119 QPDFObjectHandle const& decode_parms) 1119 QPDFObjectHandle const& decode_parms)
1120 { 1120 {
1121 auto sdp = std::shared_ptr<StreamDataProvider>(new FunctionProvider(provider)); 1121 auto sdp = std::shared_ptr<StreamDataProvider>(new FunctionProvider(provider));
1122 - asStreamWithAssert()->replaceStreamData(sdp, filter, decode_parms); 1122 + as_stream(error).replaceStreamData(sdp, filter, decode_parms);
1123 } 1123 }
1124 1124
1125 void 1125 void
@@ -1129,7 +1129,7 @@ QPDFObjectHandle::replaceStreamData( @@ -1129,7 +1129,7 @@ QPDFObjectHandle::replaceStreamData(
1129 QPDFObjectHandle const& decode_parms) 1129 QPDFObjectHandle const& decode_parms)
1130 { 1130 {
1131 auto sdp = std::shared_ptr<StreamDataProvider>(new FunctionProvider(provider)); 1131 auto sdp = std::shared_ptr<StreamDataProvider>(new FunctionProvider(provider));
1132 - asStreamWithAssert()->replaceStreamData(sdp, filter, decode_parms); 1132 + as_stream(error).replaceStreamData(sdp, filter, decode_parms);
1133 } 1133 }
1134 1134
1135 std::map<std::string, QPDFObjectHandle> 1135 std::map<std::string, QPDFObjectHandle>
@@ -1348,8 +1348,7 @@ QPDFObjectHandle::getStreamJSON( @@ -1348,8 +1348,7 @@ QPDFObjectHandle::getStreamJSON(
1348 Pipeline* p, 1348 Pipeline* p,
1349 std::string const& data_filename) 1349 std::string const& data_filename)
1350 { 1350 {
1351 - return asStreamWithAssert()->getStreamJSON(  
1352 - json_version, json_data, decode_level, p, data_filename); 1351 + return as_stream(error).getStreamJSON(json_version, json_data, decode_level, p, data_filename);
1353 } 1352 }
1354 1353
1355 QPDFObjectHandle 1354 QPDFObjectHandle
@@ -1552,7 +1551,7 @@ QPDFObjectHandle::addContentTokenFilter(std::shared_ptr&lt;TokenFilter&gt; filter) @@ -1552,7 +1551,7 @@ QPDFObjectHandle::addContentTokenFilter(std::shared_ptr&lt;TokenFilter&gt; filter)
1552 void 1551 void
1553 QPDFObjectHandle::addTokenFilter(std::shared_ptr<TokenFilter> filter) 1552 QPDFObjectHandle::addTokenFilter(std::shared_ptr<TokenFilter> filter)
1554 { 1553 {
1555 - return asStreamWithAssert()->addTokenFilter(filter); 1554 + return as_stream(error).addTokenFilter(filter);
1556 } 1555 }
1557 1556
1558 QPDFObjectHandle 1557 QPDFObjectHandle
libqpdf/QPDF_Stream.cc
@@ -12,6 +12,7 @@ @@ -12,6 +12,7 @@
12 #include <qpdf/QIntC.hh> 12 #include <qpdf/QIntC.hh>
13 #include <qpdf/QPDF.hh> 13 #include <qpdf/QPDF.hh>
14 #include <qpdf/QPDFExc.hh> 14 #include <qpdf/QPDFExc.hh>
  15 +#include <qpdf/QPDFObjectHandle_private.hh>
15 #include <qpdf/QTC.hh> 16 #include <qpdf/QTC.hh>
16 #include <qpdf/QUtil.hh> 17 #include <qpdf/QUtil.hh>
17 #include <qpdf/SF_ASCII85Decode.hh> 18 #include <qpdf/SF_ASCII85Decode.hh>
@@ -22,6 +23,9 @@ @@ -22,6 +23,9 @@
22 23
23 #include <stdexcept> 24 #include <stdexcept>
24 25
  26 +using namespace std::literals;
  27 +using namespace qpdf;
  28 +
25 namespace 29 namespace
26 { 30 {
27 class SF_Crypt: public QPDFStreamFilter 31 class SF_Crypt: public QPDFStreamFilter
@@ -60,16 +64,24 @@ namespace @@ -60,16 +64,24 @@ namespace
60 class StreamBlobProvider 64 class StreamBlobProvider
61 { 65 {
62 public: 66 public:
63 - StreamBlobProvider(QPDF_Stream* stream, qpdf_stream_decode_level_e decode_level);  
64 - void operator()(Pipeline*); 67 + StreamBlobProvider(Stream stream, qpdf_stream_decode_level_e decode_level) :
  68 + stream(stream),
  69 + decode_level(decode_level)
  70 + {
  71 + }
  72 + void
  73 + operator()(Pipeline* p)
  74 + {
  75 + stream.pipeStreamData(p, nullptr, 0, decode_level, false, false);
  76 + }
65 77
66 private: 78 private:
67 - QPDF_Stream* stream; 79 + Stream stream;
68 qpdf_stream_decode_level_e decode_level; 80 qpdf_stream_decode_level_e decode_level;
69 }; 81 };
70 } // namespace 82 } // namespace
71 83
72 -std::map<std::string, std::string> QPDF_Stream::filter_abbreviations = { 84 +std::map<std::string, std::string> Stream::filter_abbreviations = {
73 // The PDF specification provides these filter abbreviations for use in inline images, but 85 // The PDF specification provides these filter abbreviations for use in inline images, but
74 // according to table H.1 in the pre-ISO versions of the PDF specification, Adobe Reader also 86 // according to table H.1 in the pre-ISO versions of the PDF specification, Adobe Reader also
75 // accepts them for stream filters. 87 // accepts them for stream filters.
@@ -82,8 +94,8 @@ std::map&lt;std::string, std::string&gt; QPDF_Stream::filter_abbreviations = { @@ -82,8 +94,8 @@ std::map&lt;std::string, std::string&gt; QPDF_Stream::filter_abbreviations = {
82 {"/DCT", "/DCTDecode"}, 94 {"/DCT", "/DCTDecode"},
83 }; 95 };
84 96
85 -std::map<std::string, std::function<std::shared_ptr<QPDFStreamFilter>()>>  
86 - QPDF_Stream::filter_factories = { 97 +std::map<std::string, std::function<std::shared_ptr<QPDFStreamFilter>()>> Stream::filter_factories =
  98 + {
87 {"/Crypt", []() { return std::make_shared<SF_Crypt>(); }}, 99 {"/Crypt", []() { return std::make_shared<SF_Crypt>(); }},
88 {"/FlateDecode", SF_FlateLzwDecode::flate_factory}, 100 {"/FlateDecode", SF_FlateLzwDecode::flate_factory},
89 {"/LZWDecode", SF_FlateLzwDecode::lzw_factory}, 101 {"/LZWDecode", SF_FlateLzwDecode::lzw_factory},
@@ -93,19 +105,6 @@ std::map&lt;std::string, std::function&lt;std::shared_ptr&lt;QPDFStreamFilter&gt;()&gt;&gt; @@ -93,19 +105,6 @@ std::map&lt;std::string, std::function&lt;std::shared_ptr&lt;QPDFStreamFilter&gt;()&gt;&gt;
93 {"/ASCIIHexDecode", SF_ASCIIHexDecode::factory}, 105 {"/ASCIIHexDecode", SF_ASCIIHexDecode::factory},
94 }; 106 };
95 107
96 -StreamBlobProvider::StreamBlobProvider(  
97 - QPDF_Stream* stream, qpdf_stream_decode_level_e decode_level) :  
98 - stream(stream),  
99 - decode_level(decode_level)  
100 -{  
101 -}  
102 -  
103 -void  
104 -StreamBlobProvider::operator()(Pipeline* p)  
105 -{  
106 - this->stream->pipeStreamData(p, nullptr, 0, decode_level, false, false);  
107 -}  
108 -  
109 QPDF_Stream::QPDF_Stream( 108 QPDF_Stream::QPDF_Stream(
110 QPDF* qpdf, QPDFObjGen og, QPDFObjectHandle stream_dict, qpdf_offset_t offset, size_t length) : 109 QPDF* qpdf, QPDFObjGen og, QPDFObjectHandle stream_dict, qpdf_offset_t offset, size_t length) :
111 QPDFValue(::ot_stream, qpdf, og), 110 QPDFValue(::ot_stream, qpdf, og),
@@ -137,25 +136,13 @@ QPDF_Stream::copy(bool shallow) @@ -137,25 +136,13 @@ QPDF_Stream::copy(bool shallow)
137 } 136 }
138 137
139 void 138 void
140 -QPDF_Stream::registerStreamFilter( 139 +Stream::registerStreamFilter(
141 std::string const& filter_name, std::function<std::shared_ptr<QPDFStreamFilter>()> factory) 140 std::string const& filter_name, std::function<std::shared_ptr<QPDFStreamFilter>()> factory)
142 { 141 {
143 filter_factories[filter_name] = factory; 142 filter_factories[filter_name] = factory;
144 } 143 }
145 144
146 void 145 void
147 -QPDF_Stream::setFilterOnWrite(bool val)  
148 -{  
149 - this->filter_on_write = val;  
150 -}  
151 -  
152 -bool  
153 -QPDF_Stream::getFilterOnWrite() const  
154 -{  
155 - return this->filter_on_write;  
156 -}  
157 -  
158 -void  
159 QPDF_Stream::disconnect() 146 QPDF_Stream::disconnect()
160 { 147 {
161 this->stream_provider = nullptr; 148 this->stream_provider = nullptr;
@@ -175,8 +162,20 @@ QPDF_Stream::writeJSON(int json_version, JSON::Writer&amp; jw) @@ -175,8 +162,20 @@ QPDF_Stream::writeJSON(int json_version, JSON::Writer&amp; jw)
175 stream_dict.writeJSON(json_version, jw); 162 stream_dict.writeJSON(json_version, jw);
176 } 163 }
177 164
  165 +QPDF_Stream*
  166 +Stream::stream() const
  167 +{
  168 + if (obj) {
  169 + if (auto s = obj->as<QPDF_Stream>()) {
  170 + return s;
  171 + }
  172 + }
  173 + throw std::runtime_error("operation for stream attempted on object of type dictionary");
  174 + return nullptr; // unreachable
  175 +}
  176 +
178 JSON 177 JSON
179 -QPDF_Stream::getStreamJSON( 178 +Stream::getStreamJSON(
180 int json_version, 179 int json_version,
181 qpdf_json_stream_data_e json_data, 180 qpdf_json_stream_data_e json_data,
182 qpdf_stream_decode_level_e decode_level, 181 qpdf_stream_decode_level_e decode_level,
@@ -190,13 +189,13 @@ QPDF_Stream::getStreamJSON( @@ -190,13 +189,13 @@ QPDF_Stream::getStreamJSON(
190 pb.finish(); 189 pb.finish();
191 auto result = JSON::parse(pb.getString()); 190 auto result = JSON::parse(pb.getString());
192 if (json_data == qpdf_sj_inline) { 191 if (json_data == qpdf_sj_inline) {
193 - result.addDictionaryMember("data", JSON::makeBlob(StreamBlobProvider(this, decode_level))); 192 + result.addDictionaryMember("data", JSON::makeBlob(StreamBlobProvider(*this, decode_level)));
194 } 193 }
195 return result; 194 return result;
196 } 195 }
197 196
198 qpdf_stream_decode_level_e 197 qpdf_stream_decode_level_e
199 -QPDF_Stream::writeStreamJSON( 198 +Stream::writeStreamJSON(
200 int json_version, 199 int json_version,
201 JSON::Writer& jw, 200 JSON::Writer& jw,
202 qpdf_json_stream_data_e json_data, 201 qpdf_json_stream_data_e json_data,
@@ -205,6 +204,7 @@ QPDF_Stream::writeStreamJSON( @@ -205,6 +204,7 @@ QPDF_Stream::writeStreamJSON(
205 std::string const& data_filename, 204 std::string const& data_filename,
206 bool no_data_key) 205 bool no_data_key)
207 { 206 {
  207 + auto s = stream();
208 switch (json_data) { 208 switch (json_data) {
209 case qpdf_sj_none: 209 case qpdf_sj_none:
210 case qpdf_sj_inline: 210 case qpdf_sj_inline:
@@ -232,7 +232,7 @@ QPDF_Stream::writeStreamJSON( @@ -232,7 +232,7 @@ QPDF_Stream::writeStreamJSON(
232 if (json_data == qpdf_sj_none) { 232 if (json_data == qpdf_sj_none) {
233 jw.writeNext(); 233 jw.writeNext();
234 jw << R"("dict": )"; 234 jw << R"("dict": )";
235 - stream_dict.writeJSON(json_version, jw); 235 + s->stream_dict.writeJSON(json_version, jw);
236 jw.writeEnd('}'); 236 jw.writeEnd('}');
237 return decode_level; 237 return decode_level;
238 } 238 }
@@ -264,7 +264,7 @@ QPDF_Stream::writeStreamJSON( @@ -264,7 +264,7 @@ QPDF_Stream::writeStreamJSON(
264 throw std::logic_error("QPDF_Stream: failed to get stream data"); 264 throw std::logic_error("QPDF_Stream: failed to get stream data");
265 } 265 }
266 // We can use unsafeShallowCopy because we are only touching top-level keys. 266 // We can use unsafeShallowCopy because we are only touching top-level keys.
267 - auto dict = stream_dict.unsafeShallowCopy(); 267 + auto dict = s->stream_dict.unsafeShallowCopy();
268 dict.removeKey("/Length"); 268 dict.removeKey("/Length");
269 if (filter && filtered) { 269 if (filter && filtered) {
270 dict.removeKey("/Filter"); 270 dict.removeKey("/Filter");
@@ -305,48 +305,19 @@ QPDF_Stream::setDictDescription() @@ -305,48 +305,19 @@ QPDF_Stream::setDictDescription()
305 } 305 }
306 } 306 }
307 307
308 -QPDFObjectHandle  
309 -QPDF_Stream::getDict() const  
310 -{  
311 - return this->stream_dict;  
312 -}  
313 -  
314 -bool  
315 -QPDF_Stream::isDataModified() const  
316 -{  
317 - return (!this->token_filters.empty());  
318 -}  
319 -  
320 -size_t  
321 -QPDF_Stream::getLength() const  
322 -{  
323 - return this->length;  
324 -}  
325 -  
326 -std::shared_ptr<Buffer>  
327 -QPDF_Stream::getStreamDataBuffer() const  
328 -{  
329 - return this->stream_data;  
330 -}  
331 -  
332 -std::shared_ptr<QPDFObjectHandle::StreamDataProvider>  
333 -QPDF_Stream::getStreamDataProvider() const  
334 -{  
335 - return this->stream_provider;  
336 -}  
337 -  
338 std::shared_ptr<Buffer> 308 std::shared_ptr<Buffer>
339 -QPDF_Stream::getStreamData(qpdf_stream_decode_level_e decode_level) 309 +Stream::getStreamData(qpdf_stream_decode_level_e decode_level)
340 { 310 {
  311 + auto s = stream();
341 Pl_Buffer buf("stream data buffer"); 312 Pl_Buffer buf("stream data buffer");
342 bool filtered; 313 bool filtered;
343 pipeStreamData(&buf, &filtered, 0, decode_level, false, false); 314 pipeStreamData(&buf, &filtered, 0, decode_level, false, false);
344 if (!filtered) { 315 if (!filtered) {
345 throw QPDFExc( 316 throw QPDFExc(
346 qpdf_e_unsupported, 317 qpdf_e_unsupported,
347 - qpdf->getFilename(), 318 + s->qpdf->getFilename(),
348 "", 319 "",
349 - this->parsed_offset, 320 + s->parsed_offset,
350 "getStreamData called on unfilterable stream"); 321 "getStreamData called on unfilterable stream");
351 } 322 }
352 QTC::TC("qpdf", "QPDF_Stream getStreamData"); 323 QTC::TC("qpdf", "QPDF_Stream getStreamData");
@@ -354,15 +325,16 @@ QPDF_Stream::getStreamData(qpdf_stream_decode_level_e decode_level) @@ -354,15 +325,16 @@ QPDF_Stream::getStreamData(qpdf_stream_decode_level_e decode_level)
354 } 325 }
355 326
356 std::shared_ptr<Buffer> 327 std::shared_ptr<Buffer>
357 -QPDF_Stream::getRawStreamData() 328 +Stream::getRawStreamData()
358 { 329 {
  330 + auto s = stream();
359 Pl_Buffer buf("stream data buffer"); 331 Pl_Buffer buf("stream data buffer");
360 if (!pipeStreamData(&buf, nullptr, 0, qpdf_dl_none, false, false)) { 332 if (!pipeStreamData(&buf, nullptr, 0, qpdf_dl_none, false, false)) {
361 throw QPDFExc( 333 throw QPDFExc(
362 qpdf_e_unsupported, 334 qpdf_e_unsupported,
363 - qpdf->getFilename(), 335 + s->qpdf->getFilename(),
364 "", 336 "",
365 - this->parsed_offset, 337 + s->parsed_offset,
366 "error getting raw stream data"); 338 "error getting raw stream data");
367 } 339 }
368 QTC::TC("qpdf", "QPDF_Stream getRawStreamData"); 340 QTC::TC("qpdf", "QPDF_Stream getRawStreamData");
@@ -370,14 +342,15 @@ QPDF_Stream::getRawStreamData() @@ -370,14 +342,15 @@ QPDF_Stream::getRawStreamData()
370 } 342 }
371 343
372 bool 344 bool
373 -QPDF_Stream::filterable( 345 +Stream::filterable(
374 std::vector<std::shared_ptr<QPDFStreamFilter>>& filters, 346 std::vector<std::shared_ptr<QPDFStreamFilter>>& filters,
375 bool& specialized_compression, 347 bool& specialized_compression,
376 bool& lossy_compression) 348 bool& lossy_compression)
377 { 349 {
  350 + auto s = stream();
378 // Check filters 351 // Check filters
379 352
380 - QPDFObjectHandle filter_obj = this->stream_dict.getKey("/Filter"); 353 + QPDFObjectHandle filter_obj = s->stream_dict.getKey("/Filter");
381 bool filters_okay = true; 354 bool filters_okay = true;
382 355
383 std::vector<std::string> filter_names; 356 std::vector<std::string> filter_names;
@@ -432,7 +405,7 @@ QPDF_Stream::filterable( @@ -432,7 +405,7 @@ QPDF_Stream::filterable(
432 405
433 // See if we can support any decode parameters that are specified. 406 // See if we can support any decode parameters that are specified.
434 407
435 - QPDFObjectHandle decode_obj = this->stream_dict.getKey("/DecodeParms"); 408 + QPDFObjectHandle decode_obj = s->stream_dict.getKey("/DecodeParms");
436 std::vector<QPDFObjectHandle> decode_parms; 409 std::vector<QPDFObjectHandle> decode_parms;
437 if (decode_obj.isArray() && (decode_obj.getArrayNItems() == 0)) { 410 if (decode_obj.isArray() && (decode_obj.getArrayNItems() == 0)) {
438 decode_obj = QPDFObjectHandle::newNull(); 411 decode_obj = QPDFObjectHandle::newNull();
@@ -479,7 +452,7 @@ QPDF_Stream::filterable( @@ -479,7 +452,7 @@ QPDF_Stream::filterable(
479 } 452 }
480 453
481 bool 454 bool
482 -QPDF_Stream::pipeStreamData( 455 +Stream::pipeStreamData(
483 Pipeline* pipeline, 456 Pipeline* pipeline,
484 bool* filterp, 457 bool* filterp,
485 int encode_flags, 458 int encode_flags,
@@ -487,6 +460,7 @@ QPDF_Stream::pipeStreamData( @@ -487,6 +460,7 @@ QPDF_Stream::pipeStreamData(
487 bool suppress_warnings, 460 bool suppress_warnings,
488 bool will_retry) 461 bool will_retry)
489 { 462 {
  463 + auto s = stream();
490 std::vector<std::shared_ptr<QPDFStreamFilter>> filters; 464 std::vector<std::shared_ptr<QPDFStreamFilter>> filters;
491 bool specialized_compression = false; 465 bool specialized_compression = false;
492 bool lossy_compression = false; 466 bool lossy_compression = false;
@@ -543,7 +517,7 @@ QPDF_Stream::pipeStreamData( @@ -543,7 +517,7 @@ QPDF_Stream::pipeStreamData(
543 pipeline = new_pipeline.get(); 517 pipeline = new_pipeline.get();
544 } 518 }
545 519
546 - for (auto iter = this->token_filters.rbegin(); iter != this->token_filters.rend(); ++iter) { 520 + for (auto iter = s->token_filters.rbegin(); iter != s->token_filters.rend(); ++iter) {
547 new_pipeline = 521 new_pipeline =
548 std::make_shared<Pl_QPDFTokenizer>("token filter", (*iter).get(), pipeline); 522 std::make_shared<Pl_QPDFTokenizer>("token filter", (*iter).get(), pipeline);
549 to_delete.push_back(new_pipeline); 523 to_delete.push_back(new_pipeline);
@@ -562,25 +536,25 @@ QPDF_Stream::pipeStreamData( @@ -562,25 +536,25 @@ QPDF_Stream::pipeStreamData(
562 } 536 }
563 } 537 }
564 538
565 - if (this->stream_data.get()) { 539 + if (s->stream_data.get()) {
566 QTC::TC("qpdf", "QPDF_Stream pipe replaced stream data"); 540 QTC::TC("qpdf", "QPDF_Stream pipe replaced stream data");
567 - pipeline->write(this->stream_data->getBuffer(), this->stream_data->getSize()); 541 + pipeline->write(s->stream_data->getBuffer(), s->stream_data->getSize());
568 pipeline->finish(); 542 pipeline->finish();
569 - } else if (this->stream_provider.get()) { 543 + } else if (s->stream_provider.get()) {
570 Pl_Count count("stream provider count", pipeline); 544 Pl_Count count("stream provider count", pipeline);
571 - if (this->stream_provider->supportsRetry()) {  
572 - if (!this->stream_provider->provideStreamData(  
573 - og, &count, suppress_warnings, will_retry)) { 545 + if (s->stream_provider->supportsRetry()) {
  546 + if (!s->stream_provider->provideStreamData(
  547 + s->og, &count, suppress_warnings, will_retry)) {
574 filter = false; 548 filter = false;
575 success = false; 549 success = false;
576 } 550 }
577 } else { 551 } else {
578 - this->stream_provider->provideStreamData(og, &count); 552 + s->stream_provider->provideStreamData(s->og, &count);
579 } 553 }
580 qpdf_offset_t actual_length = count.getCount(); 554 qpdf_offset_t actual_length = count.getCount();
581 qpdf_offset_t desired_length = 0; 555 qpdf_offset_t desired_length = 0;
582 - if (success && this->stream_dict.hasKey("/Length")) {  
583 - desired_length = this->stream_dict.getKey("/Length").getIntValue(); 556 + if (success && s->stream_dict.hasKey("/Length")) {
  557 + desired_length = s->stream_dict.getKey("/Length").getIntValue();
584 if (actual_length == desired_length) { 558 if (actual_length == desired_length) {
585 QTC::TC("qpdf", "QPDF_Stream pipe use stream provider"); 559 QTC::TC("qpdf", "QPDF_Stream pipe use stream provider");
586 } else { 560 } else {
@@ -588,25 +562,25 @@ QPDF_Stream::pipeStreamData( @@ -588,25 +562,25 @@ QPDF_Stream::pipeStreamData(
588 // This would be caused by programmer error on the part of a library user, not by 562 // This would be caused by programmer error on the part of a library user, not by
589 // invalid input data. 563 // invalid input data.
590 throw std::runtime_error( 564 throw std::runtime_error(
591 - "stream data provider for " + og.unparse(' ') + " provided " + 565 + "stream data provider for " + s->og.unparse(' ') + " provided " +
592 std::to_string(actual_length) + " bytes instead of expected " + 566 std::to_string(actual_length) + " bytes instead of expected " +
593 std::to_string(desired_length) + " bytes"); 567 std::to_string(desired_length) + " bytes");
594 } 568 }
595 } else if (success) { 569 } else if (success) {
596 QTC::TC("qpdf", "QPDF_Stream provider length not provided"); 570 QTC::TC("qpdf", "QPDF_Stream provider length not provided");
597 - this->stream_dict.replaceKey("/Length", QPDFObjectHandle::newInteger(actual_length)); 571 + s->stream_dict.replaceKey("/Length", QPDFObjectHandle::newInteger(actual_length));
598 } 572 }
599 - } else if (this->parsed_offset == 0) { 573 + } else if (s->parsed_offset == 0) {
600 QTC::TC("qpdf", "QPDF_Stream pipe no stream data"); 574 QTC::TC("qpdf", "QPDF_Stream pipe no stream data");
601 throw std::logic_error("pipeStreamData called for stream with no data"); 575 throw std::logic_error("pipeStreamData called for stream with no data");
602 } else { 576 } else {
603 QTC::TC("qpdf", "QPDF_Stream pipe original stream data"); 577 QTC::TC("qpdf", "QPDF_Stream pipe original stream data");
604 if (!QPDF::Pipe::pipeStreamData( 578 if (!QPDF::Pipe::pipeStreamData(
605 - this->qpdf,  
606 - og,  
607 - this->parsed_offset,  
608 - this->length,  
609 - this->stream_dict, 579 + s->qpdf,
  580 + s->og,
  581 + s->parsed_offset,
  582 + s->length,
  583 + s->stream_dict,
610 pipeline, 584 pipeline,
611 suppress_warnings, 585 suppress_warnings,
612 will_retry)) { 586 will_retry)) {
@@ -634,60 +608,52 @@ QPDF_Stream::pipeStreamData( @@ -634,60 +608,52 @@ QPDF_Stream::pipeStreamData(
634 } 608 }
635 609
636 void 610 void
637 -QPDF_Stream::replaceStreamData( 611 +Stream::replaceStreamData(
638 std::shared_ptr<Buffer> data, 612 std::shared_ptr<Buffer> data,
639 QPDFObjectHandle const& filter, 613 QPDFObjectHandle const& filter,
640 QPDFObjectHandle const& decode_parms) 614 QPDFObjectHandle const& decode_parms)
641 { 615 {
642 - this->stream_data = data;  
643 - this->stream_provider = nullptr; 616 + auto s = stream();
  617 + s->stream_data = data;
  618 + s->stream_provider = nullptr;
644 replaceFilterData(filter, decode_parms, data->getSize()); 619 replaceFilterData(filter, decode_parms, data->getSize());
645 } 620 }
646 621
647 void 622 void
648 -QPDF_Stream::replaceStreamData( 623 +Stream::replaceStreamData(
649 std::shared_ptr<QPDFObjectHandle::StreamDataProvider> provider, 624 std::shared_ptr<QPDFObjectHandle::StreamDataProvider> provider,
650 QPDFObjectHandle const& filter, 625 QPDFObjectHandle const& filter,
651 QPDFObjectHandle const& decode_parms) 626 QPDFObjectHandle const& decode_parms)
652 { 627 {
653 - this->stream_provider = provider;  
654 - this->stream_data = nullptr; 628 + auto s = stream();
  629 + s->stream_provider = provider;
  630 + s->stream_data = nullptr;
655 replaceFilterData(filter, decode_parms, 0); 631 replaceFilterData(filter, decode_parms, 0);
656 } 632 }
657 633
658 void 634 void
659 -QPDF_Stream::addTokenFilter(std::shared_ptr<QPDFObjectHandle::TokenFilter> token_filter)  
660 -{  
661 - this->token_filters.push_back(token_filter);  
662 -}  
663 -  
664 -void  
665 -QPDF_Stream::replaceFilterData( 635 +Stream::replaceFilterData(
666 QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms, size_t length) 636 QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms, size_t length)
667 { 637 {
  638 + auto s = stream();
668 if (filter) { 639 if (filter) {
669 - stream_dict.replaceKey("/Filter", filter); 640 + s->stream_dict.replaceKey("/Filter", filter);
670 } 641 }
671 if (decode_parms) { 642 if (decode_parms) {
672 - stream_dict.replaceKey("/DecodeParms", decode_parms); 643 + s->stream_dict.replaceKey("/DecodeParms", decode_parms);
673 } 644 }
674 if (length == 0) { 645 if (length == 0) {
675 QTC::TC("qpdf", "QPDF_Stream unknown stream length"); 646 QTC::TC("qpdf", "QPDF_Stream unknown stream length");
676 - stream_dict.removeKey("/Length"); 647 + s->stream_dict.removeKey("/Length");
677 } else { 648 } else {
678 - stream_dict.replaceKey("/Length", QPDFObjectHandle::newInteger(QIntC::to_longlong(length))); 649 + s->stream_dict.replaceKey(
  650 + "/Length", QPDFObjectHandle::newInteger(QIntC::to_longlong(length)));
679 } 651 }
680 } 652 }
681 653
682 void 654 void
683 -QPDF_Stream::replaceDict(QPDFObjectHandle const& new_dict)  
684 -{  
685 - this->stream_dict = new_dict;  
686 - setDictDescription();  
687 -}  
688 -  
689 -void  
690 -QPDF_Stream::warn(std::string const& message) 655 +Stream::warn(std::string const& message)
691 { 656 {
692 - this->qpdf->warn(qpdf_e_damaged_pdf, "", this->parsed_offset, message); 657 + auto s = stream();
  658 + s->qpdf->warn(qpdf_e_damaged_pdf, "", s->parsed_offset, message);
693 } 659 }
libqpdf/QPDF_json.cc
@@ -5,6 +5,7 @@ @@ -5,6 +5,7 @@
5 #include <qpdf/Pl_Base64.hh> 5 #include <qpdf/Pl_Base64.hh>
6 #include <qpdf/Pl_StdioFile.hh> 6 #include <qpdf/Pl_StdioFile.hh>
7 #include <qpdf/QIntC.hh> 7 #include <qpdf/QIntC.hh>
  8 +#include <qpdf/QPDFObjectHandle_private.hh>
8 #include <qpdf/QPDFObject_private.hh> 9 #include <qpdf/QPDFObject_private.hh>
9 #include <qpdf/QPDFValue.hh> 10 #include <qpdf/QPDFValue.hh>
10 #include <qpdf/QPDF_Null.hh> 11 #include <qpdf/QPDF_Null.hh>
@@ -821,7 +822,7 @@ void @@ -821,7 +822,7 @@ void
821 writeJSONStreamFile( 822 writeJSONStreamFile(
822 int version, 823 int version,
823 JSON::Writer& jw, 824 JSON::Writer& jw,
824 - QPDF_Stream& stream, 825 + qpdf::Stream& stream,
825 int id, 826 int id,
826 qpdf_stream_decode_level_e decode_level, 827 qpdf_stream_decode_level_e decode_level,
827 std::string const& file_prefix) 828 std::string const& file_prefix)
@@ -894,13 +895,13 @@ QPDF::writeJSON( @@ -894,13 +895,13 @@ QPDF::writeJSON(
894 } else { 895 } else {
895 jw << "\n },\n \"" << key; 896 jw << "\n },\n \"" << key;
896 } 897 }
897 - if (auto* stream = obj.getObjectPtr()->as<QPDF_Stream>()) { 898 + if (auto stream = obj.as_stream()) {
898 jw << "\": {\n \"stream\": "; 899 jw << "\": {\n \"stream\": ";
899 if (json_stream_data == qpdf_sj_file) { 900 if (json_stream_data == qpdf_sj_file) {
900 writeJSONStreamFile( 901 writeJSONStreamFile(
901 - version, jw, *stream, og.getObj(), decode_level, file_prefix); 902 + version, jw, stream, og.getObj(), decode_level, file_prefix);
902 } else { 903 } else {
903 - stream->writeStreamJSON( 904 + stream.writeStreamJSON(
904 version, jw, json_stream_data, decode_level, nullptr, ""); 905 version, jw, json_stream_data, decode_level, nullptr, "");
905 } 906 }
906 } else { 907 } else {
libqpdf/qpdf/QPDFObjectHandle_private.hh
@@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
6 #include <qpdf/QPDFObject_private.hh> 6 #include <qpdf/QPDFObject_private.hh>
7 #include <qpdf/QPDF_Array.hh> 7 #include <qpdf/QPDF_Array.hh>
8 #include <qpdf/QPDF_Dictionary.hh> 8 #include <qpdf/QPDF_Dictionary.hh>
  9 +#include <qpdf/QPDF_Stream.hh>
9 10
10 namespace qpdf 11 namespace qpdf
11 { 12 {
@@ -80,6 +81,123 @@ namespace qpdf @@ -80,6 +81,123 @@ namespace qpdf
80 } 81 }
81 }; 82 };
82 83
  84 + class Stream final: public BaseHandle
  85 + {
  86 + public:
  87 + explicit Stream(std::shared_ptr<QPDFObject> const& obj) :
  88 + BaseHandle(obj)
  89 + {
  90 + }
  91 +
  92 + explicit Stream(std::shared_ptr<QPDFObject>&& obj) :
  93 + BaseHandle(std::move(obj))
  94 + {
  95 + }
  96 +
  97 + QPDFObjectHandle
  98 + getDict() const
  99 + {
  100 + return stream()->stream_dict;
  101 + }
  102 + bool
  103 + isDataModified() const
  104 + {
  105 + return !stream()->token_filters.empty();
  106 + }
  107 + void
  108 + setFilterOnWrite(bool val)
  109 + {
  110 + stream()->filter_on_write = val;
  111 + }
  112 + bool
  113 + getFilterOnWrite() const
  114 + {
  115 + return stream()->filter_on_write;
  116 + }
  117 +
  118 + // Methods to help QPDF copy foreign streams
  119 + size_t
  120 + getLength() const
  121 + {
  122 + return stream()->length;
  123 + }
  124 + std::shared_ptr<Buffer>
  125 + getStreamDataBuffer() const
  126 + {
  127 + return stream()->stream_data;
  128 + }
  129 + std::shared_ptr<QPDFObjectHandle::StreamDataProvider>
  130 + getStreamDataProvider() const
  131 + {
  132 + return stream()->stream_provider;
  133 + }
  134 +
  135 + // See comments in QPDFObjectHandle.hh for these methods.
  136 + bool pipeStreamData(
  137 + Pipeline* p,
  138 + bool* tried_filtering,
  139 + int encode_flags,
  140 + qpdf_stream_decode_level_e decode_level,
  141 + bool suppress_warnings,
  142 + bool will_retry);
  143 + std::shared_ptr<Buffer> getStreamData(qpdf_stream_decode_level_e level);
  144 + std::shared_ptr<Buffer> getRawStreamData();
  145 + void replaceStreamData(
  146 + std::shared_ptr<Buffer> data,
  147 + QPDFObjectHandle const& filter,
  148 + QPDFObjectHandle const& decode_parms);
  149 + void replaceStreamData(
  150 + std::shared_ptr<QPDFObjectHandle::StreamDataProvider> provider,
  151 + QPDFObjectHandle const& filter,
  152 + QPDFObjectHandle const& decode_parms);
  153 + void
  154 + addTokenFilter(std::shared_ptr<QPDFObjectHandle::TokenFilter> token_filter)
  155 + {
  156 + stream()->token_filters.emplace_back(token_filter);
  157 + }
  158 + JSON getStreamJSON(
  159 + int json_version,
  160 + qpdf_json_stream_data_e json_data,
  161 + qpdf_stream_decode_level_e decode_level,
  162 + Pipeline* p,
  163 + std::string const& data_filename);
  164 + qpdf_stream_decode_level_e writeStreamJSON(
  165 + int json_version,
  166 + JSON::Writer& jw,
  167 + qpdf_json_stream_data_e json_data,
  168 + qpdf_stream_decode_level_e decode_level,
  169 + Pipeline* p,
  170 + std::string const& data_filename,
  171 + bool no_data_key = false);
  172 + void
  173 + replaceDict(QPDFObjectHandle const& new_dict)
  174 + {
  175 + auto s = stream();
  176 + s->stream_dict = new_dict;
  177 + s->setDictDescription();
  178 + }
  179 +
  180 + static void registerStreamFilter(
  181 + std::string const& filter_name,
  182 + std::function<std::shared_ptr<QPDFStreamFilter>()> factory);
  183 +
  184 + private:
  185 + QPDF_Stream* stream() const;
  186 +
  187 + bool filterable(
  188 + std::vector<std::shared_ptr<QPDFStreamFilter>>& filters,
  189 + bool& specialized_compression,
  190 + bool& lossy_compression);
  191 + void replaceFilterData(
  192 + QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms, size_t length);
  193 +
  194 + void warn(std::string const& message);
  195 +
  196 + static std::map<std::string, std::string> filter_abbreviations;
  197 + static std::map<std::string, std::function<std::shared_ptr<QPDFStreamFilter>()>>
  198 + filter_factories;
  199 + };
  200 +
83 inline qpdf_object_type_e 201 inline qpdf_object_type_e
84 BaseHandle::type_code() const 202 BaseHandle::type_code() const
85 { 203 {
@@ -98,7 +216,7 @@ QPDFObjectHandle::as_array(qpdf::typed options) const @@ -98,7 +216,7 @@ QPDFObjectHandle::as_array(qpdf::typed options) const
98 (options & qpdf::optional && type_code() == ::ot_null)) { 216 (options & qpdf::optional && type_code() == ::ot_null)) {
99 return qpdf::Array(obj); 217 return qpdf::Array(obj);
100 } 218 }
101 - return qpdf::Array({}); 219 + return qpdf::Array(std::shared_ptr<QPDFObject>());
102 } 220 }
103 221
104 inline qpdf::Dictionary 222 inline qpdf::Dictionary
@@ -114,4 +232,17 @@ QPDFObjectHandle::as_dictionary(qpdf::typed options) const @@ -114,4 +232,17 @@ QPDFObjectHandle::as_dictionary(qpdf::typed options) const
114 return qpdf::Dictionary(std::shared_ptr<QPDFObject>()); 232 return qpdf::Dictionary(std::shared_ptr<QPDFObject>());
115 } 233 }
116 234
  235 +inline qpdf::Stream
  236 +QPDFObjectHandle::as_stream(qpdf::typed options) const
  237 +{
  238 + if (options & qpdf::any_flag || type_code() == ::ot_stream ||
  239 + (options & qpdf::optional && type_code() == ::ot_null)) {
  240 + return qpdf::Stream(obj);
  241 + }
  242 + if (options & qpdf::error) {
  243 + assertType("stream", false);
  244 + }
  245 + return qpdf::Stream(std::shared_ptr<QPDFObject>());
  246 +}
  247 +
117 #endif // OBJECTHANDLE_PRIVATE_HH 248 #endif // OBJECTHANDLE_PRIVATE_HH
libqpdf/qpdf/QPDF_Stream.hh
@@ -4,6 +4,7 @@ @@ -4,6 +4,7 @@
4 #include <qpdf/Types.h> 4 #include <qpdf/Types.h>
5 5
6 #include <qpdf/QPDFObjectHandle.hh> 6 #include <qpdf/QPDFObjectHandle.hh>
  7 +#include <qpdf/QPDFObject_private.hh>
7 #include <qpdf/QPDFStreamFilter.hh> 8 #include <qpdf/QPDFStreamFilter.hh>
8 #include <qpdf/QPDFValue.hh> 9 #include <qpdf/QPDFValue.hh>
9 10
@@ -25,69 +26,15 @@ class QPDF_Stream final: public QPDFValue @@ -25,69 +26,15 @@ class QPDF_Stream final: public QPDFValue
25 void setDescription( 26 void setDescription(
26 QPDF*, std::shared_ptr<QPDFValue::Description>& description, qpdf_offset_t offset) final; 27 QPDF*, std::shared_ptr<QPDFValue::Description>& description, qpdf_offset_t offset) final;
27 void disconnect() final; 28 void disconnect() final;
28 - QPDFObjectHandle getDict() const;  
29 - bool isDataModified() const;  
30 - void setFilterOnWrite(bool);  
31 - bool getFilterOnWrite() const;  
32 -  
33 - // Methods to help QPDF copy foreign streams  
34 - size_t getLength() const;  
35 - std::shared_ptr<Buffer> getStreamDataBuffer() const;  
36 - std::shared_ptr<QPDFObjectHandle::StreamDataProvider> getStreamDataProvider() const;  
37 -  
38 - // See comments in QPDFObjectHandle.hh for these methods.  
39 - bool pipeStreamData(  
40 - Pipeline*,  
41 - bool* tried_filtering,  
42 - int encode_flags,  
43 - qpdf_stream_decode_level_e decode_level,  
44 - bool suppress_warnings,  
45 - bool will_retry);  
46 - std::shared_ptr<Buffer> getStreamData(qpdf_stream_decode_level_e);  
47 - std::shared_ptr<Buffer> getRawStreamData();  
48 - void replaceStreamData(  
49 - std::shared_ptr<Buffer> data,  
50 - QPDFObjectHandle const& filter,  
51 - QPDFObjectHandle const& decode_parms);  
52 - void replaceStreamData(  
53 - std::shared_ptr<QPDFObjectHandle::StreamDataProvider> provider,  
54 - QPDFObjectHandle const& filter,  
55 - QPDFObjectHandle const& decode_parms);  
56 - void addTokenFilter(std::shared_ptr<QPDFObjectHandle::TokenFilter> token_filter);  
57 - JSON getStreamJSON(  
58 - int json_version,  
59 - qpdf_json_stream_data_e json_data,  
60 - qpdf_stream_decode_level_e decode_level,  
61 - Pipeline* p,  
62 - std::string const& data_filename);  
63 - qpdf_stream_decode_level_e writeStreamJSON(  
64 - int json_version,  
65 - JSON::Writer& jw,  
66 - qpdf_json_stream_data_e json_data,  
67 - qpdf_stream_decode_level_e decode_level,  
68 - Pipeline* p,  
69 - std::string const& data_filename,  
70 - bool no_data_key = false);  
71 -  
72 - void replaceDict(QPDFObjectHandle const& new_dict);  
73 -  
74 - static void registerStreamFilter(  
75 - std::string const& filter_name, std::function<std::shared_ptr<QPDFStreamFilter>()> factory);  
76 29
77 private: 30 private:
  31 + friend class qpdf::Stream;
  32 +
78 QPDF_Stream( 33 QPDF_Stream(
79 QPDF*, QPDFObjGen og, QPDFObjectHandle stream_dict, qpdf_offset_t offset, size_t length); 34 QPDF*, QPDFObjGen og, QPDFObjectHandle stream_dict, qpdf_offset_t offset, size_t length);
80 - static std::map<std::string, std::string> filter_abbreviations;  
81 - static std::map<std::string, std::function<std::shared_ptr<QPDFStreamFilter>()>>  
82 - filter_factories;  
83 35
84 void replaceFilterData( 36 void replaceFilterData(
85 QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms, size_t length); 37 QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms, size_t length);
86 - bool filterable(  
87 - std::vector<std::shared_ptr<QPDFStreamFilter>>& filters,  
88 - bool& specialized_compression,  
89 - bool& lossy_compression);  
90 - void warn(std::string const& message);  
91 void setDictDescription(); 38 void setDictDescription();
92 39
93 bool filter_on_write; 40 bool filter_on_write;