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     SPDX-FileCopyrightText: 2016 Aaron Bishop <erroneous@gmail.com>
0006 
0007     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0008 */
0009 
0010 #include "parserutils.hpp"
0011 
0012 #include <QScriptValue>
0013 #include <QScriptEngine>
0014 
0015 namespace ParserStrings {
0016 
0017 QString TYPE_ARRAY() { return QStringLiteral("array"); }
0018 QString TYPE_BITFIELD() { return QStringLiteral("bitfield"); }
0019 QString TYPE_ENUM() { return QStringLiteral("enum"); }
0020 QString TYPE_FLAGS() { return QStringLiteral("flags"); }
0021 QString TYPE_PRIMITIVE() { return QStringLiteral("primitive"); }
0022 QString TYPE_STRING() { return QStringLiteral("string"); }
0023 QString TYPE_STRUCT() { return QStringLiteral("struct"); }
0024 QString TYPE_UNION() { return QStringLiteral("union"); }
0025 QString TYPE_POINTER() { return QStringLiteral("pointer"); }
0026 QString TYPE_TAGGED_UNION() { return QStringLiteral("taggedUnion"); }
0027 
0028 QString TYPE_ENUMDEF() { return QStringLiteral("enumDef"); }
0029 QString TYPE_ALTERNATIVES() { return QStringLiteral("alternatives"); }
0030 QString TYPE_GROUP() { return QStringLiteral("group"); }
0031 
0032 QString PROPERTY_DEFAULT_LOCK_OFFSET() { return QStringLiteral("defaultLockOffset"); }
0033 
0034 QString PROPERTY_NAME() { return QStringLiteral("name"); }
0035 QString PROPERTY_BYTEORDER() { return QStringLiteral("byteOrder"); }
0036 QString PROPERTY_PARENT() { return QStringLiteral("parent"); }
0037 QString PROPERTY_VALIDATION_ERROR() { return QStringLiteral("validationError"); }
0038 QString PROPERTY_VALID() { return QStringLiteral("valid"); }
0039 QString PROPERTY_ABLE_TO_READ() { return QStringLiteral("wasAbleToRead"); }
0040 QString PROPERTY_UPDATE_FUNC() { return QStringLiteral("updateFunc"); }
0041 QString PROPERTY_VALIDATION_FUNC() { return QStringLiteral("validationFunc"); }
0042 QString PROPERTY_TO_STRING_FUNC() { return QStringLiteral("toStringFunc"); }
0043 QString PROPERTY_DATATYPE() { return QStringLiteral("datatype"); }
0044 QString PROPERTY_CUSTOM_TYPE_NAME() { return QStringLiteral("typeName"); }
0045 
0046 QString PROPERTY_ENUM_VALUES() { return QStringLiteral("enumValues"); }
0047 
0048 QString PROPERTY_ENUM_NAME() { return QStringLiteral("enumName"); }
0049 
0050 QString PROPERTY_TYPE() { return QStringLiteral("type"); }
0051 
0052 QString PROPERTY_LENGTH() { return QStringLiteral("length"); }
0053 
0054 QString PROPERTY_WIDTH() { return QStringLiteral("width"); }
0055 QString PROPERTY_CHILDREN() { return QStringLiteral("fields"); }
0056 QString PROPERTY_CHILD_COUNT() { return QStringLiteral("childCount"); }
0057 QString PROPERTY_CHILD() { return QStringLiteral("child"); }
0058 
0059 QString PROPERTY_CHAR_COUNT() { return QStringLiteral("charCount"); }
0060 QString PROPERTY_BYTE_COUNT() { return QStringLiteral("byteCount"); }
0061 QString PROPERTY_MAX_CHAR_COUNT() { return QStringLiteral("maxCharCount"); }
0062 QString PROPERTY_MAX_BYTE_COUNT() { return QStringLiteral("maxByteCount"); }
0063 QString PROPERTY_TERMINATED_BY() { return QStringLiteral("terminatedBy"); }
0064 QString PROPERTY_ENCODING() { return QStringLiteral("encoding"); }
0065 // primitive
0066 QString PROPERTY_VALUE() { return QStringLiteral("value"); }
0067 // pointer
0068 QString PROPERTY_TARGET() { return QStringLiteral("target"); }
0069 QString PROPERTY_SCALE() { return QStringLiteral("scale"); }
0070 QString PROPERTY_INTERPRET_FUNC() { return QStringLiteral("interpretFunc"); }
0071 // tagged union
0072 QString PROPERTY_ALTERNATIVES() { return QStringLiteral("alternatives"); }
0073 QString PROPERTY_DEFAULT_CHILDREN() { return QStringLiteral("defaultFields"); }
0074 QString PROPERTY_SELECT_IF() { return QStringLiteral("selectIf"); }
0075 QString PROPERTY_STRUCT_NAME() { return QStringLiteral("structName"); }
0076 
0077 QString PROPERTY_INTERNAL_TYPE() { return QStringLiteral("__type"); }
0078 
0079 QStringList ALL_PROPERTIES()
0080 {
0081     return QStringList {
0082         PROPERTY_ABLE_TO_READ(),
0083         PROPERTY_ALTERNATIVES(),
0084         PROPERTY_BYTEORDER(),
0085         PROPERTY_BYTE_COUNT(),
0086         PROPERTY_CHAR_COUNT(),
0087         PROPERTY_CHAR_COUNT(),
0088         PROPERTY_CHILD(),
0089         PROPERTY_CHILDREN(),
0090         PROPERTY_CHILD_COUNT(),
0091         PROPERTY_DATATYPE(),
0092         PROPERTY_DEFAULT_CHILDREN(),
0093         PROPERTY_ENCODING(),
0094         PROPERTY_ENUM_NAME(),
0095         PROPERTY_ENUM_VALUES(),
0096         PROPERTY_INTERNAL_TYPE(),
0097         PROPERTY_INTERPRET_FUNC(),
0098         PROPERTY_LENGTH(),
0099         PROPERTY_MAX_BYTE_COUNT(),
0100         PROPERTY_MAX_CHAR_COUNT(),
0101         PROPERTY_NAME(),
0102         PROPERTY_PARENT(),
0103         PROPERTY_SCALE(),
0104         PROPERTY_SELECT_IF(),
0105         PROPERTY_STRUCT_NAME(),
0106         PROPERTY_TARGET(),
0107         PROPERTY_TERMINATED_BY(),
0108         PROPERTY_TYPE(),
0109         PROPERTY_UPDATE_FUNC(),
0110         PROPERTY_VALID(),
0111         PROPERTY_VALIDATION_ERROR(),
0112         PROPERTY_VALIDATION_FUNC(),
0113         PROPERTY_VALUE(),
0114         PROPERTY_WIDTH()
0115     };
0116 }
0117 
0118 QString NAME_POINTER_VALUE_TYPE() { return QStringLiteral("<pointer value type>"); }
0119 QString NAME_POINTER_TARGET() { return QStringLiteral("<pointer target>"); }
0120 QString NAME_ARRAY_TYPE() { return QStringLiteral("<array type>"); }
0121 }
0122 
0123 ParsedNumber<int> ParserUtils::intFromString(const QString& str)
0124 {
0125     int value = 0;
0126     bool okay = false;
0127     if (str.startsWith(QLatin1String("0x"))) {
0128         value = str.midRef(2).toInt(&okay, 16);
0129     } else if (str.startsWith(QLatin1String("-0x"))) {
0130         // special case for minimum possible value
0131         if (str == QLatin1String("-0x80000000")) {
0132             return ParsedNumber<int>(-0x80000000, str, true);
0133         }
0134         value = -str.midRef(3).toInt(&okay, 16);
0135     } else {
0136         value = str.toInt(&okay, 10);
0137     }
0138     return ParsedNumber<int>(value, str, okay);
0139 }
0140 
0141 ParsedNumber<uint> ParserUtils::uintFromString(const QString& str)
0142 {
0143     uint value = 0;
0144     bool okay;
0145     if (str.startsWith(QLatin1String("0x"))) {
0146         value = str.midRef(2).toUInt(&okay, 16);
0147     } else {
0148         value = str.toUInt(&okay, 10);
0149     }
0150     return ParsedNumber<uint>(value, str, okay);
0151 }
0152 
0153 ParsedNumber<quint64> ParserUtils::uint64FromString(const QString& str)
0154 {
0155     quint64 value = 0;
0156     bool okay;
0157     if (str.startsWith(QLatin1String("0x"))) {
0158         value = str.midRef(2).toULongLong(&okay, 16);
0159     } else {
0160         value = str.toULongLong(&okay, 10);
0161     }
0162     return ParsedNumber<quint64>(value, str, okay);
0163 }
0164 
0165 DataInformation::DataInformationEndianess ParserUtils::byteOrderFromString(const QString& string,
0166                                                                            const LoggerWithContext& logger)
0167 {
0168     const QString lower = string.toLower();
0169     if (lower == QLatin1String("bigendian") || lower == QLatin1String("big-endian")) {
0170         return DataInformation::DataInformationEndianess::EndianessBig;
0171     }
0172     if (lower == QLatin1String("littleendian") || lower == QLatin1String("little-endian")) {
0173         return DataInformation::DataInformationEndianess::EndianessLittle;
0174     }
0175     if (lower == QLatin1String("fromsettings") || lower == QLatin1String("from-settings")) {
0176         return DataInformation::DataInformationEndianess::EndianessFromSettings;
0177     }
0178     if (lower == QLatin1String("inherit")) {
0179         return DataInformation::DataInformationEndianess::EndianessInherit;
0180     }
0181 
0182     logger.warn().nospace() << "Unrecognized byte order '" << string << "', defaulting to 'inherit'";
0183     return DataInformation::DataInformationEndianess::EndianessInherit;
0184 }
0185 
0186 ParsedNumber<int> ParserUtils::intFromScriptValue(const QScriptValue& val)
0187 {
0188     if (val.isNumber()) {
0189         // check whether it is in range
0190         const qsreal doubleVal = val.toNumber();
0191         const int value = val.toInt32();
0192         if (doubleVal != qsreal(value)) {
0193             return ParsedNumber<int>::badInput(val.toString());
0194         }
0195         return ParsedNumber<int>(value, val.toString(), true);
0196     }
0197     if (val.isString()) {
0198         return intFromString(val.toString());
0199     }
0200     return ParsedNumber<int>::badInput(val.toString());
0201 }
0202 
0203 ParsedNumber<uint> ParserUtils::uintFromScriptValue(const QScriptValue& val)
0204 {
0205     if (val.isNumber()) {
0206         // check whether it is in range
0207         const uint value = val.toUInt32();
0208         const qsreal doubleVal = val.toNumber();
0209         if (doubleVal != qsreal(value)) {
0210             return ParsedNumber<uint>::badInput(val.toString());
0211         }
0212         return ParsedNumber<uint>(value, val.toString(), true);
0213     }
0214     if (val.isString()) {
0215         return uintFromString(val.toString());
0216     }
0217     return ParsedNumber<uint>::badInput(val.toString());
0218 }
0219 
0220 ParsedNumber<quint64> ParserUtils::uint64FromScriptValue(const QScriptValue& val)
0221 {
0222     if (val.isNumber()) {
0223         // check whether it is in range
0224         const uint value = val.toUInt32();
0225         const qsreal doubleVal = val.toNumber();
0226         if (doubleVal != qsreal(value)) {
0227             return ParsedNumber<quint64>::badInput(val.toString());
0228         }
0229         return ParsedNumber<quint64>(value, val.toString(), true);
0230     }
0231     if (val.isString()) {
0232         return uint64FromString(val.toString());
0233     }
0234     return ParsedNumber<quint64>::badInput(val.toString());
0235 }
0236 
0237 QString ParserUtils::byteOrderToString(DataInformation::DataInformationEndianess order)
0238 {
0239     if (order == DataInformation::DataInformationEndianess::EndianessLittle) {
0240         return QStringLiteral("littleEndian");
0241     }
0242     if (order == DataInformation::DataInformationEndianess::EndianessBig) {
0243         return QStringLiteral("bigEndian");
0244     }
0245     if (order == DataInformation::DataInformationEndianess::EndianessFromSettings) {
0246         return QStringLiteral("fromSettings");
0247     }
0248     return QStringLiteral("inherit");
0249 }
0250 
0251 StringDataInformation::StringType ParserUtils::toStringEncoding(const QString& str, const LoggerWithContext& logger)
0252 {
0253     QString enc = str.toLower();
0254     if (enc == QLatin1String("ascii")) {
0255         return StringDataInformation::StringType::ASCII;
0256     }
0257     if (enc == QLatin1String("ebcdic")) {
0258         return StringDataInformation::StringType::EBCDIC;
0259     }
0260     if (enc == QLatin1String("latin1") || enc == QLatin1String("latin-1")) {
0261         return StringDataInformation::StringType::Latin1;
0262     }
0263     if (enc.startsWith(QLatin1String("utf"))) {
0264         QStringRef ref = enc.midRef(3);
0265         if (ref.at(0) == QLatin1Char('-')) {
0266             ref = enc.midRef(4); // strip '-'
0267         }
0268         if (ref == QLatin1String("8")) {
0269             return StringDataInformation::StringType::UTF8;
0270         }
0271 
0272         if (ref == QLatin1String("16") || ref == QLatin1String("16le") || ref == QLatin1String("16-le")) {
0273             return StringDataInformation::StringType::UTF16_LE;
0274         }
0275         if (ref == QLatin1String("16be") || ref == QLatin1String("16-be")) {
0276             return StringDataInformation::StringType::UTF16_BE;
0277         }
0278         if (ref == QLatin1String("32") || ref == QLatin1String("32le") || ref == QLatin1String("32-le")) {
0279             return StringDataInformation::StringType::UTF32_LE;
0280         }
0281         if (ref == QLatin1String("32be") || ref == QLatin1String("32-be")) {
0282             return StringDataInformation::StringType::UTF32_BE;
0283         }
0284     }
0285     logger.warn() << "Unrecognized string encoding: " << enc;
0286     return StringDataInformation::StringType::InvalidEncoding;
0287 }
0288 
0289 QScriptValue ParserUtils::functionSafeEval(QScriptEngine* engine, const QString& str)
0290 {
0291     if (str.isEmpty()) {
0292         return {};
0293     }
0294     // must wrap in parentheses, see https://bugreports.qt-project.org/browse/QTBUG-5757
0295     QScriptValue ret = engine->evaluate(QLatin1Char('(') + str + QLatin1Char(')'));
0296     if (!ret.isFunction()) {
0297         return {str};
0298     }
0299     return ret;
0300 }