Bugfix - find inline image stream length

This commit is contained in:
Jakub Melka 2020-09-20 11:53:46 +02:00
parent 5e603b7781
commit a9acfa31e3
3 changed files with 88 additions and 2 deletions

View File

@ -21,6 +21,7 @@
#include "pdfimage.h"
#include "pdfpattern.h"
#include "pdfexecutionpolicy.h"
#include "pdfstreamfilters.h"
#include <QPainterPathStroker>
@ -548,8 +549,21 @@ void PDFPageContentProcessor::processContent(const QByteArray& content)
}
else if (dictionary->hasKey("Filter"))
{
// We will use EI operator position to determine stream length
dataLength = operatorEIPosition - startDataPosition;
dataLength = -1;
// We will try to use stream filter hint
PDFDocumentDataLoaderDecorator loader(m_document);
QByteArray filterName = loader.readNameFromDictionary(dictionary, "Filter");
if (!filterName.isEmpty())
{
dataLength = PDFStreamFilterStorage::getStreamDataLength(content, filterName, startDataPosition);
}
if (dataLength == -1)
{
// We will use EI operator position to determine stream length
dataLength = operatorEIPosition - startDataPosition;
}
}
else
{

View File

@ -457,6 +457,44 @@ QByteArray PDFFlateDecodeFilter::recompress(const QByteArray& data)
return result;
}
PDFInteger PDFFlateDecodeFilter::getStreamDataLength(const QByteArray& data, PDFInteger offset) const
{
if (offset < 0 || offset >= data.size())
{
return -1;
}
z_stream stream = { };
stream.next_in = const_cast<Bytef*>(convertByteArrayToUcharPtr(data) + offset);
stream.avail_in = data.size() - offset;
std::array<Bytef, 1024> outputBuffer = { };
int error = inflateInit(&stream);
if (error != Z_OK)
{
return -1;
}
do
{
stream.next_out = outputBuffer.data();
stream.avail_out = static_cast<uInt>(outputBuffer.size());
error = inflate(&stream, Z_NO_FLUSH);
} while (error == Z_OK);
PDFInteger dataLength = stream.total_in;
inflateEnd(&stream);
if (error == Z_STREAM_END)
{
return dataLength;
}
return -1;
}
QByteArray PDFFlateDecodeFilter::uncompress(const QByteArray& data)
{
QByteArray result;
@ -676,6 +714,16 @@ QByteArray PDFStreamFilterStorage::getDecodedStream(const PDFStream* stream, con
return getDecodedStream(stream, [](const PDFObject& object) -> const PDFObject& { return object; }, securityHandler);
}
PDFInteger PDFStreamFilterStorage::getStreamDataLength(const QByteArray& data, const QByteArray& filterName, PDFInteger offset)
{
if (const PDFStreamFilter* filter = getFilter(filterName))
{
return filter->getStreamDataLength(data, offset);
}
return -1;
}
PDFStreamFilterStorage::PDFStreamFilterStorage()
{
// Initialize map with the filters
@ -931,4 +979,12 @@ QByteArray PDFCryptFilter::apply(const QByteArray& data,
return securityHandler->decryptByFilter(data, cryptFilterName, objectReference);
}
PDFInteger PDFStreamFilter::getStreamDataLength(const QByteArray& data, PDFInteger offset) const
{
Q_UNUSED(data);
Q_UNUSED(offset);
return -1;
}
} // namespace pdf

View File

@ -54,6 +54,14 @@ public:
/// \param securityHandler Security handler for Crypt filters
static QByteArray getDecodedStream(const PDFStream* stream, const PDFSecurityHandler* securityHandler);
/// Tries to find stream data length using given filter. Stream will
/// start at given \p offset in \p data. If stream length cannot be determined,
/// then -1 is returned.
/// \param data Buffer data
/// \param filterName Filter name
/// \param offset Offset to buffer, at which stream data starts
static PDFInteger getStreamDataLength(const QByteArray& data, const QByteArray& filterName, PDFInteger offset);
struct StreamFilters
{
bool valid = true;
@ -148,6 +156,12 @@ public:
{
return apply(data, [](const PDFObject& object) -> const PDFObject& { return object; }, parameters, securityHandler);
}
/// Tries to find stream data length. Stream will start at given \p offset in \p data.
/// If stream length cannot be determined, then -1 is returned.
/// \param data Buffer data
/// \param offset Offset to buffer, at which stream data starts
virtual PDFInteger getStreamDataLength(const QByteArray& data, PDFInteger offset) const;
};
class PDFFORQTLIBSHARED_EXPORT PDFAsciiHexDecodeFilter : public PDFStreamFilter
@ -197,6 +211,8 @@ public:
const PDFObject& parameters,
const PDFSecurityHandler* securityHandler) const override;
virtual PDFInteger getStreamDataLength(const QByteArray& data, PDFInteger offset) const;
/// Recompresses data. So, first, data are decompressed, and then
/// recompressed again with maximal compress ratio possible.
/// \param data Compressed data to be recompressed