File indexing completed on 2024-05-05 12:19:04
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 2015 Christoph Cullmann <cullmann@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include <QCommandLineParser> 0009 #include <QCoreApplication> 0010 #include <QDir> 0011 #include <QFile> 0012 #include <QFileInfo> 0013 #include <QJsonDocument> 0014 #include <QRegularExpression> 0015 #include <QVariant> 0016 0017 #include <KConfig> 0018 #include <KConfigGroup> 0019 0020 int main(int argc, char *argv[]) 0021 { 0022 // construct app and set some version 0023 QCoreApplication app(argc, argv); 0024 app.setApplicationVersion(QStringLiteral("1.0")); 0025 0026 // generic parser config 0027 QCommandLineParser parser; 0028 parser.addVersionOption(); 0029 parser.setApplicationDescription(QStringLiteral("Converts .protocol files to json")); 0030 parser.addHelpOption(); 0031 0032 // -o/--output 0033 const QCommandLineOption outputOption(QStringList{QStringLiteral("o"), QStringLiteral("output")}, 0034 QStringLiteral("Output file name for JSON data."), 0035 QStringLiteral("name")); 0036 parser.addOption(outputOption); 0037 0038 // files to open 0039 parser.addPositionalArgument(QStringLiteral("files"), QStringLiteral(".protocol files to read."), QStringLiteral("[files...]")); 0040 0041 // parse 0042 parser.process(app); 0043 0044 // we need an output file 0045 const QString output = parser.value(QStringLiteral("output")); 0046 if (output.isEmpty()) { 0047 qFatal("No output file given, please add --output <name>."); 0048 } 0049 0050 // we need input files 0051 if (parser.positionalArguments().isEmpty()) { 0052 qFatal("No input file given, please add <files>."); 0053 } 0054 0055 // different attributes to copy 0056 const QStringList stringAttributes({QStringLiteral("protocol"), 0057 QStringLiteral("exec"), 0058 QStringLiteral("fileNameUsedForCopying"), 0059 QStringLiteral("defaultMimetype"), 0060 QStringLiteral("Icon"), 0061 QStringLiteral("config"), 0062 QStringLiteral("input"), 0063 QStringLiteral("output"), 0064 QStringLiteral("X-DocPath"), 0065 QStringLiteral("DocPath"), 0066 QStringLiteral("Class"), 0067 QStringLiteral("ProxiedBy")}); 0068 0069 const QStringList stringListAttributes( 0070 {QStringLiteral("listing"), QStringLiteral("archiveMimetype"), QStringLiteral("ExtraTypes"), QStringLiteral("Capabilities")}); 0071 0072 const QStringList boolAttributes({QStringLiteral("source"), 0073 QStringLiteral("helper"), 0074 QStringLiteral("reading"), 0075 QStringLiteral("writing"), 0076 QStringLiteral("makedir"), 0077 QStringLiteral("deleting"), 0078 QStringLiteral("linking"), 0079 QStringLiteral("moving"), 0080 QStringLiteral("opening"), 0081 QStringLiteral("truncating"), 0082 QStringLiteral("copyFromFile"), 0083 QStringLiteral("copyToFile"), 0084 QStringLiteral("renameFromFile"), 0085 QStringLiteral("renameToFile"), 0086 QStringLiteral("deleteRecursive"), 0087 QStringLiteral("determineMimetypeFromExtension"), 0088 QStringLiteral("ShowPreviews")}); 0089 0090 const QStringList intAttributes({QStringLiteral("maxInstances"), QStringLiteral("maxInstancesPerHost")}); 0091 0092 const QStringList translatedStringListAttributes({QStringLiteral("ExtraNames")}); 0093 0094 // constructed the json data by parsing all .protocol files 0095 QVariantMap protocolsData; 0096 const QRegularExpression localeRegex(QStringLiteral("^\\w+\\[(.*)\\]=")); 0097 const QStringList args = parser.positionalArguments(); 0098 for (const QString &file : args) { 0099 // get full path 0100 const QString fullFilePath(QDir::current().absoluteFilePath(file)); 0101 0102 // construct kconfig for protocol file 0103 KConfig sconfig(fullFilePath); 0104 sconfig.setLocale(QString()); 0105 KConfigGroup config(&sconfig, "Protocol"); 0106 0107 // name must be set, sanity check that file got read 0108 const QString name(config.readEntry("protocol")); 0109 if (name.isEmpty()) { 0110 qFatal("Failed to read input file %s.", qPrintable(fullFilePath)); 0111 } 0112 0113 // construct protocol data 0114 QVariantMap protocolData; 0115 0116 // convert the different types 0117 for (const QString &key : stringAttributes) { 0118 if (config.hasKey(key)) { 0119 protocolData.insert(key, config.readEntry(key, QString())); 0120 } 0121 } 0122 for (const QString &key : stringListAttributes) { 0123 if (config.hasKey(key)) { 0124 protocolData.insert(key, config.readEntry(key, QStringList())); 0125 } 0126 } 0127 for (const QString &key : boolAttributes) { 0128 if (config.hasKey(key)) { 0129 protocolData.insert(key, config.readEntry(key, bool(false))); 0130 } 0131 } 0132 for (const QString &key : intAttributes) { 0133 if (config.hasKey(key)) { 0134 protocolData.insert(key, config.readEntry(key, int(0))); 0135 } 0136 } 0137 0138 // handle translated keys 0139 for (const QString &key : translatedStringListAttributes) { 0140 // read untranslated entry first in any case! 0141 sconfig.setLocale(QString()); 0142 const QStringList untranslatedValues = config.readEntry(key, QStringList()); 0143 if (!untranslatedValues.isEmpty()) { 0144 protocolData.insert(key, untranslatedValues); 0145 } 0146 0147 // collect all locales for this key 0148 QFile f(fullFilePath); 0149 QStringList foundLocalesForKey; 0150 if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) { 0151 qFatal("Failed to open file %s.", qPrintable(fullFilePath)); 0152 } 0153 while (!f.atEnd()) { 0154 const QString line = QString::fromUtf8(f.readLine()); 0155 const QRegularExpressionMatch match = localeRegex.match(line); 0156 if (match.hasMatch()) { 0157 foundLocalesForKey.append(match.captured(1)); 0158 } 0159 } 0160 0161 // insert all entries for all found locales, reparse config for this 0162 for (const QString &locale : std::as_const(foundLocalesForKey)) { 0163 sconfig.setLocale(locale); 0164 protocolData.insert(QStringLiteral("%1[%2]").arg(key, locale), config.readEntry(key, QStringList())); 0165 } 0166 } 0167 0168 // use basename of protocol for toplevel map in json, like it is done for .protocol files 0169 const QString baseName(QFileInfo(fullFilePath).baseName()); 0170 protocolsData.insert(baseName, protocolData); 0171 } 0172 0173 // pack in our namespace 0174 QVariantMap jsonData; 0175 jsonData.insert(QStringLiteral("KDE-KIO-Protocols"), protocolsData); 0176 0177 // create outfile, after all has worked! 0178 QFile outFile(output); 0179 if (!outFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { 0180 qFatal("Failed to open output file %s.", qPrintable(output)); 0181 } 0182 0183 // write out json 0184 outFile.write(QJsonDocument::fromVariant(QVariant(jsonData)).toJson()); 0185 0186 // be done 0187 return 0; 0188 }