From f29c5732f6dbb2c928a088bb14dfb63b600ca9c8 Mon Sep 17 00:00:00 2001 From: Matthew Vogt Date: Fri, 20 Apr 2012 14:50:03 +1000 Subject: [PATCH] Remove relative directory elements in import paths Avoid unnecessary conversions to/from QUrl. Change-Id: If52e78cfdaf4fe344f34d961e300b21dd4a11fb2 Reviewed-by: Michael Brasser Reviewed-by: Chris Adams --- src/qml/qml/qqmlimport.cpp | 41 ++++++++++++++++++---- .../data/componentUrlCanonicalization.4.qml | 28 +++++++++++++++ .../data/componentUrlCanonicalization.5.qml | 4 +++ tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp | 27 ++++++++++---- 4 files changed, 87 insertions(+), 13 deletions(-) create mode 100644 tests/auto/qml/qqmlcomponent/data/componentUrlCanonicalization.4.qml create mode 100644 tests/auto/qml/qqmlcomponent/data/componentUrlCanonicalization.5.qml diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index 90228f1..a8a3ed0 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -63,9 +63,6 @@ static bool greaterThan(const QString &s1, const QString &s2) QString resolveLocalUrl(const QString &url, const QString &relative) { - return QUrl(url).resolved(QUrl(relative)).toString(); - - //XXX Find out why this broke with new QUrl. if (relative.contains(QLatin1Char(':'))) { // contains a host name return QUrl(url).resolved(QUrl(relative)).toString(); @@ -74,11 +71,41 @@ QString resolveLocalUrl(const QString &url, const QString &relative) } else if (relative.at(0) == QLatin1Char('/') || !url.contains(QLatin1Char('/'))) { return relative; } else { + QString base(url.left(url.lastIndexOf(QLatin1Char('/')) + 1)); + if (relative == QLatin1String(".")) - return url.left(url.lastIndexOf(QLatin1Char('/')) + 1); - else if (relative.startsWith(QLatin1String("./"))) - return url.left(url.lastIndexOf(QLatin1Char('/')) + 1) + relative.mid(2); - return url.left(url.lastIndexOf(QLatin1Char('/')) + 1) + relative; + return base; + + base.append(relative); + + // Remove any relative directory elements in the path + const QLatin1Char dot('.'); + const QLatin1Char slash('/'); + + int length = base.length(); + int index = 0; + while ((index = base.indexOf(QLatin1String("/."), index)) != -1) { + if ((length > (index + 2)) && (base.at(index + 2) == dot) && + (length == (index + 3) || (base.at(index + 3) == slash))) { + // Either "/../" or "/.." + int previous = base.lastIndexOf(slash, index - 1); + if (previous == -1) + break; + + int removeLength = (index - previous) + 3; + base.remove(previous + 1, removeLength); + length -= removeLength; + index = previous; + } else if ((length == (index + 2)) || (base.at(index + 2) == slash)) { + // Either "/./" or "/." + base.remove(index, 2); + length -= 2; + } else { + ++index; + } + } + + return base; } } diff --git a/tests/auto/qml/qqmlcomponent/data/componentUrlCanonicalization.4.qml b/tests/auto/qml/qqmlcomponent/data/componentUrlCanonicalization.4.qml new file mode 100644 index 0000000..cddaf64 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/componentUrlCanonicalization.4.qml @@ -0,0 +1,28 @@ +import QtQuick 2.0 +import "SpecificComponent" +import "./SpecificComponent" +import "././SpecificComponent" +import "./././SpecificComponent" +import "SpecificComponent/." +import "SpecificComponent/./" +import "SpecificComponent/./." +import "SpecificComponent/././" +import "SpecificComponent/././." +import "SpecificComponent/./././" +import "../data/SpecificComponent" +import "./../data/SpecificComponent" +import ".././data/SpecificComponent" +import "SpecificComponent/nonexistent/../." +import "SpecificComponent/nonexistent/.././" +import "SpecificComponent/nonexistent/./.." +import "SpecificComponent/nonexistent/./../" +import "SpecificComponent/nonexistent/nonexistent/../.." +import "SpecificComponent/nonexistent/nonexistent/../../" +import "SpecificComponent/nonexistent/nonexistent/nonexistent/../../.." +import "SpecificComponent/nonexistent/nonexistent/nonexistent/../../../" +import "SpecificComponent/.././SpecificComponent" +import "SpecificComponent/./../SpecificComponent" + +Item { + property bool success : true +} diff --git a/tests/auto/qml/qqmlcomponent/data/componentUrlCanonicalization.5.qml b/tests/auto/qml/qqmlcomponent/data/componentUrlCanonicalization.5.qml new file mode 100644 index 0000000..66993ab --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/componentUrlCanonicalization.5.qml @@ -0,0 +1,4 @@ +import "../../../../../../Invalid" + +Item { +} diff --git a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp index eebb558..b534d0c 100644 --- a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp +++ b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp @@ -323,10 +323,9 @@ void tst_qqmlcomponent::componentUrlCanonicalization() // load components via import QQmlEngine engine; QQmlComponent component(&engine, testFileUrl("componentUrlCanonicalization.qml")); - QObject *object = component.create(); + QScopedPointer object(component.create()); QVERIFY(object != 0); QVERIFY(object->property("success").toBool()); - delete object; } { @@ -334,20 +333,36 @@ void tst_qqmlcomponent::componentUrlCanonicalization() // import of the other if it were not already loaded. QQmlEngine engine; QQmlComponent component(&engine, testFileUrl("componentUrlCanonicalization.2.qml")); - QObject *object = component.create(); + QScopedPointer object(component.create()); QVERIFY(object != 0); QVERIFY(object->property("success").toBool()); - delete object; } { // load components with more deeply nested imports QQmlEngine engine; QQmlComponent component(&engine, testFileUrl("componentUrlCanonicalization.3.qml")); - QObject *object = component.create(); + QScopedPointer object(component.create()); QVERIFY(object != 0); QVERIFY(object->property("success").toBool()); - delete object; + } + + { + // load components with unusually specified import paths + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("componentUrlCanonicalization.4.qml")); + QScopedPointer object(component.create()); + QVERIFY(object != 0); + QVERIFY(object->property("success").toBool()); + } + + { + // Do not crash with various nonsense import paths + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("componentUrlCanonicalization.5.qml")); + QTest::ignoreMessage(QtWarningMsg, QLatin1String("QQmlComponent: Component is not ready").data()); + QScopedPointer object(component.create()); + QVERIFY(object == 0); } } -- 2.7.4