diff options
Diffstat (limited to 'libqpdf')
-rw-r--r-- | libqpdf/Buffer.cc | 18 | ||||
-rw-r--r-- | libqpdf/CMakeLists.txt | 2 | ||||
-rw-r--r-- | libqpdf/Pl_Buffer.cc | 19 | ||||
-rw-r--r-- | libqpdf/QPDF.cc | 25 | ||||
-rw-r--r-- | libqpdf/QPDFAcroFormDocumentHelper.cc | 3 | ||||
-rw-r--r-- | libqpdf/QPDFObjectHandle.cc | 3 | ||||
-rw-r--r-- | libqpdf/QPDFPageObjectHelper.cc | 5 | ||||
-rw-r--r-- | libqpdf/QPDFWriter.cc | 19 | ||||
-rw-r--r-- | libqpdf/QPDF_Stream.cc | 25 | ||||
-rw-r--r-- | libqpdf/QPDF_encryption.cc | 25 | ||||
-rw-r--r-- | libqpdf/QPDF_linearization.cc | 21 | ||||
-rw-r--r-- | libqpdf/SF_FlateLzwDecode.cc | 2 | ||||
-rw-r--r-- | libqpdf/qpdf-c.cc | 12 |
13 files changed, 104 insertions, 75 deletions
diff --git a/libqpdf/Buffer.cc b/libqpdf/Buffer.cc index 3dddd5db..20453a40 100644 --- a/libqpdf/Buffer.cc +++ b/libqpdf/Buffer.cc @@ -27,6 +27,14 @@ Buffer::Members::Members(size_t size, unsigned char* buf, bool own_memory) : } } +Buffer::Members::Members(std::string&& content) : + str(std::move(content)), + own_memory(false), + size(str.size()), + buf(reinterpret_cast<unsigned char*>(str.data())) +{ +} + Buffer::Members::~Members() { if (this->own_memory) { @@ -44,11 +52,21 @@ Buffer::Buffer(size_t size) : { } +Buffer::Buffer(std::string&& content) : + m(new Members(std::move(content))) +{ +} + Buffer::Buffer(unsigned char* buf, size_t size) : m(new Members(size, buf, false)) { } +Buffer::Buffer(std::string& content) : + m(new Members(content.size(), reinterpret_cast<unsigned char*>(content.data()), false)) +{ +} + Buffer::Buffer(Buffer const& rhs) { assert(test_mode); diff --git a/libqpdf/CMakeLists.txt b/libqpdf/CMakeLists.txt index c6a122c6..eb30b622 100644 --- a/libqpdf/CMakeLists.txt +++ b/libqpdf/CMakeLists.txt @@ -590,10 +590,12 @@ if(INSTALL_CMAKE_PACKAGE) install(EXPORT libqpdfTargets NAMESPACE qpdf:: FILE libqpdfTargets.cmake + COMPONENT ${COMPONENT_DEV} DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/qpdf) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/qpdfConfigVersion.cmake ${CMAKE_CURRENT_BINARY_DIR}/qpdfConfig.cmake + COMPONENT ${COMPONENT_DEV} DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/qpdf) endif() diff --git a/libqpdf/Pl_Buffer.cc b/libqpdf/Pl_Buffer.cc index 766c04b5..9994bedd 100644 --- a/libqpdf/Pl_Buffer.cc +++ b/libqpdf/Pl_Buffer.cc @@ -19,7 +19,7 @@ Pl_Buffer::~Pl_Buffer() // NOLINT (modernize-use-equals-default) void Pl_Buffer::write(unsigned char const* buf, size_t len) { - m->data.insert(m->data.end(), buf, buf + len); + m->data.append(reinterpret_cast<char const*>(buf), len); m->ready = false; if (getNext(true)) { @@ -42,15 +42,20 @@ Pl_Buffer::getBuffer() if (!m->ready) { throw std::logic_error("Pl_Buffer::getBuffer() called when not ready"); } + auto* b = new Buffer(std::move(m->data)); + m->data.clear(); + return b; +} - auto size = m->data.size(); - auto* b = new Buffer(size); - if (size > 0) { - unsigned char* p = b->getBuffer(); - memcpy(p, m->data.data(), size); +std::string +Pl_Buffer::getString() +{ + if (!m->ready) { + throw std::logic_error("Pl_Buffer::getString() called when not ready"); } + auto s = std::move(m->data); m->data.clear(); - return b; + return s; } std::shared_ptr<Buffer> diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index 473cf5f0..f6badc35 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -2413,29 +2413,23 @@ QPDF::pipeStreamData( bool suppress_warnings, bool will_retry) { - std::vector<std::shared_ptr<Pipeline>> to_delete; + std::unique_ptr<Pipeline> to_delete; if (encp->encrypted) { decryptStream(encp, file, qpdf_for_warning, pipeline, og, stream_dict, to_delete); } bool attempted_finish = false; - bool success = false; try { file->seek(offset, SEEK_SET); - char buf[10240]; - while (length > 0) { - size_t to_read = (sizeof(buf) < length ? sizeof(buf) : length); - size_t len = file->read(buf, to_read); - if (len == 0) { - throw damagedPDF( - file, "", file->getLastOffset(), "unexpected EOF reading stream data"); - } - length -= len; - pipeline->write(buf, len); + auto buf = std::make_unique<char[]>(length); + if (auto read = file->read(buf.get(), length); read != length) { + throw damagedPDF( + file, "", offset + toO(read), "unexpected EOF reading stream data"); } + pipeline->write(buf.get(), length); attempted_finish = true; pipeline->finish(); - success = true; + return true; } catch (QPDFExc& e) { if (!suppress_warnings) { qpdf_for_warning.warn(e); @@ -2458,8 +2452,7 @@ QPDF::pipeStreamData( file, "", file->getLastOffset(), - "stream will be re-processed without" - " filtering to avoid data loss")); + "stream will be re-processed without filtering to avoid data loss")); } } } @@ -2470,7 +2463,7 @@ QPDF::pipeStreamData( // ignore } } - return success; + return false ; } bool diff --git a/libqpdf/QPDFAcroFormDocumentHelper.cc b/libqpdf/QPDFAcroFormDocumentHelper.cc index 5a54bf75..f2daa0c7 100644 --- a/libqpdf/QPDFAcroFormDocumentHelper.cc +++ b/libqpdf/QPDFAcroFormDocumentHelper.cc @@ -584,8 +584,7 @@ QPDFAcroFormDocumentHelper::adjustDefaultAppearances( ResourceReplacer rr(dr_map, rf.getNamesByResourceType()); Pl_Buffer buf_pl("filtered DA"); da_stream.filterAsContents(&rr, &buf_pl); - auto buf = buf_pl.getBufferSharedPointer(); - std::string new_da(reinterpret_cast<char*>(buf->getBuffer()), buf->getSize()); + std::string new_da = buf_pl.getString(); obj.replaceKey("/DA", QPDFObjectHandle::newString(new_da)); } diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc index d5ac137a..d543f98e 100644 --- a/libqpdf/QPDFObjectHandle.cc +++ b/libqpdf/QPDFObjectHandle.cc @@ -1708,8 +1708,7 @@ QPDFObjectHandle::pipeContentStreams( need_newline = (lc.getLastChar() != static_cast<unsigned char>('\n')); QTC::TC("qpdf", "QPDFObjectHandle need_newline", need_newline ? 0 : 1); } - std::unique_ptr<Buffer> b(buf.getBuffer()); - p->write(b->getBuffer(), b->getSize()); + p->writeString(buf.getString()); p->finish(); } diff --git a/libqpdf/QPDFPageObjectHelper.cc b/libqpdf/QPDFPageObjectHelper.cc index fd6e5215..54bb5cac 100644 --- a/libqpdf/QPDFPageObjectHelper.cc +++ b/libqpdf/QPDFPageObjectHelper.cc @@ -175,14 +175,11 @@ InlineImageTracker::handleToken(QPDFTokenizer::Token const& token) size_t len = image_data.length(); if (len >= this->min_size) { QTC::TC("qpdf", "QPDFPageObjectHelper externalize inline image"); - Pl_Buffer b("image_data"); - b.writeString(image_data); - b.finish(); QPDFObjectHandle dict = convertIIDict(QPDFObjectHandle::parse(dict_str)); dict.replaceKey("/Length", QPDFObjectHandle::newInteger(QIntC::to_longlong(len))); std::string name = resources.getUniqueResourceName("/IIm", this->min_suffix); QPDFObjectHandle image = - QPDFObjectHandle::newStream(this->qpdf, b.getBufferSharedPointer()); + QPDFObjectHandle::newStream(this->qpdf, std::make_shared<Buffer>(std::move(image_data))); image.replaceDict(dict); resources.getKey("/XObject").replaceKey(name, image); write(name); diff --git a/libqpdf/QPDFWriter.cc b/libqpdf/QPDFWriter.cc index db3b42e0..981fc755 100644 --- a/libqpdf/QPDFWriter.cc +++ b/libqpdf/QPDFWriter.cc @@ -1579,10 +1579,7 @@ QPDFWriter::unparseObject( m->cur_data_key.length()); pl.writeString(val); pl.finish(); - auto buf = bufpl.getBufferSharedPointer(); - val = QPDF_String( - std::string(reinterpret_cast<char*>(buf->getBuffer()), buf->getSize())) - .unparse(true); + val = QPDF_String(bufpl.getString()).unparse(true); } else { auto tmp_ph = QUtil::make_unique_cstr(val); char* tmp = tmp_ph.get(); @@ -1661,8 +1658,7 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) // Set up a stream to write the stream data into a buffer. Pipeline* next = pushPipeline(new Pl_Buffer("object stream")); - if ((m->compress_streams || (m->stream_decode_level == qpdf_dl_none)) && - (!m->qdf_mode)) { + if (m->compress_streams && !m->qdf_mode) { compressed = true; next = pushPipeline(new Pl_Flate("compress object stream", next, Pl_Flate::a_deflate)); @@ -2293,15 +2289,20 @@ QPDFWriter::writeHintStream(int hint_id) std::shared_ptr<Buffer> hint_buffer; int S = 0; int O = 0; + bool compressed = (m->compress_streams && !m->qdf_mode); QPDF::Writer::generateHintStream( - m->pdf, m->xref, m->lengths, m->obj_renumber_no_gen, hint_buffer, S, O); + m->pdf, m->xref, m->lengths, m->obj_renumber_no_gen, hint_buffer, S, O, compressed); openObject(hint_id); setDataKey(hint_id); size_t hlen = hint_buffer->getSize(); - writeString("<< /Filter /FlateDecode /S "); + writeString("<< "); + if (compressed) { + writeString("/Filter /FlateDecode "); + } + writeString("/S "); writeString(std::to_string(S)); if (O) { writeString(" /O "); @@ -2420,7 +2421,7 @@ QPDFWriter::writeXRefStream( Pipeline* p = pushPipeline(new Pl_Buffer("xref stream")); bool compressed = false; - if ((m->compress_streams || (m->stream_decode_level == qpdf_dl_none)) && (!m->qdf_mode)) { + if (m->compress_streams && !m->qdf_mode) { compressed = true; if (!skip_compression) { // Write the stream dictionary for compression but don't actually compress. This helps diff --git a/libqpdf/QPDF_Stream.cc b/libqpdf/QPDF_Stream.cc index 45d6fb70..a43d91ff 100644 --- a/libqpdf/QPDF_Stream.cc +++ b/libqpdf/QPDF_Stream.cc @@ -216,29 +216,28 @@ QPDF_Stream::getStreamJSON( auto dict = this->stream_dict; JSON result = JSON::makeDictionary(); if (json_data != qpdf_sj_none) { - std::shared_ptr<Buffer> buf; + Pl_Discard discard; + Pl_Buffer buf_pl{"stream data"}; + // buf_pl contains valid data and is ready for retrieval of the data. + bool buf_pl_ready = false; bool filtered = false; bool filter = (decode_level != qpdf_dl_none); for (int attempt = 1; attempt <= 2; ++attempt) { - Pl_Discard discard; - std::shared_ptr<Pl_Buffer> buf_pl; - Pipeline* data_pipeline = nullptr; + Pipeline* data_pipeline = &discard; if (json_data == qpdf_sj_file) { // We need to capture the data to write - buf_pl = std::make_shared<Pl_Buffer>("stream data"); - data_pipeline = buf_pl.get(); - } else { - data_pipeline = &discard; + data_pipeline = &buf_pl; } bool succeeded = pipeStreamData(data_pipeline, &filtered, 0, decode_level, false, (attempt == 1)); - if ((!succeeded) || (filter && (!filtered))) { + if (!succeeded || (filter && !filtered)) { // Try again filter = false; decode_level = qpdf_dl_none; + buf_pl.getString(); // reset buf_pl } else { - if (buf_pl.get()) { - buf = buf_pl->getBufferSharedPointer(); + if (json_data == qpdf_sj_file) { + buf_pl_ready = true; } break; } @@ -252,10 +251,10 @@ QPDF_Stream::getStreamJSON( } if (json_data == qpdf_sj_file) { result.addDictionaryMember("datafile", JSON::makeString(data_filename)); - if (!buf.get()) { + if (!buf_pl_ready) { throw std::logic_error("QPDF_Stream: failed to get stream data in json file mode"); } - p->write(buf->getBuffer(), buf->getSize()); + p->writeString(buf_pl.getString()); } else if (json_data == qpdf_sj_inline) { result.addDictionaryMember( "data", JSON::makeBlob(StreamBlobProvider(this, decode_level))); diff --git a/libqpdf/QPDF_encryption.cc b/libqpdf/QPDF_encryption.cc index b5cc44ee..1dd7b963 100644 --- a/libqpdf/QPDF_encryption.cc +++ b/libqpdf/QPDF_encryption.cc @@ -229,13 +229,11 @@ process_with_aes( aes.writeString(data); } aes.finish(); - auto bufp = buffer.getBufferSharedPointer(); if (outlength == 0) { - outlength = bufp->getSize(); + return buffer.getString(); } else { - outlength = std::min(outlength, bufp->getSize()); + return buffer.getString().substr(0, outlength); } - return {reinterpret_cast<char*>(bufp->getBuffer()), outlength}; } static std::string @@ -1021,8 +1019,7 @@ QPDF::decryptString(std::string& str, QPDFObjGen const& og) key.length()); pl.writeString(str); pl.finish(); - auto buf = bufpl.getBufferSharedPointer(); - str = std::string(reinterpret_cast<char*>(buf->getBuffer()), buf->getSize()); + str = bufpl.getString(); } else { QTC::TC("qpdf", "QPDF_encryption rc4 decode string"); size_t vlen = str.length(); @@ -1041,6 +1038,9 @@ QPDF::decryptString(std::string& str, QPDFObjGen const& og) } } +// Prepend a decryption pipeline to 'pipeline'. The decryption pipeline (returned as +// 'decrypt_pipeline' must be owned by the caller to ensure that it stays alive while the pipeline +// is in use. void QPDF::decryptStream( std::shared_ptr<EncryptionParameters> encp, @@ -1049,7 +1049,7 @@ QPDF::decryptStream( Pipeline*& pipeline, QPDFObjGen const& og, QPDFObjectHandle& stream_dict, - std::vector<std::shared_ptr<Pipeline>>& heap) + std::unique_ptr<Pipeline>& decrypt_pipeline) { std::string type; if (stream_dict.getKey("/Type").isName()) { @@ -1085,8 +1085,7 @@ QPDF::decryptStream( crypt_params.getKey("/Name").isName()) { QTC::TC("qpdf", "QPDF_encrypt crypt array"); method = interpretCF(encp, crypt_params.getKey("/Name")); - method_source = "stream's Crypt " - "decode parameters (array)"; + method_source = "stream's Crypt decode parameters (array)"; } } } @@ -1135,10 +1134,9 @@ QPDF::decryptStream( } } std::string key = getKeyForObject(encp, og, use_aes); - std::shared_ptr<Pipeline> new_pipeline; if (use_aes) { QTC::TC("qpdf", "QPDF_encryption aes decode stream"); - new_pipeline = std::make_shared<Pl_AES_PDF>( + decrypt_pipeline = std::make_unique<Pl_AES_PDF>( "AES stream decryption", pipeline, false, @@ -1146,14 +1144,13 @@ QPDF::decryptStream( key.length()); } else { QTC::TC("qpdf", "QPDF_encryption rc4 decode stream"); - new_pipeline = std::make_shared<Pl_RC4>( + decrypt_pipeline = std::make_unique<Pl_RC4>( "RC4 stream decryption", pipeline, QUtil::unsigned_char_pointer(key), toI(key.length())); } - pipeline = new_pipeline.get(); - heap.push_back(new_pipeline); + pipeline = decrypt_pipeline.get(); } void diff --git a/libqpdf/QPDF_linearization.cc b/libqpdf/QPDF_linearization.cc index 469b9933..1657d54a 100644 --- a/libqpdf/QPDF_linearization.cc +++ b/libqpdf/QPDF_linearization.cc @@ -1748,10 +1748,10 @@ QPDF::writeHSharedObject(BitWriter& w) void QPDF::writeHGeneric(BitWriter& w, HGeneric& t) { - w.writeBitsInt(t.first_object, 32); // 1 - w.writeBits(toULL(t.first_object_offset), 32); // 2 - w.writeBitsInt(t.nobjects, 32); // 3 - w.writeBitsInt(t.group_length, 32); // 4 + w.writeBitsInt(t.first_object, 32); // 1 + w.writeBits(toULL(t.first_object_offset), 32); // 2 + w.writeBitsInt(t.nobjects, 32); // 3 + w.writeBitsInt(t.group_length, 32); // 4 } void @@ -1761,7 +1761,8 @@ QPDF::generateHintStream( std::map<int, int> const& obj_renumber, std::shared_ptr<Buffer>& hint_buffer, int& S, - int& O) + int& O, + bool compressed) { // Populate actual hint table values calculateHPageOffset(xref, lengths, obj_renumber); @@ -1771,8 +1772,14 @@ QPDF::generateHintStream( // Write the hint stream itself into a compressed memory buffer. Write through a counter so we // can get offsets. Pl_Buffer hint_stream("hint stream"); - Pl_Flate f("compress hint stream", &hint_stream, Pl_Flate::a_deflate); - Pl_Count c("count", &f); + Pipeline* next = &hint_stream; + std::shared_ptr<Pipeline> flate; + if (compressed) { + flate = + std::make_shared<Pl_Flate>("compress hint stream", &hint_stream, Pl_Flate::a_deflate); + next = flate.get(); + } + Pl_Count c("count", next); BitWriter w(&c); writeHPageOffset(w); diff --git a/libqpdf/SF_FlateLzwDecode.cc b/libqpdf/SF_FlateLzwDecode.cc index db663429..a291145f 100644 --- a/libqpdf/SF_FlateLzwDecode.cc +++ b/libqpdf/SF_FlateLzwDecode.cc @@ -11,7 +11,7 @@ SF_FlateLzwDecode::SF_FlateLzwDecode(bool lzw) : lzw(lzw), // Initialize values to their defaults as per the PDF spec predictor(1), - columns(0), + columns(1), colors(1), bits_per_component(8), early_code_change(true) diff --git a/libqpdf/qpdf-c.cc b/libqpdf/qpdf-c.cc index 1f7b85cb..b45b564b 100644 --- a/libqpdf/qpdf-c.cc +++ b/libqpdf/qpdf-c.cc @@ -1949,3 +1949,15 @@ qpdf_write_json( }); return status; } + +std::shared_ptr<QPDF> +qpdf_c_get_qpdf(qpdf_data qpdf) +{ + return qpdf->qpdf; +} + +QPDF_ERROR_CODE +qpdf_c_wrap(qpdf_data qpdf, std::function<void()> fn) +{ + return trap_errors(qpdf, [&fn](qpdf_data) { fn(); }); +} |