QtQml: Allow basic name quoting in qmldir files
This adds support for quoted file names and for escaping quotes and backslashes with '\'. It breaks support for file names that genuinely start with a quote. [ChangeLog][QtQml] You can now quote file names in qmldir files using '"'. This is so that you can write file names with spaces in them. '\' functions as an escape character, allowing you to escape quotes that are part of file names and backslash itself. Task-number: QTBUG-131916 Change-Id: Ia89e60153d3fafa273034f81da37166f30284c76 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
parent
33c13102bf
commit
bac4723a30
|
@ -62,9 +62,59 @@ inline static void scanToEnd(const QChar *&ch) {
|
|||
++ch;
|
||||
}
|
||||
|
||||
inline static void scanWord(const QChar *&ch) {
|
||||
inline static QString scanWord(const QChar *&ch) {
|
||||
const QChar *begin = ch;
|
||||
while (!ch->isSpace() && !ch->isNull())
|
||||
++ch;
|
||||
return QString(begin, ch - begin);
|
||||
}
|
||||
|
||||
QString QQmlDirParser::scanQuotedWord(const QChar *&ch, quint16 lineNumber, quint16 columnNumber)
|
||||
{
|
||||
Q_ASSERT(*ch == QLatin1Char('"'));
|
||||
++ch;
|
||||
|
||||
QString result;
|
||||
|
||||
const QChar *begin = ch;
|
||||
while (*ch != QLatin1Char('"')) {
|
||||
if (ch->isNull()) {
|
||||
reportError(lineNumber, columnNumber,
|
||||
QStringLiteral("file ends inside a quoted string"));
|
||||
result.append(begin, ch - begin);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (*ch == QLatin1Char('\n') || *ch == QLatin1Char('\r')) {
|
||||
reportError(lineNumber, columnNumber,
|
||||
QStringLiteral("line breaks in quoted strings are not supported as they "
|
||||
"are not portable between different operating systems"));
|
||||
result.append(begin, ch - begin);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (*ch == QLatin1Char('\\')) {
|
||||
result.append(begin, ch - begin);
|
||||
++ch;
|
||||
++columnNumber;
|
||||
if (*ch != QLatin1Char('"') && *ch != QLatin1Char('\\')) {
|
||||
reportError(lineNumber, columnNumber,
|
||||
QStringLiteral("only '\"' and '\\' can be escaped"));
|
||||
return result;
|
||||
}
|
||||
begin = ch;
|
||||
}
|
||||
|
||||
++ch;
|
||||
++columnNumber;
|
||||
}
|
||||
|
||||
result.append(begin, ch - begin);
|
||||
|
||||
Q_ASSERT(*ch == QLatin1Char('"'));
|
||||
++ch;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -142,16 +192,18 @@ bool QQmlDirParser::parse(const QString &source)
|
|||
scanToEnd(ch);
|
||||
break;
|
||||
}
|
||||
const QChar *start = ch;
|
||||
scanWord(ch);
|
||||
if (sectionCount < 4) {
|
||||
sections[sectionCount++] = source.mid(start-source.constData(), ch-start);
|
||||
} else {
|
||||
reportError(lineNumber, start-lineStart, QLatin1String("unexpected token"));
|
||||
|
||||
if (sectionCount >= 4) {
|
||||
reportError(lineNumber, ch - lineStart, QLatin1String("unexpected token"));
|
||||
scanToEnd(ch);
|
||||
invalidLine = true;
|
||||
break;
|
||||
}
|
||||
|
||||
sections[sectionCount++] = (*ch == QLatin1Char('"'))
|
||||
? scanQuotedWord(ch, lineNumber, ch - lineStart)
|
||||
: scanWord(ch);
|
||||
|
||||
scanSpace(ch);
|
||||
} while (*ch != QLatin1Char('\n') && !ch->isNull());
|
||||
|
||||
|
|
|
@ -140,6 +140,7 @@ public:
|
|||
private:
|
||||
bool maybeAddComponent(const QString &typeName, const QString &fileName, const QString &version, QHash<QString,Component> &hash, int lineNumber = -1, bool multi = true);
|
||||
void reportError(quint16 line, quint16 column, const QString &message);
|
||||
QString scanQuotedWord(const QChar *&ch, quint16 lineNumber, quint16 columnNumber);
|
||||
|
||||
private:
|
||||
QList<QQmlJS::DiagnosticMessage> _errors;
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
# "Comment"
|
||||
|
||||
module ModuleNamespace
|
||||
plugin PluginA "plugina.so" # More "comment"
|
||||
|
||||
ComponentA 1.0 "componenta\"1_0.qml"
|
||||
ScriptA 1.0 "scripta 1_0.js"
|
||||
|
||||
# "
|
||||
ComponentA 1.5 "componenta\\1_5.qml"
|
||||
ComponentB 1.5 "componentb 1_5.qml
|
|
@ -0,0 +1,11 @@
|
|||
# "Comment"
|
||||
|
||||
module ModuleNamespace
|
||||
plugin PluginA "plugina.so" # More "comment"
|
||||
|
||||
ComponentA 1.0 "componenta\"1_0.qml"
|
||||
ScriptA 1.0 "scripta 1_0.js"
|
||||
|
||||
# "
|
||||
ComponentA 1.5 "componenta\\1_5.qml"
|
||||
ComponentB 1.5 "componentb 1_5.qml\
|
|
@ -0,0 +1,11 @@
|
|||
# "Comment"
|
||||
|
||||
module ModuleNamespace
|
||||
plugin PluginA "plugin\a.so" # More "comment"
|
||||
|
||||
ComponentA 1.0 "componenta\"1_0.qml"
|
||||
ScriptA 1.0 "scripta 1_0.js"
|
||||
|
||||
# "
|
||||
ComponentA 1.5 "componenta\\1_5.qml"
|
||||
ComponentB 1.5 "componentb 1_5.qml"
|
|
@ -0,0 +1,12 @@
|
|||
# "Comment"
|
||||
|
||||
module ModuleNamespace
|
||||
plugin PluginA "plugin
|
||||
a.so" # More "comment"
|
||||
|
||||
ComponentA 1.0 "componenta\"1_0.qml"
|
||||
ScriptA 1.0 "scripta 1_0.js"
|
||||
|
||||
# "
|
||||
ComponentA 1.5 "componenta\\1_5.qml"
|
||||
ComponentB 1.5 "componentb 1_5.qml"
|
|
@ -0,0 +1,11 @@
|
|||
# "Comment"
|
||||
|
||||
module ModuleNamespace
|
||||
plugin PluginA "plugina.so" # More "comment"
|
||||
|
||||
ComponentA 1.0 "componenta\"1_0.qml"
|
||||
ScriptA 1.0 "scripta 1_0.js"
|
||||
|
||||
# "
|
||||
ComponentA 1.5 "componenta\\1_5.qml"
|
||||
ComponentB 1.5 "componentb 1_5.qml"
|
|
@ -335,6 +335,76 @@ void tst_qqmldirparser::parse_data()
|
|||
<< QStringList()
|
||||
<< false;
|
||||
|
||||
QTest::newRow("quoted")
|
||||
<< "quoted/qmldir"
|
||||
<< QString()
|
||||
<< QStringList()
|
||||
<< (QStringList() << "PluginA|plugina.so")
|
||||
<< QStringList()
|
||||
<< (QStringList() << "ComponentA|componenta\"1_0.qml|1|0|false"
|
||||
<< "ComponentA|componenta\\1_5.qml|1|5|false"
|
||||
<< "ComponentB|componentb 1_5.qml|1|5|false")
|
||||
<< (QStringList() << "ScriptA|scripta 1_0.js|1|0")
|
||||
<< QStringList()
|
||||
<< false;
|
||||
|
||||
QTest::newRow("ends-in-quoted")
|
||||
<< "ends-in-quoted/qmldir"
|
||||
<< QString()
|
||||
<< (QStringList() << "qmldir:11:33: file ends inside a quoted string")
|
||||
<< (QStringList() << "PluginA|plugina.so")
|
||||
<< QStringList()
|
||||
<< (QStringList() << "ComponentA|componenta\"1_0.qml|1|0|false"
|
||||
<< "ComponentA|componenta\\1_5.qml|1|5|false"
|
||||
<< "ComponentB|componentb 1_5.qml|1|5|false")
|
||||
<< (QStringList() << "ScriptA|scripta 1_0.js|1|0")
|
||||
<< QStringList()
|
||||
<< false;
|
||||
|
||||
QTest::newRow("invalid-escaped")
|
||||
<< "invalid-escaped/qmldir"
|
||||
<< QString()
|
||||
<< (QStringList()
|
||||
<< "qmldir:4:22: only '\"' and '\\' can be escaped"
|
||||
<< "qmldir:4: plugin directive requires one or two arguments, but 3 were provided")
|
||||
<< QStringList()
|
||||
<< QStringList()
|
||||
<< (QStringList() << "ComponentA|componenta\"1_0.qml|1|0|false"
|
||||
<< "ComponentA|componenta\\1_5.qml|1|5|false"
|
||||
<< "ComponentB|componentb 1_5.qml|1|5|false")
|
||||
<< (QStringList() << "ScriptA|scripta 1_0.js|1|0")
|
||||
<< QStringList()
|
||||
<< false;
|
||||
|
||||
QTest::newRow("escaped-end-of-file")
|
||||
<< "escaped-end-of-file/qmldir"
|
||||
<< QString()
|
||||
<< (QStringList() << "qmldir:11:34: only '\"' and '\\' can be escaped")
|
||||
<< (QStringList() << "PluginA|plugina.so")
|
||||
<< QStringList()
|
||||
<< (QStringList() << "ComponentA|componenta\"1_0.qml|1|0|false"
|
||||
<< "ComponentA|componenta\\1_5.qml|1|5|false"
|
||||
<< "ComponentB|componentb 1_5.qml|1|5|false")
|
||||
<< (QStringList() << "ScriptA|scripta 1_0.js|1|0")
|
||||
<< QStringList()
|
||||
<< false;
|
||||
|
||||
QTest::newRow("line-break-in-quoted")
|
||||
<< "line-break-in-quoted/qmldir"
|
||||
<< QString()
|
||||
<< (QStringList()
|
||||
<< "qmldir:4:21: line breaks in quoted strings are not supported as they are not "
|
||||
"portable between different operating systems"
|
||||
<< "qmldir:5: a component declaration requires two or three arguments, but 1 were provided")
|
||||
<< (QStringList() << "PluginA|plugin")
|
||||
<< QStringList()
|
||||
<< (QStringList() << "ComponentA|componenta\"1_0.qml|1|0|false"
|
||||
<< "ComponentA|componenta\\1_5.qml|1|5|false"
|
||||
<< "ComponentB|componentb 1_5.qml|1|5|false")
|
||||
<< (QStringList() << "ScriptA|scripta 1_0.js|1|0")
|
||||
<< QStringList()
|
||||
<< false;
|
||||
|
||||
QTest::newRow("designersupported-yes")
|
||||
<< "designersupported-yes/qmldir"
|
||||
<< QString()
|
||||
|
|
Loading…
Reference in New Issue