Avoid unnecessary conversions to/from QUrl.
Change-Id: If52e78cfdaf4fe344f34d961e300b21dd4a11fb2
Reviewed-by: Michael Brasser <michael.brasser@nokia.com>
Reviewed-by: Chris Adams <christopher.adams@nokia.com>
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();
} 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 "/..<END>"
+ 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 "/.<END>"
+ base.remove(index, 2);
+ length -= 2;
+ } else {
+ ++index;
+ }
+ }
+
+ return base;
}
}
--- /dev/null
+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
+}
--- /dev/null
+import "../../../../../../Invalid"
+
+Item {
+}
// load components via import
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("componentUrlCanonicalization.qml"));
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != 0);
QVERIFY(object->property("success").toBool());
- delete object;
}
{
// import of the other if it were not already loaded.
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("componentUrlCanonicalization.2.qml"));
- QObject *object = component.create();
+ QScopedPointer<QObject> 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<QObject> 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<QObject> 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<QObject> object(component.create());
+ QVERIFY(object == 0);
}
}