Commit 9a06fc541ce00361f12f6231b2f7556615cbccb7
1 parent
ab5a01c6
ready to implement replacement stream data
git-svn-id: svn+q:///qpdf/trunk@987 71b93d88-0707-0410-a8cf-f5a4172ac649
Showing
6 changed files
with
132 additions
and
4 deletions
include/qpdf/QPDFObjectHandle.hh
| @@ -152,6 +152,9 @@ class QPDFObjectHandle | @@ -152,6 +152,9 @@ class QPDFObjectHandle | ||
| 152 | // Remove key, doing nothing if key does not exist | 152 | // Remove key, doing nothing if key does not exist |
| 153 | QPDF_DLL | 153 | QPDF_DLL |
| 154 | void removeKey(std::string const& key); | 154 | void removeKey(std::string const& key); |
| 155 | + // If the object is null, remove the key. Otherwise, replace it. | ||
| 156 | + QPDF_DLL | ||
| 157 | + void replaceOrRemoveKey(std::string const& key, QPDFObjectHandle); | ||
| 155 | 158 | ||
| 156 | // Methods for stream objects | 159 | // Methods for stream objects |
| 157 | QPDF_DLL | 160 | QPDF_DLL |
| @@ -183,6 +186,64 @@ class QPDFObjectHandle | @@ -183,6 +186,64 @@ class QPDFObjectHandle | ||
| 183 | bool pipeStreamData(Pipeline*, bool filter, | 186 | bool pipeStreamData(Pipeline*, bool filter, |
| 184 | bool normalize, bool compress); | 187 | bool normalize, bool compress); |
| 185 | 188 | ||
| 189 | + // Replace this stream's stream data with the given data buffer, | ||
| 190 | + // and replace the /Filter and /DecodeParms keys in the stream | ||
| 191 | + // dictionary with the given values. (If either value is empty, | ||
| 192 | + // the corresponding key is removed.) The stream's /Length key is | ||
| 193 | + // replaced with the length of the data buffer. The stream is | ||
| 194 | + // interpreted as if the data read from the file, after any | ||
| 195 | + // decryption filters have been applied, is as presented. | ||
| 196 | + QPDF_DLL | ||
| 197 | + void replaceStreamData(PointerHolder<Buffer> data, | ||
| 198 | + QPDFObjectHandle filter, | ||
| 199 | + QPDFObjectHandle decode_parms); | ||
| 200 | + class StreamDataHandler | ||
| 201 | + { | ||
| 202 | + public: | ||
| 203 | + QPDF_DLL | ||
| 204 | + virtual ~StreamDataHandler() | ||
| 205 | + { | ||
| 206 | + } | ||
| 207 | + | ||
| 208 | + // See replaceStreamData(StreamDataHandler) below for a | ||
| 209 | + // description of how to override this function. | ||
| 210 | + virtual void | ||
| 211 | + replaceStreamData(Buffer const& in_data, | ||
| 212 | + std::string const& in_filter, | ||
| 213 | + std::string const& in_decode_parms, | ||
| 214 | + bool filtered, | ||
| 215 | + Buffer& out_data, | ||
| 216 | + std::string& out_filter, | ||
| 217 | + std::string& out_decode_parms, | ||
| 218 | + bool& persist) = 0; | ||
| 219 | + }; | ||
| 220 | + // Provide a hook for doing dynamic replacement of the stream's | ||
| 221 | + // data. When the stream's data is accessed either with | ||
| 222 | + // pipeStreamData or with getStreamData, if the stream doesn't | ||
| 223 | + // already have replacement data, an attempt is first made to | ||
| 224 | + // filter the stream's original data. If the attempt is | ||
| 225 | + // successful, the stream's filtered original data is passed to | ||
| 226 | + // the handler as in_data, and filtered is true. If the original | ||
| 227 | + // data cannot be processed, then in_data is the original raw data | ||
| 228 | + // (after any decryption filters have been applied) and filtered | ||
| 229 | + // is false. If the original input data has no filters applied, | ||
| 230 | + // the filtered is true. This way, if filtered is true, the | ||
| 231 | + // caller knows that in_data contains the fully filtered data. | ||
| 232 | + // The handler then provides replacement data, /Filter, and | ||
| 233 | + // /DecodeParms (handled is in the simpler form of | ||
| 234 | + // replaceStreamData above). If the persist argument is set to | ||
| 235 | + // true, then the replacement data is stored in the stream object | ||
| 236 | + // where it will be used on subsequent attempts to retrieve the | ||
| 237 | + // data (rather than calling the handler). If persist is set to | ||
| 238 | + // false, then the data will be used that one time and not saved. | ||
| 239 | + // In that case, the handler will be invoked again if the stream | ||
| 240 | + // data is accessed another time. Writing a handler that sets | ||
| 241 | + // persist to true essentially allows delaying the computation of | ||
| 242 | + // the stream data, while setting it to false reduces the amount | ||
| 243 | + // of memory that is used. | ||
| 244 | + QPDF_DLL | ||
| 245 | + void replaceStreamData(PointerHolder<StreamDataHandler> dh); | ||
| 246 | + | ||
| 186 | // return 0 for direct objects | 247 | // return 0 for direct objects |
| 187 | QPDF_DLL | 248 | QPDF_DLL |
| 188 | int getObjectID() const; | 249 | int getObjectID() const; |
libqpdf/QPDFObjectHandle.cc
| @@ -319,6 +319,15 @@ QPDFObjectHandle::removeKey(std::string const& key) | @@ -319,6 +319,15 @@ QPDFObjectHandle::removeKey(std::string const& key) | ||
| 319 | return dynamic_cast<QPDF_Dictionary*>(obj.getPointer())->removeKey(key); | 319 | return dynamic_cast<QPDF_Dictionary*>(obj.getPointer())->removeKey(key); |
| 320 | } | 320 | } |
| 321 | 321 | ||
| 322 | +void | ||
| 323 | +QPDFObjectHandle::replaceOrRemoveKey(std::string const& key, | ||
| 324 | + QPDFObjectHandle value) | ||
| 325 | +{ | ||
| 326 | + assertType("Dictionary", isDictionary()); | ||
| 327 | + return dynamic_cast<QPDF_Dictionary*>( | ||
| 328 | + obj.getPointer())->replaceOrRemoveKey(key, value); | ||
| 329 | +} | ||
| 330 | + | ||
| 322 | // Stream accessors | 331 | // Stream accessors |
| 323 | QPDFObjectHandle | 332 | QPDFObjectHandle |
| 324 | QPDFObjectHandle::getDict() | 333 | QPDFObjectHandle::getDict() |
| @@ -343,6 +352,23 @@ QPDFObjectHandle::pipeStreamData(Pipeline* p, bool filter, | @@ -343,6 +352,23 @@ QPDFObjectHandle::pipeStreamData(Pipeline* p, bool filter, | ||
| 343 | p, filter, normalize, compress); | 352 | p, filter, normalize, compress); |
| 344 | } | 353 | } |
| 345 | 354 | ||
| 355 | +void | ||
| 356 | +QPDFObjectHandle::replaceStreamData(PointerHolder<Buffer> data, | ||
| 357 | + QPDFObjectHandle filter, | ||
| 358 | + QPDFObjectHandle decode_parms) | ||
| 359 | +{ | ||
| 360 | + assertType("Stream", isStream()); | ||
| 361 | + dynamic_cast<QPDF_Stream*>(obj.getPointer())->replaceStreamData( | ||
| 362 | + data, filter, decode_parms); | ||
| 363 | +} | ||
| 364 | + | ||
| 365 | +void | ||
| 366 | +QPDFObjectHandle::replaceStreamData(PointerHolder<StreamDataHandler> dh) | ||
| 367 | +{ | ||
| 368 | + assertType("Stream", isStream()); | ||
| 369 | + dynamic_cast<QPDF_Stream*>(obj.getPointer())->replaceStreamData(dh); | ||
| 370 | +} | ||
| 371 | + | ||
| 346 | int | 372 | int |
| 347 | QPDFObjectHandle::getObjectID() const | 373 | QPDFObjectHandle::getObjectID() const |
| 348 | { | 374 | { |
libqpdf/QPDF_Dictionary.cc
| @@ -92,3 +92,17 @@ QPDF_Dictionary::removeKey(std::string const& key) | @@ -92,3 +92,17 @@ QPDF_Dictionary::removeKey(std::string const& key) | ||
| 92 | // no-op if key does not exist | 92 | // no-op if key does not exist |
| 93 | this->items.erase(key); | 93 | this->items.erase(key); |
| 94 | } | 94 | } |
| 95 | + | ||
| 96 | +void | ||
| 97 | +QPDF_Dictionary::replaceOrRemoveKey(std::string const& key, | ||
| 98 | + QPDFObjectHandle value) | ||
| 99 | +{ | ||
| 100 | + if (value.isNull()) | ||
| 101 | + { | ||
| 102 | + removeKey(key); | ||
| 103 | + } | ||
| 104 | + else | ||
| 105 | + { | ||
| 106 | + replaceKey(key, value); | ||
| 107 | + } | ||
| 108 | +} |
libqpdf/QPDF_Stream.cc
| @@ -319,9 +319,30 @@ QPDF_Stream::pipeStreamData(Pipeline* pipeline, bool filter, | @@ -319,9 +319,30 @@ QPDF_Stream::pipeStreamData(Pipeline* pipeline, bool filter, | ||
| 319 | } | 319 | } |
| 320 | } | 320 | } |
| 321 | 321 | ||
| 322 | + // XXX handle stream_data and stream_data_handler | ||
| 322 | QPDF::Pipe::pipeStreamData(this->qpdf, this->objid, this->generation, | 323 | QPDF::Pipe::pipeStreamData(this->qpdf, this->objid, this->generation, |
| 323 | this->offset, this->length, | 324 | this->offset, this->length, |
| 324 | this->stream_dict, pipeline); | 325 | this->stream_dict, pipeline); |
| 325 | 326 | ||
| 326 | return filter; | 327 | return filter; |
| 327 | } | 328 | } |
| 329 | + | ||
| 330 | +void | ||
| 331 | +QPDF_Stream::replaceStreamData(PointerHolder<Buffer> data, | ||
| 332 | + QPDFObjectHandle filter, | ||
| 333 | + QPDFObjectHandle decode_parms) | ||
| 334 | +{ | ||
| 335 | + this->stream_data = data; | ||
| 336 | + this->stream_dict.replaceOrRemoveKey("/Filter", filter); | ||
| 337 | + this->stream_dict.replaceOrRemoveKey("/DecodeParms", decode_parms); | ||
| 338 | + this->stream_dict.replaceKey("/Length", | ||
| 339 | + QPDFObjectHandle::newInteger( | ||
| 340 | + data.getPointer()->getSize())); | ||
| 341 | +} | ||
| 342 | + | ||
| 343 | +void | ||
| 344 | +QPDF_Stream::replaceStreamData( | ||
| 345 | + PointerHolder<QPDFObjectHandle::StreamDataHandler> dh) | ||
| 346 | +{ | ||
| 347 | + this->stream_data_handler = dh; | ||
| 348 | +} |
libqpdf/qpdf/QPDF_Dictionary.hh
| @@ -26,6 +26,8 @@ class QPDF_Dictionary: public QPDFObject | @@ -26,6 +26,8 @@ class QPDF_Dictionary: public QPDFObject | ||
| 26 | void replaceKey(std::string const& key, QPDFObjectHandle const&); | 26 | void replaceKey(std::string const& key, QPDFObjectHandle const&); |
| 27 | // Remove key, doing nothing if key does not exist | 27 | // Remove key, doing nothing if key does not exist |
| 28 | void removeKey(std::string const& key); | 28 | void removeKey(std::string const& key); |
| 29 | + // If object is null, replace key; otherwise, remove key | ||
| 30 | + void replaceOrRemoveKey(std::string const& key, QPDFObjectHandle); | ||
| 29 | 31 | ||
| 30 | protected: | 32 | protected: |
| 31 | virtual void releaseResolved(); | 33 | virtual void releaseResolved(); |
libqpdf/qpdf/QPDF_Stream.hh
| @@ -18,24 +18,28 @@ class QPDF_Stream: public QPDFObject | @@ -18,24 +18,28 @@ class QPDF_Stream: public QPDFObject | ||
| 18 | virtual std::string unparse(); | 18 | virtual std::string unparse(); |
| 19 | QPDFObjectHandle getDict() const; | 19 | QPDFObjectHandle getDict() const; |
| 20 | 20 | ||
| 21 | - // See comments in QPDFObjectHandle.hh | 21 | + // See comments in QPDFObjectHandle.hh for these methods. |
| 22 | bool pipeStreamData(Pipeline*, bool filter, | 22 | bool pipeStreamData(Pipeline*, bool filter, |
| 23 | bool normalize, bool compress); | 23 | bool normalize, bool compress); |
| 24 | - | ||
| 25 | - // See comments in QPDFObjectHandle.hh | ||
| 26 | PointerHolder<Buffer> getStreamData(); | 24 | PointerHolder<Buffer> getStreamData(); |
| 25 | + void replaceStreamData(PointerHolder<Buffer> data, | ||
| 26 | + QPDFObjectHandle filter, | ||
| 27 | + QPDFObjectHandle decode_parms); | ||
| 28 | + void replaceStreamData( | ||
| 29 | + PointerHolder<QPDFObjectHandle::StreamDataHandler> dh); | ||
| 27 | 30 | ||
| 28 | private: | 31 | private: |
| 29 | bool filterable(std::vector<std::string>& filters, | 32 | bool filterable(std::vector<std::string>& filters, |
| 30 | int& predictor, int& columns, bool& early_code_change); | 33 | int& predictor, int& columns, bool& early_code_change); |
| 31 | 34 | ||
| 32 | - | ||
| 33 | QPDF* qpdf; | 35 | QPDF* qpdf; |
| 34 | int objid; | 36 | int objid; |
| 35 | int generation; | 37 | int generation; |
| 36 | QPDFObjectHandle stream_dict; | 38 | QPDFObjectHandle stream_dict; |
| 37 | off_t offset; | 39 | off_t offset; |
| 38 | int length; | 40 | int length; |
| 41 | + PointerHolder<QPDFObjectHandle::StreamDataHandler> stream_data_handler; | ||
| 42 | + PointerHolder<Buffer> stream_data; | ||
| 39 | }; | 43 | }; |
| 40 | 44 | ||
| 41 | #endif // __QPDF_STREAM_HH__ | 45 | #endif // __QPDF_STREAM_HH__ |