diff --git a/include/qpdf/QPDF.hh b/include/qpdf/QPDF.hh index 6e567569..ce841f8f 100644 --- a/include/qpdf/QPDF.hh +++ b/include/qpdf/QPDF.hh @@ -1073,7 +1073,6 @@ class QPDF QPDFObject* resolve(QPDFObjGen og); void resolveObjectsInStream(int obj_stream_number); void stopOnError(std::string const& message); - QPDFObjectHandle reserveStream(QPDFObjGen const& og); QPDFObjGen nextObjGen(); QPDFObjectHandle newIndirect(QPDFObjGen const&, std::shared_ptr const&); QPDFObjectHandle makeIndirectFromQPDFObject(std::shared_ptr const& obj); diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index 6200a192..582ace8f 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -1547,7 +1547,7 @@ QPDF::readStream(QPDFObjectHandle& object, QPDFObjGen og, qpdf_offset_t offset) throw; } } - object = newIndirect(og, QPDF_Stream::create(this, og, object, stream_offset, length)); + object = {QPDF_Stream::create(this, og, object, stream_offset, length)}; } void @@ -2101,12 +2101,6 @@ QPDF::newStream(std::string const& data) return result; } -QPDFObjectHandle -QPDF::reserveStream(QPDFObjGen const& og) -{ - return {QPDF_Stream::create(this, og, QPDFObjectHandle::newDictionary(), 0, 0)}; -} - std::shared_ptr QPDF::getObjectForParser(int id, int gen, bool parse_pdf) { @@ -2177,7 +2171,7 @@ QPDF::replaceObject(int objid, int generation, QPDFObjectHandle oh) void QPDF::replaceObject(QPDFObjGen const& og, QPDFObjectHandle oh) { - if (oh.isIndirect() || !oh.isInitialized()) { + if (!oh.isInitialized() || (oh.isIndirect() && !(oh.isStream() && oh.getObjGen() == og))) { QTC::TC("qpdf", "QPDF replaceObject called with indirect object"); throw std::logic_error("QPDF::replaceObject called with indirect object handle"); } diff --git a/libqpdf/QPDF_Stream.cc b/libqpdf/QPDF_Stream.cc index 9e1df57c..16bd019c 100644 --- a/libqpdf/QPDF_Stream.cc +++ b/libqpdf/QPDF_Stream.cc @@ -107,12 +107,8 @@ StreamBlobProvider::operator()(Pipeline* p) } QPDF_Stream::QPDF_Stream( - QPDF* qpdf, - QPDFObjGen const& og, - QPDFObjectHandle stream_dict, - qpdf_offset_t offset, - size_t length) : - QPDFValue(::ot_stream), + QPDF* qpdf, QPDFObjGen og, QPDFObjectHandle stream_dict, qpdf_offset_t offset, size_t length) : + QPDFValue(::ot_stream, qpdf, og), filter_on_write(true), stream_dict(stream_dict), length(length) @@ -128,11 +124,7 @@ QPDF_Stream::QPDF_Stream( std::shared_ptr QPDF_Stream::create( - QPDF* qpdf, - QPDFObjGen const& og, - QPDFObjectHandle stream_dict, - qpdf_offset_t offset, - size_t length) + QPDF* qpdf, QPDFObjGen og, QPDFObjectHandle stream_dict, qpdf_offset_t offset, size_t length) { return do_create(new QPDF_Stream(qpdf, og, stream_dict, offset, length)); } diff --git a/libqpdf/QPDF_json.cc b/libqpdf/QPDF_json.cc index 26814f5d..559ef951 100644 --- a/libqpdf/QPDF_json.cc +++ b/libqpdf/QPDF_json.cc @@ -397,14 +397,12 @@ QPDF::JSONReactor::containerEnd(JSON const& value) QTC::TC("qpdf", "QPDF_json data datafile both or neither"); error( value.getStart(), - "new \"stream\" must have exactly one of \"data\" or " - "\"datafile\""); + "new \"stream\" must have exactly one of \"data\" or \"datafile\""); } else if (saw_datafile) { QTC::TC("qpdf", "QPDF_json data and datafile"); error( value.getStart(), - "existing \"stream\" may at most one of \"data\" or " - "\"datafile\""); + "existing \"stream\" may at most one of \"data\" or \"datafile\""); } else { QTC::TC("qpdf", "QPDF_json no stream data in update mode"); } @@ -427,15 +425,15 @@ QPDF::JSONReactor::containerEnd(JSON const& value) void QPDF::JSONReactor::replaceObject(QPDFObjectHandle&& replacement, JSON const& value) { - if (replacement.isIndirect()) { + auto& tos = stack.back(); + auto og = tos.object.getObjGen(); + if (replacement.isIndirect() && !(replacement.isStream() && replacement.getObjGen() == og)) { error( replacement.getParsedOffset(), "the value of an object may not be an indirect object reference"); return; } - auto& tos = stack.back(); - auto og = tos.object.getObjGen(); - this->pdf.replaceObject(og, replacement); + pdf.replaceObject(og, replacement); next_obj = pdf.getObject(og); setObjectDescription(tos.object, value); } @@ -575,8 +573,11 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value) if (tos.object.isStream()) { QTC::TC("qpdf", "QPDF_json updating existing stream"); } else { - this->this_stream_needs_data = true; - replaceObject(pdf.reserveStream(tos.object.getObjGen()), value); + this_stream_needs_data = true; + replaceObject( + QPDF_Stream::create( + &pdf, tos.object.getObjGen(), QPDFObjectHandle::newDictionary(), 0, 0), + value); } next_obj = tos.object; } else { diff --git a/libqpdf/qpdf/QPDF_Stream.hh b/libqpdf/qpdf/QPDF_Stream.hh index 3fcbc428..0acdf71d 100644 --- a/libqpdf/qpdf/QPDF_Stream.hh +++ b/libqpdf/qpdf/QPDF_Stream.hh @@ -13,22 +13,18 @@ class Pipeline; class QPDF; -class QPDF_Stream: public QPDFValue +class QPDF_Stream final: public QPDFValue { public: - ~QPDF_Stream() override = default; - static std::shared_ptr create( - QPDF*, - QPDFObjGen const& og, - QPDFObjectHandle stream_dict, - qpdf_offset_t offset, - size_t length); - std::shared_ptr copy(bool shallow = false) override; - std::string unparse() override; - void writeJSON(int json_version, JSON::Writer& p) override; + ~QPDF_Stream() final = default; + static std::shared_ptr + create(QPDF*, QPDFObjGen og, QPDFObjectHandle stream_dict, qpdf_offset_t offset, size_t length); + std::shared_ptr copy(bool shallow = false) final; + std::string unparse() final; + void writeJSON(int json_version, JSON::Writer& p) final; void setDescription( - QPDF*, std::shared_ptr& description, qpdf_offset_t offset) override; - void disconnect() override; + QPDF*, std::shared_ptr& description, qpdf_offset_t offset) final; + void disconnect() final; QPDFObjectHandle getDict() const; bool isDataModified() const; void setFilterOnWrite(bool); @@ -80,11 +76,7 @@ class QPDF_Stream: public QPDFValue private: QPDF_Stream( - QPDF*, - QPDFObjGen const& og, - QPDFObjectHandle stream_dict, - qpdf_offset_t offset, - size_t length); + QPDF*, QPDFObjGen og, QPDFObjectHandle stream_dict, qpdf_offset_t offset, size_t length); static std::map filter_abbreviations; static std::map()>> filter_factories;