/* SPDX-FileCopyrightText: 2005 Tobias Koenig SPDX-License-Identifier: MIT */ #include "compiler.h" #include "settings.h" #include #include #include #include #include #include #include #include #include static const char *WSDL2CPP_DESCRIPTION = "KDAB's WSDL to C++ compiler"; static const char *WSDL2CPP_VERSION_STR = "2.1"; static void showHelp(const char *appName) { fprintf(stderr, "%s %s\n", WSDL2CPP_DESCRIPTION, WSDL2CPP_VERSION_STR); fprintf(stderr, "Usage:\n" " Header file: %s [options] -o \n" " Impl. file: %s [options] -o -impl \n" " Both files : %s [options] -both \n" "\n" "Options:\n" " -h, -help display this help and exit\n" " -v, -version display version\n" " -s, -service name of the service to generate\n" " -o output the generated file into \n" " -impl generate the implementation(.cpp) file, and #include \n" " -both generate both the header(.h) and the implementation(.cpp) file\n" " -server generate server-side base class, instead of client service\n" " -exportMacro set the export declaration to use for generated classes\n" " -namespace put all generated classes into the given C++ namespace\n" " -namespaceMapping \n" " add the uri=code mapping\n" " if begins with '@', read from file instead\n" " one entry per line\n" " (affects the generated class names)\n" " -optional-element-type \n" " use as the getter return value for optional elements.\n" " can be either raw-pointer, boost-optional or std-optional\n" " -keep-unused-types keep the wsdl unused types to the cpp generation step\n" " -import-path search for files first in this path before\n" " downloading them. may be specified multiple times.\n" " the file needs to be located at:\n" " //\n" " -use-local-files-only only use local files instead of downloading them\n" " automatically. this can be used to force the correct\n" " use of the import-path option\n" " -help-on-missing When groups or basic types could not be found, display\n" " available types (helps with wrong namespaces)\n" #if !defined(QT_NO_SSL) " -pkcs12file Load a certificate from a PKCS12 file. You can use this option\n" " if the WSDL file (or files referring to it) is served from a \n" " location which require certificate based authentication\n" " -pkcs12password Pass the password for the certificate file if required.\n" " This option is not secure and should be used with caution\n" " if other users of the machine are capable to see the running\n" " processes ran by the current user.\n" #endif " -no-sync Do not generate synchronous API methods to the client code\n" " -no-async Do not generate asynchronous API methods to the client code\n" " -no-async-jobs Do not generate asynchronous job API classes to the client code\n" "\n", appName, appName, appName); } int main(int argc, char **argv) { QCoreApplication app(argc, argv); Q_INIT_RESOURCE(schemas); const char *fileName = nullptr; QFileInfo outputFile; bool both = false; bool impl = false; bool outfileGiven = false; bool server = false; QString headerFile; QString serviceName; QString exportMacro; QString nameSpace; Settings::NSMapping nsmapping; // XML mappings from URL to short code Settings::OptionalElementType optionalElementType = Settings::ENone; bool keepUnusedTypes = false; QStringList importPathList; bool useLocalFilesOnly = false; bool helpOnMissing = false; bool skipAsync = false, skipSync = false, skipAsyncJobs = false; #if !defined(QT_NO_SSL) QString pkcs12File, pkcs12Password; #endif int arg = 1; while (arg < argc) { QString opt = QString::fromLocal8Bit(argv[arg]); if (opt == QLatin1String("-h") || opt == QLatin1String("-help")) { showHelp(argv[0]); return 0; } else if (opt == QLatin1String("-impl")) { impl = true; ++arg; if (!argv[arg]) { showHelp(argv[0]); return 1; } headerFile = QFile::decodeName(argv[arg]); } else if (opt == QLatin1String("-both")) { both = true; ++arg; if (!argv[arg]) { showHelp(argv[0]); return 1; } outputFile.setFile(QFile::decodeName(argv[arg])); } else if (opt == QLatin1String("-server")) { server = true; } else if (opt == QLatin1String("-v") || opt == QLatin1String("-version")) { fprintf(stderr, "%s %s\n", WSDL2CPP_DESCRIPTION, WSDL2CPP_VERSION_STR); return 0; } else if (opt == QLatin1String("-o") || opt == QLatin1String("-output")) { ++arg; if (!argv[arg]) { showHelp(argv[0]); return 1; } outfileGiven = true; outputFile.setFile(QFile::decodeName(argv[arg])); } else if (opt == QLatin1String("-s") || opt == QLatin1String("-service")) { ++arg; if (!argv[arg]) { showHelp(argv[0]); return 1; } serviceName = QFile::decodeName(argv[arg]); } else if (opt == QLatin1String("-exportMacro")) { ++arg; if (!argv[arg]) { showHelp(argv[0]); return 1; } exportMacro = argv[arg]; } else if (opt == QLatin1String("-namespace")) { ++arg; if (!argv[arg]) { showHelp(argv[0]); return 1; } nameSpace = argv[arg]; } else if (opt == QLatin1String("-namespaceMapping")) { ++arg; if (!argv[arg]) { showHelp(argv[0]); return 1; } QString mapping = argv[arg]; if (mapping.startsWith('@')) { QString mappingFileName = QFile::decodeName(argv[arg] + 1); // +1 to skip the '@' QFile file(mappingFileName); if (!file.open(QIODevice::ReadOnly)) { fprintf(stderr, "Error reading %s: %s\n", QFile::encodeName(mappingFileName).constData(), qPrintable(file.errorString())); showHelp(argv[0]); return 1; } while (!file.atEnd()) { QString mapping = file.readLine().trimmed(); if (mapping.startsWith('#')) { continue; } QString uri = mapping.section("=", 0, -2); QString target = mapping.section("=", -1, -1); if (!uri.isEmpty() && !target.isEmpty()) { nsmapping[uri] = std::move(target); } } } else { QString uri = mapping.section("=", 0, -2); QString target = mapping.section("=", -1, -1); nsmapping[uri] = std::move(target); } } else if (opt == QLatin1String("-optional-element-type")) { ++arg; if (!argv[arg]) { showHelp(argv[0]); return 1; } QLatin1String optType(argv[arg]); if (optType == QLatin1String("raw-pointer")) { optionalElementType = Settings::ERawPointer; } else if (optType == QLatin1String("boost-optional")) { optionalElementType = Settings::EBoostOptional; } else if (optType == QLatin1String("std-optional")) { optionalElementType = Settings::EStdOptional; } } else if (opt == QLatin1String("-keep-unused-types")) { keepUnusedTypes = true; } else if (opt == QLatin1String("-import-path")) { ++arg; if (!argv[arg]) { showHelp(argv[0]); return 1; } importPathList.append(QFile::decodeName(argv[arg])); } else if (opt == QLatin1String("-use-local-files-only")) { useLocalFilesOnly = true; } else if (opt == QLatin1String("-help-on-missing")) { helpOnMissing = true; #if !defined(QT_NO_SSL) } else if (opt == QLatin1String("-pkcs12file")) { ++arg; if (!argv[arg]) { showHelp(argv[0]); return 1; } pkcs12File = QLatin1String(argv[arg]); } else if (opt == QLatin1String("-pkcs12password")) { ++arg; if (!argv[arg]) { showHelp(argv[0]); return 1; } pkcs12Password = QLatin1String(argv[arg]); #endif } else if (opt == QLatin1String("-no-sync")) { skipSync = true; } else if (opt == QLatin1String("-no-async")) { skipAsync = true; } else if (opt == QLatin1String("-no-async-jobs")) { skipAsyncJobs = true; } else if (!fileName) { fileName = argv[arg]; } else { showHelp(argv[0]); return 1; } ++arg; } if (!fileName) { showHelp(argv[0]); return 1; } // if you're saying "just make the impl-file", you can't // also say "make both the header and the impl" if (both && (outfileGiven || impl)) { showHelp(argv[0]); return 1; } if (both) { Settings::self()->setGenerateHeader(true); Settings::self()->setGenerateImplementation(true); Settings::self()->setHeaderFileName(outputFile.fileName() + ".h"); Settings::self()->setImplementationFileName(outputFile.fileName() + ".cpp"); } else if (impl) { Settings::self()->setGenerateHeader(false); Settings::self()->setGenerateImplementation(true); Settings::self()->setHeaderFileName(headerFile); Settings::self()->setImplementationFileName(outputFile.fileName()); } else { Settings::self()->setGenerateHeader(true); Settings::self()->setGenerateImplementation(false); Settings::self()->setHeaderFileName(outputFile.fileName()); Settings::self()->setImplementationFileName("UNUSED"); } Settings::self()->setGenerateServerCode(server); Settings::self()->setOutputDirectory(outputFile.absolutePath()); Settings::self()->setWsdlFile(fileName); Settings::self()->setWantedService(serviceName); Settings::self()->setExportDeclaration(exportMacro); Settings::self()->setNameSpace(nameSpace); Settings::self()->setNamespaceMapping(nsmapping); Settings::self()->setOptionalElementType(optionalElementType); Settings::self()->setKeepUnusedTypes(keepUnusedTypes); Settings::self()->setImportPathList(importPathList); Settings::self()->setUseLocalFilesOnly(useLocalFilesOnly); Settings::self()->setHelpOnMissing(helpOnMissing); Settings::self()->setSkipSync(skipSync); Settings::self()->setSkipAsync(skipAsync); Settings::self()->setSkipAsyncJobs(skipAsyncJobs); KWSDL::Compiler compiler; #if !defined(QT_NO_SSL) if (!pkcs12File.isEmpty()) { QFile certFile(pkcs12File); if (certFile.open(QFile::ReadOnly)) { QSslKey key; QSslCertificate certificate; QList caCertificates; const bool certificateLoaded = QSslCertificate::importPkcs12(&certFile, &key, &certificate, &caCertificates, pkcs12Password.toLocal8Bit()); certFile.close(); if (!certificateLoaded) { fprintf(stderr, "Unable to load the %s certificate file\n", pkcs12File.toLocal8Bit().constData()); if (!pkcs12Password.isEmpty()) fprintf(stderr, "Please make sure that you have passed the correct password\n"); else fprintf(stderr, "Maybe it is password protected?\n"); return 1; } // set the loaded certificate info as default SSL config QSslConfiguration sslConfig = QSslConfiguration::defaultConfiguration(); sslConfig.setPrivateKey(key); sslConfig.setLocalCertificate(certificate); sslConfig.setCaCertificates(caCertificates); QSslConfiguration::setDefaultConfiguration(sslConfig); } else { fprintf(stderr, "Failed to open the %s certificate file for reading\n", pkcs12File.toLocal8Bit().constData()); return 1; } } #endif // so that we have an event loop, for downloads QTimer::singleShot(0, &compiler, &KWSDL::Compiler::run); return app.exec(); }