From 9744414c66e3f85700ebc8b32d90f45ff97221bd Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Sat, 19 Aug 2017 09:18:14 -0400 Subject: Enable finer grained control of stream decoding This commit adds several API methods that enable control over which types of filters QPDF will attempt to decode. It also adds support for /RunLengthDecode and /DCTDecode filters for both encoding and decoding. --- libqpdf/QPDF_Stream.cc | 68 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 55 insertions(+), 13 deletions(-) (limited to 'libqpdf/QPDF_Stream.cc') diff --git a/libqpdf/QPDF_Stream.cc b/libqpdf/QPDF_Stream.cc index 31d583b8..bcf9be92 100644 --- a/libqpdf/QPDF_Stream.cc +++ b/libqpdf/QPDF_Stream.cc @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #include @@ -82,10 +84,10 @@ QPDF_Stream::getDict() const } PointerHolder -QPDF_Stream::getStreamData() +QPDF_Stream::getStreamData(qpdf_stream_decode_level_e decode_level) { Pl_Buffer buf("stream data buffer"); - if (! pipeStreamData(&buf, true, false, false, false)) + if (! pipeStreamData(&buf, 0, decode_level, false)) { throw std::logic_error("getStreamData called on unfilterable stream"); } @@ -97,7 +99,7 @@ PointerHolder QPDF_Stream::getRawStreamData() { Pl_Buffer buf("stream data buffer"); - pipeStreamData(&buf, false, false, false, false); + pipeStreamData(&buf, 0, qpdf_dl_none, false); QTC::TC("qpdf", "QPDF_Stream getRawStreamData"); return buf.getBuffer(); } @@ -178,6 +180,8 @@ QPDF_Stream::understandDecodeParams( bool QPDF_Stream::filterable(std::vector& filters, + bool& specialized_compression, + bool& lossy_compression, int& predictor, int& columns, bool& early_code_change) { @@ -254,11 +258,20 @@ QPDF_Stream::filterable(std::vector& filters, filter = filter_abbreviations[filter]; } - if (! ((filter == "/Crypt") || - (filter == "/FlateDecode") || - (filter == "/LZWDecode") || - (filter == "/ASCII85Decode") || - (filter == "/ASCIIHexDecode"))) + if (filter == "/RunLengthDecode") + { + specialized_compression = true; + } + else if (filter == "/DCTDecode") + { + specialized_compression = true; + lossy_compression = true; + } + else if (! ((filter == "/Crypt") || + (filter == "/FlateDecode") || + (filter == "/LZWDecode") || + (filter == "/ASCII85Decode") || + (filter == "/ASCIIHexDecode"))) { filterable = false; } @@ -350,17 +363,35 @@ QPDF_Stream::filterable(std::vector& filters, } bool -QPDF_Stream::pipeStreamData(Pipeline* pipeline, bool filter, - bool normalize, bool compress, +QPDF_Stream::pipeStreamData(Pipeline* pipeline, + unsigned long encode_flags, + qpdf_stream_decode_level_e decode_level, bool suppress_warnings) { std::vector filters; int predictor = 1; int columns = 0; bool early_code_change = true; + bool specialized_compression = false; + bool lossy_compression = false; + bool filter = (! ((encode_flags == 0) && (decode_level == qpdf_dl_none))); if (filter) { - filter = filterable(filters, predictor, columns, early_code_change); + filter = filterable(filters, specialized_compression, lossy_compression, + predictor, columns, early_code_change); + if ((decode_level < qpdf_dl_all) && lossy_compression) + { + filter = false; + } + if ((decode_level < qpdf_dl_specialized) && specialized_compression) + { + filter = false; + } + QTC::TC("qpdf", "QPDF_Stream special filters", + (! filter) ? 0 : + lossy_compression ? 1 : + specialized_compression ? 2 : + 3); } if (pipeline == 0) @@ -375,14 +406,14 @@ QPDF_Stream::pipeStreamData(Pipeline* pipeline, bool filter, if (filter) { - if (compress) + if (encode_flags & qpdf_ef_compress) { pipeline = new Pl_Flate("compress object stream", pipeline, Pl_Flate::a_deflate); to_delete.push_back(pipeline); } - if (normalize) + if (encode_flags & qpdf_ef_normalize) { pipeline = new Pl_QPDFTokenizer("normalizer", pipeline); to_delete.push_back(pipeline); @@ -427,6 +458,17 @@ QPDF_Stream::pipeStreamData(Pipeline* pipeline, bool filter, early_code_change); to_delete.push_back(pipeline); } + else if (filter == "/RunLengthDecode") + { + pipeline = new Pl_RunLength("runlength decode", pipeline, + Pl_RunLength::a_decode); + to_delete.push_back(pipeline); + } + else if (filter == "/DCTDecode") + { + pipeline = new Pl_DCT("DCT decode", pipeline); + to_delete.push_back(pipeline); + } else { throw std::logic_error( -- cgit v1.2.3-54-g00ecf