diff options
-rw-r--r-- | src/plugins/imageformats/svg/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/plugins/imageformats/svg/qsvgiohandler.cpp | 24 | ||||
-rw-r--r-- | src/svg/qsvgtinydocument.cpp | 53 | ||||
-rw-r--r-- | src/svg/qsvgtinydocument_p.h | 19 | ||||
-rw-r--r-- | tests/auto/qsvgplugin/CMakeLists.txt | 4 | ||||
-rw-r--r-- | tests/auto/qsvgplugin/simple_Utf32BE.svg.gz | bin | 0 -> 185 bytes | |||
-rw-r--r-- | tests/auto/qsvgplugin/simple_Utf8.svgz | bin | 0 -> 141 bytes | |||
-rw-r--r-- | tests/auto/qsvgplugin/tst_qsvgplugin.cpp | 2 |
8 files changed, 70 insertions, 34 deletions
diff --git a/src/plugins/imageformats/svg/CMakeLists.txt b/src/plugins/imageformats/svg/CMakeLists.txt index 140e281..ec69a02 100644 --- a/src/plugins/imageformats/svg/CMakeLists.txt +++ b/src/plugins/imageformats/svg/CMakeLists.txt @@ -14,5 +14,5 @@ qt_internal_add_plugin(QSvgPlugin LIBRARIES Qt::Core Qt::Gui - Qt::Svg + Qt::SvgPrivate ) diff --git a/src/plugins/imageformats/svg/qsvgiohandler.cpp b/src/plugins/imageformats/svg/qsvgiohandler.cpp index 570c982..1212f80 100644 --- a/src/plugins/imageformats/svg/qsvgiohandler.cpp +++ b/src/plugins/imageformats/svg/qsvgiohandler.cpp @@ -6,6 +6,7 @@ #ifndef QT_NO_SVGRENDERER #include "qsvgrenderer.h" +#include "private/qsvgtinydocument_p.h" #include "qimage.h" #include "qpixmap.h" #include "qpainter.h" @@ -84,25 +85,6 @@ QSvgIOHandler::~QSvgIOHandler() delete d; } -static bool isPossiblySvg(QIODevice *device, bool *isCompressed = nullptr) -{ - constexpr int bufSize = 64; - char buf[bufSize]; - const qint64 readLen = device->peek(buf, bufSize); - if (readLen < 8) - return false; -# ifndef QT_NO_COMPRESS - if (quint8(buf[0]) == 0x1f && quint8(buf[1]) == 0x8b) { - if (isCompressed) - *isCompressed = true; - return true; - } -# endif - QTextStream str(QByteArray::fromRawData(buf, readLen)); - QByteArray ba = str.read(16).trimmed().toLatin1(); - return ba.startsWith("<?xml") || ba.startsWith("<svg") || ba.startsWith("<!--") || ba.startsWith("<!DOCTYPE svg"); -} - bool QSvgIOHandler::canRead() const { if (!device()) @@ -111,7 +93,7 @@ bool QSvgIOHandler::canRead() const return true; // Will happen if we have been asked for the size bool isCompressed = false; - if (isPossiblySvg(device(), &isCompressed)) { + if (QSvgTinyDocument::isLikelySvg(device(), &isCompressed)) { setFormat(isCompressed ? "svgz" : "svg"); return true; } @@ -237,7 +219,7 @@ bool QSvgIOHandler::supportsOption(ImageOption option) const bool QSvgIOHandler::canRead(QIODevice *device) { - return isPossiblySvg(device); + return QSvgTinyDocument::isLikelySvg(device); } QT_END_NAMESPACE diff --git a/src/svg/qsvgtinydocument.cpp b/src/svg/qsvgtinydocument.cpp index 246df7b..94f21ca 100644 --- a/src/svg/qsvgtinydocument.cpp +++ b/src/svg/qsvgtinydocument.cpp @@ -21,6 +21,8 @@ QT_BEGIN_NAMESPACE +using namespace Qt::StringLiterals; + QSvgTinyDocument::QSvgTinyDocument(QtSvg::Options options) : QSvgStructureNode(0) , m_widthPercent(false) @@ -37,6 +39,19 @@ QSvgTinyDocument::~QSvgTinyDocument() { } +static bool hasSvgHeader(const QByteArray &buf) +{ + QTextStream s(buf); // Handle multi-byte encodings + QString h = s.readAll(); + QStringView th = QStringView(h).trimmed(); + bool matched = false; + if (th.startsWith("<svg"_L1) || th.startsWith("<!DOCTYPE svg"_L1)) + matched = true; + else if (th.startsWith("<?xml"_L1) || th.startsWith("<!--"_L1)) + matched = th.contains("<!DOCTYPE svg"_L1) || th.contains("<svg"_L1); + return matched; +} + #ifndef QT_NO_COMPRESS static QByteArray qt_inflateSvgzDataFrom(QIODevice *device, bool doCheckContent = true); # ifdef QT_BUILD_INTERNAL @@ -124,8 +139,7 @@ static QByteArray qt_inflateSvgzDataFrom(QIODevice *device, bool doCheckContent) if (doCheckContent) { // Quick format check, equivalent to QSvgIOHandler::canRead() - QByteArray buf = destination.left(16); - if (!buf.contains("<?xml") && !buf.contains("<svg") && !buf.contains("<!--") && !buf.contains("<!DOCTYPE svg")) { + if (!hasSvgHeader(destination)) { inflateEnd(&zlibStream); qCWarning(lcSvgHandler, "Error while inflating gzip file: SVG format check failed"); return QByteArray(); @@ -521,4 +535,39 @@ void QSvgTinyDocument::setFramesPerSecond(int num) m_fps = num; } +bool QSvgTinyDocument::isLikelySvg(QIODevice *device, bool *isCompressed) +{ + constexpr int bufSize = 4096; + char buf[bufSize]; + char inflateBuf[bufSize]; + bool useInflateBuf = false; + int readLen = device->peek(buf, bufSize); + if (readLen < 8) + return false; +#ifndef QT_NO_COMPRESS + if (quint8(buf[0]) == 0x1f && quint8(buf[1]) == 0x8b) { + // Indicates gzip compressed content, i.e. svgz + z_stream zlibStream; + zlibStream.avail_in = readLen; + zlibStream.next_out = reinterpret_cast<Bytef *>(inflateBuf); + zlibStream.avail_out = bufSize; + zlibStream.next_in = reinterpret_cast<Bytef *>(buf); + zlibStream.zalloc = Z_NULL; + zlibStream.zfree = Z_NULL; + zlibStream.opaque = Z_NULL; + if (inflateInit2(&zlibStream, MAX_WBITS + 16) != Z_OK) + return false; + int zlibResult = inflate(&zlibStream, Z_NO_FLUSH); + inflateEnd(&zlibStream); + if ((zlibResult != Z_OK && zlibResult != Z_STREAM_END) || zlibStream.total_out < 8) + return false; + readLen = zlibStream.total_out; + if (isCompressed) + *isCompressed = true; + useInflateBuf = true; + } +#endif + return hasSvgHeader(QByteArray::fromRawData(useInflateBuf ? inflateBuf : buf, readLen)); +} + QT_END_NAMESPACE diff --git a/src/svg/qsvgtinydocument_p.h b/src/svg/qsvgtinydocument_p.h index 9501a95..a3f5489 100644 --- a/src/svg/qsvgtinydocument_p.h +++ b/src/svg/qsvgtinydocument_p.h @@ -39,23 +39,24 @@ public: static QSvgTinyDocument *load(const QString &file, QtSvg::Options options = {}); static QSvgTinyDocument *load(const QByteArray &contents, QtSvg::Options options = {}); static QSvgTinyDocument *load(QXmlStreamReader *contents, QtSvg::Options options = {}); + static bool isLikelySvg(QIODevice *device, bool *isCompressed = nullptr); public: QSvgTinyDocument(QtSvg::Options options); ~QSvgTinyDocument(); Type type() const override; - QSize size() const; + inline QSize size() const; void setWidth(int len, bool percent); void setHeight(int len, bool percent); - int width() const; - int height() const; - bool widthPercent() const; - bool heightPercent() const; + inline int width() const; + inline int height() const; + inline bool widthPercent() const; + inline bool heightPercent() const; - bool preserveAspectRatio() const; + inline bool preserveAspectRatio() const; void setPreserveAspectRatio(bool on); - QRectF viewBox() const; + inline QRectF viewBox() const; void setViewBox(const QRectF &rect); QtSvg::Options options() const; @@ -79,10 +80,10 @@ public: QSvgPaintStyleProperty *namedStyle(const QString &id) const; void restartAnimation(); - int currentElapsed() const; + inline int currentElapsed() const; bool animated() const; void setAnimated(bool a); - int animationDuration() const; + inline int animationDuration() const; int currentFrame() const; void setCurrentFrame(int); void setFramesPerSecond(int num); diff --git a/tests/auto/qsvgplugin/CMakeLists.txt b/tests/auto/qsvgplugin/CMakeLists.txt index ffeef84..e9a516c 100644 --- a/tests/auto/qsvgplugin/CMakeLists.txt +++ b/tests/auto/qsvgplugin/CMakeLists.txt @@ -17,7 +17,7 @@ qt_internal_add_test(tst_qsvgplugin LIBRARIES Qt::Gui Qt::GuiPrivate - Qt::Svg + Qt::SvgPrivate Qt::Widgets ) @@ -39,10 +39,12 @@ set(resources_resource_files "wide_size_viewbox.svg" "wide_viewbox.svg" "simple_Utf8.svg" + "simple_Utf8.svgz" "simple_Utf16LE.svg" "simple_Utf16BE.svg" "simple_Utf32LE.svg" "simple_Utf32BE.svg" + "simple_Utf32BE.svg.gz" "invalid_xml.svg" "xml_not_svg.svg" "invalid_then_valid.svg" diff --git a/tests/auto/qsvgplugin/simple_Utf32BE.svg.gz b/tests/auto/qsvgplugin/simple_Utf32BE.svg.gz Binary files differnew file mode 100644 index 0000000..569a73f --- /dev/null +++ b/tests/auto/qsvgplugin/simple_Utf32BE.svg.gz diff --git a/tests/auto/qsvgplugin/simple_Utf8.svgz b/tests/auto/qsvgplugin/simple_Utf8.svgz Binary files differnew file mode 100644 index 0000000..a51f38f --- /dev/null +++ b/tests/auto/qsvgplugin/simple_Utf8.svgz diff --git a/tests/auto/qsvgplugin/tst_qsvgplugin.cpp b/tests/auto/qsvgplugin/tst_qsvgplugin.cpp index 762d373..0c9796e 100644 --- a/tests/auto/qsvgplugin/tst_qsvgplugin.cpp +++ b/tests/auto/qsvgplugin/tst_qsvgplugin.cpp @@ -138,10 +138,12 @@ void tst_QSvgPlugin::encodings_data() QTest::addColumn<QString>("filename"); QTest::newRow("utf-8") << QFINDTESTDATA("simple_Utf8.svg"); + QTest::newRow("utf-8_z") << QFINDTESTDATA("simple_Utf8.svgz"); QTest::newRow("utf-16LE") << QFINDTESTDATA("simple_Utf16LE.svg"); QTest::newRow("utf-16BE") << QFINDTESTDATA("simple_Utf16BE.svg"); QTest::newRow("utf-32LE") << QFINDTESTDATA("simple_Utf32LE.svg"); QTest::newRow("utf-32BE") << QFINDTESTDATA("simple_Utf32BE.svg"); + QTest::newRow("utf-32BE_z") << QFINDTESTDATA("simple_Utf32BE.svg.gz"); } void tst_QSvgPlugin::encodings() |