1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Volker Krause <volker.krause@kdab.com>
4 ** Copyright (C) 2016 Intel Corporation.
5 ** Contact: https://www.qt.io/licensing/
6 **
7 ** This file is part of the tools applications of the Qt Toolkit
8 **
9 ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
10 ** Commercial License Usage
11 ** Licensees holding valid commercial Qt licenses may use this file in
12 ** accordance with the commercial license agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and The Qt Company. For licensing terms
15 ** and conditions see https://www.qt.io/terms-conditions. For further
16 ** information use the contact form at https://www.qt.io/contact-us.
17 **
18 ** GNU General Public License Usage
19 ** Alternatively, this file may be used under the terms of the GNU
20 ** General Public License version 3 as published by the Free Software
21 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
22 ** included in the packaging of this file. Please review the following
23 ** information to ensure the GNU General Public License requirements will
24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25 **
26 ** $QT_END_LICENSE$
27 **
28 ****************************************************************************/
29 
30 #include <QCommandLineParser>
31 #include <QCoreApplication>
32 #include <QDir>
33 #include <QFile>
34 #include <QJsonDocument>
35 #include <QJsonObject>
36 #include <QLibrary>
37 #include <QPluginLoader>
38 #include <QStringList>
39 
40 #include <iostream>
41 
42 enum PrintOption {
43     PrintIID = 0x01,
44     PrintClassName = 0x02,
45     PrintQtInfo = 0x04,
46     PrintUserData = 0x08
47 };
Q_DECLARE_FLAGS(PrintOptions,PrintOption)48 Q_DECLARE_FLAGS(PrintOptions, PrintOption)
49 Q_DECLARE_OPERATORS_FOR_FLAGS(PrintOptions)
50 
51 int main(int argc, char** argv)
52 {
53     QCoreApplication app(argc, argv);
54     QCoreApplication::setApplicationName(QStringLiteral("qplugininfo"));
55     QCoreApplication::setApplicationVersion(QStringLiteral(QT_VERSION_STR));
56 
57     QCommandLineParser parser;
58     parser.setApplicationDescription(QStringLiteral("Qt5 plugin meta-data dumper"));
59     QCommandLineOption jsonFormatOption(QStringList() << "f" << "json-format",
60                                         QStringLiteral("Print JSON data as: indented, compact"), QStringLiteral("format"));
61     QCommandLineOption fullJsonOption("full-json",
62                                       QStringLiteral("Print the plugin metadata in JSON format"));
63     QCommandLineOption printOption(QStringList() << "p" << QStringLiteral("print"),
64                                    QStringLiteral("Print detail (iid, classname, qtinfo, userdata)"), QStringLiteral("detail"));
65     jsonFormatOption.setDefaultValue(QStringLiteral("indented"));
66     printOption.setDefaultValues(QStringList() << QStringLiteral("iid") << QStringLiteral("qtinfo") << QStringLiteral("userdata"));
67 
68     parser.addOption(fullJsonOption);
69     parser.addOption(jsonFormatOption);
70     parser.addOption(printOption);
71     parser.addHelpOption();
72     parser.addVersionOption();
73     parser.addPositionalArgument(QStringLiteral("plugin"), QStringLiteral("Plug-in of which to read the meta data."), QStringLiteral("<plugin>"));
74     parser.process(app);
75 
76     if (parser.positionalArguments().isEmpty())
77         parser.showHelp(1);
78 
79     bool fullJson = parser.isSet(fullJsonOption);
80     QJsonDocument::JsonFormat jsonFormat = parser.value(jsonFormatOption) == "indented" ? QJsonDocument::Indented : QJsonDocument::Compact;
81     QStringList printOptionList = parser.values(printOption);
82     PrintOptions print;
83     if (printOptionList.contains("iid"))
84         print |= PrintIID;
85     if (printOptionList.contains("classname"))
86         print |= PrintClassName;
87     if (printOptionList.contains("qtinfo"))
88         print |= PrintQtInfo;
89     if (printOptionList.contains("userdata"))
90         print |= PrintUserData;
91 
92     int retval = 0;
93     const QStringList positionalArguments = parser.positionalArguments();
94     for (const QString &plugin : positionalArguments) {
95         QByteArray pluginNativeName = QFile::encodeName(QDir::toNativeSeparators(plugin));
96         if (!QFile::exists(plugin)) {
97             std::cerr << "qtplugininfo: " << pluginNativeName.constData() << ": No such file or directory." << std::endl;
98             retval = 1;
99             continue;
100         }
101         if (!QLibrary::isLibrary(plugin)) {
102             std::cerr << "qtplugininfo: " << pluginNativeName.constData() << ": Not a plug-in." << std::endl;
103             retval = 1;
104             continue;
105         }
106 
107         QPluginLoader loader(plugin);
108         QJsonObject metaData = loader.metaData();
109         if (metaData.isEmpty()) {
110             std::cerr << "qtplugininfo: " << pluginNativeName.constData() << ": No plug-in meta-data found: "
111                       << qPrintable(loader.errorString()) << std::endl;
112             retval = 1;
113             continue;
114         }
115 
116         QString iid = metaData.value("IID").toString();
117         QString className = metaData.value("className").toString();
118         QJsonValue debug = metaData.value("debug");
119         int version = metaData.value("version").toInt();
120         QJsonValue userData = metaData.value("MetaData");
121 
122         if ((version >> 16) != (QT_VERSION >> 16)) {
123             std::cerr << "qtplugininfo: " << pluginNativeName.constData()
124                       << ": Qt version mismatch - got major version " << (version >> 16)
125                       << ", expected " << (QT_VERSION >> 16) << std::endl;
126             retval = 1;
127             continue;
128         }
129         if (iid.isEmpty() || className.isEmpty() || debug.isNull()) {
130             std::cerr << "qtplugininfo: " << pluginNativeName.constData() << ": invalid metadata, missing required fields:";
131             if (iid.isEmpty())
132                 std::cerr << " iid";
133             if (className.isEmpty())
134                 std::cerr << " className";
135             if (debug.isNull())
136                 std::cerr << " debug";
137             std::cerr << std::endl;
138             retval = 1;
139             continue;
140         }
141 
142         if (parser.positionalArguments().size() != 1)
143             std::cout << pluginNativeName.constData() << ": ";
144         if (fullJson) {
145             std::cout << QJsonDocument(metaData).toJson(jsonFormat).constData();
146             if (jsonFormat == QJsonDocument::Compact)
147                 std::cout << std::endl;
148         } else {
149             if (print & PrintIID)
150                 std::cout << "IID \"" << qPrintable(iid) << "\" ";
151             if (print & PrintClassName)
152                 std::cout << "class " << qPrintable(className) << ' ';
153             if (print & PrintQtInfo)
154                 std::cout << "Qt " << (version >> 16) << '.' << ((version >> 8) & 0xFF) << '.' << (version & 0xFF)
155                           << (debug.toBool() ? " (debug)" : " (release)");
156             std::cout << std::endl;
157             if (print & PrintUserData) {
158                 if (userData.isObject())
159                     std::cout << "User Data: " << QJsonDocument(userData.toObject()).toJson().constData();
160                 else if (!userData.isNull()) {
161                     std::cerr << "qtplugininfo: " << pluginNativeName.constData() << ": invalid metadata, user data is not a JSON object" << std::endl;
162                     retval = 1;
163                 }
164             }
165         }
166     }
167 
168     return retval;
169 }
170