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;
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) {
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) {
}
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());
{
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;
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)
pclose(adbCommand);
}
- adbCommand = runAdb(*options, QLatin1String(" ls ") + directory);
+ adbCommand = runAdb(*options, QLatin1String(" ls ") + shellQuote(directory));
if (adbCommand == 0)
return false;
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));
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) {
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;
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;
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");
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) {
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) {
{
FILE *adbCommand = runAdb(options,
QString::fromLatin1(" push %1 /data/local/tmp/qt/")
- .arg(options.temporaryDirectoryName));
+ .arg(shellQuote(options.temporaryDirectoryName)));
if (adbCommand == 0)
return false;