2
* This file is part of the Okteta Kasten Framework, made within the KDE community.
4
* Copyright 2012 Alex Richardson <alex.richardson@gmx.de>
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU Lesser General Public
8
* License as published by the Free Software Foundation; either
9
* version 2.1 of the License, or (at your option) version 3, or any
10
* later version accepted by the membership of KDE e.V. (or its
11
* successor approved by the membership of KDE e.V.), which shall
12
* act as a proxy defined in Section 6 of version 3 of the license.
14
* This library is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17
* Lesser General Public License for more details.
19
* You should have received a copy of the GNU Lesser General Public
20
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
23
#include "scriptvalueconverter.h"
24
#include "scriptvalueconverter_p.h"
26
#include "../datatypes/array/arraydatainformation.h"
27
#include "../datatypes/uniondatainformation.h"
28
#include "../datatypes/structuredatainformation.h"
29
#include "../datatypes/primitive/enumdatainformation.h"
30
#include "../datatypes/primitive/flagdatainformation.h"
31
#include "../datatypes/primitive/enumdefinition.h"
32
#include "../datatypes/strings/stringdata.h"
33
#include "../datatypes/strings/stringdatainformation.h"
34
#include "../datatypes/primitive/bitfield/boolbitfielddatainformation.h"
35
#include "../datatypes/primitive/bitfield/unsignedbitfielddatainformation.h"
36
#include "../datatypes/primitive/bitfield/signedbitfielddatainformation.h"
37
#include "../datatypes/primitivefactory.h"
38
#include "../datatypes/additionaldata.h"
40
#include "../parsers/abstractstructureparser.h"
42
#include "scriptlogger.h"
44
#include <QScriptValueIterator>
46
namespace ScriptValueConverter
49
DataInformation* toDataInformation(const QScriptValue& value, const QString& passedName,
52
//check function array and date, since they are objects too
55
//apparently regexp is a function
56
logger->error(value) << "Cannot convert a RegExp object to DataInformation!";
59
if (value.isFunction())
61
logger->error(value) << "Cannot convert a Function object to DataInformation!";
66
logger->error(value) << "Cannot convert a Array object to DataInformation!";
71
logger->error(value) << "Cannot convert a Date object to DataInformation!";
76
logger->error(value) << "Cannot convert a Error object to DataInformation!";
79
//variant and qobject are also object types, however they cannot appear from user code, no need to check
81
const QString name = passedName.isEmpty() ? i18n("<no name specified>") : passedName;
82
DataInformation* returnVal;
83
//if it is a string, we convert to primitive type, if not it has to be an object
85
return toPrimitive(value, name, logger); //a type string is also okay
87
if (!value.isObject())
90
logger->error(value) << "Cannot convert Boolean to DataInformation!";
91
else if (value.isNull())
92
logger->error(value) << "Cannot convert null to DataInformation!";
93
else if (value.isUndefined())
94
logger->error(value) << "Cannot convert undefined to DataInformation!";
95
else if (value.isNumber())
96
logger->error(value) << "Cannot convert Number to DataInformation!";
98
logger->error(value) << "Cannot convert object of unknown type to DataInformation!";
100
return 0; //no point trying to convert
103
QString type = value.property(QLatin1String("type")).toString().toLower(); //to lower just to be safe
107
<< "Cannot convert object since type of object could not be determined!";
110
if (type == QLatin1String("array"))
111
returnVal = toArray(value, name, logger);
113
else if (type == QLatin1String("struct"))
114
returnVal = toStruct(value, name, logger);
116
else if (type == QLatin1String("union"))
117
returnVal = toUnion(value, name, logger);
119
else if (type == QLatin1String("bitfield"))
120
returnVal = toBitfield(value, name, logger);
122
else if (type == QLatin1String("enum"))
123
returnVal = toEnum(value, name, false, logger);
125
else if (type == QLatin1String("flags"))
126
returnVal = toEnum(value, name, true, logger);
128
else if (type == QLatin1String("string"))
129
returnVal = toString(value, name, logger);
131
//now it can only be a primitive type or something invalid
133
returnVal = toPrimitive(value, name, logger);
137
//successfully parsed -> add the validate and update functions to the additional data
138
QScriptValue updateFunc = value.property(QLatin1String("updateFunc"));
139
QScriptValue validationFunc = value.property(QLatin1String("validationFunc"));
140
QScriptValue byteOrder = value.property(QLatin1String("byteOrder"));
141
if (byteOrder.isValid())
142
returnVal->setByteOrder(
143
AbstractStructureParser::byteOrderFromString(byteOrder.toString(), logger));
145
if (updateFunc.isFunction())
146
returnVal->setUpdateFunc(updateFunc);
148
if (validationFunc.isFunction())
149
returnVal->setValidationFunc(updateFunc);
154
ArrayDataInformation* toArray(const QScriptValue& value, const QString& name, ScriptLogger* logger)
156
//we can safely assume that type == "array"
157
int length = value.property(QLatin1String("length")).toInt32();
160
logger->error(value) << "array length is less than 0:" << length;
163
QScriptValue childType = value.property(QLatin1String("childType"));
164
DataInformation* arrayType = toDataInformation(childType, QString(), logger);
167
logger->error(childType) << "Failed to convert array type to valid object!";
170
return new ArrayDataInformation(name, length, arrayType);
173
AbstractBitfieldDataInformation* toBitfield(const QScriptValue& value, const QString& name,
174
ScriptLogger* logger)
176
//we can safely assume that type == "bitfield"
177
int width = value.property(QLatin1String("width")).toInt32();
178
if (width < 0 || width > 64)
180
logger->error(value) << "bitfield width is outside of range 1-64:" << width;
183
QString bitfieldType = value.property(QLatin1String("bitfieldType")).toString();
184
if (bitfieldType.toLower() == QLatin1String("bool"))
185
return new BoolBitfieldDataInformation(name, width);
187
else if (bitfieldType.toLower() == QLatin1String("signed"))
188
return new SignedBitfieldDataInformation(name, width);
190
else if (bitfieldType.toLower() == QLatin1String("unsigned"))
191
return new UnsignedBitfieldDataInformation(name, width);
193
logger->error(value).nospace() << "invalid bitfield type specified: '" << bitfieldType
194
<< "'. Only 'bool', 'signed' or 'unsigned' are valid.";
198
PrimitiveDataInformation* toPrimitive(const QScriptValue& value, const QString& name,
199
ScriptLogger* logger)
202
value.isString() ? value.toString() : value.property(QLatin1String("type")).toString();
203
if (typeString.isEmpty())
205
logger->error(value) << "Object is neither string nor object with type property"
206
", cannot convert it to primitive";
209
PrimitiveDataType primitiveType = PrimitiveFactory::typeStringToType(typeString);
210
if (primitiveType == Type_Invalid || primitiveType == Type_Bitfield)
212
logger->error(value) << "unrecognised primitive type: " << typeString;
215
return PrimitiveFactory::newInstance(name, primitiveType);
218
StructureDataInformation* toStruct(const QScriptValue& value, const QString& name,
219
ScriptLogger* logger)
221
QScriptValue valueChildren = value.property(QLatin1String("children"));
222
QVector<DataInformation*> fields = convertValues(valueChildren, logger);
224
if (fields.isEmpty())
225
logger->info(value) << "No children were found for struct, this is could be a mistake.";
227
StructureDataInformation* structData = new StructureDataInformation(name, fields);
231
UnionDataInformation* toUnion(const QScriptValue& value, const QString& name, ScriptLogger* logger)
233
QScriptValue valueChildren = value.property(QLatin1String("children"));
234
QVector<DataInformation*> fields = convertValues(valueChildren, logger);
236
if (fields.isEmpty())
237
logger->info(value) << "No children were found for union, this is could be a mistake.";
240
UnionDataInformation* unionData = new UnionDataInformation(name, fields);
244
AbstractEnumDataInformation* toEnum(const QScriptValue& value, const QString& name, bool flags,
245
ScriptLogger* logger)
247
//TODO also allow bitfields
248
QString typeString = value.property(QLatin1String("enumType")).toString();
249
PrimitiveDataType primitiveType = PrimitiveFactory::typeStringToType(typeString);
250
if (primitiveType == Type_Invalid)
252
logger->error(value) << "unrecognised primitive type: " << typeString;
256
QScriptValue enumValuesObj = value.property(QLatin1String("enumValues"));
257
if (!enumValuesObj.isValid() || !enumValuesObj.isObject())
259
logger->warn(enumValuesObj) << "Could not parse enumerators since variable with key-value"
260
"structure was expected";
263
QMap<AllPrimitiveTypes, QString> enumValues =
264
AbstractEnumDataInformation::parseEnumValues(enumValuesObj, logger, primitiveType);
266
QString enumName = value.property(QLatin1String("enumName")).toString();
267
EnumDefinition::Ptr def(new EnumDefinition(enumValues, enumName, primitiveType));
268
PrimitiveDataInformation* primData = PrimitiveFactory::newInstance(name, primitiveType);
273
return new FlagDataInformation(name, primData, def);
275
return new EnumDataInformation(name, primData, def);
278
StringDataInformation* toString(const QScriptValue& value, const QString& name,
279
ScriptLogger* logger)
281
//TODO check for bad parameters
282
const QScriptValue terminatedBy = value.property(QLatin1String("terminatedBy"));
283
const QScriptValue charCount = value.property(QLatin1String("maxCharCount"));
284
const QScriptValue byteCount = value.property(QLatin1String("maxByteCount"));
285
const QScriptValue encoding = value.property(QLatin1String("encoding"));
287
StringData::TerminationModes mode = StringData::None;
288
if (terminatedBy.isNumber())
289
mode |= StringData::Sequence;
290
if (charCount.isNumber())
291
mode |= StringData::CharCount;
292
if (byteCount.isNumber())
293
mode |= StringData::ByteCount;
295
if ((mode & StringData::CharCount) && (mode & StringData::ByteCount))
296
mode &= ~StringData::ByteCount; //when both exists charcount wins
298
StringDataInformation* data = new StringDataInformation(name, encoding.toString());
299
//if mode is None, we assume zero terminated strings
300
if (mode == StringData::None)
302
mode = StringData::Sequence;
303
data->setTerminationCodePoint(0);
305
else if (mode & StringData::Sequence)
307
const uint term = terminatedBy.toUInt32();
308
data->setTerminationCodePoint(term);
310
if (mode & StringData::CharCount)
312
const int count = charCount.toInt32();
313
data->setMaxCharCount(qMax(count, 0));
315
if (mode & StringData::ByteCount)
317
const int count = byteCount.toInt32();
318
data->setMaxByteCount(qMax(count, 0));
323
} //namespace ScriptValueConverter