File indexing completed on 2024-06-30 05:51:31
0001 /* 0002 This file is part of the Okteta Kasten Framework, made within the KDE community. 0003 0004 SPDX-FileCopyrightText: 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 "stringscriptclass.hpp" 0010 #include "../../datatypes/strings/stringdatainformation.hpp" 0011 #include "../../parsers/parserutils.hpp" 0012 #include <structureslogging.hpp> 0013 0014 StringScriptClass::StringScriptClass(QScriptEngine* eng, ScriptHandlerInfo* handlerInfo) 0015 : DefaultScriptClass(eng, handlerInfo) 0016 { 0017 mIterableProperties.reserve(mIterableProperties.size() + 6); 0018 // read-only properties 0019 s_lengthInCodepoints = eng->toStringHandle(ParserStrings::PROPERTY_CHAR_COUNT()); 0020 mIterableProperties.append(qMakePair(s_lengthInCodepoints, QScriptValue::ReadOnly | QScriptValue::Undeletable)); 0021 s_lengthInBytes = eng->toStringHandle(ParserStrings::PROPERTY_BYTE_COUNT()); 0022 mIterableProperties.append(qMakePair(s_lengthInBytes, QScriptValue::ReadOnly | QScriptValue::Undeletable)); 0023 0024 // read-write properties 0025 s_maxByteCount = eng->toStringHandle(ParserStrings::PROPERTY_MAX_BYTE_COUNT()); 0026 mIterableProperties.append(qMakePair(s_maxByteCount, QScriptValue::PropertyFlags(QScriptValue::Undeletable))); 0027 s_maxCharCount = eng->toStringHandle(ParserStrings::PROPERTY_MAX_CHAR_COUNT()); 0028 mIterableProperties.append(qMakePair(s_maxCharCount, QScriptValue::PropertyFlags(QScriptValue::Undeletable))); 0029 s_terminatedBy = eng->toStringHandle(ParserStrings::PROPERTY_TERMINATED_BY()); 0030 mIterableProperties.append(qMakePair(s_terminatedBy, QScriptValue::PropertyFlags(QScriptValue::Undeletable))); 0031 s_encoding = eng->toStringHandle(ParserStrings::PROPERTY_ENCODING()); 0032 mIterableProperties.append(qMakePair(s_encoding, QScriptValue::PropertyFlags(QScriptValue::Undeletable))); 0033 0034 mStringPrototype = eng->newObject(); 0035 mStringPrototype.setProperty(QStringLiteral("toString"), eng->newFunction(String_proto_toString)); 0036 } 0037 0038 StringScriptClass::~StringScriptClass() = default; 0039 0040 bool StringScriptClass::queryAdditionalProperty(const DataInformation* data, const QScriptString& name, QScriptClass::QueryFlags* flags, uint* id) 0041 { 0042 Q_UNUSED(data) 0043 // no need to modify flags since both read and write are handled 0044 if (name == s_maxByteCount || name == s_maxCharCount || name == s_terminatedBy 0045 || name == s_encoding) { 0046 return true; 0047 } 0048 if (name == s_lengthInCodepoints || name == s_lengthInBytes) { 0049 *flags &= ~HandlesWriteAccess; 0050 return true; 0051 } 0052 0053 bool isArrayIndex; 0054 quint32 pos = name.toArrayIndex(&isArrayIndex); 0055 if (isArrayIndex && pos <= uint(data->asString()->stringLength())) { 0056 *id = pos + 1; // add 1 to distinguish from the default value of 0 0057 *flags &= ~HandlesWriteAccess; // writing is not yet supported 0058 return true; 0059 } 0060 return false; // not found 0061 } 0062 0063 bool StringScriptClass::additionalPropertyFlags(const DataInformation* data, const QScriptString& name, uint id, QScriptValue::PropertyFlags* flags) 0064 { 0065 Q_UNUSED(data) 0066 Q_UNUSED(name) 0067 if (id != 0) { 0068 *flags |= QScriptValue::ReadOnly; 0069 return true; 0070 } 0071 return false; 0072 } 0073 0074 QScriptValue StringScriptClass::additionalProperty(const DataInformation* data, const QScriptString& name, uint id) 0075 { 0076 const StringDataInformation* sData = data->asString(); 0077 0078 if (id != 0) { 0079 quint32 pos = id - 1; 0080 if (pos >= uint(sData->stringLength())) { 0081 return engine()->currentContext()->throwError(QScriptContext::RangeError, 0082 QStringLiteral("Attempting to access string index %1, but length is %2").arg( 0083 QString::number(pos), QString::number(sData->stringLength()))); 0084 } 0085 return sData->valueAt(pos); 0086 } 0087 if (name == s_lengthInCodepoints) { 0088 return sData->stringLength(); 0089 } 0090 if (name == s_lengthInBytes) { 0091 return sData->stringByteLength(); 0092 } 0093 if (name == s_encoding) { 0094 return sData->encodingName(); 0095 } 0096 if (name == s_maxCharCount) { 0097 return sData->maxCharCount(); 0098 } 0099 if (name == s_maxByteCount) { 0100 return sData->maxByteCount(); 0101 } 0102 if (name == s_terminatedBy) { 0103 return sData->terminationCodePoint(); 0104 } 0105 return {}; 0106 } 0107 0108 bool StringScriptClass::setAdditionalProperty(DataInformation* data, const QScriptString& name, uint, const QScriptValue& value) 0109 { 0110 StringDataInformation* sData = data->asString(); 0111 0112 if (name == s_maxCharCount) { 0113 if (value.isNull()) { 0114 sData->logInfo() << "Unsetting max char count."; 0115 sData->unsetTerminationMode(StringData::CharCount); 0116 } else { 0117 ParsedNumber<uint> result = ParserUtils::uintFromScriptValue(value); 0118 if (result.isValid) { 0119 sData->setMaxCharCount(result.value); 0120 } else { 0121 sData->logError() << "Could not set maximum char count, invalid argument: " << value.toString(); 0122 } 0123 } 0124 return true; 0125 } 0126 if (name == s_maxByteCount) { 0127 if (value.isNull()) { 0128 sData->logInfo() << "Unsetting max byte count."; 0129 sData->unsetTerminationMode(StringData::ByteCount); 0130 } else { 0131 ParsedNumber<uint> result = ParserUtils::uintFromScriptValue(value); 0132 if (result.isValid) { 0133 sData->setMaxByteCount(result.value); 0134 } else { 0135 sData->logError() << "Could not set maximum byte count, invalid argument: " << value.toString(); 0136 } 0137 } 0138 return true; 0139 } 0140 if (name == s_terminatedBy) { 0141 if (value.isNull()) { 0142 sData->logInfo() << "Unsetting termination character."; 0143 sData->unsetTerminationMode(StringData::Sequence); 0144 } else { 0145 if (value.isString()) { 0146 QString str = value.toString(); 0147 // we don't handle surrogate pairs, if you want to set that use a number instead. 0148 if (str.length() != 1) { 0149 sData->logError() << "Setting termination char: expected one char or a code point number" 0150 ", got a string with length " << str.length(); 0151 } else { 0152 sData->setTerminationCodePoint(str[0].unicode()); 0153 } 0154 } else { 0155 ParsedNumber<uint> result = ParserUtils::uintFromScriptValue(value); 0156 if (result.isValid) { 0157 sData->setTerminationCodePoint(result.value); 0158 } else { 0159 sData->logError() << "Could not set maximum byte count, invalid argument: " << value.toString(); 0160 } 0161 } 0162 } 0163 return true; 0164 } 0165 if (name == s_encoding) { 0166 QString enc = value.toString(); 0167 StringDataInformation::StringType encoding = ParserUtils::toStringEncoding(enc, 0168 LoggerWithContext(sData->logger(), sData->fullObjectPath())); 0169 if (encoding == StringDataInformation::StringType::InvalidEncoding) { 0170 sData->logError() << "Attempting to set invalid encoding:" << enc; 0171 } else { 0172 sData->setEncoding(encoding); 0173 } 0174 return true; 0175 } 0176 return false; 0177 } 0178 0179 QScriptValue StringScriptClass::prototype() const 0180 { 0181 return mStringPrototype; 0182 } 0183 0184 QScriptValue StringScriptClass::String_proto_toString(QScriptContext* ctx, QScriptEngine* eng) 0185 { 0186 DataInformation* data = toDataInformation(ctx->thisObject().data()); 0187 if (!data) { 0188 qCWarning(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "could not cast data"; 0189 return eng->undefinedValue(); 0190 } 0191 return data->wasAbleToRead() ? data->valueString() : eng->undefinedValue(); 0192 }