Files
main/desktop/toolkit/qt5/qt5-svg/files/qt_kde.patch
T
2022-04-18 16:18:54 +03:00

597 lines
21 KiB
Diff
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
diff --git a/src/plugins/imageformats/svg/qsvgiohandler.cpp b/src/plugins/imageformats/svg/qsvgiohandler.cpp
index bd39b2a..fd3529a 100644
--- a/src/plugins/imageformats/svg/qsvgiohandler.cpp
+++ b/src/plugins/imageformats/svg/qsvgiohandler.cpp
@@ -118,6 +118,24 @@ 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
{
@@ -126,15 +144,9 @@ bool QSvgIOHandler::canRead() const
if (d->loaded && !d->readDone)
return true; // Will happen if we have been asked for the size
- QByteArray buf = device()->peek(16);
-#ifndef QT_NO_COMPRESS
- if (buf.startsWith("\x1f\x8b")) {
- setFormat("svgz");
- return true;
- } else
-#endif
- if (buf.contains("<?xml") || buf.contains("<svg") || buf.contains("<!--") || buf.contains("<!DOCTYPE svg")) {
- setFormat("svg");
+ bool isCompressed = false;
+ if (isPossiblySvg(device(), &isCompressed)) {
+ setFormat(isCompressed ? "svgz" : "svg");
return true;
}
return false;
@@ -177,6 +189,8 @@ bool QSvgIOHandler::read(QImage *image)
}
}
if (!finalSize.isEmpty()) {
+ if (qMax(finalSize.width(), finalSize.height()) > 0xffff)
+ return false; // Assume corrupted file
image->fill(d->backColor.rgba());
QPainter p(image);
d->r.render(&p, bounds);
@@ -260,12 +274,7 @@ bool QSvgIOHandler::supportsOption(ImageOption option) const
bool QSvgIOHandler::canRead(QIODevice *device)
{
- QByteArray buf = device->peek(16);
- return
-#ifndef QT_NO_COMPRESS
- buf.startsWith("\x1f\x8b") ||
-#endif
- buf.contains("<?xml") || buf.contains("<svg") || buf.contains("<!--") || buf.contains("<!DOCTYPE svg");
+ return isPossiblySvg(device);
}
QT_END_NAMESPACE
diff --git a/src/svg/qsvghandler.cpp b/src/svg/qsvghandler.cpp
index b3d9aaf..f2653af 100644
--- a/src/svg/qsvghandler.cpp
+++ b/src/svg/qsvghandler.cpp
@@ -673,7 +673,8 @@ static qreal toDouble(const QChar *&str)
val = -val;
} else {
val = QByteArray::fromRawData(temp, pos).toDouble();
- if (qFpClassify(val) != FP_NORMAL)
+ // Do not tolerate values too wild to be represented normally by floats
+ if (qFpClassify(float(val)) != FP_NORMAL)
val = 0;
}
return val;
@@ -727,15 +728,25 @@ static QVector<qreal> parseNumbersList(const QChar *&str)
return points;
}
-static inline void parseNumbersArray(const QChar *&str, QVarLengthArray<qreal, 8> &points)
+static inline void parseNumbersArray(const QChar *&str, QVarLengthArray<qreal, 8> &points,
+ const char *pattern = nullptr)
{
+ const size_t patternLen = qstrlen(pattern);
while (str->isSpace())
++str;
while (isDigit(str->unicode()) ||
*str == QLatin1Char('-') || *str == QLatin1Char('+') ||
*str == QLatin1Char('.')) {
- points.append(toDouble(str));
+ if (patternLen && pattern[points.size() % patternLen] == 'f') {
+ // flag expected, may only be 0 or 1
+ if (*str != QLatin1Char('0') && *str != QLatin1Char('1'))
+ return;
+ points.append(*str == QLatin1Char('0') ? 0.0 : 1.0);
+ ++str;
+ } else {
+ points.append(toDouble(str));
+ }
while (str->isSpace())
++str;
@@ -1382,8 +1393,10 @@ static void parseFont(QSvgNode *node,
case FontSizeNone:
break;
case FontSizeValue: {
- QSvgHandler::LengthType dummy; // should always be pixel size
- fontStyle->setSize(parseLength(attributes.fontSize, dummy, handler));
+ QSvgHandler::LengthType type;
+ qreal fs = parseLength(attributes.fontSize, type, handler);
+ fs = convertToPixels(fs, true, type);
+ fontStyle->setSize(qMin(fs, qreal(0xffff)));
}
break;
default:
@@ -1614,6 +1627,7 @@ static void pathArc(QPainterPath &path,
static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
{
+ const int maxElementCount = 0x7fff; // Assume file corruption if more path elements than this
qreal x0 = 0, y0 = 0; // starting point
qreal x = 0, y = 0; // current point
char lastMode = 0;
@@ -1621,28 +1635,31 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
const QChar *str = dataStr.constData();
const QChar *end = str + dataStr.size();
- while (str != end) {
+ bool ok = true;
+ while (ok && str != end) {
while (str->isSpace() && (str + 1) != end)
++str;
QChar pathElem = *str;
++str;
QChar endc = *end;
*const_cast<QChar *>(end) = 0; // parseNumbersArray requires 0-termination that QStringRef cannot guarantee
+ const char *pattern = nullptr;
+ if (pathElem == QLatin1Char('a') || pathElem == QLatin1Char('A'))
+ pattern = "rrrffrr";
QVarLengthArray<qreal, 8> arg;
- parseNumbersArray(str, arg);
+ parseNumbersArray(str, arg, pattern);
*const_cast<QChar *>(end) = endc;
if (pathElem == QLatin1Char('z') || pathElem == QLatin1Char('Z'))
arg.append(0);//dummy
const qreal *num = arg.constData();
int count = arg.count();
- while (count > 0) {
+ while (ok && count > 0) {
qreal offsetX = x; // correction offsets
qreal offsetY = y; // for relative commands
switch (pathElem.unicode()) {
case 'm': {
if (count < 2) {
- num++;
- count--;
+ ok = false;
break;
}
x = x0 = num[0] + offsetX;
@@ -1659,8 +1676,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
break;
case 'M': {
if (count < 2) {
- num++;
- count--;
+ ok = false;
break;
}
x = x0 = num[0];
@@ -1686,8 +1702,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
break;
case 'l': {
if (count < 2) {
- num++;
- count--;
+ ok = false;
break;
}
x = num[0] + offsetX;
@@ -1700,8 +1715,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
break;
case 'L': {
if (count < 2) {
- num++;
- count--;
+ ok = false;
break;
}
x = num[0];
@@ -1741,8 +1755,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
break;
case 'c': {
if (count < 6) {
- num += count;
- count = 0;
+ ok = false;
break;
}
QPointF c1(num[0] + offsetX, num[1] + offsetY);
@@ -1758,8 +1771,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
}
case 'C': {
if (count < 6) {
- num += count;
- count = 0;
+ ok = false;
break;
}
QPointF c1(num[0], num[1]);
@@ -1775,8 +1787,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
}
case 's': {
if (count < 4) {
- num += count;
- count = 0;
+ ok = false;
break;
}
QPointF c1;
@@ -1797,8 +1808,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
}
case 'S': {
if (count < 4) {
- num += count;
- count = 0;
+ ok = false;
break;
}
QPointF c1;
@@ -1819,8 +1829,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
}
case 'q': {
if (count < 4) {
- num += count;
- count = 0;
+ ok = false;
break;
}
QPointF c(num[0] + offsetX, num[1] + offsetY);
@@ -1835,8 +1844,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
}
case 'Q': {
if (count < 4) {
- num += count;
- count = 0;
+ ok = false;
break;
}
QPointF c(num[0], num[1]);
@@ -1851,8 +1859,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
}
case 't': {
if (count < 2) {
- num += count;
- count = 0;
+ ok = false;
break;
}
QPointF e(num[0] + offsetX, num[1] + offsetY);
@@ -1872,8 +1879,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
}
case 'T': {
if (count < 2) {
- num += count;
- count = 0;
+ ok = false;
break;
}
QPointF e(num[0], num[1]);
@@ -1893,8 +1899,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
}
case 'a': {
if (count < 7) {
- num += count;
- count = 0;
+ ok = false;
break;
}
qreal rx = (*num++);
@@ -1916,8 +1921,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
break;
case 'A': {
if (count < 7) {
- num += count;
- count = 0;
+ ok = false;
break;
}
qreal rx = (*num++);
@@ -1938,12 +1942,15 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
}
break;
default:
- return false;
+ ok = false;
+ break;
}
lastMode = pathElem.toLatin1();
+ if (path.elementCount() > maxElementCount)
+ ok = false;
}
}
- return true;
+ return ok;
}
static bool parseStyle(QSvgNode *node,
@@ -2357,6 +2364,27 @@ static bool parseAnimateNode(QSvgNode *parent,
return true;
}
+static int parseClockValue(QString str, bool *ok)
+{
+ int res = 0;
+ int ms = 1000;
+ str = str.trimmed();
+ if (str.endsWith(QLatin1String("ms"))) {
+ str.chop(2);
+ ms = 1;
+ } else if (str.endsWith(QLatin1String("s"))) {
+ str.chop(1);
+ }
+ double val = ms * toDouble(str, ok);
+ if (ok) {
+ if (val > std::numeric_limits<int>::min() && val < std::numeric_limits<int>::max())
+ res = static_cast<int>(val);
+ else
+ *ok = false;
+ }
+ return res;
+}
+
static bool parseAnimateColorNode(QSvgNode *parent,
const QXmlStreamAttributes &attributes,
QSvgHandler *handler)
@@ -2390,23 +2418,13 @@ static bool parseAnimateColorNode(QSvgNode *parent,
}
}
- int ms = 1000;
- beginStr = beginStr.trimmed();
- if (beginStr.endsWith(QLatin1String("ms"))) {
- beginStr.chop(2);
- ms = 1;
- } else if (beginStr.endsWith(QLatin1String("s"))) {
- beginStr.chop(1);
- }
- durStr = durStr.trimmed();
- if (durStr.endsWith(QLatin1String("ms"))) {
- durStr.chop(2);
- ms = 1;
- } else if (durStr.endsWith(QLatin1String("s"))) {
- durStr.chop(1);
- }
- int begin = static_cast<int>(toDouble(beginStr) * ms);
- int end = static_cast<int>((toDouble(durStr) + begin) * ms);
+ bool ok = true;
+ int begin = parseClockValue(beginStr, &ok);
+ if (!ok)
+ return false;
+ int end = begin + parseClockValue(durStr, &ok);
+ if (!ok || end <= begin)
+ return false;
QSvgAnimateColor *anim = new QSvgAnimateColor(begin, end, 0);
anim->setArgs((targetStr == QLatin1String("fill")), colors);
@@ -2496,24 +2514,13 @@ static bool parseAnimateTransformNode(QSvgNode *parent,
}
}
- int ms = 1000;
- beginStr = beginStr.trimmed();
- if (beginStr.endsWith(QLatin1String("ms"))) {
- beginStr.chop(2);
- ms = 1;
- } else if (beginStr.endsWith(QLatin1String("s"))) {
- beginStr.chop(1);
- }
- int begin = static_cast<int>(toDouble(beginStr) * ms);
- durStr = durStr.trimmed();
- if (durStr.endsWith(QLatin1String("ms"))) {
- durStr.chop(2);
- ms = 1;
- } else if (durStr.endsWith(QLatin1String("s"))) {
- durStr.chop(1);
- ms = 1000;
- }
- int end = static_cast<int>(toDouble(durStr)*ms) + begin;
+ bool ok = true;
+ int begin = parseClockValue(beginStr, &ok);
+ if (!ok)
+ return false;
+ int end = begin + parseClockValue(durStr, &ok);
+ if (!ok || end <= begin)
+ return false;
QSvgAnimateTransform::TransformType type = QSvgAnimateTransform::Empty;
if (typeStr == QLatin1String("translate")) {
@@ -2569,6 +2576,8 @@ static QSvgNode *createCircleNode(QSvgNode *parent,
qreal ncx = toDouble(cx);
qreal ncy = toDouble(cy);
qreal nr = toDouble(r);
+ if (nr < 0.0)
+ return nullptr;
QRectF rect(ncx-nr, ncy-nr, nr*2, nr*2);
QSvgNode *circle = new QSvgCircle(parent, rect);
@@ -2979,8 +2988,8 @@ static QSvgNode *createPathNode(QSvgNode *parent,
QPainterPath qpath;
qpath.setFillRule(Qt::WindingFill);
- //XXX do error handling
- parsePathDataFast(data, qpath);
+ if (!parsePathDataFast(data, qpath))
+ qCWarning(lcSvgHandler, "Invalid path data; path truncated.");
QSvgNode *path = new QSvgPath(parent, qpath);
return path;
@@ -3039,13 +3048,16 @@ static QSvgStyleProperty *createRadialGradientNode(QSvgNode *node,
qreal ncx = 0.5;
qreal ncy = 0.5;
- qreal nr = 0.5;
if (!cx.isEmpty())
ncx = toDouble(cx);
if (!cy.isEmpty())
ncy = toDouble(cy);
+
+ qreal nr = 0.0;
if (!r.isEmpty())
nr = toDouble(r);
+ if (nr <= 0.0)
+ return nullptr;
qreal nfx = ncx;
if (!fx.isEmpty())
@@ -3341,7 +3353,9 @@ static QSvgNode *createTextNode(QSvgNode *parent,
//### editable and rotate not handled
QSvgHandler::LengthType type;
qreal nx = parseLength(x, type, handler);
+ nx = convertToPixels(nx, true, type);
qreal ny = parseLength(y, type, handler);
+ ny = convertToPixels(ny, true, type);
QSvgNode *text = new QSvgText(parent, QPointF(nx, ny));
return text;
@@ -3682,9 +3696,7 @@ void QSvgHandler::parse()
case QXmlStreamReader::EndElement:
endElement(xml->name());
++remainingUnfinishedElements;
- // if we are using somebody else's qxmlstreamreader
- // we should not read until the end of the stream
- done = !m_ownsReader && (xml->name() == QLatin1String("svg"));
+ done = (xml->name() == QLatin1String("svg"));
break;
case QXmlStreamReader::Characters:
characters(xml->text());
diff --git a/src/svg/qsvgstructure.cpp b/src/svg/qsvgstructure.cpp
index b89608b..89c9e4e 100644
--- a/src/svg/qsvgstructure.cpp
+++ b/src/svg/qsvgstructure.cpp
@@ -255,9 +255,13 @@ inline static bool isSupportedSvgFeature(const QString &str)
};
if (str.length() <= MAX_WORD_LENGTH && str.length() >= MIN_WORD_LENGTH) {
+ const char16_t unicode44 = str.at(44).unicode();
+ const char16_t unicode45 = str.at(45).unicode();
+ if (unicode44 >= sizeof(asso_values) || unicode45 >= sizeof(asso_values))
+ return false;
const int key = str.length()
- + asso_values[str.at(45).unicode()]
- + asso_values[str.at(44).unicode()];
+ + asso_values[unicode45]
+ + asso_values[unicode44];
if (key <= MAX_HASH_VALUE && key >= 0)
return str == QLatin1String(wordlist[key]);
}
diff --git a/tests/auto/qsvgplugin/simple_Utf16BE.svg b/tests/auto/qsvgplugin/simple_Utf16BE.svg
new file mode 100644
index 0000000..c3312cb
Binary files /dev/null and b/tests/auto/qsvgplugin/simple_Utf16BE.svg differ
diff --git a/tests/auto/qsvgplugin/simple_Utf16LE.svg b/tests/auto/qsvgplugin/simple_Utf16LE.svg
new file mode 100644
index 0000000..cdbeda9
Binary files /dev/null and b/tests/auto/qsvgplugin/simple_Utf16LE.svg differ
diff --git a/tests/auto/qsvgplugin/simple_Utf32BE.svg b/tests/auto/qsvgplugin/simple_Utf32BE.svg
new file mode 100644
index 0000000..0d5d02c
Binary files /dev/null and b/tests/auto/qsvgplugin/simple_Utf32BE.svg differ
diff --git a/tests/auto/qsvgplugin/simple_Utf32LE.svg b/tests/auto/qsvgplugin/simple_Utf32LE.svg
new file mode 100644
index 0000000..58a7159
Binary files /dev/null and b/tests/auto/qsvgplugin/simple_Utf32LE.svg differ
diff --git a/tests/auto/qsvgplugin/simple_Utf8.svg b/tests/auto/qsvgplugin/simple_Utf8.svg
new file mode 100644
index 0000000..2052c48
--- /dev/null
+++ b/tests/auto/qsvgplugin/simple_Utf8.svg
@@ -0,0 +1,3 @@
+<svg version="1.0" xmlns="http://www.w3.org/2000/svg">
+ <circle cx="50" cy="50" r="25" fill="#00ff00" />
+</svg>
diff --git a/tests/auto/qsvgplugin/tst_qsvgplugin.cpp b/tests/auto/qsvgplugin/tst_qsvgplugin.cpp
index e1f84f3..73bbe8b 100644
--- a/tests/auto/qsvgplugin/tst_qsvgplugin.cpp
+++ b/tests/auto/qsvgplugin/tst_qsvgplugin.cpp
@@ -61,6 +61,8 @@ private slots:
void checkSize_data();
void checkSize();
void checkImageInclude();
+ void encodings_data();
+ void encodings();
};
@@ -145,6 +147,36 @@ void tst_QSvgPlugin::checkImageInclude()
logMessages.clear();
}
+void tst_QSvgPlugin::encodings_data()
+{
+ QTest::addColumn<QString>("filename");
+
+ QTest::newRow("utf-8") << QFINDTESTDATA("simple_Utf8.svg");
+ 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");
+}
+
+void tst_QSvgPlugin::encodings()
+{
+ QFETCH(QString, filename);
+
+ {
+ QFile file(filename);
+ file.open(QIODevice::ReadOnly);
+ QVERIFY(QSvgIOHandler::canRead(&file));
+ }
+
+ QFile file(filename);
+ file.open(QIODevice::ReadOnly);
+ QSvgIOHandler plugin;
+ plugin.setDevice(&file);
+ QVERIFY(plugin.canRead());
+ QImage img;
+ QVERIFY(plugin.read(&img));
+ QCOMPARE(img.size(), QSize(50, 50));
+}
QTEST_MAIN(tst_QSvgPlugin)
#include "tst_qsvgplugin.moc"
diff --git a/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp b/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp
index 8f1f03b..36c76ec 100644
--- a/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp
+++ b/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp
@@ -74,6 +74,7 @@ private slots:
void fillRule();
void opacity();
void paths();
+ void paths2();
void displayMode();
void strokeInherit();
void testFillInheritance();
@@ -1047,6 +1048,19 @@ void tst_QSvgRenderer::paths()
}
}
+void tst_QSvgRenderer::paths2()
+{
+ const char *svg =
+ "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\">"
+ "<path d=\"M 3 8 A 5 5 0 1013 8\" id=\"path1\"/>"
+ "</svg>";
+
+ QByteArray data(svg);
+ QSvgRenderer renderer(data);
+ QVERIFY(renderer.isValid());
+ QCOMPARE(renderer.boundsOnElement(QLatin1String("path1")).toRect(), QRect(3, 8, 10, 5));
+}
+
void tst_QSvgRenderer::displayMode()
{
static const char *svgs[] = {