aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/qpdf/QPDFObjectHandle.hh61
-rw-r--r--libqpdf/QPDFObjectHandle.cc26
-rw-r--r--libqpdf/QPDF_Dictionary.cc14
-rw-r--r--libqpdf/QPDF_Stream.cc21
-rw-r--r--libqpdf/qpdf/QPDF_Dictionary.hh2
-rw-r--r--libqpdf/qpdf/QPDF_Stream.hh12
6 files changed, 132 insertions, 4 deletions
diff --git a/include/qpdf/QPDFObjectHandle.hh b/include/qpdf/QPDFObjectHandle.hh
index 7feb602d..83e3592f 100644
--- a/include/qpdf/QPDFObjectHandle.hh
+++ b/include/qpdf/QPDFObjectHandle.hh
@@ -152,6 +152,9 @@ class QPDFObjectHandle
// Remove key, doing nothing if key does not exist
QPDF_DLL
void removeKey(std::string const& key);
+ // If the object is null, remove the key. Otherwise, replace it.
+ QPDF_DLL
+ void replaceOrRemoveKey(std::string const& key, QPDFObjectHandle);
// Methods for stream objects
QPDF_DLL
@@ -183,6 +186,64 @@ class QPDFObjectHandle
bool pipeStreamData(Pipeline*, bool filter,
bool normalize, bool compress);
+ // Replace this stream's stream data with the given data buffer,
+ // and replace the /Filter and /DecodeParms keys in the stream
+ // dictionary with the given values. (If either value is empty,
+ // the corresponding key is removed.) The stream's /Length key is
+ // replaced with the length of the data buffer. The stream is
+ // interpreted as if the data read from the file, after any
+ // decryption filters have been applied, is as presented.
+ QPDF_DLL
+ void replaceStreamData(PointerHolder<Buffer> data,
+ QPDFObjectHandle filter,
+ QPDFObjectHandle decode_parms);
+ class StreamDataHandler
+ {
+ public:
+ QPDF_DLL
+ virtual ~StreamDataHandler()
+ {
+ }
+
+ // See replaceStreamData(StreamDataHandler) below for a
+ // description of how to override this function.
+ virtual void
+ replaceStreamData(Buffer const& in_data,
+ std::string const& in_filter,
+ std::string const& in_decode_parms,
+ bool filtered,
+ Buffer& out_data,
+ std::string& out_filter,
+ std::string& out_decode_parms,
+ bool& persist) = 0;
+ };
+ // Provide a hook for doing dynamic replacement of the stream's
+ // data. When the stream's data is accessed either with
+ // pipeStreamData or with getStreamData, if the stream doesn't
+ // already have replacement data, an attempt is first made to
+ // filter the stream's original data. If the attempt is
+ // successful, the stream's filtered original data is passed to
+ // the handler as in_data, and filtered is true. If the original
+ // data cannot be processed, then in_data is the original raw data
+ // (after any decryption filters have been applied) and filtered
+ // is false. If the original input data has no filters applied,
+ // the filtered is true. This way, if filtered is true, the
+ // caller knows that in_data contains the fully filtered data.
+ // The handler then provides replacement data, /Filter, and
+ // /DecodeParms (handled is in the simpler form of
+ // replaceStreamData above). If the persist argument is set to
+ // true, then the replacement data is stored in the stream object
+ // where it will be used on subsequent attempts to retrieve the
+ // data (rather than calling the handler). If persist is set to
+ // false, then the data will be used that one time and not saved.
+ // In that case, the handler will be invoked again if the stream
+ // data is accessed another time. Writing a handler that sets
+ // persist to true essentially allows delaying the computation of
+ // the stream data, while setting it to false reduces the amount
+ // of memory that is used.
+ QPDF_DLL
+ void replaceStreamData(PointerHolder<StreamDataHandler> dh);
+
// return 0 for direct objects
QPDF_DLL
int getObjectID() const;
diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc
index 677c2347..2fff0e31 100644
--- a/libqpdf/QPDFObjectHandle.cc
+++ b/libqpdf/QPDFObjectHandle.cc
@@ -319,6 +319,15 @@ QPDFObjectHandle::removeKey(std::string const& key)
return dynamic_cast<QPDF_Dictionary*>(obj.getPointer())->removeKey(key);
}
+void
+QPDFObjectHandle::replaceOrRemoveKey(std::string const& key,
+ QPDFObjectHandle value)
+{
+ assertType("Dictionary", isDictionary());
+ return dynamic_cast<QPDF_Dictionary*>(
+ obj.getPointer())->replaceOrRemoveKey(key, value);
+}
+
// Stream accessors
QPDFObjectHandle
QPDFObjectHandle::getDict()
@@ -343,6 +352,23 @@ QPDFObjectHandle::pipeStreamData(Pipeline* p, bool filter,
p, filter, normalize, compress);
}
+void
+QPDFObjectHandle::replaceStreamData(PointerHolder<Buffer> data,
+ QPDFObjectHandle filter,
+ QPDFObjectHandle decode_parms)
+{
+ assertType("Stream", isStream());
+ dynamic_cast<QPDF_Stream*>(obj.getPointer())->replaceStreamData(
+ data, filter, decode_parms);
+}
+
+void
+QPDFObjectHandle::replaceStreamData(PointerHolder<StreamDataHandler> dh)
+{
+ assertType("Stream", isStream());
+ dynamic_cast<QPDF_Stream*>(obj.getPointer())->replaceStreamData(dh);
+}
+
int
QPDFObjectHandle::getObjectID() const
{
diff --git a/libqpdf/QPDF_Dictionary.cc b/libqpdf/QPDF_Dictionary.cc
index ccaab4a8..838a37e6 100644
--- a/libqpdf/QPDF_Dictionary.cc
+++ b/libqpdf/QPDF_Dictionary.cc
@@ -92,3 +92,17 @@ QPDF_Dictionary::removeKey(std::string const& key)
// no-op if key does not exist
this->items.erase(key);
}
+
+void
+QPDF_Dictionary::replaceOrRemoveKey(std::string const& key,
+ QPDFObjectHandle value)
+{
+ if (value.isNull())
+ {
+ removeKey(key);
+ }
+ else
+ {
+ replaceKey(key, value);
+ }
+}
diff --git a/libqpdf/QPDF_Stream.cc b/libqpdf/QPDF_Stream.cc
index d0dd2e5f..500dfb10 100644
--- a/libqpdf/QPDF_Stream.cc
+++ b/libqpdf/QPDF_Stream.cc
@@ -319,9 +319,30 @@ QPDF_Stream::pipeStreamData(Pipeline* pipeline, bool filter,
}
}
+ // XXX handle stream_data and stream_data_handler
QPDF::Pipe::pipeStreamData(this->qpdf, this->objid, this->generation,
this->offset, this->length,
this->stream_dict, pipeline);
return filter;
}
+
+void
+QPDF_Stream::replaceStreamData(PointerHolder<Buffer> data,
+ QPDFObjectHandle filter,
+ QPDFObjectHandle decode_parms)
+{
+ this->stream_data = data;
+ this->stream_dict.replaceOrRemoveKey("/Filter", filter);
+ this->stream_dict.replaceOrRemoveKey("/DecodeParms", decode_parms);
+ this->stream_dict.replaceKey("/Length",
+ QPDFObjectHandle::newInteger(
+ data.getPointer()->getSize()));
+}
+
+void
+QPDF_Stream::replaceStreamData(
+ PointerHolder<QPDFObjectHandle::StreamDataHandler> dh)
+{
+ this->stream_data_handler = dh;
+}
diff --git a/libqpdf/qpdf/QPDF_Dictionary.hh b/libqpdf/qpdf/QPDF_Dictionary.hh
index e75de01b..e84b549e 100644
--- a/libqpdf/qpdf/QPDF_Dictionary.hh
+++ b/libqpdf/qpdf/QPDF_Dictionary.hh
@@ -26,6 +26,8 @@ class QPDF_Dictionary: public QPDFObject
void replaceKey(std::string const& key, QPDFObjectHandle const&);
// Remove key, doing nothing if key does not exist
void removeKey(std::string const& key);
+ // If object is null, replace key; otherwise, remove key
+ void replaceOrRemoveKey(std::string const& key, QPDFObjectHandle);
protected:
virtual void releaseResolved();
diff --git a/libqpdf/qpdf/QPDF_Stream.hh b/libqpdf/qpdf/QPDF_Stream.hh
index c969255d..cc7cbf0a 100644
--- a/libqpdf/qpdf/QPDF_Stream.hh
+++ b/libqpdf/qpdf/QPDF_Stream.hh
@@ -18,24 +18,28 @@ class QPDF_Stream: public QPDFObject
virtual std::string unparse();
QPDFObjectHandle getDict() const;
- // See comments in QPDFObjectHandle.hh
+ // See comments in QPDFObjectHandle.hh for these methods.
bool pipeStreamData(Pipeline*, bool filter,
bool normalize, bool compress);
-
- // See comments in QPDFObjectHandle.hh
PointerHolder<Buffer> getStreamData();
+ void replaceStreamData(PointerHolder<Buffer> data,
+ QPDFObjectHandle filter,
+ QPDFObjectHandle decode_parms);
+ void replaceStreamData(
+ PointerHolder<QPDFObjectHandle::StreamDataHandler> dh);
private:
bool filterable(std::vector<std::string>& filters,
int& predictor, int& columns, bool& early_code_change);
-
QPDF* qpdf;
int objid;
int generation;
QPDFObjectHandle stream_dict;
off_t offset;
int length;
+ PointerHolder<QPDFObjectHandle::StreamDataHandler> stream_data_handler;
+ PointerHolder<Buffer> stream_data;
};
#endif // __QPDF_STREAM_HH__