File indexing completed on 2025-01-05 05:23:44

0001 /*
0002     This file is part of the Okteta Kasten Framework, made within the KDE community.
0003 
0004     SPDX-FileCopyrightText: 2010, 2011, 2012 Alex Richardson <alex.richardson@gmx.de>
0005 
0006     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0007 */
0008 
0009 #include "scriptfileparser.hpp"
0010 
0011 #include "scriptvalueconverter.hpp"
0012 #include "parserutils.hpp"
0013 #include "../datatypes/topleveldatainformation.hpp"
0014 #include "../datatypes/dummydatainformation.hpp"
0015 #include "../script/scriptengineinitializer.hpp"
0016 #include "../script/scriptlogger.hpp"
0017 
0018 #include <QScriptEngine>
0019 
0020 ScriptFileParser::ScriptFileParser(const QString& pluginName, const QString& absolutePath)
0021     : AbstractStructureParser(pluginName, absolutePath)
0022 {
0023 }
0024 
0025 ScriptFileParser::~ScriptFileParser() = default;
0026 
0027 QStringList ScriptFileParser::parseStructureNames() const
0028 {
0029     return {mPluginName};
0030 }
0031 
0032 QVector<TopLevelDataInformation*> ScriptFileParser::parseStructures() const
0033 {
0034     QVector<TopLevelDataInformation*> ret;
0035 
0036     QScriptEngine* engine = ScriptEngineInitializer::newEngine();
0037     auto* logger = new ScriptLogger();
0038 
0039     QScriptValue value = loadScriptValue(logger, engine);
0040     DataInformation* dataInf;
0041     if (!value.isValid()) {
0042         dataInf = new DummyDataInformation(nullptr, mPluginName);
0043     } else {
0044         dataInf = ScriptValueConverter::convert(value, mPluginName, logger);
0045     }
0046 
0047     if (!dataInf) {
0048         dataInf = new DummyDataInformation(nullptr, mPluginName);
0049     }
0050     const QFileInfo fileInfo(mAbsolutePath);
0051     auto* top = new TopLevelDataInformation(dataInf, logger, engine, fileInfo);
0052     // handle default lock offset
0053     QScriptValue lockOffset = value.property(ParserStrings::PROPERTY_DEFAULT_LOCK_OFFSET());
0054     if (lockOffset.isValid()) {
0055         ParsedNumber<quint64> offset = ParserUtils::uint64FromScriptValue(lockOffset);
0056         if (!offset.isValid) {
0057             dataInf->logError() << "Default lock offset is not a valid number:" << offset.string;
0058         } else {
0059             top->setDefaultLockOffset(offset.value);
0060         }
0061     }
0062     ret.append(top);
0063     return ret;
0064 }
0065 
0066 QScriptValue ScriptFileParser::loadScriptValue(ScriptLogger* logger, QScriptEngine* engine) const
0067 {
0068     QFile scriptFile(mAbsolutePath);
0069     if (!scriptFile.open(QIODevice::ReadOnly)) {
0070         logger->error() << "Could not open file " << mAbsolutePath;
0071         return {};
0072     }
0073 
0074     QTextStream stream(&scriptFile);
0075     QString contents = stream.readAll();
0076     scriptFile.close();
0077     engine->evaluate(contents, mAbsolutePath);
0078     if (engine->hasUncaughtException()) {
0079         // check if it was a syntax error:
0080         QScriptSyntaxCheckResult syntaxError = QScriptEngine::checkSyntax(contents);
0081         if (syntaxError.state() == QScriptSyntaxCheckResult::Error) {
0082             // give a detailed syntax error message
0083             logger->error() << "Syntax error in script: " << syntaxError.errorMessage();
0084             logger->error() << "Line number: " << syntaxError.errorLineNumber()
0085                             << "Column:" << syntaxError.errorColumnNumber();
0086         } else {
0087             // just print the generic exception message
0088             logger->error() << "Error evaluating script: " << engine->uncaughtException().toString();
0089             logger->error() << "Line number: " << engine->uncaughtExceptionLineNumber();
0090             logger->error() << "Backtrace: " << engine->uncaughtExceptionBacktrace();
0091         }
0092         return {};
0093     }
0094     QScriptValue obj = engine->globalObject();
0095     QScriptValue initMethod = obj.property(QStringLiteral("init"));
0096     if (!initMethod.isFunction()) {
0097         logger->error() << "Script has no 'init' function! Cannot evaluate script!";
0098         return {};
0099     }
0100 
0101     QScriptValue thisObj = engine->newObject();
0102     QScriptValueList args;
0103     QScriptValue result = initMethod.call(thisObj, args);
0104     if (result.isError()) {
0105         logger->error() << "Exception occurred while calling init():" << result.toString();
0106         return {};
0107     }
0108     return result;
0109 }