summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@digia.com>2014-04-11 11:48:15 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-04-14 13:06:10 +0200
commita03dc073c155b9ac82e17a49e68ada61a4d4605b (patch)
tree8f4890d1b2c4e68c23bfa4c3277b7aede09c4897
parente2710f83dfad87b9380090640718e627494636f9 (diff)
downloadqttools-a03dc073c155b9ac82e17a49e68ada61a4d4605b.tar.gz
androiddeployqt: Escape arguments to shell tools
Code is borrowed from qmake to escape and quote arguments passed to shell tools as needed. Task-number: QTBUG-38249 Change-Id: I4932df3963b0c1706374b4ba78c5e23c8e3304d2 Reviewed-by: Christian Stromme <christian.stromme@digia.com>
-rw-r--r--src/androiddeployqt/main.cpp146
1 files changed, 109 insertions, 37 deletions
diff --git a/src/androiddeployqt/main.cpp b/src/androiddeployqt/main.cpp
index de8cf13a8..02eb063bb 100644
--- a/src/androiddeployqt/main.cpp
+++ b/src/androiddeployqt/main.cpp
@@ -175,6 +175,78 @@ struct Options
QStringList features;
};
+// Copy-pasted from qmake/library/ioutil.cpp
+inline static bool hasSpecialChars(const QString &arg, const uchar (&iqm)[16])
+{
+ for (int x = arg.length() - 1; x >= 0; --x) {
+ ushort c = arg.unicode()[x].unicode();
+ if ((c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7))))
+ return true;
+ }
+ return false;
+}
+
+static QString shellQuoteUnix(const QString &arg)
+{
+ // Chars that should be quoted (TM). This includes:
+ static const uchar iqm[] = {
+ 0xff, 0xff, 0xff, 0xff, 0xdf, 0x07, 0x00, 0xd8,
+ 0x00, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x78
+ }; // 0-32 \'"$`<>|;&(){}*?#!~[]
+
+ if (!arg.length())
+ return QString::fromLatin1("\"\"");
+
+ QString ret(arg);
+ if (hasSpecialChars(ret, iqm)) {
+ ret.replace(QLatin1Char('\''), QLatin1String("'\\''"));
+ ret.prepend(QLatin1Char('\''));
+ ret.append(QLatin1Char('\''));
+ }
+ return ret;
+}
+
+static QString shellQuoteWin(const QString &arg)
+{
+ // Chars that should be quoted (TM). This includes:
+ // - control chars & space
+ // - the shell meta chars "&()<>^|
+ // - the potential separators ,;=
+ static const uchar iqm[] = {
+ 0xff, 0xff, 0xff, 0xff, 0x45, 0x13, 0x00, 0x78,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10
+ };
+
+ if (!arg.length())
+ return QString::fromLatin1("\"\"");
+
+ QString ret(arg);
+ if (hasSpecialChars(ret, iqm)) {
+ // Quotes are escaped and their preceding backslashes are doubled.
+ // It's impossible to escape anything inside a quoted string on cmd
+ // level, so the outer quoting must be "suspended".
+ ret.replace(QRegExp(QLatin1String("(\\\\*)\"")), QLatin1String("\"\\1\\1\\^\"\""));
+ // The argument must not end with a \ since this would be interpreted
+ // as escaping the quote -- rather put the \ behind the quote: e.g.
+ // rather use "foo"\ than "foo\"
+ int i = ret.length();
+ while (i > 0 && ret.at(i - 1) == QLatin1Char('\\'))
+ --i;
+ ret.insert(i, QLatin1Char('"'));
+ ret.prepend(QLatin1Char('"'));
+ }
+ return ret;
+}
+
+static QString shellQuote(const QString &arg)
+{
+ if (QDir::separator() == QLatin1Char('\\'))
+ return shellQuoteWin(arg);
+ else
+ return shellQuoteUnix(arg);
+}
+
+
Options parseOptions()
{
Options options;
@@ -1185,7 +1257,7 @@ QStringList getQtLibsFromElf(const Options &options, const QString &fileName)
return QStringList();
}
- readElf = QString::fromLatin1("\"%1\" -d -W %2").arg(readElf).arg(fileName);
+ readElf = QString::fromLatin1("%1 -d -W %2").arg(shellQuote(readElf)).arg(shellQuote(fileName));
FILE *readElfCommand = popen(readElf.toLocal8Bit().constData(), "r");
if (readElfCommand == 0) {
@@ -1329,7 +1401,7 @@ bool stripFile(const Options &options, const QString &fileName)
return false;
}
- strip = QString::fromLatin1("\"%1\" %2").arg(strip).arg(fileName);
+ strip = QString::fromLatin1("%1 %2").arg(shellQuote(strip)).arg(shellQuote(fileName));
FILE *stripCommand = popen(strip.toLocal8Bit().constData(), "r");
if (stripCommand == 0) {
@@ -1405,9 +1477,9 @@ FILE *runAdb(const Options &options, const QString &arguments)
}
QString installOption;
if (!options.installLocation.isEmpty())
- installOption = QLatin1String(" -s ") + options.installLocation;
+ installOption = QLatin1String(" -s ") + shellQuote(options.installLocation);
- adb = QString::fromLatin1("\"%1\"%2 %3").arg(adb).arg(installOption).arg(arguments);
+ adb = QString::fromLatin1("%1%2 %3").arg(shellQuote(adb)).arg(installOption).arg(arguments);
if (options.verbose)
fprintf(stdout, "Running command \"%s\"\n", adb.toLocal8Bit().constData());
@@ -1425,7 +1497,7 @@ bool fetchRemoteModifications(Options *options, const QString &directory)
{
options->fetchedRemoteModificationDates = true;
- FILE *adbCommand = runAdb(*options, QLatin1String(" shell cat ") + directory + QLatin1String("/modification.txt"));
+ FILE *adbCommand = runAdb(*options, QLatin1String(" shell cat ") + shellQuote(directory + QLatin1String("/modification.txt")));
if (adbCommand == 0)
return false;
@@ -1437,7 +1509,7 @@ bool fetchRemoteModifications(Options *options, const QString &directory)
pclose(adbCommand);
if (options->qtInstallDirectory != qtPath) {
- adbCommand = runAdb(*options, QLatin1String(" shell rm -r ") + directory);
+ adbCommand = runAdb(*options, QLatin1String(" shell rm -r ") + shellQuote(directory));
if (options->verbose) {
fprintf(stdout, " -- Removing old Qt libs.\n");
while (fgets(buffer, sizeof(buffer), adbCommand) != 0)
@@ -1446,7 +1518,7 @@ bool fetchRemoteModifications(Options *options, const QString &directory)
pclose(adbCommand);
}
- adbCommand = runAdb(*options, QLatin1String(" ls ") + directory);
+ adbCommand = runAdb(*options, QLatin1String(" ls ") + shellQuote(directory));
if (adbCommand == 0)
return false;
@@ -1639,10 +1711,10 @@ bool createAndroidProject(const Options &options)
return false;
}
- androidTool = QString::fromLatin1("\"%1\" update project --path %2 --target %3 --name QtApp")
- .arg(androidTool)
- .arg(options.outputDirectory)
- .arg(options.androidPlatform);
+ androidTool = QString::fromLatin1("%1 update project --path %2 --target %3 --name QtApp")
+ .arg(shellQuote(androidTool))
+ .arg(shellQuote(options.outputDirectory))
+ .arg(shellQuote(options.androidPlatform));
if (options.verbose)
fprintf(stdout, " -- Command: %s\n", qPrintable(androidTool));
@@ -1705,7 +1777,7 @@ bool buildAndroidProject(const Options &options)
return false;
}
- QString ant = QString::fromLatin1("\"%1\" %2").arg(antTool).arg(options.releasePackage ? QLatin1String(" release") : QLatin1String(" debug"));
+ QString ant = QString::fromLatin1("%1 %2").arg(shellQuote(antTool)).arg(options.releasePackage ? QLatin1String(" release") : QLatin1String(" debug"));
FILE *antCommand = popen(ant.toLocal8Bit().constData(), "r");
if (antCommand == 0) {
@@ -1739,7 +1811,7 @@ bool uninstallApk(const Options &options)
fprintf(stdout, "Uninstalling old Android package %s if present.\n", qPrintable(options.packageName));
- FILE *adbCommand = runAdb(options, QLatin1String(" uninstall ") + options.packageName);
+ FILE *adbCommand = runAdb(options, QLatin1String(" uninstall ") + shellQuote(options.packageName));
if (adbCommand == 0)
return false;
@@ -1781,10 +1853,10 @@ bool installApk(const Options &options)
FILE *adbCommand = runAdb(options,
QLatin1String(" install -r ")
- + options.outputDirectory
- + QLatin1String("/bin/")
- + apkName(options)
- + QLatin1String(".apk"));
+ + shellQuote(options.outputDirectory)
+ + shellQuote(QLatin1String("/bin/")
+ + apkName(options)
+ + QLatin1String(".apk")));
if (adbCommand == 0)
return false;
@@ -1864,29 +1936,29 @@ bool signPackage(const Options &options)
return false;
}
- jarSignerTool = QString::fromLatin1("\"%1\" -sigalg \"%2\" -digestalg \"%3\" -keystore \"%4\"")
- .arg(jarSignerTool).arg(options.sigAlg).arg(options.digestAlg).arg(options.keyStore);
+ jarSignerTool = QString::fromLatin1("%1 -sigalg %2 -digestalg %3 -keystore %4")
+ .arg(shellQuote(jarSignerTool)).arg(shellQuote(options.sigAlg)).arg(shellQuote(options.digestAlg)).arg(shellQuote(options.keyStore));
if (!options.keyStorePassword.isEmpty())
- jarSignerTool += QString::fromLatin1(" -storepass \"%1\"").arg(options.keyStorePassword);
+ jarSignerTool += QString::fromLatin1(" -storepass %1").arg(shellQuote(options.keyStorePassword));
if (!options.storeType.isEmpty())
- jarSignerTool += QString::fromLatin1(" -storetype \"%1\"").arg(options.storeType);
+ jarSignerTool += QString::fromLatin1(" -storetype %1").arg(shellQuote(options.storeType));
if (!options.keyPass.isEmpty())
- jarSignerTool += QString::fromLatin1(" -keypass \"%1\"").arg(options.keyPass);
+ jarSignerTool += QString::fromLatin1(" -keypass %1").arg(shellQuote(options.keyPass));
if (!options.sigFile.isEmpty())
- jarSignerTool += QString::fromLatin1(" -sigfile \"%1\"").arg(options.sigFile);
+ jarSignerTool += QString::fromLatin1(" -sigfile %1").arg(shellQuote(options.sigFile));
if (!options.signedJar.isEmpty())
- jarSignerTool += QString::fromLatin1(" -signedjar \"%1\"").arg(options.signedJar);
+ jarSignerTool += QString::fromLatin1(" -signedjar %1").arg(shellQuote(options.signedJar));
if (!options.tsaUrl.isEmpty())
- jarSignerTool += QString::fromLatin1(" -tsa \"%1\"").arg(options.tsaUrl);
+ jarSignerTool += QString::fromLatin1(" -tsa %1").arg(shellQuote(options.tsaUrl));
if (!options.tsaCert.isEmpty())
- jarSignerTool += QString::fromLatin1(" -tsacert \"%1\"").arg(options.tsaCert);
+ jarSignerTool += QString::fromLatin1(" -tsacert %1").arg(shellQuote(options.tsaCert));
if (options.internalSf)
jarSignerTool += QLatin1String(" -internalsf");
@@ -1897,12 +1969,12 @@ bool signPackage(const Options &options)
if (options.protectedAuthenticationPath)
jarSignerTool += QLatin1String(" -protected");
- jarSignerTool += QString::fromLatin1(" %1 \"%2\"")
- .arg(options.outputDirectory
+ jarSignerTool += QString::fromLatin1(" %1 %2")
+ .arg(shellQuote(options.outputDirectory
+ QLatin1String("/bin/")
+ apkName(options)
- + QLatin1String("-unsigned.apk"))
- .arg(options.keyStoreAlias);
+ + QLatin1String("-unsigned.apk")))
+ .arg(shellQuote(options.keyStoreAlias));
FILE *jarSignerCommand = popen(jarSignerTool.toLocal8Bit().constData(), "r");
if (jarSignerCommand == 0) {
@@ -1934,17 +2006,17 @@ bool signPackage(const Options &options)
return false;
}
- zipAlignTool = QString::fromLatin1("\"%1\"%2 -f 4 %3 %4")
- .arg(zipAlignTool)
+ zipAlignTool = QString::fromLatin1("%1%2 -f 4 %3 %4")
+ .arg(shellQuote(zipAlignTool))
.arg(options.verbose ? QString::fromLatin1(" -v") : QString())
- .arg(options.outputDirectory
+ .arg(shellQuote(options.outputDirectory
+ QLatin1String("/bin/")
+ apkName(options)
- + QLatin1String("-unsigned.apk "))
- .arg(options.outputDirectory
+ + QLatin1String("-unsigned.apk")))
+ .arg(shellQuote(options.outputDirectory
+ QLatin1String("/bin/")
+ apkName(options)
- + QLatin1String(".apk"));
+ + QLatin1String(".apk")));
FILE *zipAlignCommand = popen(zipAlignTool.toLocal8Bit(), "r");
if (zipAlignCommand == 0) {
@@ -2003,7 +2075,7 @@ bool deployAllToLocalTmp(const Options &options)
{
FILE *adbCommand = runAdb(options,
QString::fromLatin1(" push %1 /data/local/tmp/qt/")
- .arg(options.temporaryDirectoryName));
+ .arg(shellQuote(options.temporaryDirectoryName)));
if (adbCommand == 0)
return false;