diff options
author | Liang Qi <liang.qi@theqtcompany.com> | 2016-02-19 18:37:26 +0100 |
---|---|---|
committer | Liang Qi <liang.qi@theqtcompany.com> | 2016-02-19 18:37:26 +0100 |
commit | 852f4e4cf87d7db0eaa87384b1589e151f76e6cd (patch) | |
tree | 73bc838da6bde8b66e26c2e1a34ff319584edf82 | |
parent | 863a6621d14caf67adcf3f30cb955a268765f0f1 (diff) | |
parent | 98eebb2dc1830b262d72e748817aee25e54d0d35 (diff) |
Merge remote-tracking branch 'origin/5.6' into 5.7v5.7.0-alpha1
Conflicts:
.qmake.conf
Change-Id: Ibd5f6052bd07152fbe344505308563d9857771e9
-rw-r--r-- | src/assistant/help/qhelpsearchindexwriter_clucene.cpp | 10 | ||||
-rw-r--r-- | src/designer/src/components/formeditor/formwindow.cpp | 5 | ||||
-rw-r--r-- | src/macdeployqt/shared/shared.cpp | 82 | ||||
-rw-r--r-- | src/macdeployqt/shared/shared.h | 4 | ||||
-rw-r--r-- | src/qdoc/cppcodemarker.cpp | 15 | ||||
-rw-r--r-- | src/qdoc/cppcodeparser.cpp | 46 | ||||
-rw-r--r-- | src/qdoc/cppcodeparser.h | 2 | ||||
-rw-r--r-- | src/qdoc/generator.cpp | 22 | ||||
-rw-r--r-- | src/qdoc/htmlgenerator.cpp | 2 | ||||
-rw-r--r-- | src/qdoc/main.cpp | 5 | ||||
-rw-r--r-- | src/qdoc/node.cpp | 33 | ||||
-rw-r--r-- | src/qdoc/node.h | 18 | ||||
-rw-r--r-- | src/qdoc/qdocindexfiles.cpp | 20 | ||||
-rw-r--r-- | src/qdoc/qdoctagfiles.cpp | 10 | ||||
-rw-r--r-- | src/qdoc/tokenizer.cpp | 2 | ||||
-rw-r--r-- | src/qdoc/tokenizer.h | 3 | ||||
-rw-r--r-- | src/qtdiag/main.cpp | 4 | ||||
-rw-r--r-- | src/qtdiag/qtdiag.cpp | 51 | ||||
-rw-r--r-- | src/qtdiag/qtdiag.h | 3 | ||||
-rw-r--r-- | src/winrtrunner/appxengine.cpp | 332 | ||||
-rw-r--r-- | src/winrtrunner/appxengine.h | 1 | ||||
-rw-r--r-- | src/winrtrunner/appxengine_p.h | 1 | ||||
-rw-r--r-- | src/winrtrunner/appxphoneengine.cpp | 12 | ||||
-rw-r--r-- | src/winrtrunner/winrtrunner.pro | 3 |
24 files changed, 641 insertions, 45 deletions
diff --git a/src/assistant/help/qhelpsearchindexwriter_clucene.cpp b/src/assistant/help/qhelpsearchindexwriter_clucene.cpp index 96d46e0a4..f2a757f2e 100644 --- a/src/assistant/help/qhelpsearchindexwriter_clucene.cpp +++ b/src/assistant/help/qhelpsearchindexwriter_clucene.cpp @@ -331,6 +331,16 @@ static bool operator<(const QTextHtmlEntity &entity, const QString &entityStr) return QLatin1String(entity.name) < entityStr; } +static bool operator<(const QString &entityStr, const QTextHtmlEntity &entity) +{ + return entityStr < QLatin1String(entity.name); +} + +static bool operator<(const QTextHtmlEntity &entity, const QTextHtmlEntity &entity2) +{ + return QLatin1String(entity.name) < QLatin1String(entity2.name); +} + static QChar resolveEntity(const QString &entity) { const QTextHtmlEntity *start = &entities[0]; diff --git a/src/designer/src/components/formeditor/formwindow.cpp b/src/designer/src/components/formeditor/formwindow.cpp index d51090553..3d09740ad 100644 --- a/src/designer/src/components/formeditor/formwindow.cpp +++ b/src/designer/src/components/formeditor/formwindow.cpp @@ -2182,8 +2182,6 @@ void FormWindow::layoutContainer(QWidget *w, int type) w = core()->widgetFactory()->containerOfWidget(w); const QObjectList l = w->children(); - if (l.isEmpty()) - return; // find managed widget children QWidgetList widgets; const QObjectList::const_iterator ocend = l.constEnd(); @@ -2194,6 +2192,9 @@ void FormWindow::layoutContainer(QWidget *w, int type) widgets.append(widget); } + if (widgets.isEmpty()) // QTBUG-50563, observed when using hand-edited forms. + return; + LayoutCommand *cmd = new LayoutCommand(this); cmd->init(mainContainer(), widgets, static_cast<LayoutInfo::Type>(type), w); clearSelection(false); diff --git a/src/macdeployqt/shared/shared.cpp b/src/macdeployqt/shared/shared.cpp index 3cd98fc2c..f92110276 100644 --- a/src/macdeployqt/shared/shared.cpp +++ b/src/macdeployqt/shared/shared.cpp @@ -351,6 +351,19 @@ QStringList findAppFrameworkNames(const QString &appBundlePath) return frameworks; } +QStringList findAppFrameworkPaths(const QString &appBundlePath) +{ + QStringList frameworks; + QString searchPath = appBundlePath + "/Contents/Frameworks/"; + QDirIterator iter(searchPath, QStringList() << QString::fromLatin1("*.framework"), QDir::Dirs); + while (iter.hasNext()) { + iter.next(); + frameworks << iter.fileInfo().filePath(); + } + + return frameworks; +} + QStringList findAppLibraries(const QString &appBundlePath) { QStringList result; @@ -1241,7 +1254,7 @@ void codesignFile(const QString &identity, const QString &filePath) LogNormal() << "codesign" << filePath; QProcess codesign; - codesign.start("codesign", QStringList() << "--preserve-metadata=identifier,entitlements,resource-rules" + codesign.start("codesign", QStringList() << "--preserve-metadata=identifier,entitlements" << "--force" << "-s" << identity << filePath); codesign.waitForFinished(-1); @@ -1254,7 +1267,7 @@ void codesignFile(const QString &identity, const QString &filePath) } } -void codesign(const QString &identity, const QString &appBundlePath) +QSet<QString> codesignBundle(const QString &identity, const QString &appBundlePath) { // Code sign all binaries in the app bundle. This needs to // be done inside-out, e.g sign framework dependencies @@ -1280,10 +1293,37 @@ void codesign(const QString &identity, const QString &appBundlePath) foreach (const QString &binary, foundPluginBinaries) pendingBinaries.push(binary); - QStringList foundLibraries = findAppBundleFiles(appBundlePath + "/Contents/Frameworks/"); - foreach (const QString &binary, foundLibraries) - pendingBinaries.push(binary); + // Add frameworks for processing. + QStringList frameworkPaths = findAppFrameworkPaths(appBundlePath); + foreach (const QString &frameworkPath, frameworkPaths) { + + // Add all files for a framework as a catch all. + QStringList bundleFiles = findAppBundleFiles(frameworkPath); + foreach (const QString &binary, bundleFiles) + pendingBinaries.push(binary); + // Prioritise first to sign any additional inner bundles found in the Helpers folder (e.g + // used by QtWebEngine). + QDirIterator helpersIterator(frameworkPath, QStringList() << QString::fromLatin1("Helpers"), QDir::Dirs | QDir::NoSymLinks, QDirIterator::Subdirectories); + while (helpersIterator.hasNext()) { + helpersIterator.next(); + QString helpersPath = helpersIterator.filePath(); + QStringList innerBundleNames = QDir(helpersPath).entryList(QStringList() << "*.app", QDir::Dirs); + foreach (const QString &innerBundleName, innerBundleNames) + signedBinaries += codesignBundle(identity, helpersPath + "/" + innerBundleName); + } + + // Also make sure to sign any libraries that will not be found by otool because they + // are not linked and won't be seen as a dependency. + QDirIterator librariesIterator(frameworkPath, QStringList() << QString::fromLatin1("Libraries"), QDir::Dirs | QDir::NoSymLinks, QDirIterator::Subdirectories); + while (librariesIterator.hasNext()) { + librariesIterator.next(); + QString librariesPath = librariesIterator.filePath(); + bundleFiles = findAppBundleFiles(librariesPath); + foreach (const QString &binary, bundleFiles) + pendingBinaries.push(binary); + } + } // Sign all binares; use otool to find and sign dependencies first. while (!pendingBinaries.isEmpty()) { @@ -1293,17 +1333,39 @@ void codesign(const QString &identity, const QString &appBundlePath) // Check if there are unsigned dependencies, sign these first QStringList dependencies = getBinaryDependencies(rootBinariesPath, binary).toSet().subtract(signedBinaries).toList(); + if (!dependencies.isEmpty()) { pendingBinaries.push(binary); - foreach (const QString &dependency, dependencies) + int dependenciesSkipped = 0; + foreach (const QString &dependency, dependencies) { + // Skip dependencies that are outside the current app bundle, because this might + // cause a codesign error if the current bundle is part of the dependency (e.g. + // a bundle is part of a framework helper, and depends on that framework). + // The dependencies will be taken care of after the current bundle is signed. + if (!dependency.startsWith(appBundlePath)) { + ++dependenciesSkipped; + LogNormal() << "Skipping outside dependency: " << dependency; + continue; + } pendingBinaries.push(dependency); - continue; + } + + // If all dependencies were skipped, make sure the binary is actually signed, instead + // of going into an infinite loop. + if (dependenciesSkipped == dependencies.size()) { + pendingBinaries.pop(); + } else { + continue; + } } + // All dependencies are signed, now sign this binary codesignFile(identity, binary); signedBinaries.insert(binary); } + LogNormal() << "Finished codesigning " << appBundlePath << "with identity" << identity; + // Verify code signature QProcess codesign; codesign.start("codesign", QStringList() << "--deep" << "-v" << appBundlePath); @@ -1315,6 +1377,12 @@ void codesign(const QString &identity, const QString &appBundlePath) } else if (!err.isEmpty()) { LogDebug() << err; } + + return signedBinaries; +} + +void codesign(const QString &identity, const QString &appBundlePath) { + codesignBundle(identity, appBundlePath); } void createDiskImage(const QString &appBundlePath) diff --git a/src/macdeployqt/shared/shared.h b/src/macdeployqt/shared/shared.h index d94033b54..2368b370d 100644 --- a/src/macdeployqt/shared/shared.h +++ b/src/macdeployqt/shared/shared.h @@ -36,6 +36,7 @@ #include <QString> #include <QStringList> #include <QDebug> +#include <QSet> extern int logLevel; #define LogError() if (logLevel < 0) {} else qDebug() << "ERROR:" @@ -86,7 +87,6 @@ public: bool isFramework; }; - inline QDebug operator<<(QDebug debug, const ApplicationBundleInfo &info); void changeQtFrameworks(const QString appPath, const QString &qtPath, bool useDebugLibs); @@ -108,7 +108,9 @@ void runStrip(const QString &binaryPath); void stripAppBinary(const QString &bundlePath); QString findAppBinary(const QString &appBundlePath); QStringList findAppFrameworkNames(const QString &appBundlePath); +QStringList findAppFrameworkPaths(const QString &appBundlePath); void codesignFile(const QString &identity, const QString &filePath); +QSet<QString> codesignBundle(const QString &identity, const QString &appBundlePath); void codesign(const QString &identity, const QString &appBundlePath); void createDiskImage(const QString &appBundlePath); void fixupFramework(const QString &appBundlePath); diff --git a/src/qdoc/cppcodemarker.cpp b/src/qdoc/cppcodemarker.cpp index b0e4e823d..0f413c7f5 100644 --- a/src/qdoc/cppcodemarker.cpp +++ b/src/qdoc/cppcodemarker.cpp @@ -179,8 +179,14 @@ QString CppCodeMarker::markedUpSynopsis(const Node *node, if (style == Summary || style == Accessors) { if (func->virtualness() != FunctionNode::NonVirtual) synopsis.prepend("virtual "); + if (func->isFinal()) + synopsis.append(" final"); if (func->virtualness() == FunctionNode::PureVirtual) synopsis.append(" = 0"); + else if (func->isDeleted()) + synopsis.append(" = delete"); + else if (func->isDefaulted()) + synopsis.append(" = default"); } else if (style == Subpage) { if (!func->returnType().isEmpty() && func->returnType() != "void") @@ -190,8 +196,13 @@ QString CppCodeMarker::markedUpSynopsis(const Node *node, QStringList bracketed; if (func->isStatic()) { bracketed += "static"; - } - else if (func->virtualness() != FunctionNode::NonVirtual) { + } else if (func->isDeleted()) { + bracketed += "delete"; + } else if (func->isDefaulted()) { + bracketed += "default"; + } else if (func->virtualness() != FunctionNode::NonVirtual) { + if (func->isFinal()) + bracketed += "final"; if (func->virtualness() == FunctionNode::PureVirtual) bracketed += "pure"; bracketed += "virtual"; diff --git a/src/qdoc/cppcodeparser.cpp b/src/qdoc/cppcodeparser.cpp index 0405cc2c2..03b74b83e 100644 --- a/src/qdoc/cppcodeparser.cpp +++ b/src/qdoc/cppcodeparser.cpp @@ -1179,7 +1179,7 @@ bool CppCodeParser::matchTemplateHeader() return matchTemplateAngles(); } -bool CppCodeParser::matchDataType(CodeChunk *dataType, QString *var) +bool CppCodeParser::matchDataType(CodeChunk *dataType, QString *var, bool qProp) { /* This code is really hard to follow... sorry. The loop is there to match @@ -1255,7 +1255,7 @@ bool CppCodeParser::matchDataType(CodeChunk *dataType, QString *var) } while (match(Tok_Ampersand) || match(Tok_Aster) || match(Tok_const) || - match(Tok_Caret)) + match(Tok_Caret) || match(Tok_Ellipsis)) dataType->append(previousLexeme()); if (match(Tok_LeftParenAster)) { @@ -1305,6 +1305,10 @@ bool CppCodeParser::matchDataType(CodeChunk *dataType, QString *var) if (varComment.exactMatch(previousLexeme())) *var = varComment.cap(1); } + else if (qProp && (match(Tok_default) || match(Tok_final))) { + // Hack to make 'default' and 'final' work again in Q_PROPERTY + *var = previousLexeme(); + } } if (tok == Tok_LeftBracket) { @@ -1512,7 +1516,7 @@ bool CppCodeParser::matchFunctionDecl(Aggregate *parent, } if (parent && (tok == Tok_Semicolon || tok == Tok_LeftBracket || - tok == Tok_Colon) + tok == Tok_Colon || tok == Tok_Equal) && access != Node::Private) { if (tok == Tok_LeftBracket) { returnType.appendHotspot(); @@ -1528,7 +1532,7 @@ bool CppCodeParser::matchFunctionDecl(Aggregate *parent, return false; } } - else if (tok == Tok_Colon) { + else if (tok == Tok_Colon || tok == Tok_Equal) { returnType.appendHotspot(); while (tok != Tok_Semicolon && tok != Tok_Eoi) { @@ -1570,11 +1574,18 @@ bool CppCodeParser::matchFunctionDecl(Aggregate *parent, // look for const bool matchedConst = match(Tok_const); + bool matchFinal = match(Tok_final); - // look for 0 indicating pure virtual - if (match(Tok_Equal) && match(Tok_Number)) - virtuality = FunctionNode::PureVirtual; - + bool isDeleted = false; + bool isDefaulted = false; + if (match(Tok_Equal)) { + if (match(Tok_Number)) // look for 0 indicating pure virtual + virtuality = FunctionNode::PureVirtual; + else if (match(Tok_delete)) + isDeleted = true; + else if (match(Tok_default)) + isDefaulted = true; + } // look for colon indicating ctors which must be skipped if (match(Tok_Colon)) { while (tok != Tok_LeftBrace && tok != Tok_Eoi) @@ -1644,6 +1655,9 @@ bool CppCodeParser::matchFunctionDecl(Aggregate *parent, func->setStatic(matched_static); func->setConst(matchedConst); func->setVirtualness(virtuality); + func->setIsDeleted(isDeleted); + func->setIsDefaulted(isDefaulted); + func->setFinal(matchFinal); if (isQPrivateSignal) func->setPrivateSignal(); if (!pvect.isEmpty()) { @@ -1732,6 +1746,9 @@ bool CppCodeParser::matchClassDecl(Aggregate *parent, } } } + + const QString className = previousLexeme(); + match(Tok_final); // ignore C++11 final class-virt-specifier if (tok != Tok_Colon && tok != Tok_LeftBrace) return false; @@ -1739,7 +1756,7 @@ bool CppCodeParser::matchClassDecl(Aggregate *parent, So far, so good. We have 'class Foo {' or 'class Foo :'. This is enough to recognize a class definition. */ - ClassNode *classe = new ClassNode(parent, previousLexeme()); + ClassNode *classe = new ClassNode(parent, className); classe->setAccess(access); classe->setLocation(location()); if (compat) @@ -1931,8 +1948,15 @@ bool CppCodeParser::matchEnumDecl(Aggregate *parent) if (!match(Tok_enum)) return false; + if (tok == Tok_struct || tok == Tok_class) + readToken(); // ignore C++11 struct or class attribute if (match(Tok_Ident)) name = previousLexeme(); + if (match(Tok_Colon)) { // ignore C++11 enum-base + CodeChunk dataType; + if (!matchDataType(&dataType)) + return false; + } if (tok != Tok_LeftBrace) return false; @@ -1995,7 +2019,7 @@ bool CppCodeParser::matchProperty(Aggregate *parent) QString name; CodeChunk dataType; - if (!matchDataType(&dataType, &name)) + if (!matchDataType(&dataType, &name, true)) return false; PropertyNode *property = new PropertyNode(parent, name); @@ -2004,7 +2028,7 @@ bool CppCodeParser::matchProperty(Aggregate *parent) property->setDataType(dataType.toString()); while (tok != Tok_RightParen && tok != Tok_Eoi) { - if (!match(Tok_Ident)) + if (!match(Tok_Ident) && !match(Tok_default) && !match(Tok_final)) return false; QString key = previousLexeme(); QString value; diff --git a/src/qdoc/cppcodeparser.h b/src/qdoc/cppcodeparser.h index ec0448232..7c110d2bb 100644 --- a/src/qdoc/cppcodeparser.h +++ b/src/qdoc/cppcodeparser.h @@ -117,7 +117,7 @@ protected: bool matchModuleQualifier(QString& name); bool matchTemplateAngles(CodeChunk *type = 0); bool matchTemplateHeader(); - bool matchDataType(CodeChunk *type, QString *var = 0); + bool matchDataType(CodeChunk *type, QString *var = 0, bool qProp = false); bool matchParameter(QVector<Parameter>& pvect, bool& isQPrivateSignal); bool matchFunctionDecl(Aggregate *parent, QStringList *parentPathPtr, diff --git a/src/qdoc/generator.cpp b/src/qdoc/generator.cpp index 81ad2a94b..c8c2ecefd 100644 --- a/src/qdoc/generator.cpp +++ b/src/qdoc/generator.cpp @@ -752,8 +752,26 @@ void Generator::generateBody(const Node *node, CodeMarker *marker) } } if (node->doc().isEmpty()) { - if (!node->isWrapper() && !quiet && !node->isReimplemented()) { // ### might be unnecessary - node->location().warning(tr("No documentation for '%1'").arg(node->plainFullName())); + /* + Test for special function, like a destructor or copy constructor, + that has no documentation. + */ + if (node->type() == Node::Function) { + const FunctionNode* func = static_cast<const FunctionNode*>(node); + if (func->isDtor()) { + Text text; + text << "Destroys the instance of "; + text << func->parent()->name() << "."; + if (func->isVirtual()) + text << " The destructor is virtual."; + generateText(text, node, marker); + } + else if (!node->isWrapper() && !quiet && !node->isReimplemented()) { + node->location().warning(tr("No documentation for '%1'").arg(node->plainSignature())); + } + } + else if (!node->isWrapper() && !quiet && !node->isReimplemented()) { + node->location().warning(tr("No documentation for '%1'").arg(node->plainSignature())); } } else { diff --git a/src/qdoc/htmlgenerator.cpp b/src/qdoc/htmlgenerator.cpp index 6b43cc653..74b93b14d 100644 --- a/src/qdoc/htmlgenerator.cpp +++ b/src/qdoc/htmlgenerator.cpp @@ -3218,7 +3218,7 @@ void HtmlGenerator::generateList(const Node* relative, CodeMarker* marker, const comment where the topic is \group, \module, \qmlmodule, or \jsmodule */ - if (!relative || !relative->isCollectionNode()) { + if (relative && !relative->isCollectionNode()) { relative->doc().location().warning(tr("\\generatelist {%1} is only allowed in \\group, " "\\module, \\qmlmodule, and \\jsmodule comments.").arg(selector)); return; diff --git a/src/qdoc/main.cpp b/src/qdoc/main.cpp index 8ebebda79..500a085cc 100644 --- a/src/qdoc/main.cpp +++ b/src/qdoc/main.cpp @@ -728,8 +728,11 @@ int main(int argc, char **argv) Generator::setQDocPass(Generator::Prepare); if (parser.isSet(generateOption)) Generator::setQDocPass(Generator::Generate); - if (parser.isSet(singleExecOption)) + if (parser.isSet(singleExecOption)) { Generator::setSingleExec(); + if (parser.isSet(indexDirOption)) + qDebug() << "WARNING: -indexdir option ignored: Index files are not used in -single-exec mode."; + } if (parser.isSet(writeQaPagesOption)) Generator::setWriteQaPages(); if (parser.isSet(logProgressOption)) diff --git a/src/qdoc/node.cpp b/src/qdoc/node.cpp index 9740f984f..d91d473ce 100644 --- a/src/qdoc/node.cpp +++ b/src/qdoc/node.cpp @@ -165,6 +165,29 @@ QString Node::plainFullName(const Node* relative) const } /*! + Constructs and returns the node's fully qualified signature + by recursively ascending the parent links and prepending each + parent name + "::" to the plain signature. The return type is + not included. + */ +QString Node::plainSignature() const +{ + if (name_.isEmpty()) + return QLatin1String("global"); + + QString fullName; + const Node* node = this; + while (node) { + fullName.prepend(node->signature(false, true)); + if (node->parent()->name().isEmpty()) + break; + fullName.prepend(QLatin1String("::")); + node = node->parent(); + } + return fullName; +} + +/*! Constructs and returns this node's full name. */ QString Node::fullName(const Node* relative) const @@ -1951,6 +1974,9 @@ FunctionNode::FunctionNode(Aggregate *parent, const QString& name) attached_(false), privateSignal_(false), overload_(false), + isDeleted_(false), + isDefaulted_(false), + isFinal_(false), reimplementedFrom_(0) { setGenus(Node::CPP); @@ -1974,6 +2000,9 @@ FunctionNode::FunctionNode(NodeType type, Aggregate *parent, const QString& name attached_(attached), privateSignal_(false), overload_(false), + isDeleted_(false), + isDefaulted_(false), + isFinal_(false), reimplementedFrom_(0) { setGenus(Node::QML); @@ -2133,10 +2162,10 @@ QStringList FunctionNode::reconstructParameters(bool values) const is true, the default values of the parameters are included, if present. */ -QString FunctionNode::signature(bool values) const +QString FunctionNode::signature(bool values, bool noReturnType) const { QString s; - if (!returnType().isEmpty()) + if (!noReturnType && !returnType().isEmpty()) s = returnType() + QLatin1Char(' '); s += name() + QLatin1Char('('); QStringList reconstructedParameters = reconstructParameters(values); diff --git a/src/qdoc/node.h b/src/qdoc/node.h index 945bc2187..9df3dd70a 100644 --- a/src/qdoc/node.h +++ b/src/qdoc/node.h @@ -159,7 +159,9 @@ public: QString plainName() const; QString plainFullName(const Node* relative = 0) const; + QString plainSignature() const; QString fullName(const Node* relative=0) const; + virtual QString signature(bool , bool ) const { return plainName(); } const QString& fileNameBase() const { return fileNameBase_; } bool hasFileNameBase() const { return !fileNameBase_.isEmpty(); } @@ -894,6 +896,8 @@ public: bool isOverload() const { return overload_; } bool isReimplemented() const Q_DECL_OVERRIDE { return reimplemented_; } bool isFunction() const Q_DECL_OVERRIDE { return true; } + bool isDtor() const { return (metaness_ == Dtor); } + bool isVirtual() const { return (virtualness_ == NormalVirtual); } virtual bool isQmlSignal() const Q_DECL_OVERRIDE { return (type() == Node::QmlSignal) && (genus() == Node::QML); } @@ -926,7 +930,7 @@ public: bool hasActiveAssociatedProperty() const; QStringList reconstructParameters(bool values = false) const; - QString signature(bool values = false) const; + virtual QString signature(bool values, bool noReturnType = false) const; virtual QString element() const Q_DECL_OVERRIDE { return parent()->name(); } virtual bool isAttached() const Q_DECL_OVERRIDE { return attached_; } virtual bool isQtQuickNode() const Q_DECL_OVERRIDE { return parent()->isQtQuickNode(); } @@ -945,6 +949,15 @@ public: void debug() const; + bool isDeleted() const { return isDeleted_; } + void setIsDeleted(bool b) { isDeleted_ = b; } + + bool isDefaulted() const { return isDefaulted_; } + void setIsDefaulted(bool b) { isDefaulted_ = b; } + + void setFinal(bool b) { isFinal_ = b; } + bool isFinal() const { return isFinal_; } + private: void addAssociatedProperty(PropertyNode* property); @@ -961,6 +974,9 @@ private: bool attached_: 1; bool privateSignal_: 1; bool overload_ : 1; + bool isDeleted_ : 1; + bool isDefaulted_ : 1; + bool isFinal_ : 1; unsigned char overloadNumber_; QVector<Parameter> parameters_; const FunctionNode* reimplementedFrom_; diff --git a/src/qdoc/qdocindexfiles.cpp b/src/qdoc/qdocindexfiles.cpp index b3bf064fa..f588638fe 100644 --- a/src/qdoc/qdocindexfiles.cpp +++ b/src/qdoc/qdocindexfiles.cpp @@ -523,6 +523,9 @@ void QDocIndexFiles::readIndexSection(QXmlStreamReader& reader, functionNode->setMetaness(meta); functionNode->setConst(attributes.value(QLatin1String("const")) == QLatin1String("true")); functionNode->setStatic(attributes.value(QLatin1String("static")) == QLatin1String("true")); + functionNode->setIsDeleted(attributes.value(QLatin1String("delete")) == QLatin1String("true")); + functionNode->setIsDefaulted(attributes.value(QLatin1String("default")) == QLatin1String("true")); + functionNode->setFinal(attributes.value(QLatin1String("final")) == QLatin1String("true")); if (attributes.value(QLatin1String("overload")) == QLatin1String("true")) { functionNode->setOverloadFlag(true); functionNode->setOverloadNumber(attributes.value(QLatin1String("overload-number")).toUInt()); @@ -1245,6 +1248,9 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, writer.writeAttribute("const", functionNode->isConst()?"true":"false"); writer.writeAttribute("static", functionNode->isStatic()?"true":"false"); writer.writeAttribute("overload", functionNode->isOverload()?"true":"false"); + writer.writeAttribute("delete", functionNode->isDeleted() ? "true" : "false"); + writer.writeAttribute("default", functionNode->isDefaulted() ? "true" : "false"); + writer.writeAttribute("final", functionNode->isFinal() ? "true" : "false"); if (functionNode->isOverload()) writer.writeAttribute("overload-number", QString::number(functionNode->overloadNumber())); if (functionNode->relates()) { @@ -1267,9 +1273,17 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, Note: The "signature" attribute is written to the index file, but it is not read back in. Is that ok? */ - QString signature = functionNode->signature(); + QString signature = functionNode->signature(false); if (functionNode->isConst()) signature += " const"; + if (functionNode->isFinal()) + signature += " final"; + if (functionNode->virtualness() == FunctionNode::PureVirtual) + signature += " = 0"; + else if (functionNode->isDeleted()) + signature += " = delete"; + else if (functionNode->isDefaulted()) + signature += " = default"; writer.writeAttribute("signature", signature); for (int i = 0; i < functionNode->parameters().size(); ++i) { @@ -1483,9 +1497,9 @@ bool compareNodes(const Node* n1, const Node* n2) else if (f1->isConst() > f2->isConst()) return false; - if (f1->signature() < f2->signature()) + if (f1->signature(false) < f2->signature(false)) return true; - else if (f1->signature() > f2->signature()) + else if (f1->signature(false) > f2->signature(false)) return false; } diff --git a/src/qdoc/qdoctagfiles.cpp b/src/qdoc/qdoctagfiles.cpp index 1210ac7c3..cc5b30c8e 100644 --- a/src/qdoc/qdoctagfiles.cpp +++ b/src/qdoc/qdoctagfiles.cpp @@ -271,7 +271,7 @@ void QDocTagFiles::generateTagFileMembers(QXmlStreamWriter& writer, const Aggreg writer.writeAttribute("virtualness", "virtual"); break; case FunctionNode::PureVirtual: - writer.writeAttribute("virtual", "pure"); + writer.writeAttribute("virtualness", "pure"); break; default: break; @@ -287,12 +287,18 @@ void QDocTagFiles::generateTagFileMembers(QXmlStreamWriter& writer, const Aggreg QStringList pieces = gen_->fullDocumentLocation(node, false).split(QLatin1Char('#')); writer.writeTextElement("anchorfile", pieces[0]); writer.writeTextElement("anchor", pieces[1]); - QString signature = functionNode->signature(); + QString signature = functionNode->signature(false); signature = signature.mid(signature.indexOf(QChar('('))).trimmed(); if (functionNode->isConst()) signature += " const"; + if (functionNode->isFinal()) + signature += " final"; if (functionNode->virtualness() == FunctionNode::PureVirtual) signature += " = 0"; + else if (functionNode->isDeleted()) + signature += " = delete"; + else if (functionNode->isDefaulted()) + signature += " = default"; writer.writeTextElement("arglist", signature); } writer.writeEndElement(); // member diff --git a/src/qdoc/tokenizer.cpp b/src/qdoc/tokenizer.cpp index 987fff548..f723debe7 100644 --- a/src/qdoc/tokenizer.cpp +++ b/src/qdoc/tokenizer.cpp @@ -59,7 +59,7 @@ static const char *kwords[] = { "private", "protected", "public", "short", "signals", "signed", "slots", "static", "struct", "template", "typedef", "typename", "union", "unsigned", "using", "virtual", "void", "volatile", - "__int64", + "__int64", "default", "delete", "final", "Q_OBJECT", "Q_OVERRIDE", "Q_PROPERTY", diff --git a/src/qdoc/tokenizer.h b/src/qdoc/tokenizer.h index 41a3ffd93..2f293379f 100644 --- a/src/qdoc/tokenizer.h +++ b/src/qdoc/tokenizer.h @@ -66,7 +66,8 @@ enum { Tok_Eoi, Tok_Ampersand, Tok_Aster, Tok_Caret, Tok_LeftParen, Tok_public, Tok_short, Tok_signals, Tok_signed, Tok_slots, Tok_static, Tok_struct, Tok_template, Tok_typedef, Tok_typename, Tok_union, Tok_unsigned, Tok_using, Tok_virtual, - Tok_void, Tok_volatile, Tok_int64, Tok_Q_OBJECT, Tok_Q_OVERRIDE, + Tok_void, Tok_volatile, Tok_int64, Tok_default, Tok_delete, Tok_final, + Tok_Q_OBJECT, Tok_Q_OVERRIDE, Tok_Q_PROPERTY, Tok_Q_PRIVATE_PROPERTY, Tok_Q_DECLARE_SEQUENTIAL_ITERATOR, Tok_Q_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR, Tok_Q_DECLARE_ASSOCIATIVE_ITERATOR, diff --git a/src/qtdiag/main.cpp b/src/qtdiag/main.cpp index 6bc42bc2c..7e304d401 100644 --- a/src/qtdiag/main.cpp +++ b/src/qtdiag/main.cpp @@ -53,14 +53,18 @@ int main(int argc, char **argv) QCommandLineParser commandLineParser; const QCommandLineOption noGlOption(QStringLiteral("no-gl"), QStringLiteral("Do not output GL information")); const QCommandLineOption glExtensionOption(QStringLiteral("gl-extensions"), QStringLiteral("List GL extensions")); + const QCommandLineOption fontOption(QStringLiteral("fonts"), QStringLiteral("Output list of fonts")); commandLineParser.setApplicationDescription(QStringLiteral("Prints diagnostic output about the Qt library.")); commandLineParser.addOption(noGlOption); commandLineParser.addOption(glExtensionOption); + commandLineParser.addOption(fontOption); commandLineParser.addHelpOption(); commandLineParser.process(app); unsigned flags = commandLineParser.isSet(noGlOption) ? 0u : unsigned(QtDiagGl); if (commandLineParser.isSet(glExtensionOption)) flags |= QtDiagGlExtensions; + if (commandLineParser.isSet(fontOption)) + flags |= QtDiagFonts; std::wcout << qtDiag(flags).toStdWString(); return 0; diff --git a/src/qtdiag/qtdiag.cpp b/src/qtdiag/qtdiag.cpp index 4e9a25f28..310cbea08 100644 --- a/src/qtdiag/qtdiag.cpp +++ b/src/qtdiag/qtdiag.cpp @@ -113,6 +113,16 @@ QTextStream &operator<<(QTextStream &str, const QFont &f) return str; } +QTextStream &operator<<(QTextStream &str, QPlatformScreen::SubpixelAntialiasingType st) +{ + static const char *enumValues[] = { + "Subpixel_None", "Subpixel_RGB", "Subpixel_BGR", "Subpixel_VRGB", "Subpixel_VBGR" + }; + str << (size_t(st) < sizeof(enumValues) / sizeof(enumValues[0]) + ? enumValues[st] : "<Unknown>"); + return str; +} + #ifndef QT_NO_OPENGL QTextStream &operator<<(QTextStream &str, const QSurfaceFormat &format) @@ -222,6 +232,18 @@ static QString formatQDebug(T t) return result; } +// Helper to format a type via QDebug, stripping the class name. +template <class T> +static QString formatValueQDebug(T t) +{ + QString result = formatQDebug(t).trimmed(); + if (result.endsWith(QLatin1Char(')'))) { + result.chop(1); + result.remove(0, result.indexOf(QLatin1Char('(')) + 1); + } + return result; +} + static inline QByteArrayList qtFeatures() { QByteArrayList result; @@ -445,11 +467,7 @@ QString qtDiag(unsigned flags) << " from " << platformTheme->themeHint(QPlatformTheme::IconThemeSearchPaths).toStringList() << '\n'; } if (const QFont *systemFont = platformTheme->font()) - str << " System font : " << *systemFont<< '\n'; - str << " General font : " << QFontDatabase::systemFont(QFontDatabase::GeneralFont) << '\n' - << " Fixed font : " << QFontDatabase::systemFont(QFontDatabase::FixedFont) << '\n' - << " Title font : " << QFontDatabase::systemFont(QFontDatabase::TitleFont) << '\n' - << " Smallest font: " << QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont) << '\n'; + str << "\n System font : " << *systemFont<< '\n'; if (platformTheme->usePlatformNativeDialog(QPlatformTheme::FileDialog)) str << " Native file dialog\n"; @@ -460,6 +478,27 @@ QString qtDiag(unsigned flags) if (platformTheme->usePlatformNativeDialog(QPlatformTheme::MessageDialog)) str << " Native message dialog\n"; + str << "\nFonts:\n General font : " << QFontDatabase::systemFont(QFontDatabase::GeneralFont) << '\n' + << " Fixed font : " << QFontDatabase::systemFont(QFontDatabase::FixedFont) << '\n' + << " Title font : " << QFontDatabase::systemFont(QFontDatabase::TitleFont) << '\n' + << " Smallest font: " << QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont) << '\n'; + if (flags & QtDiagFonts) { + QFontDatabase fontDatabase; + const QStringList families = fontDatabase.families(); + str << "\n Families (" << families.size() << "):\n"; + for (int i = 0, count = families.size(); i < count; ++i) + str << " " << families.at(i) << '\n'; + + const QList<int> standardSizes = QFontDatabase::standardSizes(); + str << "\n Standard Sizes:"; + for (int i = 0, count = standardSizes.size(); i < count; ++i) + str << ' ' << standardSizes.at(i); + QList<QFontDatabase::WritingSystem> writingSystems = fontDatabase.writingSystems(); + str << "\n\n Writing systems:\n"; + for (int i = 0, count = writingSystems.size(); i < count; ++i) + str << " " << formatValueQDebug(writingSystems.at(i)) << '\n'; + } + const QList<QScreen*> screens = QGuiApplication::screens(); const int screenCount = screens.size(); str << "\nScreens: " << screenCount << ", High DPI scaling: " @@ -490,7 +529,7 @@ QString qtDiag(unsigned flags) << " Logical DPI: " << dpi; if (dpi != nativeDpi) str << " (native: " << nativeDpi << ')'; - str << "\n "; + str << ' ' << platformScreen->subpixelAntialiasingTypeHint() << "\n "; if (QHighDpiScaling::isActive()) str << "High DPI scaling factor: " << QHighDpiScaling::factor(screen) << ' '; str << "DevicePixelRatio: " << screen->devicePixelRatio() diff --git a/src/qtdiag/qtdiag.h b/src/qtdiag/qtdiag.h index 9076c9b7e..3729a53a4 100644 --- a/src/qtdiag/qtdiag.h +++ b/src/qtdiag/qtdiag.h @@ -40,7 +40,8 @@ QT_BEGIN_NAMESPACE enum QtDiagFlags { QtDiagGl = 0x1, - QtDiagGlExtensions = 0x2 + QtDiagGlExtensions = 0x2, + QtDiagFonts = 0x4 }; QString qtDiag(unsigned flags = 0); diff --git a/src/winrtrunner/appxengine.cpp b/src/winrtrunner/appxengine.cpp index eacf52db9..c74f7c4b4 100644 --- a/src/winrtrunner/appxengine.cpp +++ b/src/winrtrunner/appxengine.cpp @@ -52,6 +52,9 @@ #include <wrl.h> #include <windows.applicationmodel.h> #include <windows.management.deployment.h> +#if _MSC_VER >= 1900 +#include <wincrypt.h> +#endif using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; @@ -62,6 +65,240 @@ using namespace ABI::Windows::System; QT_USE_NAMESPACE +#if _MSC_VER >= 1900 +// *********** Taken from MSDN Example code +// https://msdn.microsoft.com/en-us/library/windows/desktop/jj835834%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396 + +#define SIGNER_SUBJECT_FILE 0x01 +#define SIGNER_NO_ATTR 0x00 +#define SIGNER_CERT_POLICY_CHAIN_NO_ROOT 0x08 +#define SIGNER_CERT_STORE 0x02 + +typedef struct _SIGNER_FILE_INFO +{ + DWORD cbSize; + LPCWSTR pwszFileName; + HANDLE hFile; +} SIGNER_FILE_INFO; + +typedef struct _SIGNER_BLOB_INFO +{ + DWORD cbSize; + GUID *pGuidSubject; + DWORD cbBlob; + BYTE *pbBlob; + LPCWSTR pwszDisplayName; +} SIGNER_BLOB_INFO; + +typedef struct _SIGNER_SUBJECT_INFO +{ + DWORD cbSize; + DWORD *pdwIndex; + DWORD dwSubjectChoice; + union + { + SIGNER_FILE_INFO *pSignerFileInfo; + SIGNER_BLOB_INFO *pSignerBlobInfo; + }; +} SIGNER_SUBJECT_INFO, *PSIGNER_SUBJECT_INFO; + +typedef struct _SIGNER_ATTR_AUTHCODE +{ + DWORD cbSize; + BOOL fCommercial; + BOOL fIndividual; + LPCWSTR pwszName; + LPCWSTR pwszInfo; +} SIGNER_ATTR_AUTHCODE; + +typedef struct _SIGNER_SIGNATURE_INFO +{ + DWORD cbSize; + ALG_ID algidHash; + DWORD dwAttrChoice; + union + { + SIGNER_ATTR_AUTHCODE *pAttrAuthcode; + }; + PCRYPT_ATTRIBUTES psAuthenticated; + PCRYPT_ATTRIBUTES psUnauthenticated; +} SIGNER_SIGNATURE_INFO, *PSIGNER_SIGNATURE_INFO; + +typedef struct _SIGNER_PROVIDER_INFO +{ + DWORD cbSize; + LPCWSTR pwszProviderName; + DWORD dwProviderType; + DWORD dwKeySpec; + DWORD dwPvkChoice; + union + { + LPWSTR pwszPvkFileName; + LPWSTR pwszKeyContainer; + }; +} SIGNER_PROVIDER_INFO, *PSIGNER_PROVIDER_INFO; + +typedef struct _SIGNER_SPC_CHAIN_INFO +{ + DWORD cbSize; + LPCWSTR pwszSpcFile; + DWORD dwCertPolicy; + HCERTSTORE hCertStore; +} SIGNER_SPC_CHAIN_INFO; + +typedef struct _SIGNER_CERT_STORE_INFO +{ + DWORD cbSize; + PCCERT_CONTEXT pSigningCert; + DWORD dwCertPolicy; + HCERTSTORE hCertStore; +} SIGNER_CERT_STORE_INFO; + +typedef struct _SIGNER_CERT +{ + DWORD cbSize; + DWORD dwCertChoice; + union + { + LPCWSTR pwszSpcFile; + SIGNER_CERT_STORE_INFO *pCertStoreInfo; + SIGNER_SPC_CHAIN_INFO *pSpcChainInfo; + }; + HWND hwnd; +} SIGNER_CERT, *PSIGNER_CERT; + +typedef struct _SIGNER_CONTEXT +{ + DWORD cbSize; + DWORD cbBlob; + BYTE *pbBlob; +} SIGNER_CONTEXT, *PSIGNER_CONTEXT; + +typedef struct _SIGNER_SIGN_EX2_PARAMS +{ + DWORD dwFlags; + PSIGNER_SUBJECT_INFO pSubjectInfo; + PSIGNER_CERT pSigningCert; + PSIGNER_SIGNATURE_INFO pSignatureInfo; + PSIGNER_PROVIDER_INFO pProviderInfo; + DWORD dwTimestampFlags; + PCSTR pszAlgorithmOid; + PCWSTR pwszTimestampURL; + PCRYPT_ATTRIBUTES pCryptAttrs; + PVOID pSipData; + PSIGNER_CONTEXT *pSignerContext; + PVOID pCryptoPolicy; + PVOID pReserved; +} SIGNER_SIGN_EX2_PARAMS, *PSIGNER_SIGN_EX2_PARAMS; + +typedef struct _APPX_SIP_CLIENT_DATA +{ + PSIGNER_SIGN_EX2_PARAMS pSignerParams; + IUnknown* pAppxSipState; +} APPX_SIP_CLIENT_DATA, *PAPPX_SIP_CLIENT_DATA; + +bool signAppxPackage(PCCERT_CONTEXT signingCertContext, LPCWSTR packageFilePath) +{ + HRESULT hr = S_OK; + + DWORD signerIndex = 0; + + SIGNER_FILE_INFO fileInfo = {}; + fileInfo.cbSize = sizeof(SIGNER_FILE_INFO); + fileInfo.pwszFileName = packageFilePath; + + SIGNER_SUBJECT_INFO subjectInfo = {}; + subjectInfo.cbSize = sizeof(SIGNER_SUBJECT_INFO); + subjectInfo.pdwIndex = &signerIndex; + subjectInfo.dwSubjectChoice = SIGNER_SUBJECT_FILE; + subjectInfo.pSignerFileInfo = &fileInfo; + + SIGNER_CERT_STORE_INFO certStoreInfo = {}; + certStoreInfo.cbSize = sizeof(SIGNER_CERT_STORE_INFO); + certStoreInfo.dwCertPolicy = SIGNER_CERT_POLICY_CHAIN_NO_ROOT; + certStoreInfo.pSigningCert = signingCertContext; + + SIGNER_CERT cert = {}; + cert.cbSize = sizeof(SIGNER_CERT); + cert.dwCertChoice = SIGNER_CERT_STORE; + cert.pCertStoreInfo = &certStoreInfo; + + // The algidHash of the signature to be created must match the + // hash algorithm used to create the app package + SIGNER_SIGNATURE_INFO signatureInfo = {}; + signatureInfo.cbSize = sizeof(SIGNER_SIGNATURE_INFO); + signatureInfo.algidHash = CALG_SHA_512; + signatureInfo.dwAttrChoice = SIGNER_NO_ATTR; + + SIGNER_SIGN_EX2_PARAMS signerParams = {}; + signerParams.pSubjectInfo = &subjectInfo; + signerParams.pSigningCert = &cert; + signerParams.pSignatureInfo = &signatureInfo; + + APPX_SIP_CLIENT_DATA sipClientData = {}; + sipClientData.pSignerParams = &signerParams; + signerParams.pSipData = &sipClientData; + + // Type definition for invoking SignerSignEx2 via GetProcAddress + typedef HRESULT (WINAPI *SignerSignEx2Function)( + DWORD, + PSIGNER_SUBJECT_INFO, + PSIGNER_CERT, + PSIGNER_SIGNATURE_INFO, + PSIGNER_PROVIDER_INFO, + DWORD, + PCSTR, + PCWSTR, + PCRYPT_ATTRIBUTES, + PVOID, + PSIGNER_CONTEXT *, + PVOID, + PVOID); + + // Load the SignerSignEx2 function from MSSign32.dll + HMODULE msSignModule = LoadLibraryEx( + L"MSSign32.dll", + NULL, + LOAD_LIBRARY_SEARCH_SYSTEM32); + + if (!msSignModule) { + qCWarning(lcWinRtRunner) << "LoadLibraryEx failed to load MSSign32.dll."; + return false; + } + + SignerSignEx2Function SignerSignEx2 = reinterpret_cast<SignerSignEx2Function>( + GetProcAddress(msSignModule, "SignerSignEx2")); + if (!SignerSignEx2) { + qCWarning(lcWinRtRunner) << "Could not resolve SignerSignEx2"; + FreeLibrary(msSignModule); + return false; + } + hr = SignerSignEx2(signerParams.dwFlags, + signerParams.pSubjectInfo, + signerParams.pSigningCert, + signerParams.pSignatureInfo, + signerParams.pProviderInfo, + signerParams.dwTimestampFlags, + signerParams.pszAlgorithmOid, + signerParams.pwszTimestampURL, + signerParams.pCryptAttrs, + signerParams.pSipData, + signerParams.pSignerContext, + signerParams.pCryptoPolicy, + signerParams.pReserved); + + FreeLibrary(msSignModule); + + RETURN_FALSE_IF_FAILED("Could not sign package."); + + if (sipClientData.pAppxSipState) + sipClientData.pAppxSipState->Release(); + + return true; +} +// ************ MSDN +#endif // MSC_VER >= 1900 + bool AppxEngine::getManifestFile(const QString &fileName, QString *manifest) { if (!QFile::exists(fileName)) { @@ -194,6 +431,14 @@ AppxEngine::AppxEngine(Runner *runner, AppxEnginePrivate *dd) d->packageFamilyName = QString::fromWCharArray(packageFamilyName); CoTaskMemFree(packageFamilyName); +#if _MSC_VER >= 1900 + LPWSTR publisher; + packageId->GetPublisher(&publisher); + CHECK_RESULT_FATAL("Failed to retrieve publisher name from package.", return); + d->publisherName = QString::fromWCharArray(publisher); + CoTaskMemFree(publisher); +#endif // _MSC_VER >= 1900 + ComPtr<IAppxManifestApplicationsEnumerator> applications; hr = manifestReader->GetApplications(&applications); CHECK_RESULT_FATAL("Failed to get a list of applications from the manifest.", return); @@ -441,3 +686,90 @@ bool AppxEngine::createPackage(const QString &packageFileName) return true; } + +bool AppxEngine::sign(const QString &fileName) +{ +#if _MSC_VER >= 1900 + Q_D(const AppxEngine); + BYTE buffer[256]; + DWORD bufferSize = 256; + + if (!CertStrToName(X509_ASN_ENCODING, wchar(d->publisherName), CERT_X500_NAME_STR, 0, buffer, &bufferSize, 0)) { + qCWarning(lcWinRtRunner) << "CertStrToName failed"; + return false; + } + CERT_NAME_BLOB certBlob; + certBlob.cbData = bufferSize; + certBlob.pbData = buffer; + + CRYPT_ALGORITHM_IDENTIFIER identifier; + identifier.pszObjId = strdup(szOID_RSA_SHA256RSA); + identifier.Parameters.cbData = 0; + identifier.Parameters.pbData = NULL; + + CERT_EXTENSIONS extensions; + extensions.cExtension = 2; + extensions.rgExtension = new CERT_EXTENSION[2]; + + // Basic Constraints + CERT_BASIC_CONSTRAINTS2_INFO constraintsInfo; + constraintsInfo.fCA = FALSE; + constraintsInfo.fPathLenConstraint = FALSE; + constraintsInfo.dwPathLenConstraint = 0; + + BYTE *constraintsEncoded = NULL; + DWORD encodedSize = 0; + CryptEncodeObject(X509_ASN_ENCODING, X509_BASIC_CONSTRAINTS2, &constraintsInfo, + constraintsEncoded, &encodedSize); + constraintsEncoded = new BYTE[encodedSize]; + if (!CryptEncodeObject(X509_ASN_ENCODING, X509_BASIC_CONSTRAINTS2, &constraintsInfo, + constraintsEncoded, &encodedSize)) { + qCWarning(lcWinRtRunner) << "Could not encode basic constraints."; + delete [] constraintsEncoded; + return false; + } + + extensions.rgExtension[0].pszObjId = strdup(szOID_BASIC_CONSTRAINTS2); + extensions.rgExtension[0].fCritical = TRUE; + extensions.rgExtension[0].Value.cbData = encodedSize; + extensions.rgExtension[0].Value.pbData = constraintsEncoded; + + // Code Signing + char *codeSign = strdup(szOID_PKIX_KP_CODE_SIGNING); + CERT_ENHKEY_USAGE enhancedUsage; + enhancedUsage.cUsageIdentifier = 1; + enhancedUsage.rgpszUsageIdentifier = &codeSign; + + BYTE *enhancedKeyEncoded = 0; + encodedSize = 0; + CryptEncodeObject(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE, &enhancedUsage, + enhancedKeyEncoded, &encodedSize); + enhancedKeyEncoded = new BYTE[encodedSize]; + if (!CryptEncodeObject(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE, &enhancedUsage, + enhancedKeyEncoded, &encodedSize)) { + qCWarning(lcWinRtRunner) << "Could not encode enhanced key usage."; + delete [] constraintsEncoded; + return false; + } + + extensions.rgExtension[1].pszObjId = strdup(szOID_ENHANCED_KEY_USAGE); + extensions.rgExtension[1].fCritical = TRUE; + extensions.rgExtension[1].Value.cbData = encodedSize; + extensions.rgExtension[1].Value.pbData = enhancedKeyEncoded; + + PCCERT_CONTEXT context = CertCreateSelfSignCertificate(NULL, &certBlob, NULL, NULL, + &identifier, NULL, NULL, &extensions); + + delete [] constraintsEncoded; + + if (!context) { + qCWarning(lcWinRtRunner) << "Failed to create self sign certificate:" << GetLastError(); + return false; + } + + return signAppxPackage(context, wchar(fileName)); +#else // _MSC_VER < 1900 + Q_UNUSED(fileName); + return true; +#endif // _MSC_VER < 1900 +} diff --git a/src/winrtrunner/appxengine.h b/src/winrtrunner/appxengine.h index 30b03fe07..4aec67588 100644 --- a/src/winrtrunner/appxengine.h +++ b/src/winrtrunner/appxengine.h @@ -63,6 +63,7 @@ protected: bool installDependencies(); bool createPackage(const QString &packageFileName); + bool sign(const QString &fileName); static bool getManifestFile(const QString &fileName, QString *manifest = 0); QScopedPointer<AppxEnginePrivate> d_ptr; diff --git a/src/winrtrunner/appxengine_p.h b/src/winrtrunner/appxengine_p.h index 4d20acf91..982c484b2 100644 --- a/src/winrtrunner/appxengine_p.h +++ b/src/winrtrunner/appxengine_p.h @@ -73,6 +73,7 @@ public: QString manifest; QString packageFullName; QString packageFamilyName; + QString publisherName; ABI::Windows::System::ProcessorArchitecture packageArchitecture; QString executable; qint64 pid; diff --git a/src/winrtrunner/appxphoneengine.cpp b/src/winrtrunner/appxphoneengine.cpp index e7cbf6709..edbb58ea5 100644 --- a/src/winrtrunner/appxphoneengine.cpp +++ b/src/winrtrunner/appxphoneengine.cpp @@ -258,6 +258,14 @@ AppxPhoneEngine::~AppxPhoneEngine() QString AppxPhoneEngine::extensionSdkPath() const { +#if _MSC_VER >= 1900 + const QByteArray extensionSdkDirRaw = qgetenv("ExtensionSdkDir"); + if (extensionSdkDirRaw.isEmpty()) { + qCWarning(lcWinRtRunner) << "The environment variable ExtensionSdkDir is not set."; + return QString(); + } + return QString::fromLocal8Bit(extensionSdkDirRaw); +#else // _MSC_VER < 1900 HKEY regKey; LONG hr = RegOpenKeyEx( HKEY_LOCAL_MACHINE, @@ -278,6 +286,7 @@ QString AppxPhoneEngine::extensionSdkPath() const return QString::fromWCharArray(pathData, (pathLength - 1) / sizeof(wchar_t)) + QLatin1String("ExtensionSDKs"); +#endif // _MSC_VER < 1900 } bool AppxPhoneEngine::installPackage(IAppxManifestReader *reader, const QString &filePath) @@ -384,6 +393,9 @@ bool AppxPhoneEngine::install(bool removeFirst) if (!createPackage(packageFileName)) return false; + if (!sign(packageFileName)) + return false; + ComPtr<IStream> manifestStream; hr = SHCreateStreamOnFile(wchar(d->manifest), STGM_READ, &manifestStream); RETURN_FALSE_IF_FAILED("Failed to open manifest stream"); diff --git a/src/winrtrunner/winrtrunner.pro b/src/winrtrunner/winrtrunner.pro index c98f0df70..73ca2cdd4 100644 --- a/src/winrtrunner/winrtrunner.pro +++ b/src/winrtrunner/winrtrunner.pro @@ -17,4 +17,7 @@ win32-msvc2013|win32-msvc2015 { include(../shared/corecon/corecon.pri) } +# Windows 10 requires signing +*msvc2015: LIBS += -lcrypt32 + load(qt_tool) |