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: 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 "scriptvalueconverter.hpp" 0010 #include "scriptvalueconverter_p.hpp" 0011 0012 #include "datainformationfactory.hpp" 0013 #include "parserutils.hpp" 0014 #include "../datatypes/uniondatainformation.hpp" 0015 #include "../datatypes/structuredatainformation.hpp" 0016 #include "../datatypes/strings/stringdata.hpp" 0017 #include "../datatypes/strings/stringdatainformation.hpp" 0018 #include "../script/scriptlogger.hpp" 0019 0020 using namespace ParserStrings; 0021 0022 namespace ScriptValueConverter { 0023 0024 DataInformation* toDataInformation(const QScriptValue& value, const ParserInfo& oldInfo) 0025 { 0026 if (!value.isValid()) { 0027 oldInfo.error() << "invalid value passed!"; 0028 return nullptr; 0029 } 0030 ParserInfo info(oldInfo); 0031 QString nameOverride = value.property(PROPERTY_NAME()).toString(); 0032 if (!nameOverride.isEmpty()) { 0033 info.name = nameOverride; 0034 } 0035 0036 // check function array and date, since they are objects too 0037 if (value.isRegExp()) { 0038 // apparently regexp is a function 0039 info.error() << "Cannot convert a RegExp object to DataInformation!"; 0040 return nullptr; 0041 } 0042 if (value.isFunction()) { 0043 info.error() << "Cannot convert a Function object to DataInformation!"; 0044 return nullptr; 0045 } 0046 if (value.isArray()) { 0047 info.error() << "Cannot convert a Array object to DataInformation!"; 0048 return nullptr; 0049 } 0050 if (value.isDate()) { 0051 info.error() << "Cannot convert a Date object to DataInformation!"; 0052 return nullptr; 0053 } 0054 if (value.isError()) { 0055 info.error() << "Cannot convert a Error object to DataInformation!"; 0056 return nullptr; 0057 } 0058 // variant and qobject are also object types, however they cannot appear from user code, no need to check 0059 0060 // if it is a string, we convert to primitive type, if not it has to be an object 0061 if (value.isString()) { 0062 return toPrimitive(value, info); // a type string is also okay 0063 0064 } 0065 if (!value.isObject()) { 0066 if (value.isBool()) { 0067 info.error() << "Cannot convert Boolean to DataInformation!"; 0068 } else if (value.isNull()) { 0069 info.error() << "Cannot convert null to DataInformation!"; 0070 } else if (value.isUndefined()) { 0071 info.error() << "Cannot convert undefined to DataInformation!"; 0072 } else if (value.isNumber()) { 0073 info.error() << "Cannot convert Number to DataInformation!"; 0074 } else { 0075 info.error() << "Cannot convert object of unknown type to DataInformation!"; 0076 } 0077 0078 return nullptr; // no point trying to convert 0079 } 0080 0081 QString type = value.property(PROPERTY_INTERNAL_TYPE()).toString(); 0082 if (type.isEmpty()) { 0083 info.error() << "Cannot convert object since type of object could not be determined!"; 0084 return nullptr; 0085 } 0086 DataInformation* returnVal = nullptr; 0087 0088 if (type == TYPE_ARRAY()) { 0089 returnVal = toArray(value, info); 0090 } else if (type == TYPE_STRUCT()) { 0091 returnVal = toStruct(value, info); 0092 } else if (type == TYPE_UNION()) { 0093 returnVal = toUnion(value, info); 0094 } else if (type == TYPE_BITFIELD()) { 0095 returnVal = toBitfield(value, info); 0096 } else if (type == TYPE_ENUM()) { 0097 returnVal = toEnum(value, false, info); 0098 } else if (type == TYPE_FLAGS()) { 0099 returnVal = toEnum(value, true, info); 0100 } else if (type == TYPE_STRING()) { 0101 returnVal = toString(value, info); 0102 } else if (type == TYPE_POINTER()) { 0103 returnVal = toPointer(value, info); 0104 } else if (type == TYPE_TAGGED_UNION()) { 0105 returnVal = toTaggedUnion(value, info); 0106 } else if (type == TYPE_PRIMITIVE()) { 0107 returnVal = toPrimitive(value, info); 0108 } else { 0109 info.error() << "Unknown type:" << type; 0110 } 0111 0112 if (returnVal) { 0113 CommonParsedData cpd(info); 0114 QString byteOrderStr = value.property(PROPERTY_BYTEORDER()).toString(); 0115 if (!byteOrderStr.isEmpty()) { 0116 cpd.endianess = ParserUtils::byteOrderFromString(byteOrderStr, 0117 LoggerWithContext(info.logger, info.context())); 0118 } 0119 cpd.updateFunc = value.property(PROPERTY_UPDATE_FUNC()); 0120 cpd.validationFunc = value.property(PROPERTY_VALIDATION_FUNC()); 0121 cpd.toStringFunc = value.property(PROPERTY_TO_STRING_FUNC()); 0122 cpd.customTypeName = value.property(PROPERTY_CUSTOM_TYPE_NAME()).toString(); 0123 if (!DataInformationFactory::commonInitialization(returnVal, cpd)) { 0124 delete returnVal; // error message has already been logged 0125 return nullptr; 0126 } 0127 } 0128 return returnVal; 0129 } 0130 0131 ArrayDataInformation* toArray(const QScriptValue& value, const ParserInfo& info) 0132 { 0133 ArrayParsedData apd(info); 0134 apd.length = value.property(PROPERTY_LENGTH()); 0135 QScriptValue childType = value.property(PROPERTY_TYPE()); 0136 ParserInfo childInfo(info); 0137 DummyDataInformation dummy(info.parent, info.name + QLatin1Char('.') + NAME_ARRAY_TYPE()); 0138 childInfo.parent = &dummy; 0139 apd.arrayType = toDataInformation(childType, childInfo); 0140 0141 return DataInformationFactory::newArray(apd); 0142 } 0143 0144 AbstractBitfieldDataInformation* toBitfield(const QScriptValue& value, const ParserInfo& info) 0145 { 0146 BitfieldParsedData bpd(info); 0147 bpd.type = value.property(PROPERTY_TYPE()).toString(); 0148 bpd.width = ParserUtils::intFromScriptValue(value.property(PROPERTY_WIDTH())); 0149 return DataInformationFactory::newBitfield(bpd); 0150 } 0151 0152 PrimitiveDataInformation* toPrimitive(const QScriptValue& value, const ParserInfo& info) 0153 { 0154 PrimitiveParsedData ppd(info); 0155 ppd.type = value.isString() ? value.toString() : value.property(PROPERTY_TYPE()).toString(); 0156 return DataInformationFactory::newPrimitive(ppd); 0157 } 0158 0159 StructureDataInformation* toStruct(const QScriptValue& value, const ParserInfo& info) 0160 { 0161 StructOrUnionParsedData supd(info); 0162 supd.children.reset(new ScriptValueChildrenParser(info, value.property(PROPERTY_CHILDREN()))); 0163 return DataInformationFactory::newStruct(supd); 0164 } 0165 0166 UnionDataInformation* toUnion(const QScriptValue& value, const ParserInfo& info) 0167 { 0168 StructOrUnionParsedData supd(info); 0169 supd.children.reset(new ScriptValueChildrenParser(info, value.property(PROPERTY_CHILDREN()))); 0170 return DataInformationFactory::newUnion(supd); 0171 } 0172 0173 PointerDataInformation* toPointer(const QScriptValue& value, const ParserInfo& info) 0174 { 0175 PointerParsedData ppd(info); 0176 QScriptValue pointerScale = value.property(PROPERTY_SCALE()); 0177 if (pointerScale.isNumber()) { 0178 // A pointer scale of magnitude > 2^53 is extremely unlikely. 0179 ppd.pointerScale = pointerScale.toInteger(); 0180 } 0181 ppd.interpretFunc = value.property(PROPERTY_INTERPRET_FUNC()); 0182 0183 ParserInfo childInfo(info); 0184 DummyDataInformation dummy(info.parent, info.name); 0185 childInfo.parent = &dummy; 0186 childInfo.name = NAME_POINTER_TARGET(); 0187 ppd.pointerTarget = toDataInformation(value.property(PROPERTY_TARGET()), childInfo); 0188 childInfo.name = NAME_POINTER_VALUE_TYPE(); 0189 ppd.valueType = toDataInformation(value.property(PROPERTY_TYPE()), childInfo); 0190 0191 return DataInformationFactory::newPointer(ppd); 0192 } 0193 0194 EnumDataInformation* toEnum(const QScriptValue& value, bool flags, const ParserInfo& info) 0195 { 0196 EnumParsedData epd(info); 0197 QScriptValue enumType = value.property(PROPERTY_TYPE()); 0198 if (enumType.isString()) { 0199 epd.type = enumType.toString(); 0200 } else if (enumType.isObject()) { 0201 epd.type = enumType.property(PROPERTY_TYPE()).toString(); 0202 } 0203 // else it stays empty 0204 epd.enumName = value.property(PROPERTY_ENUM_NAME()).toString(); 0205 epd.enumValuesObject = value.property(PROPERTY_ENUM_VALUES()); 0206 0207 if (flags) { 0208 return DataInformationFactory::newFlags(epd); 0209 } 0210 0211 return DataInformationFactory::newEnum(epd); 0212 } 0213 0214 StringDataInformation* toString(const QScriptValue& value, const ParserInfo& info) 0215 { 0216 StringParsedData spd(info); 0217 spd.encoding = value.property(PROPERTY_ENCODING()).toString(); 0218 spd.termination = ParserUtils::uintFromScriptValue(value.property(PROPERTY_TERMINATED_BY())); 0219 spd.maxByteCount = ParserUtils::uintFromScriptValue(value.property(PROPERTY_MAX_BYTE_COUNT())); 0220 spd.maxCharCount = ParserUtils::uintFromScriptValue(value.property(PROPERTY_MAX_CHAR_COUNT())); 0221 return DataInformationFactory::newString(spd); 0222 } 0223 0224 TaggedUnionDataInformation* toTaggedUnion(const QScriptValue& value, const ParserInfo& info) 0225 { 0226 TaggedUnionParsedData tpd(info); 0227 QScriptValue alternatives = value.property(PROPERTY_ALTERNATIVES()); 0228 if (!alternatives.isArray()) { 0229 info.error() << "Alternatives must be an array!"; 0230 return nullptr; 0231 } 0232 int length = alternatives.property(PROPERTY_LENGTH()).toInt32(); 0233 tpd.alternatives.reserve(length); 0234 for (int i = 0; i < length; ++i) { 0235 TaggedUnionParsedData::Alternatives alt; 0236 QScriptValue current = alternatives.property(i); 0237 alt.name = current.property(PROPERTY_STRUCT_NAME()).toString(); 0238 alt.selectIf = current.property(PROPERTY_SELECT_IF()); 0239 alt.fields = QSharedPointer<ChildrenParser>( 0240 new ScriptValueChildrenParser(info, current.property(PROPERTY_CHILDREN()))); 0241 tpd.alternatives.append(alt); 0242 } 0243 0244 tpd.children.reset(new ScriptValueChildrenParser(info, value.property(PROPERTY_CHILDREN()))); 0245 tpd.defaultFields.reset(new ScriptValueChildrenParser(info, value.property(PROPERTY_DEFAULT_CHILDREN()))); 0246 return DataInformationFactory::newTaggedUnion(tpd); 0247 } 0248 0249 } // namespace ScriptValueConverter 0250 0251 ScriptValueConverter::ScriptValueChildrenParser::ScriptValueChildrenParser(const ParserInfo& info, 0252 const QScriptValue& children) 0253 : mValue(children) 0254 , mIter(children) 0255 , mInfo(info) 0256 { 0257 } 0258 0259 ScriptValueConverter::ScriptValueChildrenParser::~ScriptValueChildrenParser() = default; 0260 0261 DataInformation* ScriptValueConverter::ScriptValueChildrenParser::next() 0262 { 0263 Q_ASSERT(hasNext()); 0264 mIter.next(); 0265 if (mValue.isArray() && mIter.name() == QLatin1String("length")) { 0266 mIter.next(); // skip length property 0267 } 0268 mInfo.name = mIter.name(); 0269 return toDataInformation(mIter.value(), mInfo); 0270 } 0271 0272 bool ScriptValueConverter::ScriptValueChildrenParser::hasNext() 0273 { 0274 if (!mIter.hasNext()) { 0275 return false; 0276 } 0277 if (mValue.isArray()) { 0278 // check if next element is length property 0279 mIter.next(); 0280 if (mIter.name() != QLatin1String("length")) { 0281 mIter.previous(); // go back and return true 0282 return true; 0283 } 0284 return mIter.hasNext(); // skipped length 0285 } 0286 0287 return true; 0288 } 0289 0290 void ScriptValueConverter::ScriptValueChildrenParser::setParent(DataInformation* newParent) 0291 { 0292 mInfo.parent = newParent; 0293 }