Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
main.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3// Qt-Security score:insignificant reason:build-tool
4
5#include "../shared/collectionconfiguration.h"
9
10#include <QtCore/QBuffer>
11#include <QtCore/QDataStream>
12#include <QtCore/QDir>
13#include <QtCore/QFileInfo>
14#include <QtCore/QLibraryInfo>
15#include <QtCore/QRegularExpression>
16#include <QtCore/QTranslator>
17
18#include <QtGui/QGuiApplication>
19
20#include <QtHelp/QHelpEngineCore>
21
22
23QT_USE_NAMESPACE
24
25class QHG {
26 Q_DECLARE_TR_FUNCTIONS(QHelpGenerator)
27};
28
29static const char QHP[] = "qhp";
30static const char QCH[] = "qch";
31
32static const char QHCP[] = "qhcp";
33static const char QHC[] = "qhc";
34
35namespace {
36 QString absoluteFilePath(const QString &basePath, const QString &fileName)
37 {
38 return QDir(basePath).absoluteFilePath(fileName);
39 }
40}
41
42int generateCollectionFile(const QByteArray &data, const QString &basePath, const QString outputFile)
43{
44 fputs(qPrintable(QHG::tr("Reading collection config file...\n")), stdout);
45 CollectionConfigReader config;
46 config.readData(data);
47 if (config.hasError()) {
48 fputs(qPrintable(QHG::tr("Collection config file error: %1\n")
49 .arg(config.errorString())), stderr);
50 return 1;
51 }
52
53 const QMap<QString, QString> &filesToGenerate = config.filesToGenerate();
54 for (auto it = filesToGenerate.cbegin(), end = filesToGenerate.cend(); it != end; ++it) {
55 fputs(qPrintable(QHG::tr("Generating help for %1...\n").arg(it.key())), stdout);
56 QHelpProjectData helpData;
57 if (!helpData.readData(absoluteFilePath(basePath, it.key()))) {
58 fprintf(stderr, "%s\n", qPrintable(helpData.errorMessage()));
59 return 1;
60 }
61
62 HelpGenerator helpGenerator;
63 if (!helpGenerator.generate(&helpData, absoluteFilePath(basePath, it.value()))) {
64 fprintf(stderr, "%s\n", qPrintable(helpGenerator.error()));
65 return 1;
66 }
67 }
68
69 fputs(qPrintable(QHG::tr("Creating collection file...\n")), stdout);
70
71 QFileInfo colFi(outputFile);
72 if (colFi.exists()) {
73 if (!colFi.dir().remove(colFi.fileName())) {
74 fputs(qPrintable(QHG::tr("The file %1 cannot be overwritten.\n")
75 .arg(outputFile)), stderr);
76 return 1;
77 }
78 }
79
80 QHelpEngineCore helpEngine(outputFile);
81 helpEngine.setReadOnly(false);
82 if (!helpEngine.setupData()) {
83 fprintf(stderr, "%s\n", qPrintable(helpEngine.error()));
84 return 1;
85 }
86
87 for (const QString &file : config.filesToRegister()) {
88 if (!helpEngine.registerDocumentation(absoluteFilePath(basePath, file))) {
89 fprintf(stderr, "%s\n", qPrintable(helpEngine.error()));
90 return 1;
91 }
92 }
93 if (!config.filesToRegister().isEmpty()) {
94 if (Q_UNLIKELY(qEnvironmentVariableIsSet("SOURCE_DATE_EPOCH"))) {
95 QDateTime dt;
96 dt.setTimeZone(QTimeZone::UTC);
97 dt.setSecsSinceEpoch(qEnvironmentVariableIntValue("SOURCE_DATE_EPOCH"));
99 } else {
101 }
102 }
103
104 if (!config.title().isEmpty())
105 CollectionConfiguration::setWindowTitle(helpEngine, config.title());
106
107 if (!config.homePage().isEmpty()) {
108 CollectionConfiguration::setDefaultHomePage(helpEngine,
109 config.homePage());
110 }
111
112 if (!config.startPage().isEmpty()) {
113 CollectionConfiguration::setLastShownPages(helpEngine,
114 QStringList(config.startPage()));
115 }
116
117 if (!config.currentFilter().isEmpty()) {
118 helpEngine.setCurrentFilter(config.currentFilter());
119 }
120
121 if (!config.cacheDirectory().isEmpty()) {
122 CollectionConfiguration::setCacheDir(helpEngine, config.cacheDirectory(),
123 config.cacheDirRelativeToCollection());
124 }
125
127 config.enableFilterFunctionality());
129 !config.hideFilterFunctionality());
131 config.enableDocumentationManager());
133 config.enableAddressBar());
135 !config.hideAddressBar());
136 uint time = QDateTime::currentMSecsSinceEpoch() / 1000;
137 if (Q_UNLIKELY(qEnvironmentVariableIsSet("SOURCE_DATE_EPOCH")))
138 time = qEnvironmentVariableIntValue("SOURCE_DATE_EPOCH");
139 CollectionConfiguration::setCreationTime(helpEngine, time);
141 config.fullTextSearchFallbackEnabled());
142
143 if (!config.applicationIcon().isEmpty()) {
144 QFile icon(absoluteFilePath(basePath, config.applicationIcon()));
145 if (!icon.open(QIODevice::ReadOnly)) {
146 fputs(qPrintable(QHG::tr("Cannot open %1.\n").arg(icon.fileName())), stderr);
147 return 1;
148 }
149 CollectionConfiguration::setApplicationIcon(helpEngine, icon.readAll());
150 }
151
152 if (config.aboutMenuTexts().size()) {
153 QByteArray ba;
154 QDataStream s(&ba, QIODevice::WriteOnly);
155 const QMap<QString, QString> &aboutMenuTexts = config.aboutMenuTexts();
156 for (auto it = aboutMenuTexts.cbegin(), end = aboutMenuTexts.cend(); it != end; ++it)
157 s << it.key() << it.value();
158 CollectionConfiguration::setAboutMenuTexts(helpEngine, ba);
159 }
160
161 if (!config.aboutIcon().isEmpty()) {
162 QFile icon(absoluteFilePath(basePath, config.aboutIcon()));
163 if (!icon.open(QIODevice::ReadOnly)) {
164 fputs(qPrintable(QHG::tr("Cannot open %1.\n").arg(icon.fileName())), stderr);
165 return 1;
166 }
167 CollectionConfiguration::setAboutIcon(helpEngine, icon.readAll());
168 }
169
170 if (config.aboutTextFiles().size()) {
171 QByteArray ba;
172 QDataStream s(&ba, QIODevice::WriteOnly);
173 QMap<QString, QByteArray> imgData;
174
175 QRegularExpression srcRegExp(QLatin1String("src=(\"(.+)\"|([^\"\\s]+)).*>"), QRegularExpression::InvertedGreedinessOption);
176 QRegularExpression imgRegExp(QLatin1String("(<img[^>]+>)"), QRegularExpression::InvertedGreedinessOption);
177
178 const QMap<QString, QString> &aboutMenuTexts = config.aboutTextFiles();
179 for (auto it = aboutMenuTexts.cbegin(), end = aboutMenuTexts.cend(); it != end; ++it) {
180 s << it.key();
181 QFileInfo fi(absoluteFilePath(basePath, it.value()));
182 QFile f(fi.absoluteFilePath());
183 if (!f.open(QIODevice::ReadOnly)) {
184 fputs(qPrintable(QHG::tr("Cannot open %1.\n").arg(f.fileName())), stderr);
185 return 1;
186 }
187 QByteArray data = f.readAll();
188 s << data;
189
190 QString contents = QString::fromUtf8(data);
191 int pos = 0;
192 QRegularExpressionMatch match;
193 while ((match = imgRegExp.match(contents, pos)).hasMatch()) {
194 QString imgTag = match.captured(1);
195 pos = match.capturedEnd();
196
197 if ((match = srcRegExp.match(imgTag)).hasMatch()) {
198 QString src = match.captured(2);
199 if (src.isEmpty())
200 src = match.captured(3);
201
202 QFile img(fi.absolutePath() + QDir::separator() + src);
203 if (img.open(QIODevice::ReadOnly)) {
204 if (!imgData.contains(src))
205 imgData.insert(src, img.readAll());
206 } else {
207 fputs(qPrintable(QHG::tr("Cannot open referenced image file %1.\n")
208 .arg(img.fileName())), stderr);
209 }
210 }
211 }
212 }
213 CollectionConfiguration::setAboutTexts(helpEngine, ba);
214 if (imgData.size()) {
215 QByteArray imageData;
216 QBuffer buffer(&imageData);
217 buffer.open(QIODevice::WriteOnly);
218 QDataStream out(&buffer);
219 out << imgData;
220 CollectionConfiguration::setAboutImages(helpEngine, imageData);
221 }
222 }
223 return 0;
224}
225
226int main(int argc, char *argv[])
227{
228 QString error;
229 QString outputFile;
230 QString inputFile;
231 QString basePath;
232 bool showHelp = false;
233 bool showVersion = false;
234 bool checkLinks = false;
235 bool silent = false;
236
237 // don't require a window manager even though we're a QGuiApplication
238 qputenv("QT_QPA_PLATFORM", QByteArrayLiteral("minimal"));
239
240 QGuiApplication app(argc, argv);
241#ifndef Q_OS_WIN32
242 QTranslator translator;
243 QTranslator qtTranslator;
244 QTranslator qt_helpTranslator;
245 QString sysLocale = QLocale::system().name();
246 QString resourceDir = QLibraryInfo::paths(QLibraryInfo::TranslationsPath).value(0);
247 if (translator.load(QLatin1String("assistant_") + sysLocale, resourceDir)
248 && qtTranslator.load(QLatin1String("qt_") + sysLocale, resourceDir)
249 && qt_helpTranslator.load(QLatin1String("qt_help_") + sysLocale, resourceDir)) {
250 app.installTranslator(&translator);
251 app.installTranslator(&qtTranslator);
252 app.installTranslator(&qt_helpTranslator);
253 }
254#endif // Q_OS_WIN32
255
256 for (int i = 1; i < argc; ++i) {
257 const QString arg = QString::fromLocal8Bit(argv[i]);
258 if (arg == QLatin1String("-o")) {
259 if (++i < argc) {
260 QFileInfo fi(QString::fromLocal8Bit(argv[i]));
261 outputFile = fi.absoluteFilePath();
262 } else {
263 error = QHG::tr("Missing output file name.");
264 }
265 } else if (arg == QLatin1String("-v")) {
266 showVersion = true;
267 } else if (arg == QLatin1String("-h")) {
268 showHelp = true;
269 } else if (arg == QLatin1String("-c")) {
270 checkLinks = true;
271 } else if (arg == QLatin1String("-s")) {
272 silent = true;
273 } else {
274 const QFileInfo fi(arg);
275 inputFile = fi.absoluteFilePath();
276 basePath = fi.absolutePath();
277 }
278 }
279
280 if (showVersion) {
281 fputs(qPrintable(QHG::tr("Qt Help Generator version 1.0 (Qt %1)\n")
282 .arg(QT_VERSION_STR)), stdout);
283 return 0;
284 }
285
286 enum InputType {
287 InputQhp,
288 InputQhcp,
289 InputUnknown
290 };
291
292 InputType inputType = InputUnknown;
293
294 if (!showHelp) {
295 if (inputFile.isEmpty()) {
296 error = QHG::tr("Missing input file name.");
297 } else {
298 const QFileInfo fi(inputFile);
299 if (fi.suffix() == QHP)
300 inputType = InputQhp;
301 else if (fi.suffix() == QHCP)
302 inputType = InputQhcp;
303
304 if (inputType == InputUnknown)
305 error = QHG::tr("Unknown input file type.");
306 }
307 }
308
309 const QString help = QHG::tr("\nUsage:\n\n"
310 "qhelpgenerator <file> [options]\n\n"
311 " -o <output-file> Generates a Qt compressed help\n"
312 " called <output-file> (*.qch) for the\n"
313 " Qt help project <file> (*.qhp).\n"
314 " Generates a Qt help collection\n"
315 " called <output-file> (*.qhc) for the\n"
316 " Qt help collection project <file> (*.qhcp).\n"
317 " If this option is not specified\n"
318 " a default name will be used\n"
319 " (*.qch for *.qhp and *.qhc for *.qhcp).\n"
320 " -c Checks whether all links in HTML files\n"
321 " point to files in this help project.\n"
322 " -s Suppresses status messages.\n"
323 " -v Displays the version of \n"
324 " qhelpgenerator.\n\n");
325
326 if (showHelp) {
327 fputs(qPrintable(help), stdout);
328 return 0;
329 } else if (!error.isEmpty()) {
330 fprintf(stderr, "%s\n\n%s", qPrintable(error), qPrintable(help));
331 return 1;
332 }
333
334 // detect input file type (qhp or qhcp)
335
336 QFile file(inputFile);
337 if (!file.open(QIODevice::ReadOnly)) {
338 fputs(qPrintable(QHG::tr("Could not open %1.\n").arg(inputFile)), stderr);
339 return 1;
340 }
341
342 const QString outputExtension = inputType == InputQhp ? QCH : QHC;
343
344 if (outputFile.isEmpty()) {
345 if (inputType == InputQhcp || !checkLinks) {
346 QFileInfo fi(inputFile);
347 outputFile = basePath + QDir::separator()
348 + fi.baseName() + QLatin1Char('.') + outputExtension;
349 }
350 } else {
351 // check if the output dir exists -- create if it doesn't
352 QFileInfo fi(outputFile);
353 QDir parentDir = fi.dir();
354 if (!parentDir.exists()) {
355 if (!parentDir.mkpath(QLatin1String("."))) {
356 fputs(qPrintable(QHG::tr("Could not create output directory: %1\n")
357 .arg(parentDir.path())), stderr);
358 }
359 }
360 }
361
362 if (inputType == InputQhp) {
363 QHelpProjectData *helpData = new QHelpProjectData();
364 if (!helpData->readData(inputFile)) {
365 fprintf(stderr, "%s\n", qPrintable(helpData->errorMessage()));
366 return 1;
367 }
368
369 HelpGenerator generator(silent);
370 bool success = true;
371 if (checkLinks)
372 success = generator.checkLinks(*helpData);
373 if (success && !outputFile.isEmpty())
374 success = generator.generate(helpData, outputFile);
375 delete helpData;
376 if (!success) {
377 fprintf(stderr, "%s\n", qPrintable(generator.error()));
378 return 1;
379 }
380 } else {
381 const QByteArray data = file.readAll();
382 return generateCollectionFile(data, basePath, outputFile);
383
384 }
385
386 return 0;
387}
static void setFullTextSearchFallbackEnabled(QHelpEngineCore &helpEngine, bool on)
static void setAddressBarVisible(QHelpEngineCore &helpEngine, bool visible)
static void setDocumentationManagerEnabled(QHelpEngineCore &helpEngine, bool enabled)
static void setAddressBarEnabled(QHelpEngineCore &helpEngine, bool enabled)
static void updateLastRegisterTime(QHelpEngineCore &helpEngine)
static void setFilterToolbarVisible(QHelpEngineCore &helpEngine, bool visible)
static void setFilterFunctionalityEnabled(QHelpEngineCore &helpEngine, bool enabled)
bool checkLinks(const QHelpProjectData &helpData)
Definition main.cpp:25
The QHelpProjectData class stores all information found in a Qt help project file.
QHelpProjectData()
Constructs a Qt help project data structure.
static const char QHP[]
Definition main.cpp:29
static const char QHC[]
Definition main.cpp:33
int generateCollectionFile(const QByteArray &data, const QString &basePath, const QString outputFile)
Definition main.cpp:42
static const char QCH[]
Definition main.cpp:30
static const char QHCP[]
Definition main.cpp:32
int main(int argc, char *argv[])
[ctor_close]