File indexing completed on 2025-01-05 05:23:46
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 "scripthandler.hpp" 0010 0011 #include "scriptengineinitializer.hpp" 0012 #include "scriptlogger.hpp" 0013 #include "classes/defaultscriptclass.hpp" 0014 #include "../datatypes/datainformation.hpp" 0015 #include "../datatypes/topleveldatainformation.hpp" 0016 #include "../datatypes/array/arraydatainformation.hpp" 0017 #include "../parsers/parserutils.hpp" 0018 // Qt 0019 #include <QStringList> 0020 #include <QScriptValue> 0021 #include <QScriptEngine> 0022 0023 ScriptHandler::ScriptHandler(QScriptEngine* engine, TopLevelDataInformation* topLevel) 0024 : mEngine(engine) 0025 , mTopLevel(topLevel) 0026 , mHandlerInfo(engine, topLevel->logger()) 0027 { 0028 } 0029 0030 ScriptHandler::~ScriptHandler() = default; 0031 0032 QScriptEngine* ScriptHandler::engine() const 0033 { 0034 return mEngine.get(); 0035 } 0036 0037 ScriptHandlerInfo* ScriptHandler::handlerInfo() 0038 { 0039 return &mHandlerInfo; 0040 } 0041 0042 void ScriptHandler::validateData(DataInformation* data) 0043 { 0044 Q_CHECK_PTR(data); 0045 0046 if (data->hasBeenValidated()) { 0047 return; 0048 } 0049 // first validate the children 0050 for (uint i = 0; i < data->childCount(); ++i) { 0051 validateData(data->childAt(i)); 0052 } 0053 0054 // check if has a validation function: 0055 QScriptValue validationFunc = data->validationFunc(); 0056 if (validationFunc.isValid()) { 0057 QScriptValue result = callFunction(validationFunc, data, ScriptHandlerInfo::Mode::Validating); 0058 if (result.isError()) { 0059 mTopLevel->logger()->error(data) << "Error occurred while validating element: " 0060 << result.toString(); 0061 data->setValidationError(QStringLiteral("Error occurred in validation: ") 0062 + result.toString()); 0063 } else if (mEngine->hasUncaughtException()) { 0064 mTopLevel->logger()->error(data) << "Error occurred while validating element:" 0065 << result.toString() << "\nBacktrace:" << mEngine->uncaughtExceptionBacktrace(); 0066 data->setValidationError(QStringLiteral("Error occurred in validation: ") 0067 + result.toString()); 0068 mEngine->clearExceptions(); 0069 } 0070 if (result.isBool() || result.isBoolean()) { 0071 data->mValidationSuccessful = result.toBool(); 0072 } 0073 if (result.isString()) { 0074 // error string 0075 QString str = result.toString(); 0076 if (!str.isEmpty()) { 0077 data->setValidationError(str); 0078 } 0079 } 0080 data->mHasBeenValidated = true; 0081 } 0082 } 0083 0084 void ScriptHandler::updateDataInformation(DataInformation* data) 0085 { 0086 Q_CHECK_PTR(data); 0087 // check if has an update function: 0088 Q_ASSERT(!data->hasBeenUpdated()); 0089 QScriptValue updateFunc = data->updateFunc(); 0090 data->mHasBeenUpdated = true; 0091 if (updateFunc.isValid()) { 0092 QString context = data->fullObjectPath(); // we mustn't use data after updateFunc.call(), save context 0093 QScriptValue result = callFunction(updateFunc, data, ScriptHandlerInfo::Mode::Updating); 0094 if (result.isError()) { 0095 mTopLevel->logger()->error(context) << "Error occurred while updating element: " 0096 << result.toString(); 0097 } 0098 if (mEngine->hasUncaughtException()) { 0099 mTopLevel->logger()->error(context) << "Error occurred while updating element:" 0100 << result.toString() << "\nBacktrace:" << mEngine->uncaughtExceptionBacktrace(); 0101 mEngine->clearExceptions(); 0102 } 0103 } 0104 } 0105 0106 void ScriptHandler::updateLength(ArrayDataInformation* array) 0107 { 0108 QScriptValue lengthFunc = array->lengthFunction(); 0109 if (lengthFunc.isValid()) { 0110 Q_ASSERT(lengthFunc.isFunction()); 0111 0112 QScriptValue result = callFunction(lengthFunc, array, ScriptHandlerInfo::Mode::DeterminingLength); 0113 if (mEngine->hasUncaughtException()) { 0114 mTopLevel->logger()->error(array) << "Error occurred while calculating length:" 0115 << result.toString() << "\nBacktrace:" << mEngine->uncaughtExceptionBacktrace(); 0116 mEngine->clearExceptions(); 0117 } 0118 ParsedNumber<uint> value = ParserUtils::uintFromScriptValue(result); 0119 if (value.isValid) { 0120 array->setArrayLength(value.value); 0121 } else { 0122 array->logError() << "Length function did not return a valid number! Result was: " << result.toString(); 0123 } 0124 } 0125 } 0126 0127 QString ScriptHandler::customToString(const DataInformation* data, const QScriptValue& func) 0128 { 0129 Q_ASSERT(func.isValid()); 0130 Q_ASSERT(func.isFunction()); 0131 Q_ASSERT(data->wasAbleToRead()); // this should never be called if EOF was reached 0132 // it is effectively const, since nothing may be modified while mode is CustomToString 0133 // const_cast is okay in this case 0134 QScriptValue result = callFunction(func, const_cast<DataInformation*>(data), ScriptHandlerInfo::Mode::CustomToString); 0135 if (result.isError()) { 0136 data->logError() << "toStringFunc caused an error:" << result.toString(); 0137 } 0138 return result.toString(); 0139 } 0140 0141 QScriptValue ScriptHandler::callFunction(QScriptValue func, DataInformation* data, 0142 ScriptHandlerInfo::Mode mode) 0143 { 0144 Q_ASSERT(func.isFunction()); 0145 // value exists, we assume it has been checked to be a function 0146 QScriptValue thisObject = data->toScriptValue(mEngine.get(), &mHandlerInfo); 0147 QScriptValue mainStruct = data->mainStructure()->toScriptValue(mEngine.get(), &mHandlerInfo); 0148 const QScriptValueList args { mainStruct }; 0149 // ensure we get the right properties 0150 mHandlerInfo.setMode(mode); 0151 QScriptValue result = func.call(thisObject, args); 0152 mHandlerInfo.setMode(ScriptHandlerInfo::Mode::None); 0153 return result; 0154 }