diff --git a/kasten/controllers/test/jsparsertest.cpp b/kasten/controllers/test/jsparsertest.cpp index b0ab7cc5..1140e3e3 100644 --- a/kasten/controllers/test/jsparsertest.cpp +++ b/kasten/controllers/test/jsparsertest.cpp @@ -1,340 +1,344 @@ /* * This file is part of the Okteta Kasten module, made within the KDE community. * * Copyright 2013 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ // TODO: find better way to work-around simple name creation for QTest::newRow #undef QT_USE_QSTRINGBUILDER #include #include #include "view/structures/script/scriptengineinitializer.h" #include "view/structures/parsers/scriptvalueconverter.h" #include "testutils.h" #include struct JsTestData { typedef std::function CheckCallback; JsTestData() {} JsTestData(const char* tag, const char* constructor, CheckCallback check) : tag(tag), constructorCall(QString::fromUtf8(constructor)), check(check) {} QByteArray tag; QString constructorCall; CheckCallback check; }; Q_DECLARE_METATYPE(JsTestData) Q_DECLARE_METATYPE(JsTestData::CheckCallback) class JsParserTest : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void testValidationFunc(); void testValidationFunc_data(); void testUpdateFunc(); void testUpdateFunc_data(); void testByteOrder(); void testByteOrder_data(); void testName(); void testName_data(); void testCustomTypeName(); void testCustomTypeName_data(); void testImport(); void testImportPathTraversal(); private: /** data gets set to the parsed result. * This is needed since functions with QVERIFY/QCOMPARE must return void */ void testCommon(DataInformation** data); private: QScriptEngine engine; QVector primitiveData; QVector bitfieldData; QVector allData; }; static JsTestData::CheckCallback primitiveTypeCheck(PrimitiveDataTypeEnum type) { return [type](DataInformation* data) { QVERIFY(data->isPrimitive()); QCOMPARE(data->asPrimitive()->type().value, type); }; } static JsTestData::CheckCallback bitfieldCheck(AbstractBitfieldDataInformation::Type type) { return [type](DataInformation* data) { QVERIFY(data->isPrimitive()); QCOMPARE(data->asBitfield()->bitfieldType(), type); }; } void JsParserTest::initTestCase() { ScriptEngineInitializer::addFuctionsToScriptEngine(&engine); primitiveData << JsTestData("float", "float()", primitiveTypeCheck(Type_Float)) << JsTestData("double", "double()", primitiveTypeCheck(Type_Double)) << JsTestData("char", "char()", primitiveTypeCheck(Type_Char)) << JsTestData("uint8", "uint8()", primitiveTypeCheck(Type_UInt8)) << JsTestData("uint16", "uint16()", primitiveTypeCheck(Type_UInt16)) << JsTestData("uint32", "uint32()", primitiveTypeCheck(Type_UInt32)) << JsTestData("uint64", "uint64()", primitiveTypeCheck(Type_UInt64)) << JsTestData("int8", "int8()", primitiveTypeCheck(Type_Int8)) << JsTestData("int16", "int16()", primitiveTypeCheck(Type_Int16)) << JsTestData("int32", "int32()", primitiveTypeCheck(Type_Int32)) << JsTestData("int64", "int64()", primitiveTypeCheck(Type_Int64)) << JsTestData("bool8", "bool8()", primitiveTypeCheck(Type_Bool8)) << JsTestData("bool16", "bool16()", primitiveTypeCheck(Type_Bool16)) << JsTestData("bool32", "bool32()", primitiveTypeCheck(Type_Bool32)) << JsTestData("bool64", "bool64()", primitiveTypeCheck(Type_Bool64)); bitfieldData << JsTestData("signed bitfield", "bitfield(\"signed\", 5)", bitfieldCheck(AbstractBitfieldDataInformation::Signed)) << JsTestData("unsigned bitfield", "bitfield(\"unsigned\", 5)", bitfieldCheck(AbstractBitfieldDataInformation::Unsigned)) << JsTestData("bool bitfield", "bitfield(\"bool\", 5)", bitfieldCheck(AbstractBitfieldDataInformation::Boolean)); allData << primitiveData << bitfieldData; //TODO struct, union, taggedUnion, pointer, flags, enum, array, string //needed so that imports can be resolved QString resources = QFINDTESTDATA("resources"); QString examples = QFINDTESTDATA("../view/structures/examples"); QVERIFY2(!resources.isEmpty(), "Test data must exist!"); QVERIFY2(!examples.isEmpty(), "Test data must exist!"); qputenv("XDG_DATA_DIRS", QFile::encodeName(QFileInfo(resources).absoluteFilePath()) + ':' + QFile::encodeName(QFileInfo(examples).absoluteFilePath())); } void JsParserTest::testByteOrder_data() { QTest::addColumn("code"); QTest::addColumn("checkFunction"); QTest::addColumn("expectedByteOrder"); //verify that default is inherit Q_FOREACH(const JsTestData& data, allData) { //default should be inherit QString codeStr = QStringLiteral("%1;"); QTest::newRow(data.tag.constData()) << codeStr.arg(data.constructorCall) << data.check << (int)DataInformation::EndianessInherit; //use set() function to specify byteOrder codeStr = QStringLiteral("%1.set({byteOrder: \"inherit\"})"); QTest::newRow((data.tag + " set() inherit").constData()) << codeStr.arg(data.constructorCall) << data.check << (int)DataInformation::EndianessInherit; codeStr = QStringLiteral("%1.set({byteOrder: \"littleEndian\"})"); QTest::newRow((data.tag + " set() little endian").constData()) << codeStr.arg(data.constructorCall) << data.check << (int)DataInformation::EndianessLittle; codeStr = QStringLiteral("%1.set({byteOrder: \"bigEndian\"})"); QTest::newRow((data.tag + " set() big endian").constData()) << codeStr.arg(data.constructorCall) << data.check << (int)DataInformation::EndianessBig; codeStr = QStringLiteral("%1.set({byteOrder: \"fromSettings\"})"); QTest::newRow((data.tag + " set() from settings").constData()) << codeStr.arg(data.constructorCall) << data.check << (int)DataInformation::EndianessFromSettings; //direct property access to specify byteOrder codeStr = QStringLiteral("var obj = %1; obj.byteOrder = \"inherit\"; obj;"); QTest::newRow((data.tag + " property assign inherit").constData()) << codeStr.arg(data.constructorCall) << data.check << (int)DataInformation::EndianessInherit; codeStr = QStringLiteral("var obj = %1; obj.byteOrder = \"little-endian\"; obj;"); QTest::newRow((data.tag + " property assign little endian").constData()) << codeStr.arg(data.constructorCall) << data.check << (int)DataInformation::EndianessLittle; codeStr = QStringLiteral("var obj = %1; obj.byteOrder = \"big-endian\"; obj;"); QTest::newRow((data.tag + " property assign big endian").constData()) << codeStr.arg(data.constructorCall) << data.check << (int)DataInformation::EndianessBig; codeStr = QStringLiteral("var obj = %1; obj.byteOrder = \"from-settings\"; obj;"); QTest::newRow((data.tag + " property assign from settings").constData()) << codeStr.arg(data.constructorCall) << data.check << (int)DataInformation::EndianessFromSettings; } } void JsParserTest::testCommon(DataInformation** dataPtr) { QFETCH(QString, code); QFETCH(JsTestData::CheckCallback, checkFunction); QScriptValue value = engine.evaluate(code); QVERIFY(value.isValid()); QVERIFY(!value.isError()); QVERIFY(value.isObject()); ScriptLogger logger; QScopedPointer data (ScriptValueConverter::convert(value, QStringLiteral("converted"), &logger)); QVERIFY(logger.rowCount() == 0); QVERIFY(data); checkFunction(data.data()); *dataPtr = data.take(); } void JsParserTest::testByteOrder() { DataInformation* data = 0; testCommon(&data); if (QTest::currentTestFailed()) return; //Qt doesn't use exceptions, we must manually check after each call QFETCH(int, expectedByteOrder); QCOMPARE((int)data->byteOrder(), expectedByteOrder); } -static const QString updateFunction = QStringLiteral("function () { /* do nothing*/; }"); +namespace { +QString updateFunction() { return QStringLiteral("function () { /* do nothing*/; }"); } +} void JsParserTest::testUpdateFunc_data() { QTest::addColumn("code"); QTest::addColumn("checkFunction"); Q_FOREACH(const JsTestData& data, allData) { - QString codeStr = QStringLiteral("%1.setUpdate(") + updateFunction + QStringLiteral(");"); + QString codeStr = QStringLiteral("%1.setUpdate(") + updateFunction() + QStringLiteral(");"); QTest::newRow((data.tag + "-setUpdate()").constData()) << codeStr.arg(data.constructorCall) << data.check; - codeStr = QStringLiteral("%1.set({updateFunc: ") + updateFunction + QStringLiteral("});"); + codeStr = QStringLiteral("%1.set({updateFunc: ") + updateFunction() + QStringLiteral("});"); QTest::newRow((data.tag + "-set()").constData()) << codeStr.arg(data.constructorCall) << data.check; - codeStr = QStringLiteral("var obj = %1; obj.updateFunc = ") + updateFunction + QStringLiteral("; obj;"); + codeStr = QStringLiteral("var obj = %1; obj.updateFunc = ") + updateFunction() + QStringLiteral("; obj;"); QTest::newRow((data.tag + "-property assign").constData()) << codeStr.arg(data.constructorCall) << data.check; } } void JsParserTest::testUpdateFunc() { DataInformation* data = 0; testCommon(&data); if (QTest::currentTestFailed()) return; //Qt doesn't use exceptions, we must manually check after each call QVERIFY(data); QScriptValue update = data->updateFunc(); QVERIFY(update.isValid()); QVERIFY(update.isFunction()); - QCOMPARE(update.toString(), updateFunction); + QCOMPARE(update.toString(), updateFunction()); } -static const QString validationFunction = QStringLiteral("function () { return true; }"); +namespace { +QString validationFunction() { return QStringLiteral("function () { return true; }"); } +} void JsParserTest::testValidationFunc_data() { QTest::addColumn("code"); QTest::addColumn("checkFunction"); Q_FOREACH(const JsTestData& data, allData) { - QString codeStr = QStringLiteral("%1.setValidation(") + validationFunction + QStringLiteral(");"); + QString codeStr = QStringLiteral("%1.setValidation(") + validationFunction() + QStringLiteral(");"); QTest::newRow((data.tag + "-setUpdate()").constData()) << codeStr.arg(data.constructorCall) << data.check; - codeStr = QStringLiteral("%1.set({validationFunc: ") + validationFunction + QStringLiteral("});"); + codeStr = QStringLiteral("%1.set({validationFunc: ") + validationFunction() + QStringLiteral("});"); QTest::newRow((data.tag + "-set()").constData()) << codeStr.arg(data.constructorCall) << data.check; - codeStr = QStringLiteral("var obj = %1; obj.validationFunc = ") + validationFunction + QStringLiteral("; obj;"); + codeStr = QStringLiteral("var obj = %1; obj.validationFunc = ") + validationFunction() + QStringLiteral("; obj;"); QTest::newRow((data.tag + "-property assign").constData()) << codeStr.arg(data.constructorCall) << data.check; } } void JsParserTest::testValidationFunc() { DataInformation* data = 0; testCommon(&data); if (QTest::currentTestFailed()) return; //Qt doesn't use exceptions, we must manually check after each call QScriptValue validation = data->validationFunc(); QVERIFY(validation.isValid()); QVERIFY(validation.isFunction()); - QCOMPARE(validation.toString(), validationFunction); + QCOMPARE(validation.toString(), validationFunction()); } void JsParserTest::testName_data() { QTest::addColumn("code"); QTest::addColumn("checkFunction"); Q_FOREACH(const JsTestData& data, allData) { QString codeStr = QStringLiteral("%1.set({name: \"expectedName\"});"); QTest::newRow((data.tag + "-set()").constData()) << codeStr.arg(data.constructorCall) << data.check; codeStr = QStringLiteral("var obj = %1;obj.name = \"expectedName\"; obj;"); QTest::newRow((data.tag + "-property assignment").constData()) << codeStr.arg(data.constructorCall) << data.check; } } void JsParserTest::testName() { DataInformation* data = 0; testCommon(&data); if (QTest::currentTestFailed()) return; //Qt doesn't use exceptions, we must manually check after each call QCOMPARE(data->name(), QString(QStringLiteral("expectedName"))); } void JsParserTest::testCustomTypeName_data() { QTest::addColumn("code"); QTest::addColumn("checkFunction"); Q_FOREACH(const JsTestData& data, allData) { QString codeStr = QStringLiteral("%1.set({typeName: 'myCustomType'});"); QTest::newRow((data.tag + "-set()").constData()) << codeStr.arg(data.constructorCall) << data.check; codeStr = QStringLiteral("var obj = %1;obj.typeName = 'myCustomType'; obj;"); QTest::newRow((data.tag + "-property assignment").constData()) << codeStr.arg(data.constructorCall) << data.check; } } void JsParserTest::testCustomTypeName() { DataInformation* data = 0; testCommon(&data); if (QTest::currentTestFailed()) return; //Qt doesn't use exceptions, we must manually check after each call QCOMPARE(data->typeName(), QString(QStringLiteral("myCustomType"))); } void JsParserTest::testImport() { QScopedPointer eng(ScriptEngineInitializer::newEngine()); QScriptValue val = eng->evaluate(QStringLiteral("s = importScript('simpleImport.js');s.foo()")); QCOMPARE(val.toString(), QString(QStringLiteral("100"))); } void JsParserTest::testImportPathTraversal() { QScopedPointer eng(ScriptEngineInitializer::newEngine()); QScriptValue val = eng->evaluate(QStringLiteral("s = importScript('../../pathtraversal.js');s.foo()")); QVERIFY(val.isError()); QCOMPARE(val.toString(), QString(QStringLiteral("Error: importScript(): You may only access installed structure files! Path traversal detected."))); } QTEST_GUILESS_MAIN(JsParserTest) #include "jsparsertest.moc" diff --git a/kasten/controllers/test/scriptclassestest.cpp b/kasten/controllers/test/scriptclassestest.cpp index b59ef9b5..2cea5cb7 100644 --- a/kasten/controllers/test/scriptclassestest.cpp +++ b/kasten/controllers/test/scriptclassestest.cpp @@ -1,447 +1,449 @@ /* * This file is part of the Okteta Kasten module, made within the KDE community. * * Copyright 2012, 2013 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include "view/structures/datatypes/primitive/primitivetemplateinfo.h" #include "view/structures/datatypes/primitive/primitivedatainformation.h" #include "view/structures/datatypes/primitive/enumdatainformation.h" #include "view/structures/datatypes/primitive/flagdatainformation.h" #include "view/structures/datatypes/primitive/pointerdatainformation.h" #include "view/structures/datatypes/primitive/bitfield/boolbitfielddatainformation.h" #include "view/structures/datatypes/primitive/bitfield/unsignedbitfielddatainformation.h" #include "view/structures/datatypes/primitive/bitfield/signedbitfielddatainformation.h" #include "view/structures/datatypes/primitivefactory.h" #include "view/structures/datatypes/topleveldatainformation.h" #include "view/structures/datatypes/strings/stringdatainformation.h" #include "view/structures/datatypes/array/arraydatainformation.h" #include "view/structures/datatypes/structuredatainformation.h" #include "view/structures/datatypes/uniondatainformation.h" #include "view/structures/script/scripthandler.h" #include "view/structures/script/classes/arrayscriptclass.h" #include "view/structures/script/classes/primitivescriptclass.h" #include "view/structures/script/classes/structunionscriptclass.h" #include "view/structures/script/classes/stringscriptclass.h" #include "view/structures/script/classes/enumscriptclass.h" #include "view/structures/script/classes/bitfieldscriptclass.h" #include "view/structures/script/classes/pointerscriptclass.h" #include "view/structures/script/scriptengineinitializer.h" #include "view/structures/script/classes/defaultscriptclass.h" #include "view/structures/script/safereference.h" #include "view/structures/parsers/scriptvalueconverter.h" #include "testutils.h" class ScriptClassesTest : public QObject { Q_OBJECT typedef QPair PropertyPair; private: static void checkProperties(const QVector& expected, DataInformation* data, const char* tag); static PropertyPair pair(const char* name, QScriptValue::PropertyFlags flags = QScriptValue::Undeletable | QScriptValue::ReadOnly) { return PropertyPair(QString::fromUtf8(name), flags); } private Q_SLOTS: void initTestCase(); //check that all properties are available in the iterator void checkIterators(); void testReplaceObject(); //check replacing datatype void cleanupTestCase(); void testSafeReferenceDeleteObject(); void testSafePrimitiveArrayReference(); void testScriptValueContents_data(); void testScriptValueContents(); private: QVector commonProperties; QVector primitiveProperties; QVector primitives; QVector enumProperties; EnumDataInformation* enumData; QScopedPointer enumDataTop; FlagDataInformation* flagData; QScopedPointer flagDataTop; QVector bitfieldProperties; SignedBitfieldDataInformation* signedBitfield; QScopedPointer signedBitfieldTop; UnsignedBitfieldDataInformation* unsignedBitfield; QScopedPointer unsignedBitfieldTop; BoolBitfieldDataInformation* boolBitfield; QScopedPointer boolBitfieldTop; QVector structUnionProperties; //without children StructureDataInformation* structData; QScopedPointer structDataTop; UnionDataInformation* unionData; QScopedPointer unionDataTop; QVector arrayProperties; //without children ArrayDataInformation* arrayData; QScopedPointer arrayDataTop; QVector stringProperties; //without children StringDataInformation* stringData; QScopedPointer stringDataTop; }; void ScriptClassesTest::initTestCase() { //we are only testing properties when updating //TODO fix this commonProperties << pair("name", QScriptValue::Undeletable) << pair("wasAbleToRead") << pair("parent") << pair("valid") << pair("validationError") << pair("byteOrder", QScriptValue::Undeletable) << pair("updateFunc", QScriptValue::Undeletable) << pair("validationFunc", QScriptValue::Undeletable) << pair("datatype", QScriptValue::Undeletable) << pair("typeName", QScriptValue::Undeletable) << pair("toStringFunc", QScriptValue::Undeletable); primitiveProperties << commonProperties << pair("value") << pair("char") << pair("int") << pair("int8") << pair("int16") << pair("int32") << pair("int64") << pair("uint") << pair("uint8") << pair("uint16") << pair("uint32") << pair("uint64") << pair("bool") << pair("float") << pair("double") << pair("int64high32") << pair("int64low32") << pair("uint64high32") << pair("uint64low32") << pair("type"); qSort(primitiveProperties); LoggerWithContext lwc(0, QString()); for (int i = Type_START; i < Type_Bitfield; ++i) { PrimitiveDataInformation* prim = PrimitiveFactory::newInstance( QStringLiteral("prim"), static_cast(i), lwc); prim->setValue(10); primitives << new TopLevelDataInformation(prim); } enumProperties << primitiveProperties << pair("enumValues", QScriptValue::Undeletable); //TODO valueString property (i.e. the current value as enumerator name) //XXX enumName qSort(enumProperties); QMap enumValues; enumValues.insert(1, QStringLiteral("one")); enumValues.insert(2, QStringLiteral("tow")); enumValues.insert(4, QStringLiteral("four")); EnumDefinition::Ptr enumDef(new EnumDefinition(enumValues, QStringLiteral("theEnum"), Type_Int32)); enumData = new EnumDataInformation(QStringLiteral("enumData"), PrimitiveFactory::newInstance(QStringLiteral("dummy"), Type_Int32, lwc), enumDef); enumDataTop.reset( new TopLevelDataInformation(enumData, 0, ScriptEngineInitializer::newEngine())); flagData = new FlagDataInformation(QStringLiteral("flagData"), PrimitiveFactory::newInstance(QStringLiteral("dummy"), Type_Int32, lwc), enumDef); flagDataTop.reset( new TopLevelDataInformation(flagData, 0, ScriptEngineInitializer::newEngine())); bitfieldProperties << primitiveProperties << pair("width", QScriptValue::Undeletable); qSort(bitfieldProperties); unsignedBitfield = new UnsignedBitfieldDataInformation(QStringLiteral("unsignedBit"), 42); unsignedBitfieldTop.reset( new TopLevelDataInformation(unsignedBitfield, 0, ScriptEngineInitializer::newEngine())); signedBitfield = new SignedBitfieldDataInformation(QStringLiteral("signedBit"), 42); signedBitfieldTop.reset( new TopLevelDataInformation(signedBitfield, 0, ScriptEngineInitializer::newEngine())); boolBitfield = new BoolBitfieldDataInformation(QStringLiteral("boolBit"), 42); boolBitfieldTop.reset( new TopLevelDataInformation(boolBitfield, 0, ScriptEngineInitializer::newEngine())); stringProperties << commonProperties << pair("terminatedBy", QScriptValue::Undeletable) << pair("byteCount") << pair("maxCharCount", QScriptValue::Undeletable) << pair("charCount") << pair("encoding", QScriptValue::Undeletable) << pair("maxByteCount", QScriptValue::Undeletable); qSort(stringProperties); stringData = new StringDataInformation(QStringLiteral("string"), StringDataInformation::Latin1); stringDataTop.reset( new TopLevelDataInformation(stringData, 0, ScriptEngineInitializer::newEngine())); arrayProperties << commonProperties << pair("length", QScriptValue::Undeletable) << pair("type", QScriptValue::Undeletable); qSort(arrayProperties); arrayData = new ArrayDataInformation(QStringLiteral("array"), 20, PrimitiveFactory::newInstance(QStringLiteral("inner"), Type_Int32, lwc)); arrayDataTop.reset( new TopLevelDataInformation(arrayData, 0, ScriptEngineInitializer::newEngine())); structUnionProperties << commonProperties << pair("childCount"); //property children is only writable -> it is not in the iterator structData = new StructureDataInformation(QStringLiteral("struct")); structDataTop.reset( new TopLevelDataInformation(structData, 0, ScriptEngineInitializer::newEngine())); unionData = new UnionDataInformation(QStringLiteral("union")); unionDataTop.reset( new TopLevelDataInformation(unionData, 0, ScriptEngineInitializer::newEngine())); qSort(structUnionProperties); } Q_DECLARE_METATYPE(QScriptClass*) static inline void scriptValueContentsAddRow(const char* tag, DataInformation* data, QScriptClass* cls) { QTest::newRow(tag) << data << cls; } void ScriptClassesTest::testScriptValueContents_data() { QTest::addColumn("data"); QTest::addColumn("scriptClass"); scriptValueContentsAddRow("struct", structData, structDataTop->scriptHandler()->handlerInfo()->mStructUnionClass.data()); scriptValueContentsAddRow("union", unionData, unionDataTop->scriptHandler()->handlerInfo()->mStructUnionClass.data()); scriptValueContentsAddRow("array", arrayData, arrayDataTop->scriptHandler()->handlerInfo()->mArrayClass.data()); scriptValueContentsAddRow("string", stringData, stringDataTop->scriptHandler()->handlerInfo()->mStringClass.data()); } void ScriptClassesTest::testScriptValueContents() { QFETCH(DataInformation*, data); QFETCH(QScriptClass*, scriptClass); QScriptValue val = data->toScriptValue(data->topLevelDataInformation()); QVERIFY(val.isValid()); QVERIFY(val.isObject()); QCOMPARE(val.scriptClass(), scriptClass); QVERIFY(val.data().isVariant()); QVariant variant = val.data().toVariant(); QVERIFY(variant.isValid()); QVERIFY(variant.canConvert()); QCOMPARE(variant.value().data(), data); QCOMPARE(DefaultScriptClass::toDataInformation(val), data); } void ScriptClassesTest::checkProperties(const QVector& expected, DataInformation* data, const char* tag) { //check in updating mode //TODO check also in other modes data->topLevelDataInformation()->scriptHandler()->handlerInfo()->setMode(ScriptHandlerInfo::Updating); QScriptValue value = data->toScriptValue(data->topLevelDataInformation()->scriptEngine(), data->topLevelDataInformation()->scriptHandler()->handlerInfo()); QScriptValueIterator it(value); QList foundProperties; while (it.hasNext()) { it.next(); foundProperties.append(qMakePair(it.name(), it.flags())); } data->topLevelDataInformation()->scriptHandler()->handlerInfo()->setMode(ScriptHandlerInfo::None); qSort(foundProperties); if (foundProperties.size() != expected.size()) { for (int i = 0; i < qMin(foundProperties.size(), expected.size()); ++i) { if (foundProperties.at(i) != expected.at(i)) qWarning() << tag << ":" << foundProperties.at(i) << ", but expected:" << expected.at(i); QCOMPARE(foundProperties.at(i).first, expected.at(i).first); QCOMPARE(foundProperties.at(i).second, expected.at(i).second); } } for (int i = 0; i < foundProperties.size(); ++i) { if (foundProperties.at(i) != expected.at(i)) qWarning() << tag << ":" << foundProperties.at(i) << "!=" << expected.at(i); QCOMPARE(foundProperties.at(i).first, expected.at(i).first); QCOMPARE(foundProperties.at(i).second, expected.at(i).second); } QCOMPARE(foundProperties.size(), expected.size()); } void ScriptClassesTest::checkIterators() { for (int i = 0; i < primitives.size(); ++i) { TopLevelDataInformation* top = primitives.at(i); checkProperties(primitiveProperties, top->actualDataInformation(), "primitives"); } checkProperties(enumProperties, enumData, "enum"); checkProperties(enumProperties, flagData, "flag"); checkProperties(bitfieldProperties, boolBitfield, "bool bitfield"); checkProperties(bitfieldProperties, signedBitfield, "signed bitfield"); checkProperties(bitfieldProperties, unsignedBitfield, "unsignedBitfield"); checkProperties(stringProperties, stringData, "string"); checkProperties(arrayProperties, arrayData, "array"); checkProperties(structUnionProperties, structData, "struct"); checkProperties(structUnionProperties, unionData, "union"); } void ScriptClassesTest::testReplaceObject() { QScriptEngine* eng = ScriptEngineInitializer::newEngine(); ScriptLogger* logger = new ScriptLogger(); logger->setLogToStdOut(true); QString unionDef = QStringLiteral( "union({\n" QT_UNICODE_LITERAL(" innerStruct : struct({ first : uint8(), second : uint16() }),\n") QT_UNICODE_LITERAL(" innerArray : array(uint8(), 5),\n") QT_UNICODE_LITERAL(" innerPointer : pointer(uint8(), double())\n") QT_UNICODE_LITERAL("});\n")); QScriptValue val = eng->evaluate(unionDef); QVERIFY(val.isObject()); DataInformation* main = ScriptValueConverter::convert(val, QStringLiteral("container"), logger, 0); QVERIFY(main); QCOMPARE(logger->rowCount(), 0); TopLevelDataInformation top(main, logger, eng); //first we read the struct, which changes the type of the first child //access it again after changing to ensure it was set properly QScriptValue structUpdate = eng->evaluate(QStringLiteral( "(function() { this.first.datatype = int32(); this.first.name = \"changed\"; })")); QVERIFY(structUpdate.isFunction()); StructureDataInformation* structData = main->childAt(0)->asStruct(); QVERIFY(structData); structData->setUpdateFunc(structUpdate); QCOMPARE(structData->name(), QString(QStringLiteral("innerStruct"))); // array changes its own type, this is the critical one //access it again after changing to ensure it was set properly QScriptValue arrayUpdate = eng->evaluate(QStringLiteral( "(function() { this.datatype = float(); this.name = \"changedToFloat\"; })")); ArrayDataInformation* arrayData = main->childAt(1)->asArray(); arrayData->setUpdateFunc(arrayUpdate); QVERIFY(arrayData); QScriptValue pointerTargetUpdate = eng->evaluate(QStringLiteral( "(function() { this.datatype = array(int8(), 5); this.parent.name = \"changedToArrayPointer\"; })")); PointerDataInformation* ptrData = main->childAt(2)->asPointer(); QVERIFY(ptrData); ptrData->pointerTarget()->setUpdateFunc(pointerTargetUpdate); QScriptValue unionUpdate = eng->evaluate(QStringLiteral( "(function() { this.datatype = ") + unionDef + QStringLiteral(" this.name = \"newContainer\"; })")); main->setUpdateFunc(unionUpdate); //now just call update QCOMPARE(structData->childCount(), 2u); QCOMPARE((int)structData->childAt(0)->asPrimitive()->type().value, (int)Type_UInt8); QCOMPARE(structData->childAt(0)->name(), QString(QStringLiteral("first"))); QCOMPARE(structData->childAt(1)->name(), QString(QStringLiteral("second"))); top.scriptHandler()->updateDataInformation(structData); //now structdata should have different children QCOMPARE(structData->childCount(), 2u); QCOMPARE((int)structData->childAt(0)->asPrimitive()->type().value, (int)Type_Int32); //different now QCOMPARE(structData->childAt(0)->name(), QString(QStringLiteral("changed"))); //different now QCOMPARE(structData->childAt(1)->name(), QString(QStringLiteral("second"))); //still the same QCOMPARE(arrayData->name(), QString(QStringLiteral("innerArray"))); top.scriptHandler()->updateDataInformation(arrayData); QVERIFY(main->childAt(1)->hasBeenUpdated()); QVERIFY(main->childAt(1)->isPrimitive()); QCOMPARE(main->childAt(1)->name(), QString(QStringLiteral("changedToFloat"))); QCOMPARE(ptrData->name(), QString(QStringLiteral("innerPointer"))); QVERIFY(main->childAt(2)->isPointer()); QVERIFY(main->childAt(2)->asPointer()->pointerTarget()->isPrimitive()); top.scriptHandler()->updateDataInformation(ptrData->pointerTarget()); QVERIFY(main->childAt(2)->isPointer()); QVERIFY(main->childAt(2)->asPointer()->pointerTarget()->isArray()); QCOMPARE(main->childAt(2)->name(), QString(QStringLiteral("changedToArrayPointer"))); //now reset to state before QCOMPARE(main->name(), QString(QStringLiteral("container"))); top.scriptHandler()->updateDataInformation(main); //main is now a dangling pointer main = top.actualDataInformation(); QString nnnname = QString(QStringLiteral("newContainer")); QCOMPARE(main->name(), nnnname); QVERIFY(main->childAt(0)->isStruct()); QCOMPARE(main->childAt(0)->name(), QString(QStringLiteral("innerStruct"))); QCOMPARE(main->childAt(1)->name(), QString(QStringLiteral("innerArray"))); QCOMPARE(main->childAt(2)->name(), QString(QStringLiteral("innerPointer"))); } -static const QString invalidObjectError = QStringLiteral("ReferenceError: Attempting to access an invalid object"); +namespace { +QString invalidObjectError() { return QStringLiteral("ReferenceError: Attempting to access an invalid object"); } +} void ScriptClassesTest::testSafePrimitiveArrayReference() { QVERIFY(arrayData->arrayType()->isPrimitive()); QVERIFY(arrayData->length() > 2); arrayDataTop->logger()->setLogToStdOut(true); QScriptEngine* eng = arrayDataTop->scriptEngine(); eng->pushContext(); eng->currentContext()->activationObject().setProperty(QStringLiteral("myArray"), arrayData->toScriptValue(arrayDataTop.data())); arrayDataTop->scriptHandler()->handlerInfo()->setMode(ScriptHandlerInfo::Updating); QScriptValue v0 = eng->evaluate(QStringLiteral("myArray[0]")); QCOMPARE(Utils::property(v0, "name").toString(), QString::number(0)); QVERIFY(DefaultScriptClass::toDataInformation(v0) != 0); //access index 1 -> index 0 should become invalid, since there is only one object available QScriptValue v1 = eng->evaluate(QStringLiteral("myArray[1]")); QVERIFY(DefaultScriptClass::toDataInformation(v1) != 0); QVERIFY(DefaultScriptClass::toDataInformation(v0) == 0); QVERIFY(!eng->hasUncaughtException()); QCOMPARE(Utils::property(v1, "name").toString(), QString::number(1)); QVERIFY(!eng->hasUncaughtException()); - QCOMPARE(Utils::property(v0, "name").toString(), invalidObjectError); + QCOMPARE(Utils::property(v0, "name").toString(), invalidObjectError()); QVERIFY(!eng->hasUncaughtException()); //even after accessing a v0 property (which will fail), v1 properties should remain valid QCOMPARE(Utils::property(v1, "name").toString(), QString::number(1)); QVERIFY(!eng->hasUncaughtException()); arrayDataTop->scriptHandler()->handlerInfo()->setMode(ScriptHandlerInfo::None); eng->popContext(); } void ScriptClassesTest::testSafeReferenceDeleteObject() { QScopedPointer top(Utils::evalAndParse("struct({bar: uint8()}).set({name: 'foo'});")); QVERIFY(top->actualDataInformation()->isStruct()); top->scriptHandler()->handlerInfo()->setMode(ScriptHandlerInfo::TaggedUnionSelection); QScriptValue val = top->actualDataInformation()->toScriptValue(top.data()); QScriptValue name = Utils::property(val, "name"); QVERIFY(name.isValid()); QVERIFY(!name.isError()); QCOMPARE(name.toString(), QString(QStringLiteral("foo"))); top->setActualDataInformation(new DummyDataInformation(0)); //val should now point to an invalid reference -> accessing name should throw an error name = Utils::property(val, "name"); QVERIFY(name.isValid()); QVERIFY(name.isError()); - QCOMPARE(name.toString(), invalidObjectError); + QCOMPARE(name.toString(), invalidObjectError()); } void ScriptClassesTest::cleanupTestCase() { qDeleteAll(primitives); } QTEST_GUILESS_MAIN(ScriptClassesTest) #include "scriptclassestest.moc" diff --git a/kasten/controllers/test/scriptvalueconvertertest.cpp b/kasten/controllers/test/scriptvalueconvertertest.cpp index 71db2420..a17350fc 100644 --- a/kasten/controllers/test/scriptvalueconvertertest.cpp +++ b/kasten/controllers/test/scriptvalueconvertertest.cpp @@ -1,314 +1,314 @@ /* * This file is part of the Okteta Kasten module, made within the KDE community. * * Copyright 2011, 2012 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "view/structures/script/scriptengineinitializer.h" #include "view/structures/allprimitivetypes.h" #include #include #include #include #include "view/structures/parsers/scriptvalueconverter.h" #include "view/structures/datatypes/datainformation.h" #include "view/structures/datatypes/primitive/primitivedatainformation.h" #include "view/structures/datatypes/primitive/enumdatainformation.h" #include "view/structures/script/scriptlogger.h" #include "view/structures/parsers/parserutils.h" class ScriptValueConverterTest : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void testPrimitives(); void testPrimitives_data(); void testParseEnum(); void basicConverterTest(); void testParseEnum_data(); private: DataInformation* convert(const QString& code); DataInformation* convert(const QScriptValue& value); QScriptValue evaluate(const char* code); void dumpLoggerOutput(); QScopedPointer engine; QScopedPointer logger; }; DataInformation* ScriptValueConverterTest::convert(const QString& code) { QScriptValue value = engine->evaluate(code); return ScriptValueConverter::convert(value, QStringLiteral("value"), logger.data()); } DataInformation* ScriptValueConverterTest::convert(const QScriptValue& value) { return ScriptValueConverter::convert(value, QStringLiteral("value"), logger.data()); } QScriptValue ScriptValueConverterTest::evaluate(const char* code) { return engine->evaluate(QString::fromUtf8(code)); } void ScriptValueConverterTest::initTestCase() { engine.reset(ScriptEngineInitializer::newEngine()); logger.reset(new ScriptLogger()); } void ScriptValueConverterTest::basicConverterTest() { logger->clear(); //check that passing functions works QScriptValue sVal = evaluate("var foo = { value : uint8(),\n" " str : struct({first : uint8(), second : uint16()}),\n" " obj : array(uint32(), 10) \n}\n foo"); QVector converted = ScriptValueConverter::convertValues(sVal, logger.data()); QCOMPARE(converted.size(), 3); QVERIFY(converted[0]->isPrimitive()); QCOMPARE(converted[0]->name(), QStringLiteral("value")); QVERIFY(converted[1]->isStruct()); QCOMPARE(converted[1]->name(), QStringLiteral("str")); QCOMPARE(converted[1]->childCount(), 2u); QVERIFY(converted[2]->isArray()); QCOMPARE(converted[2]->name(), QStringLiteral("obj")); QCOMPARE(converted[2]->childCount(), 10u); //test with an array now sVal = evaluate("var foo = [uint8(), uint16(), uint32()]; foo"); qDeleteAll(converted); converted = ScriptValueConverter::convertValues(sVal, logger.data()); QCOMPARE(converted.size(), 3); QVERIFY(converted[0]->isPrimitive()); QVERIFY(converted[1]->isPrimitive()); QVERIFY(converted[2]->isPrimitive()); QVERIFY(converted[0]->asPrimitive()->type() == Type_UInt8); QVERIFY(converted[1]->asPrimitive()->type() == Type_UInt16); QVERIFY(converted[2]->asPrimitive()->type() == Type_UInt32); QCOMPARE(converted[0]->name(), QStringLiteral("0")); QCOMPARE(converted[1]->name(), QStringLiteral("1")); QCOMPARE(converted[2]->name(), QStringLiteral("2")); //check number is not a valid object sVal = evaluate("1 + 2"); QVERIFY(sVal.isNumber()); QVERIFY2(!convert(sVal), " numbers should not be valid!"); QCOMPARE(logger->rowCount(QModelIndex()), 1); //should be exactly 1 error message sVal = evaluate("function foo() { return uint8(); }; foo"); QVERIFY(sVal.isFunction()); QVERIFY2(!convert(sVal), "functions should not be valid!"); QCOMPARE(logger->rowCount(QModelIndex()), 2); //should be exactly 2 error messages sVal = evaluate("var x = /.*/; x"); QVERIFY(sVal.isRegExp()); QVERIFY2(!convert(sVal), " regexp should not be valid!"); QCOMPARE(logger->rowCount(QModelIndex()), 3); sVal = evaluate("var obj = { x : 1 }; obj.x();"); QVERIFY(sVal.isError()); QVERIFY2(!convert(sVal), " error objects should not be valid!"); QCOMPARE(logger->rowCount(QModelIndex()), 4); sVal = evaluate("var x = [1, 2, 3]; x"); QVERIFY(sVal.isArray()); QVERIFY2(!convert(sVal), " array objects should not be valid!"); QCOMPARE(logger->rowCount(QModelIndex()), 5); sVal = evaluate("var x = new Date(); x"); QVERIFY(sVal.isDate()); QVERIFY2(!convert(sVal), " date objects should not be valid!"); QCOMPARE(logger->rowCount(QModelIndex()), 6); sVal = evaluate("var x = true; x"); QVERIFY(sVal.isBool()); QVERIFY2(!convert(sVal), " bool objects should not be valid!"); QCOMPARE(logger->rowCount(QModelIndex()), 7); sVal = evaluate("var x = null; x"); QVERIFY(sVal.isNull()); QVERIFY2(!convert(sVal), " null should not be valid!"); QCOMPARE(logger->rowCount(QModelIndex()), 8); sVal = evaluate("var x = undefined; x"); QVERIFY(sVal.isUndefined()); QVERIFY2(!convert(sVal), " undefined should not be valid!"); QCOMPARE(logger->rowCount(QModelIndex()), 9); //object with invalid entry sVal = evaluate("var foo = { value : function() { return 1; },\n" " str : struct({first : uint8(), second : uint16()}),\n" " obj : array(uint32(), 10) \n}\n foo"); qDeleteAll(converted); converted = ScriptValueConverter::convertValues(sVal, logger.data()); QCOMPARE(converted.size(), 2); //first entry is invalid QCOMPARE(logger->rowCount(QModelIndex()), 11); //this should cause 2 error messages -> 11 now //qDebug() << logger->messages(); qDeleteAll(converted); } void ScriptValueConverterTest::testPrimitives_data() { QTest::addColumn("code"); QTest::addColumn("code2"); QTest::addColumn("typeString"); QTest::addColumn("expectedType"); QTest::newRow("uint8") << "uint8()" << "new uint8()" << "UInt8" << (int) Type_UInt8; QTest::newRow("uint16") << "uint16()" << "new uint16()" << "UInt16" << (int) Type_UInt16; QTest::newRow("uint32") << "uint32()" << "new uint32()" << "UInt32" << (int) Type_UInt32; QTest::newRow("uint64") << "uint64()" << "new uint64()" << "UInt64" << (int) Type_UInt64; QTest::newRow("int8") << "int8()" << "new int8()" << "Int8" << (int) Type_Int8; QTest::newRow("int16") << "int16()" << "new int16()" << "Int16" << (int) Type_Int16; QTest::newRow("int32") << "int32()" << "new int32()" << "Int32" << (int) Type_Int32; QTest::newRow("int64") << "int64()" << "new int64()" << "Int64" << (int) Type_Int64; QTest::newRow("bool8") << "bool8()" << "new bool8()" << "Bool8" << (int) Type_Bool8; QTest::newRow("bool16") << "bool16()" << "new bool16()" << "Bool16" << (int) Type_Bool16; QTest::newRow("bool32") << "bool32()" << "new bool32()" << "Bool32" << (int) Type_Bool32; QTest::newRow("bool64") << "bool64()" << "new bool64()" << "Bool64" << (int) Type_Bool64; QTest::newRow("char") << "char()" << "new char()" << "Char" << (int) Type_Char; QTest::newRow("float") << "float()" << "new float()" << "Float" << (int) Type_Float; QTest::newRow("double") << "double()" << "new double()" << "Double" << (int) Type_Double; } void ScriptValueConverterTest::testPrimitives() { QFETCH(QString, code); QFETCH(QString, code2); QFETCH(QString, typeString); QFETCH(int, expectedType); logger->clear(); PrimitiveDataType type = static_cast(expectedType); QScriptValue val1 = engine->evaluate(code); QScriptValue val2 = engine->evaluate(code2); - QCOMPARE(val1.property(ParserStrings::PROPERTY_TYPE).toString(), typeString); - QCOMPARE(val2.property(ParserStrings::PROPERTY_TYPE).toString(), typeString); - QCOMPARE(val1.property(ParserStrings::PROPERTY_INTERNAL_TYPE).toString(), ParserStrings::TYPE_PRIMITIVE); - QCOMPARE(val2.property(ParserStrings::PROPERTY_INTERNAL_TYPE).toString(), ParserStrings::TYPE_PRIMITIVE); + QCOMPARE(val1.property(ParserStrings::PROPERTY_TYPE()).toString(), typeString); + QCOMPARE(val2.property(ParserStrings::PROPERTY_TYPE()).toString(), typeString); + QCOMPARE(val1.property(ParserStrings::PROPERTY_INTERNAL_TYPE()).toString(), ParserStrings::TYPE_PRIMITIVE()); + QCOMPARE(val2.property(ParserStrings::PROPERTY_INTERNAL_TYPE()).toString(), ParserStrings::TYPE_PRIMITIVE()); if (type == Type_Invalid) return; //the cast will fail QScopedPointer data1(ScriptValueConverter::convert(val1, QStringLiteral("val1"), logger.data())); QScopedPointer data2(ScriptValueConverter::convert(val2, QStringLiteral("val2"), logger.data())); QVERIFY(data1); QVERIFY(data2); PrimitiveDataInformation* p1 = data1->asPrimitive(); PrimitiveDataInformation* p2 = data2->asPrimitive(); QVERIFY(p1); QVERIFY(p2); QCOMPARE(p1->type(), type); QCOMPARE(p2->type(), type); if (type == Type_Bitfield) return; //the following tests don't work with bitfields QScopedPointer data3(convert(QString(QStringLiteral("\"%1\"")).arg(typeString))); QVERIFY(data3); PrimitiveDataInformation* p3 = data3->asPrimitive(); QVERIFY(p3); QCOMPARE(p3->type(), type); } void ScriptValueConverterTest::testParseEnum() { //QFETCH(QString, name); QFETCH(QString, code); QFETCH(int, expectedCount); QScriptValue val = engine->evaluate(code); QVERIFY(val.isValid()); QVERIFY(!val.isNull()); QVERIFY(!val.isUndefined()); QVERIFY(val.isObject()); - QCOMPARE(val.property(ParserStrings::PROPERTY_INTERNAL_TYPE).toString(), QString(QStringLiteral("enum"))); + QCOMPARE(val.property(ParserStrings::PROPERTY_INTERNAL_TYPE()).toString(), QString(QStringLiteral("enum"))); QScopedPointer data (ScriptValueConverter::convert(val, QStringLiteral("val"), logger.data())); if (expectedCount > 0) QVERIFY(data); else { QVERIFY(!data); return; } EnumDataInformation* e = data->asEnum(); QVERIFY(e); QMap enumVals = e->enumValues()->values(); QCOMPARE(enumVals.size(), expectedCount); if (expectedCount != 0) { QFETCH(quint64, expectedValue); //to ensure it does not match when value is not found add 1 to the default AllPrimitiveTypes result = enumVals.key(QStringLiteral("value"), expectedValue + 1); QCOMPARE(result.value(), expectedValue); } } namespace { inline QString arg2(const QString& str, const char* arg_1, const char* arg_2) { return str.arg(QString::fromUtf8(arg_1), QString::fromUtf8(arg_2)); } } void ScriptValueConverterTest::testParseEnum_data() { QString baseStr = QStringLiteral("enumeration(\"someValues\", %1, { value : %2})"); QTest::addColumn("code"); QTest::addColumn("expectedCount"); QTest::addColumn("expectedValue"); QTest::newRow("invalid_type_struct") << arg2(baseStr, "struct({ val : uint8() })", "1234.234") << 0 << quint64(0); QTest::newRow("invalid_type_array") << arg2(baseStr, "array(uint8(), 1)", "1234.234") << 0 << quint64(0); QTest::newRow("invalid_type_union") << arg2(baseStr, "union({ val : uint8() })", "1234.234") << 0 << quint64(0); QTest::newRow("invalid_type_double") << arg2(baseStr, "double()", "1234.234") << 0 << quint64(0); QTest::newRow("invalid_type_float") << arg2(baseStr, "float()", "1234.234") << 0 << quint64(0); QTest::newRow("invalid_type_string") << arg2(baseStr, "string()", "1234.234") << 0 << quint64(0); QTest::newRow("float2int8") << arg2(baseStr, "uint8()", "1.234") << 1 << quint64(1); QTest::newRow("float2int8_range") << arg2(baseStr, "uint8()", "1234.234") << 0 << quint64(0); QTest::newRow("float2int32") << arg2(baseStr, "uint32()", "1234.1234") << 1 << quint64(1234); QTest::newRow("float2int32_range") << arg2(baseStr, "uint32()", "5294967296.234") << 0 << quint64(0); QTest::newRow("float2int64") << arg2(baseStr, "uint64()", "5294967296.234") << 1 << quint64(5294967296UL); QTest::newRow("double_overflow") << arg2(baseStr, "uint64()", "9007199254740993.0") << 0 << quint64(9007199254740993UL); //only 992 and 994 can be represented as a double QTest::newRow("uint64_max_hex") << arg2(baseStr, "uint64()", "new String(\"0xFFFFFFFFFFFFFFFF\")") << 1 << quint64(0xFFFFFFFFFFFFFFFFL); QTest::newRow("uint64_max") << arg2(baseStr, "uint64()", "new String(\"18446744073709551615\")") << 1 << quint64(18446744073709551615UL); } QTEST_GUILESS_MAIN(ScriptValueConverterTest) #include "scriptvalueconvertertest.moc" diff --git a/kasten/controllers/view/structures/datatypes/primitive/primitivedatainformation.cpp b/kasten/controllers/view/structures/datatypes/primitive/primitivedatainformation.cpp index 422965b6..edbed3f8 100644 --- a/kasten/controllers/view/structures/datatypes/primitive/primitivedatainformation.cpp +++ b/kasten/controllers/view/structures/datatypes/primitive/primitivedatainformation.cpp @@ -1,72 +1,68 @@ /* * This file is part of the Okteta Kasten Framework, made within the KDE community. * * Copyright 2009, 2010, 2011, 2012 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "primitivedatainformation.h" #include "../datainformation.h" #include "../topleveldatainformation.h" #include "structviewpreferences.h" -const QString PrimitiveDataInformation::hexPrefix = QStringLiteral("0x"); -const QString PrimitiveDataInformation::octalPrefix = QStringLiteral("0o"); -const QString PrimitiveDataInformation::binaryPrefix = QStringLiteral("0b"); - Qt::ItemFlags PrimitiveDataInformation::flags(int column, bool fileLoaded) const { if (column == (int) DataInformation::ColumnValue && fileLoaded) return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable; else return Qt::ItemIsSelectable | Qt::ItemIsEnabled; } // The inline destructor makes the compiler unhappy PrimitiveDataInformation::~PrimitiveDataInformation() { } PrimitiveDataInformationWrapper::PrimitiveDataInformationWrapper(const PrimitiveDataInformationWrapper& d) : PrimitiveDataInformation(d), mValue(d.mValue->clone()) { mValue->setParent(this); } PrimitiveDataInformationWrapper::PrimitiveDataInformationWrapper(const QString& name, PrimitiveDataInformation* valueType, DataInformation* parent) : PrimitiveDataInformation(name, parent), mValue(valueType) { Q_CHECK_PTR(valueType); mValue->setParent(this); } QScriptValue PrimitiveDataInformationWrapper::valueAsQScriptValue() const { return mValue->valueAsQScriptValue(); } qint64 PrimitiveDataInformationWrapper::readData(Okteta::AbstractByteArrayModel* input, Okteta::Address address, BitCount64 bitsRemaining, quint8* bitOffset) { Q_ASSERT(mHasBeenUpdated); //update must have been called prior to reading mValue->mHasBeenUpdated = true; //value does not get updated qint64 retVal = mValue->readData(input, address, bitsRemaining, bitOffset); mWasAbleToRead = mValue->wasAbleToRead(); return retVal; } diff --git a/kasten/controllers/view/structures/datatypes/primitive/primitivedatainformation.h b/kasten/controllers/view/structures/datatypes/primitive/primitivedatainformation.h index 5e0bf33c..08573687 100644 --- a/kasten/controllers/view/structures/datatypes/primitive/primitivedatainformation.h +++ b/kasten/controllers/view/structures/datatypes/primitive/primitivedatainformation.h @@ -1,157 +1,155 @@ /* * This file is part of the Okteta Kasten Framework, made within the KDE community. * * Copyright 2009, 2010, 2011 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #ifndef PRIMITIVEDATAINFORMATION_H_ #define PRIMITIVEDATAINFORMATION_H_ #include "../datainformation.h" #include "../primitivedatatype.h" #include "../../allprimitivetypes.h" union AllPrimitiveTypes; /** * A base class for all primitive data elements (e.g. unsigned integers or floating-point numbers) */ class PrimitiveDataInformation : public DataInformation { friend class PrimitiveDataInformationTest; //that unit test needs to change mWasAbleToRead public: explicit PrimitiveDataInformation(const QString& name, DataInformation* parent = 0); virtual ~PrimitiveDataInformation(); virtual PrimitiveDataInformation* clone() const = 0; virtual Qt::ItemFlags flags(int column, bool fileLoaded = true) const; virtual bool isPrimitive() const; virtual AllPrimitiveTypes value() const = 0; virtual void setValue(AllPrimitiveTypes newValue) = 0; virtual QScriptValue valueAsQScriptValue() const = 0; virtual PrimitiveDataType type() const = 0; virtual unsigned int childCount() const { return 0; } virtual DataInformation* childAt(unsigned int) const { Q_ASSERT(false); return 0; } virtual bool canHaveChildren() const { return false; } virtual BitCount64 childPosition(const DataInformation*, Okteta::Address) const { Q_ASSERT(false); return 0; } virtual int indexOf(const DataInformation* const) const {Q_ASSERT(false); return -1; } /** @return the matching prefix for the base (nothing, '0x', '0b' or '0o') */ static QString basePrefix(int base); - static const QString binaryPrefix; - static const QString octalPrefix; - static const QString hexPrefix; + protected: virtual BitCount32 offset(unsigned int index) const; PrimitiveDataInformation(const PrimitiveDataInformation& d); }; /** * A base class for data types which just wrap an underlying primitive data type. * The basic operations (reading/writing/size/value) are simply delegated to the wrapped element. * * This is used for pointers (wrapping differently sized integers) and enumerations/bitflags * Due to the use of a PrimitiveDataInformation pointer as a member any primitive type can be wrapped. * For example pointers using a bitfield value are possible and theoretically floating point enums * (although these were not added due to float comparison issues - use the binary representation of an * equally sized integer instead). */ class PrimitiveDataInformationWrapper : public PrimitiveDataInformation { protected: PrimitiveDataInformationWrapper(const PrimitiveDataInformationWrapper& d); public: /** takes ownership of @p valueType */ PrimitiveDataInformationWrapper(const QString& name, PrimitiveDataInformation* valueType, DataInformation* parent = 0); virtual ~PrimitiveDataInformationWrapper() {} //delegate all these to the underlying object: virtual bool setData(const QVariant& value, Okteta::AbstractByteArrayModel* out, Okteta::Address address, BitCount64 bitsRemaining, quint8 bitOffset) { return mValue->setData(value, out, address, bitsRemaining, bitOffset); } virtual BitCount32 size() const { return mValue->size(); } virtual void setWidgetData(QWidget* w) const {mValue->setWidgetData(w); } virtual QVariant dataFromWidget(const QWidget* w) const { return mValue->dataFromWidget(w); } virtual QWidget* createEditWidget(QWidget* parent) const { return mValue->createEditWidget(parent); } virtual AllPrimitiveTypes value() const { return mValue->value(); } virtual void setValue(AllPrimitiveTypes newValue) { mValue->setValue(newValue); } //classes derived from this are not true primitive types (they provide additional information) virtual PrimitiveDataType type() const { return Type_Invalid; } virtual QScriptValue valueAsQScriptValue() const; //we have to do slightly more than just forward with this method virtual qint64 readData(Okteta::AbstractByteArrayModel* input, Okteta::Address address, BitCount64 bitsRemaining, quint8* bitOffset); protected: QScopedPointer mValue; }; inline BitCount32 PrimitiveDataInformation::offset(unsigned int index) const { Q_UNUSED(index) Q_ASSERT_X(false, "PrimitiveDataInformation::offset", "This should never be called"); return 0; } inline bool PrimitiveDataInformation::isPrimitive() const { return true; } inline PrimitiveDataInformation::PrimitiveDataInformation(const QString& name, DataInformation* parent) : DataInformation(name, parent) { } inline PrimitiveDataInformation::PrimitiveDataInformation(const PrimitiveDataInformation& d) : DataInformation(d) { } inline QString PrimitiveDataInformation::basePrefix(int base) { switch (base) { case 10: return QString(); - case 2: return binaryPrefix; - case 8: return octalPrefix; - case 16: return hexPrefix; + case 2: return QStringLiteral("0b"); + case 8: return QStringLiteral("0o"); + case 16: return QStringLiteral("0x"); default: Q_ASSERT_X(false, "PrimitiveDataInformation::basePrefix()", "Invalid argument!"); return QString(); } } #endif /* PRIMITIVEDATAINFORMATION_H_ */ diff --git a/kasten/controllers/view/structures/parsers/osdparser.cpp b/kasten/controllers/view/structures/parsers/osdparser.cpp index 221b85ab..a1863ff3 100644 --- a/kasten/controllers/view/structures/parsers/osdparser.cpp +++ b/kasten/controllers/view/structures/parsers/osdparser.cpp @@ -1,617 +1,619 @@ /* * This file is part of the Okteta Kasten Framework, made within the KDE community. * * Copyright 2010, 2011, 2012 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "osdparser.h" #include "datainformationfactory.h" #include "../datatypes/array/arraydatainformation.h" #include "../datatypes/uniondatainformation.h" #include "../datatypes/structuredatainformation.h" #include "../datatypes/strings/stringdatainformation.h" #include "../datatypes/strings/stringdata.h" #include "../datatypes/primitivefactory.h" #include "../datatypes/topleveldatainformation.h" #include "../datatypes/dummydatainformation.h" #include "../structuredefinitionfile.h" #include "../script/scriptlogger.h" #include "../script/scriptengineinitializer.h" #include "../structlogging.h" #include #include #include #include using namespace ParserStrings; OsdParser::OsdParser(const QString& pluginName, const QString& absolutePath) : AbstractStructureParser(pluginName, absolutePath) { } OsdParser::OsdParser(const QString& xml) : AbstractStructureParser(QString(), QString()), mXmlString(xml) { } OsdParser::~OsdParser() { } QDomDocument OsdParser::openDoc(ScriptLogger* logger) const { return mXmlString.isEmpty() ? openDocFromFile(logger) : openDocFromString(logger); } QDomDocument OsdParser::openDocFromString(ScriptLogger * logger) const { Q_CHECK_PTR(logger); Q_ASSERT(!mXmlString.isEmpty()); int errorLine, errorColumn; QString errorMsg; QDomDocument doc; if (!doc.setContent(mXmlString, false, &errorMsg, &errorLine, &errorColumn)) { const QString errorOutput = QString( QStringLiteral("error reading XML: %1\n error line=%2\nerror column=%3")) .arg(errorMsg, QString::number(errorLine), QString::number(errorColumn)); logger->error() << errorOutput; logger->info() << "XML was:" << mXmlString; return QDomDocument(); } return doc; } QDomDocument OsdParser::openDocFromFile(ScriptLogger* logger) const { Q_CHECK_PTR(logger); QFileInfo fileInfo(mAbsolutePath); if (!fileInfo.exists()) { logger->error() << "File" << mAbsolutePath << "does not exist!"; return QDomDocument(); } QFile file(fileInfo.absoluteFilePath()); if (!file.open(QIODevice::ReadOnly)) { const QString errorOutput = QStringLiteral("Could not open file ") + mAbsolutePath; logger->error() << errorOutput; return QDomDocument(); } int errorLine, errorColumn; QString errorMsg; QDomDocument doc; if (!doc.setContent(&file, false, &errorMsg, &errorLine, &errorColumn)) { const QString errorOutput = QString( QStringLiteral("error reading XML: %1\n error line=%2\nerror column=%3")) .arg(errorMsg, QString::number(errorLine), QString::number(errorColumn)); logger->error() << errorOutput; logger->info() << "File was:" << mAbsolutePath; } file.close(); return doc; } QStringList OsdParser::parseStructureNames() const { QStringList ret; QScopedPointer rootLogger(new ScriptLogger); //only needed if we get an error right now rootLogger->setLogToStdOut(true); //we cannot get our messages into the script console, so do this instead QDomDocument document = openDoc(rootLogger.data()); if (document.isNull()) return QStringList(); QDomElement rootElem = document.firstChildElement(QStringLiteral("data")); if (rootElem.isNull()) return QStringList(); for (QDomElement childElement = rootElem.firstChildElement(); !childElement.isNull(); childElement = childElement.nextSiblingElement()) { QString tag = childElement.tagName(); - if (tag == TYPE_STRUCT || tag == TYPE_ARRAY || tag == TYPE_BITFIELD || tag == TYPE_PRIMITIVE - || tag == TYPE_UNION || tag == TYPE_ENUM || tag == TYPE_FLAGS || tag == TYPE_STRING) + if (tag == TYPE_STRUCT() || tag == TYPE_ARRAY() || tag == TYPE_BITFIELD() || tag == TYPE_PRIMITIVE() + || tag == TYPE_UNION() || tag == TYPE_ENUM() || tag == TYPE_FLAGS() || tag == TYPE_STRING()) { //TODO allow e.g. - ret.append(readProperty(childElement, PROPERTY_NAME, i18n(""))); + ret.append(readProperty(childElement, PROPERTY_NAME(), i18n(""))); } else { rootLogger->error(QString()).nospace() << "Unknown tag name in plugin " << mPluginName << " :" << tag; } } return ret; } QVector OsdParser::parseStructures() const { QFileInfo fileInfo(mAbsolutePath); QVector structures; QScopedPointer rootLogger(new ScriptLogger()); //only needed in we get an error right now QDomDocument document = openDoc(rootLogger.data()); if (document.isNull()) { structures.append(new TopLevelDataInformation( new DummyDataInformation(0, fileInfo.fileName()), rootLogger.take(), 0, fileInfo)); return structures; } QDomElement rootElem = document.firstChildElement(QStringLiteral("data")); if (rootElem.isNull()) { rootLogger->error() << "Missing top level element!"; structures.append(new TopLevelDataInformation( new DummyDataInformation(0, fileInfo.fileName()), rootLogger.take(), 0, fileInfo)); return structures; } int count = 1; for (QDomElement elem = rootElem.firstChildElement(); !elem.isNull(); elem = elem.nextSiblingElement()) { - if (elem.tagName() == TYPE_ENUMDEF) + if (elem.tagName() == TYPE_ENUMDEF()) continue; //skip enum defs QScriptEngine* eng = ScriptEngineInitializer::newEngine(); //we need this for dynamic arrays ScriptLogger* logger = new ScriptLogger(); QVector enums = parseEnums(rootElem, logger); OsdParserInfo info(QString(), logger, 0, eng, enums); DataInformation* data = parseElement(elem, info); if (!data) { - QString name = readProperty(elem, PROPERTY_NAME); + QString name = readProperty(elem, PROPERTY_NAME()); if (name.isEmpty()) name = fileInfo.absoluteFilePath() + QStringLiteral("_element") + QString::number(count); qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "Failed to parse element" << elem.tagName() << name; qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "Parsing messages were:" << logger->messages(); data = new DummyDataInformation(0, name); } TopLevelDataInformation* topData = new TopLevelDataInformation(data, logger, eng, fileInfo); - QString lockOffsetStr = readProperty(elem, PROPERTY_DEFAULT_LOCK_OFFSET); + QString lockOffsetStr = readProperty(elem, PROPERTY_DEFAULT_LOCK_OFFSET()); if (!lockOffsetStr.isEmpty()) { ParsedNumber offset = ParserUtils::uint64FromString(lockOffsetStr); if (!offset.isValid) data->logError() << "Default lock offset is not a valid number:" << offset.string; else { data->logInfo() << "Default lock offset is " << offset.string; topData->setDefaultLockOffset(offset.value); } } structures.append(topData); count++; } return structures; } //TODO make type depend on the user not the definition QVector OsdParser::parseEnums(const QDomElement& rootElem, ScriptLogger* logger) { QVector ret; for (QDomElement elem = rootElem.firstChildElement(); !elem.isNull(); elem = elem.nextSiblingElement()) { - if (elem.tagName() != TYPE_ENUMDEF) + if (elem.tagName() != TYPE_ENUMDEF()) continue; QMap defs; - const QString enumName = readProperty(elem, PROPERTY_NAME, i18n("")); - const QString typeStr = readProperty(elem, PROPERTY_TYPE); + const QString enumName = readProperty(elem, PROPERTY_NAME(), i18n("")); + const QString typeStr = readProperty(elem, PROPERTY_TYPE()); if (typeStr.isEmpty()) { logger->error(enumName) << "Skipping enum definition, since no type attribute was found."; continue; } LoggerWithContext lwc(logger, QStringLiteral("enum values (") + enumName + QLatin1Char(')')); PrimitiveDataType type = PrimitiveFactory::typeStringToType(typeStr, lwc); //handle all entries for (QDomElement child = elem.firstChildElement(); !child.isNull(); child = child.nextSiblingElement()) { if (child.tagName() != QStringLiteral("entry")) continue; - QString name = readProperty(child, PROPERTY_NAME); + QString name = readProperty(child, PROPERTY_NAME()); if (name.isEmpty()) { lwc.warn() << "Entry is missing name, skipping it!"; continue; } - QString value = readProperty(child, PROPERTY_VALUE); + QString value = readProperty(child, PROPERTY_VALUE()); QPair converted = EnumDefinition::convertToEnumEntry(name, value, lwc, type); if (converted == QPair()) continue; defs.insert(converted.first, converted.second); } //now add this enum to the list of enums if (defs.isEmpty()) { lwc.error() << "Enum definition contains no valid elements!"; } else { EnumDefinition::Ptr enumDef = EnumDefinition::Ptr(new EnumDefinition(defs, enumName, type)); ret.append(enumDef); } } return ret; } //Datatypes ArrayDataInformation* OsdParser::arrayFromXML(const QDomElement& xmlElem, const OsdParserInfo& info) { ArrayParsedData apd(info); - QString lengthStr = readProperty(xmlElem, PROPERTY_LENGTH); + QString lengthStr = readProperty(xmlElem, PROPERTY_LENGTH()); if (lengthStr.isEmpty()) { info.error() << "No array length specified!"; return 0; } //must wrap in parentheses, cannot just evaluate. See https://bugreports.qt-project.org/browse/QTBUG-5757 const QScriptValue lengthFunc = ParserUtils::functionSafeEval(info.engine, lengthStr); if (lengthFunc.isValid()) { apd.length = lengthFunc; } else { apd.length = QScriptValue(lengthStr); } //first check whether there is a element and use the inner element //if that doesn't exist use the first child element as the type, but only if there is only one child - apd.arrayType = parseType(xmlElem, info, NAME_ARRAY_TYPE); + apd.arrayType = parseType(xmlElem, info, NAME_ARRAY_TYPE()); if (!apd.arrayType) { //was not specified as element or type="attribute", use first child DummyDataInformation dummy(info.parent, info.name); //dummy so that we have a proper chain OsdChildrenParser typeParser(info, xmlElem.firstChildElement()); typeParser.setParent(&dummy); if (typeParser.hasNext()) { apd.arrayType = typeParser.next(); if (typeParser.hasNext()) { info.error() << "More than one possible type for array!"; delete apd.arrayType; apd.arrayType = 0; return 0; } } } return DataInformationFactory::newArray(apd); } DataInformation* OsdParser::parseChildElement(const QDomElement& xmlElem, const OsdParserInfo& info, const QString& name) { OsdParserInfo newInfo(info); //instantiate a dummy so that a propert chain up to the root element exists DummyDataInformation dummy(info.parent, info.name); newInfo.parent = &dummy; newInfo.name = name; return parseElement(xmlElem, newInfo); } DataInformation* OsdParser::parseType(const QDomElement& xmlElem, const OsdParserInfo& info, const QString& name) { - const QString typeAttribute = xmlElem.attribute(PROPERTY_TYPE); + const QString typeAttribute = xmlElem.attribute(PROPERTY_TYPE()); if (!typeAttribute.isEmpty()) { //type was specified as a primitive string LoggerWithContext lwc(info.logger, info.context() + name); DataInformation* ret = PrimitiveFactory::newInstance(name, typeAttribute, lwc); if (!ret) { info.error() << typeAttribute << "is not a valid type identifier"; } return ret; } //we have to parse the first child element of the element - const QDomElement toParse = xmlElem.firstChildElement(PROPERTY_TYPE).firstChildElement(); + const QDomElement toParse = xmlElem.firstChildElement(PROPERTY_TYPE()).firstChildElement(); if (toParse.isNull()) { //don't log an error here, it may be okay (i.e. in arrays can be omitted) return 0; } if (!toParse.nextSiblingElement().isNull()) { info.warn() << " element has more than one child!"; } //TODO have this newInfo code only in one location DataInformation* ret = parseChildElement(toParse, info, name); if (!ret) { info.error() << "Failed to parse element defined in "; } return ret; } PointerDataInformation* OsdParser::pointerFromXML(const QDomElement& xmlElem, const OsdParserInfo& info) { PointerParsedData ppd(info); - ppd.valueType = parseType(xmlElem, info, NAME_POINTER_VALUE_TYPE); + ppd.valueType = parseType(xmlElem, info, NAME_POINTER_VALUE_TYPE()); //first check whether there is a element and use the inner element //if that doesn't exist use the first child element as the type, but only if there is only one child - QDomElement childElement = xmlElem.firstChildElement(PROPERTY_TARGET).firstChildElement(); + QDomElement childElement = xmlElem.firstChildElement(PROPERTY_TARGET()).firstChildElement(); if (childElement.isNull()) { childElement = xmlElem.firstChildElement(); if (childElement.isNull()) { info.error() << "Pointer target is missing! Please add a child element."; return 0; } else if (childElement != xmlElem.lastChildElement()) { //there is more than one child element info.error() << "There is more than one child element, cannot determine which one " "is the pointer target. Wrap the correct one in a element."; return 0; } } - ppd.pointerTarget = parseChildElement(childElement, info, NAME_POINTER_TARGET); + ppd.pointerTarget = parseChildElement(childElement, info, NAME_POINTER_TARGET()); return DataInformationFactory::newPointer(ppd); } PrimitiveDataInformation* OsdParser::primitiveFromXML(const QDomElement& xmlElem, const OsdParserInfo& info) { PrimitiveParsedData ppd(info); - ppd.type = readProperty(xmlElem, PROPERTY_TYPE); + ppd.type = readProperty(xmlElem, PROPERTY_TYPE()); return DataInformationFactory::newPrimitive(ppd); } AbstractBitfieldDataInformation* OsdParser::bitfieldFromXML(const QDomElement& xmlElem, const OsdParserInfo& info) { BitfieldParsedData bpd(info); - bpd.type = readProperty(xmlElem, PROPERTY_TYPE); - QString width = readProperty(xmlElem, PROPERTY_WIDTH); + bpd.type = readProperty(xmlElem, PROPERTY_TYPE()); + QString width = readProperty(xmlElem, PROPERTY_WIDTH()); bpd.width = ParserUtils::intFromString(width); return DataInformationFactory::newBitfield(bpd); } inline UnionDataInformation* OsdParser::unionFromXML(const QDomElement& xmlElem, const OsdParserInfo& info) { StructOrUnionParsedData supd(info); supd.children.reset(new OsdChildrenParser(info, xmlElem.firstChildElement())); return DataInformationFactory::newUnion(supd); } inline StructureDataInformation* OsdParser::structFromXML(const QDomElement& xmlElem, const OsdParserInfo& info) { StructOrUnionParsedData supd(info); supd.children.reset(new OsdChildrenParser(info, xmlElem.firstChildElement())); return DataInformationFactory::newStruct(supd); } EnumDataInformation* OsdParser::enumFromXML(const QDomElement& xmlElem, bool isFlags, const OsdParserInfo& info) { EnumParsedData epd(info); - epd.type = readProperty(xmlElem, PROPERTY_TYPE); - epd.enumName = readProperty(xmlElem, PROPERTY_ENUM_NAME); + epd.type = readProperty(xmlElem, PROPERTY_TYPE()); + epd.enumName = readProperty(xmlElem, PROPERTY_ENUM_NAME()); if (epd.enumName.isEmpty()) - epd.enumName = readProperty(xmlElem, TYPE_ENUM); //used again here as property + epd.enumName = readProperty(xmlElem, TYPE_ENUM()); //used again here as property epd.enumDef = findEnum(epd.enumName, info); if (!epd.enumDef) { info.error().nospace() << "Enum definition '" << epd.enumName << "' does not exist!"; return 0; } if (isFlags) return DataInformationFactory::newFlags(epd); else return DataInformationFactory::newEnum(epd); } StringDataInformation* OsdParser::stringFromXML(const QDomElement& xmlElem, const OsdParserInfo& info) { StringParsedData spd(info); - spd.encoding = readProperty(xmlElem, PROPERTY_ENCODING); - spd.termination = ParserUtils::uintFromString(readProperty(xmlElem, PROPERTY_TERMINATED_BY)); - spd.maxByteCount = ParserUtils::uintFromString(readProperty(xmlElem, PROPERTY_MAX_BYTE_COUNT)); - spd.maxCharCount = ParserUtils::uintFromString(readProperty(xmlElem, PROPERTY_MAX_CHAR_COUNT)); + spd.encoding = readProperty(xmlElem, PROPERTY_ENCODING()); + spd.termination = ParserUtils::uintFromString(readProperty(xmlElem, PROPERTY_TERMINATED_BY())); + spd.maxByteCount = ParserUtils::uintFromString(readProperty(xmlElem, PROPERTY_MAX_BYTE_COUNT())); + spd.maxCharCount = ParserUtils::uintFromString(readProperty(xmlElem, PROPERTY_MAX_CHAR_COUNT())); return DataInformationFactory::newString(spd); } DataInformation* OsdParser::parseElement(const QDomElement& elem, const OsdParserInfo& oldInfo) { Q_ASSERT(!elem.isNull()); DataInformation* data = 0; const QString tag = elem.tagName(); OsdParserInfo info(oldInfo); - info.name = readProperty(elem, PROPERTY_NAME, QStringLiteral("")); - if (tag == TYPE_STRUCT) + info.name = readProperty(elem, PROPERTY_NAME(), QStringLiteral("")); + if (tag == TYPE_STRUCT()) data = structFromXML(elem, info); - else if (tag == TYPE_ARRAY) + else if (tag == TYPE_ARRAY()) data = arrayFromXML(elem, info); - else if (tag == TYPE_BITFIELD) + else if (tag == TYPE_BITFIELD()) data = bitfieldFromXML(elem, info); - else if (tag == TYPE_PRIMITIVE) + else if (tag == TYPE_PRIMITIVE()) data = primitiveFromXML(elem, info); - else if (tag == TYPE_UNION) + else if (tag == TYPE_UNION()) data = unionFromXML(elem, info); - else if (tag == TYPE_ENUM) + else if (tag == TYPE_ENUM()) data = enumFromXML(elem, false, info); - else if (tag == TYPE_FLAGS) + else if (tag == TYPE_FLAGS()) data = enumFromXML(elem, true, info); - else if (tag == TYPE_STRING) + else if (tag == TYPE_STRING()) data = stringFromXML(elem, info); - else if (tag == TYPE_POINTER) + else if (tag == TYPE_POINTER()) data = pointerFromXML(elem, info); - else if (tag == TYPE_TAGGED_UNION) + else if (tag == TYPE_TAGGED_UNION()) data = taggedUnionFromXML(elem, info); else { LoggerWithContext lwc(info.logger, info.context()); //use the type tag as a primitive type data = PrimitiveFactory::newInstance(info.name, tag, lwc); if (!data) { info.error() << "Cannot parse unknown tag: " << tag; } } if (data) { CommonParsedData cpd(info); - QString byteOrderStr = readProperty(elem, PROPERTY_BYTEORDER); + QString byteOrderStr = readProperty(elem, PROPERTY_BYTEORDER()); if (!byteOrderStr.isEmpty()) cpd.endianess = ParserUtils::byteOrderFromString(byteOrderStr, LoggerWithContext(info.logger, info.context())); - cpd.updateFunc = ParserUtils::functionSafeEval(info.engine, readProperty(elem, PROPERTY_UPDATE_FUNC)); - cpd.validationFunc = ParserUtils::functionSafeEval(info.engine, readProperty(elem, PROPERTY_VALIDATION_FUNC)); - cpd.toStringFunc = ParserUtils::functionSafeEval(info.engine, readProperty(elem, PROPERTY_TO_STRING_FUNC)); - cpd.customTypeName = readProperty(elem, PROPERTY_CUSTOM_TYPE_NAME); + cpd.updateFunc = ParserUtils::functionSafeEval(info.engine, readProperty(elem, PROPERTY_UPDATE_FUNC())); + cpd.validationFunc = ParserUtils::functionSafeEval(info.engine, readProperty(elem, PROPERTY_VALIDATION_FUNC())); + cpd.toStringFunc = ParserUtils::functionSafeEval(info.engine, readProperty(elem, PROPERTY_TO_STRING_FUNC())); + cpd.customTypeName = readProperty(elem, PROPERTY_CUSTOM_TYPE_NAME()); if (!DataInformationFactory::commonInitialization(data, cpd)) { delete data; //error message has already been logged return 0; } } return data; } EnumDefinition::Ptr OsdParser::findEnum(const QString& defName, const OsdParserInfo& info) { for (int i = 0; i < info.enums.size(); ++i) { const EnumDefinition::Ptr def = info.enums.at(i); if (def->name() == defName) return def; } info.error() << "Could not find enum definition with name" << defName; return EnumDefinition::Ptr(0); } QString OsdParser::readProperty(const QDomElement& elem, const QString& property, const QString& defaultVal) { const QString attrib = elem.attribute(property); if (!attrib.isEmpty()) return attrib; //check for element now const QDomElement childElem = elem.firstChildElement(property); if (!elem.isNull()) return elem.text(); else return defaultVal; } TaggedUnionDataInformation* OsdParser::taggedUnionFromXML(const QDomElement& xmlElem, const OsdParserInfo& info) { TaggedUnionParsedData tpd(info); //can be null - QDomElement defaultChildren = xmlElem.firstChildElement(PROPERTY_DEFAULT_CHILDREN).firstChildElement(); + QDomElement defaultChildren = xmlElem.firstChildElement(PROPERTY_DEFAULT_CHILDREN()).firstChildElement(); if (defaultChildren.isNull()) info.info() << "No default fields specified, defaulting to none."; tpd.defaultFields.reset(new OsdChildrenParser(info, defaultChildren)); tpd.children.reset(new OsdChildrenParser(info, xmlElem.firstChildElement())); //now handle alternatives - QDomElement alternatives = xmlElem.firstChildElement(PROPERTY_ALTERNATIVES); + QDomElement alternatives = xmlElem.firstChildElement(PROPERTY_ALTERNATIVES()); if (alternatives.isNull()) { info.error() << "Missing element, tagged union cannot exist without at least one alternative"; return 0; } for (QDomElement elem = alternatives.firstChildElement(); !elem.isNull(); elem = elem.nextSiblingElement()) { TaggedUnionParsedData::Alternatives alt; - alt.name = readProperty(elem, PROPERTY_STRUCT_NAME); - QString selectIfStr = readProperty(elem, PROPERTY_SELECT_IF); + alt.name = readProperty(elem, PROPERTY_STRUCT_NAME()); + QString selectIfStr = readProperty(elem, PROPERTY_SELECT_IF()); QScriptValue selectIf = ParserUtils::functionSafeEval(info.engine, selectIfStr); if (!selectIf.isValid()) selectIf = selectIfStr; alt.selectIf = selectIf; - if (elem.tagName() == TYPE_GROUP) + if (elem.tagName() == TYPE_GROUP()) alt.fields = QSharedPointer(new OsdChildrenParser(info, elem.firstChildElement())); else alt.fields = QSharedPointer(new SingleElementOsdChildrenParser(info, elem)); tpd.alternatives.append(alt); } return DataInformationFactory::newTaggedUnion(tpd); } OsdChildrenParser::OsdChildrenParser(const OsdParserInfo& info, QDomElement firstChild) : mInfo(info), mElem(firstChild) { } DataInformation* OsdChildrenParser::next() { Q_ASSERT(!mElem.isNull()); //skip all known properties - while (ALL_PROPERTIES.contains(mElem.tagName())) + const QStringList allProperties = ALL_PROPERTIES(); + while (allProperties.contains(mElem.tagName())) mElem = mElem.nextSiblingElement(); if (mElem.isNull()) { mInfo.warn() << "Reached end of fields, but next() was requested!"; return 0; } DataInformation* ret = OsdParser::parseElement(mElem, mInfo); mElem = mElem.nextSiblingElement(); return ret; } OsdChildrenParser::~OsdChildrenParser() { } bool OsdChildrenParser::hasNext() { if (mElem.isNull()) return false; - while (ALL_PROPERTIES.contains(mElem.tagName())) + const QStringList allProperties = ALL_PROPERTIES(); + while (allProperties.contains(mElem.tagName())) mElem = mElem.nextSiblingElement(); //skip known properties return !mElem.isNull(); } void OsdChildrenParser::setParent(DataInformation* newParent) { mInfo.parent = newParent; } SingleElementOsdChildrenParser::SingleElementOsdChildrenParser(const OsdParserInfo& info, QDomElement element) : OsdChildrenParser(info, element), mParsed(false) { if (mElem.isNull()) info.warn() << "Null Element passed to child parser!"; } SingleElementOsdChildrenParser::~SingleElementOsdChildrenParser() { } DataInformation* SingleElementOsdChildrenParser::next() { Q_ASSERT(!mParsed); mParsed = true; return OsdParser::parseElement(mElem, mInfo); } bool SingleElementOsdChildrenParser::hasNext() { return !mParsed && !mElem.isNull(); } diff --git a/kasten/controllers/view/structures/parsers/parserutils.cpp b/kasten/controllers/view/structures/parsers/parserutils.cpp index 94f54af6..2f223a21 100644 --- a/kasten/controllers/view/structures/parsers/parserutils.cpp +++ b/kasten/controllers/view/structures/parsers/parserutils.cpp @@ -1,196 +1,273 @@ /* * This file is part of the Okteta Kasten Framework, made within the KDE community. * * Copyright 2012 Alex Richardson * Copyright 2016 Aaron Bishop * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "parserutils.h" #include #include +namespace ParserStrings { + +QString TYPE_ARRAY() { return QStringLiteral("array"); } +QString TYPE_BITFIELD() { return QStringLiteral("bitfield"); } +QString TYPE_ENUM() { return QStringLiteral("enum"); } +QString TYPE_FLAGS() { return QStringLiteral("flags"); } +QString TYPE_PRIMITIVE() { return QStringLiteral("primitive"); } +QString TYPE_STRING() { return QStringLiteral("string"); } +QString TYPE_STRUCT() { return QStringLiteral("struct"); } +QString TYPE_UNION() { return QStringLiteral("union"); } +QString TYPE_POINTER() { return QStringLiteral("pointer"); } +QString TYPE_TAGGED_UNION() { return QStringLiteral("taggedUnion"); } + +QString TYPE_ENUMDEF() { return QStringLiteral("enumDef"); } +QString TYPE_ALTERNATIVES() { return QStringLiteral("alternatives"); } +QString TYPE_GROUP() { return QStringLiteral("group"); } + +QString PROPERTY_DEFAULT_LOCK_OFFSET() { return QStringLiteral("defaultLockOffset"); } + +QString PROPERTY_NAME() { return QStringLiteral("name"); } +QString PROPERTY_BYTEORDER() { return QStringLiteral("byteOrder"); } +QString PROPERTY_PARENT() { return QStringLiteral("parent"); } +QString PROPERTY_VALIDATION_ERROR() { return QStringLiteral("validationError"); } +QString PROPERTY_VALID() { return QStringLiteral("valid"); } +QString PROPERTY_ABLE_TO_READ() { return QStringLiteral("wasAbleToRead"); } +QString PROPERTY_UPDATE_FUNC() { return QStringLiteral("updateFunc"); } +QString PROPERTY_VALIDATION_FUNC() { return QStringLiteral("validationFunc"); } +QString PROPERTY_TO_STRING_FUNC() { return QStringLiteral("toStringFunc"); } +QString PROPERTY_DATATYPE() { return QStringLiteral("datatype"); } +QString PROPERTY_CUSTOM_TYPE_NAME() { return QStringLiteral("typeName"); } + +QString PROPERTY_ENUM_VALUES() { return QStringLiteral("enumValues"); } + +QString PROPERTY_ENUM_NAME() { return QStringLiteral("enumName"); } + +QString PROPERTY_TYPE() { return QStringLiteral("type"); } + +QString PROPERTY_LENGTH() { return QStringLiteral("length"); } + +QString PROPERTY_WIDTH() { return QStringLiteral("width"); } +QString PROPERTY_CHILDREN() { return QStringLiteral("fields"); } +QString PROPERTY_CHILD_COUNT() { return QStringLiteral("childCount"); } +QString PROPERTY_CHILD() { return QStringLiteral("child"); } + +QString PROPERTY_CHAR_COUNT() { return QStringLiteral("charCount"); } +QString PROPERTY_BYTE_COUNT() { return QStringLiteral("byteCount"); } +QString PROPERTY_MAX_CHAR_COUNT() { return QStringLiteral("maxCharCount"); } +QString PROPERTY_MAX_BYTE_COUNT() { return QStringLiteral("maxByteCount"); } +QString PROPERTY_TERMINATED_BY() { return QStringLiteral("terminatedBy"); } +QString PROPERTY_ENCODING() { return QStringLiteral("encoding"); } + //primitive +QString PROPERTY_VALUE() { return QStringLiteral("value"); } + //pointer +QString PROPERTY_TARGET() { return QStringLiteral("target"); } + //tagged union +QString PROPERTY_ALTERNATIVES() { return QStringLiteral("alternatives"); } +QString PROPERTY_DEFAULT_CHILDREN() { return QStringLiteral("defaultFields"); } +QString PROPERTY_SELECT_IF() { return QStringLiteral("selectIf"); } +QString PROPERTY_STRUCT_NAME() { return QStringLiteral("structName"); } + +QString PROPERTY_INTERNAL_TYPE() { return QStringLiteral("__type"); } + +QStringList ALL_PROPERTIES() { return QStringList() + << PROPERTY_ABLE_TO_READ() << PROPERTY_ALTERNATIVES() << PROPERTY_BYTEORDER() + << PROPERTY_BYTE_COUNT() << PROPERTY_CHAR_COUNT() << PROPERTY_CHAR_COUNT() << PROPERTY_CHILD() + << PROPERTY_CHILDREN() << PROPERTY_CHILD_COUNT() << PROPERTY_DATATYPE() << PROPERTY_DEFAULT_CHILDREN() + << PROPERTY_ENCODING() << PROPERTY_ENUM_NAME() << PROPERTY_ENUM_VALUES() << PROPERTY_INTERNAL_TYPE() << + PROPERTY_LENGTH() << PROPERTY_MAX_BYTE_COUNT() << PROPERTY_MAX_CHAR_COUNT() << PROPERTY_NAME() + << PROPERTY_PARENT() << PROPERTY_SELECT_IF() << PROPERTY_STRUCT_NAME() << PROPERTY_TARGET() + << PROPERTY_TERMINATED_BY() << PROPERTY_TYPE() << PROPERTY_UPDATE_FUNC() << PROPERTY_VALID() << + PROPERTY_VALIDATION_ERROR() << PROPERTY_VALIDATION_FUNC() << PROPERTY_VALUE() << PROPERTY_WIDTH(); } + +QString NAME_POINTER_VALUE_TYPE() { return QStringLiteral(""); } +QString NAME_POINTER_TARGET() { return QStringLiteral(""); } +QString NAME_ARRAY_TYPE() { return QStringLiteral(""); } +} + ParsedNumber ParserUtils::intFromString(const QString& str) { int value = 0; bool okay = false; if (str.startsWith(QStringLiteral("0x"))) value = str.mid(2).toInt(&okay, 16); else if (str.startsWith(QStringLiteral("-0x"))) { //special case for minimum possible value if (str == QStringLiteral("-0x80000000")) return ParsedNumber(-0x80000000, str, true); value = -str.mid(3).toInt(&okay, 16); } else value = str.toInt(&okay, 10); return ParsedNumber(value, str, okay); } ParsedNumber ParserUtils::uintFromString(const QString& str) { uint value = 0; bool okay; if (str.startsWith(QStringLiteral("0x"))) value = str.mid(2).toUInt(&okay, 16); else value = str.toUInt(&okay, 10); return ParsedNumber(value, str, okay); } ParsedNumber ParserUtils::uint64FromString(const QString& str) { quint64 value = 0; bool okay; if (str.startsWith(QStringLiteral("0x"))) value = str.mid(2).toULongLong(&okay, 16); else value = str.toULongLong(&okay, 10); return ParsedNumber(value, str, okay); } DataInformation::DataInformationEndianess ParserUtils::byteOrderFromString(const QString& string, const LoggerWithContext& logger) { const QString lower = string.toLower(); if (lower == QStringLiteral("bigendian") || lower == QStringLiteral("big-endian")) return DataInformation::EndianessBig; else if (lower == QStringLiteral("littleendian") || lower == QStringLiteral("little-endian")) return DataInformation::EndianessLittle; else if (lower == QStringLiteral("fromsettings") || lower == QStringLiteral("from-settings")) return DataInformation::EndianessFromSettings; else if (lower == QStringLiteral("inherit")) return DataInformation::EndianessInherit; else { logger.warn().nospace() << "Unrecognized byte order '" << string << "', defaulting to 'inherit'"; return DataInformation::EndianessInherit; } } ParsedNumber ParserUtils::intFromScriptValue(const QScriptValue& val) { if (val.isNumber()) { //check whether it is in range const qsreal doubleVal = val.toNumber(); const int value = val.toInt32(); if (doubleVal != qsreal(value)) return ParsedNumber::badInput(val.toString()); return ParsedNumber(value, val.toString(), true); } else if (val.isString()) return intFromString(val.toString()); else return ParsedNumber::badInput(val.toString()); } ParsedNumber ParserUtils::uintFromScriptValue(const QScriptValue& val) { if (val.isNumber()) { //check whether it is in range const uint value = val.toUInt32(); const qsreal doubleVal = val.toNumber(); if (doubleVal != qsreal(value)) return ParsedNumber::badInput(val.toString()); return ParsedNumber(value, val.toString(), true); } else if (val.isString()) return uintFromString(val.toString()); else return ParsedNumber::badInput(val.toString()); } ParsedNumber ParserUtils::uint64FromScriptValue(const QScriptValue& val) { if (val.isNumber()) { //check whether it is in range const uint value = val.toUInt32(); const qsreal doubleVal = val.toNumber(); if (doubleVal != qsreal(value)) return ParsedNumber::badInput(val.toString()); return ParsedNumber(value, val.toString(), true); } else if (val.isString()) return uint64FromString(val.toString()); else return ParsedNumber::badInput(val.toString()); } QString ParserUtils::byteOrderToString(DataInformation::DataInformationEndianess order) { if (order == DataInformation::EndianessLittle) return QStringLiteral("littleEndian"); if (order == DataInformation::EndianessBig) return QStringLiteral("bigEndian"); if (order == DataInformation::EndianessFromSettings) return QStringLiteral("fromSettings"); return QStringLiteral("inherit"); } StringDataInformation::StringType ParserUtils::toStringEncoding(const QString& str, const LoggerWithContext& logger) { QString enc = str.toLower(); if (enc == QStringLiteral("ascii")) return StringDataInformation::ASCII; else if (enc == QStringLiteral("ebcdic")) return StringDataInformation::EBCDIC; else if (enc == QStringLiteral("latin1") || enc == QStringLiteral("latin-1")) return StringDataInformation::Latin1; else if (enc.startsWith(QStringLiteral("utf"))) { QStringRef ref = enc.midRef(3); if (ref.at(0) == QLatin1Char('-')) ref = enc.midRef(4); //strip '-' if (ref == QStringLiteral("8")) return StringDataInformation::UTF8; if (ref == QStringLiteral("16") || ref == QStringLiteral("16le") || ref == QStringLiteral("16-le")) { return StringDataInformation::UTF16_LE; } if (ref == QStringLiteral("16be") || ref == QStringLiteral("16-be")) { return StringDataInformation::UTF16_BE; } if (ref == QStringLiteral("32") || ref == QStringLiteral("32le") || ref == QStringLiteral("32-le")) { return StringDataInformation::UTF32_LE; } if (ref == QStringLiteral("32be") || ref == QStringLiteral("32-be")) { return StringDataInformation::UTF32_BE; } } logger.warn() << "Unrecognized string encoding: " << enc; return StringDataInformation::InvalidEncoding; } QScriptValue ParserUtils::functionSafeEval(QScriptEngine* engine, const QString& str) { if (str.isEmpty()) return QScriptValue(); //must wrap in parentheses, see https://bugreports.qt-project.org/browse/QTBUG-5757 QScriptValue ret = engine->evaluate(QLatin1Char('(') + str + QLatin1Char(')')); if (!ret.isFunction()) return QScriptValue(str); return ret; } diff --git a/kasten/controllers/view/structures/parsers/parserutils.h b/kasten/controllers/view/structures/parsers/parserutils.h index ce0e0b26..7d162276 100644 --- a/kasten/controllers/view/structures/parsers/parserutils.h +++ b/kasten/controllers/view/structures/parsers/parserutils.h @@ -1,206 +1,197 @@ /* * This file is part of the Okteta Kasten Framework, made within the KDE community. * * Copyright 2012 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #ifndef PARSERUTILS_H_ #define PARSERUTILS_H_ #include #include #include #include "../datatypes/datainformation.h" #include "../datatypes/strings/stringdatainformation.h" #include "../script/scriptlogger.h" //forward declare so I don't have to repeat in all the parsers class ArrayDataInformation; class PrimitiveDataInformation; class AbstractBitfieldDataInformation; class StructureDataInformation; class UnionDataInformation; class EnumDataInformation; class StringDataInformation; class TaggedUnionDataInformation; class PointerDataInformation; class QScriptValue; class QScriptEngine; /** For use by the parsers so that the functions don't have as many parameters */ struct ParserInfo { inline ParserInfo(const QString& name, ScriptLogger* logger, DataInformation* parent, QScriptEngine* engine) : name(name), logger(logger), parent(parent), engine(engine) { Q_CHECK_PTR(logger); } inline ParserInfo(const ParserInfo& i) : name(i.name), logger(i.logger), parent(i.parent), engine(i.engine) {} inline ~ParserInfo() {} QString name; ScriptLogger* logger; DataInformation* parent; QScriptEngine* engine; inline QString context() const { return parent ? parent->fullObjectPath() + QLatin1Char('.') + name : name; } inline QDebug info() const { return logger->info(context()); } inline QDebug warn() const { return logger->warn(context()); } inline QDebug error() const { return logger->error(context()); } }; class ChildrenParser { public: virtual DataInformation* next() = 0; virtual bool hasNext() = 0; virtual void setParent(DataInformation* parent) = 0; virtual ~ChildrenParser() {}; }; /** * Holds a number that was converted either from a QScriptValue or a QString */ template struct ParsedNumber { ParsedNumber() : value(0), isValid(false) {} ParsedNumber(T val, const QString& str, bool ok) : string(str), value(val), isValid(ok) {} QString string; T value; bool isValid; static ParsedNumber badInput(const QString& str) { return ParsedNumber(T(), str, false); } inline bool isError() { return !isValid && !string.isEmpty(); } inline bool isEmpty() { Q_ASSERT(!isValid); return string.isEmpty(); } }; namespace ParserStrings { - const QString TYPE_ARRAY = QStringLiteral("array"); - const QString TYPE_BITFIELD = QStringLiteral("bitfield"); - const QString TYPE_ENUM = QStringLiteral("enum"); - const QString TYPE_FLAGS = QStringLiteral("flags"); - const QString TYPE_PRIMITIVE = QStringLiteral("primitive"); - const QString TYPE_STRING = QStringLiteral("string"); - const QString TYPE_STRUCT = QStringLiteral("struct"); - const QString TYPE_UNION = QStringLiteral("union"); - const QString TYPE_POINTER = QStringLiteral("pointer"); - const QString TYPE_TAGGED_UNION = QStringLiteral("taggedUnion"); + QString TYPE_ARRAY(); + QString TYPE_BITFIELD(); + QString TYPE_ENUM(); + QString TYPE_FLAGS(); + QString TYPE_PRIMITIVE(); + QString TYPE_STRING(); + QString TYPE_STRUCT(); + QString TYPE_UNION(); + QString TYPE_POINTER(); + QString TYPE_TAGGED_UNION(); /** Only needed for .osd */ - const QString TYPE_ENUMDEF = QStringLiteral("enumDef"); - const QString TYPE_ALTERNATIVES = QStringLiteral("alternatives"); - const QString TYPE_GROUP= QStringLiteral("group"); + QString TYPE_ENUMDEF(); + QString TYPE_ALTERNATIVES(); + QString TYPE_GROUP(); //lock offset - const QString PROPERTY_DEFAULT_LOCK_OFFSET = QStringLiteral("defaultLockOffset"); + QString PROPERTY_DEFAULT_LOCK_OFFSET(); //all types - const QString PROPERTY_NAME = QStringLiteral("name"); - const QString PROPERTY_BYTEORDER = QStringLiteral("byteOrder"); - const QString PROPERTY_PARENT= QStringLiteral("parent"); - const QString PROPERTY_VALIDATION_ERROR = QStringLiteral("validationError"); - const QString PROPERTY_VALID = QStringLiteral("valid"); - const QString PROPERTY_ABLE_TO_READ = QStringLiteral("wasAbleToRead"); - const QString PROPERTY_UPDATE_FUNC = QStringLiteral("updateFunc"); - const QString PROPERTY_VALIDATION_FUNC = QStringLiteral("validationFunc"); - const QString PROPERTY_TO_STRING_FUNC = QStringLiteral("toStringFunc"); - const QString PROPERTY_DATATYPE = QStringLiteral("datatype"); - const QString PROPERTY_CUSTOM_TYPE_NAME = QStringLiteral("typeName"); + QString PROPERTY_NAME(); + QString PROPERTY_BYTEORDER(); + QString PROPERTY_PARENT(); + QString PROPERTY_VALIDATION_ERROR(); + QString PROPERTY_VALID(); + QString PROPERTY_ABLE_TO_READ(); + QString PROPERTY_UPDATE_FUNC(); + QString PROPERTY_VALIDATION_FUNC(); + QString PROPERTY_TO_STRING_FUNC(); + QString PROPERTY_DATATYPE(); + QString PROPERTY_CUSTOM_TYPE_NAME(); //enum - const QString PROPERTY_ENUM_VALUES = QStringLiteral("enumValues"); + QString PROPERTY_ENUM_VALUES(); //this one is javascript only - const QString PROPERTY_ENUM_NAME = QStringLiteral("enumName"); + QString PROPERTY_ENUM_NAME(); //array/bitfield - const QString PROPERTY_TYPE = QStringLiteral("type"); + QString PROPERTY_TYPE(); //array - const QString PROPERTY_LENGTH = QStringLiteral("length"); + QString PROPERTY_LENGTH(); //bitfield - const QString PROPERTY_WIDTH = QStringLiteral("width"); + QString PROPERTY_WIDTH(); //struct/union - const QString PROPERTY_CHILDREN = QStringLiteral("fields"); - const QString PROPERTY_CHILD_COUNT = QStringLiteral("childCount"); - const QString PROPERTY_CHILD = QStringLiteral("child"); + QString PROPERTY_CHILDREN(); + QString PROPERTY_CHILD_COUNT(); + QString PROPERTY_CHILD(); //strings - const QString PROPERTY_CHAR_COUNT = QStringLiteral("charCount"); - const QString PROPERTY_BYTE_COUNT = QStringLiteral("byteCount"); - const QString PROPERTY_MAX_CHAR_COUNT = QStringLiteral("maxCharCount"); - const QString PROPERTY_MAX_BYTE_COUNT = QStringLiteral("maxByteCount"); - const QString PROPERTY_TERMINATED_BY = QStringLiteral("terminatedBy"); - const QString PROPERTY_ENCODING = QStringLiteral("encoding"); + QString PROPERTY_CHAR_COUNT(); + QString PROPERTY_BYTE_COUNT(); + QString PROPERTY_MAX_CHAR_COUNT(); + QString PROPERTY_MAX_BYTE_COUNT(); + QString PROPERTY_TERMINATED_BY(); + QString PROPERTY_ENCODING(); //primitive - const QString PROPERTY_VALUE = QStringLiteral("value"); + QString PROPERTY_VALUE(); //pointer - const QString PROPERTY_TARGET = QStringLiteral("target"); + QString PROPERTY_TARGET(); //tagged union - const QString PROPERTY_ALTERNATIVES = QStringLiteral("alternatives"); - const QString PROPERTY_DEFAULT_CHILDREN = QStringLiteral("defaultFields"); - const QString PROPERTY_SELECT_IF = QStringLiteral("selectIf"); - const QString PROPERTY_STRUCT_NAME = QStringLiteral("structName"); - - const QString PROPERTY_INTERNAL_TYPE = QStringLiteral("__type"); - - const QStringList ALL_PROPERTIES = QStringList() - << PROPERTY_ABLE_TO_READ << PROPERTY_ALTERNATIVES << PROPERTY_BYTEORDER - << PROPERTY_BYTE_COUNT << PROPERTY_CHAR_COUNT << PROPERTY_CHAR_COUNT << PROPERTY_CHILD - << PROPERTY_CHILDREN << PROPERTY_CHILD_COUNT << PROPERTY_DATATYPE << PROPERTY_DEFAULT_CHILDREN - << PROPERTY_ENCODING << PROPERTY_ENUM_NAME << PROPERTY_ENUM_VALUES << PROPERTY_INTERNAL_TYPE << - PROPERTY_LENGTH << PROPERTY_MAX_BYTE_COUNT << PROPERTY_MAX_CHAR_COUNT << PROPERTY_NAME - << PROPERTY_PARENT << PROPERTY_SELECT_IF << PROPERTY_STRUCT_NAME << PROPERTY_TARGET - << PROPERTY_TERMINATED_BY << PROPERTY_TYPE << PROPERTY_UPDATE_FUNC << PROPERTY_VALID << - PROPERTY_VALIDATION_ERROR << PROPERTY_VALIDATION_FUNC << PROPERTY_VALUE << PROPERTY_WIDTH; - - const QString NAME_POINTER_VALUE_TYPE = QStringLiteral(""); - const QString NAME_POINTER_TARGET = QStringLiteral(""); - const QString NAME_ARRAY_TYPE = QStringLiteral(""); + QString PROPERTY_ALTERNATIVES(); + QString PROPERTY_DEFAULT_CHILDREN(); + QString PROPERTY_SELECT_IF(); + QString PROPERTY_STRUCT_NAME(); + QString PROPERTY_INTERNAL_TYPE(); + + QStringList ALL_PROPERTIES(); + + QString NAME_POINTER_VALUE_TYPE(); + QString NAME_POINTER_TARGET(); + QString NAME_ARRAY_TYPE(); } namespace ParserUtils { /** If string starts with 0x, the remainder is interpreted as a hexadecimal (unsigned) number * otherwise it will be parsed as a decimal number * @param str the string to convert * @return a parsed number (check the isValid member to see if conversion succeeded) */ ParsedNumber intFromString(const QString& str); /** @see ParserUtils::intFromString() */ ParsedNumber uintFromString(const QString& str); /** @see ParserUtils::intFromString() */ ParsedNumber uint64FromString(const QString& str); /** Checks whether the value is a number, and if it is converts it. * Since all script values use double internally, a valid number can be out of bounds, too * @param val the value to convert * @see ParserUtils::intFromString() */ ParsedNumber intFromScriptValue(const QScriptValue& val); /** @see ParserUtils::intFromScriptValue() */ ParsedNumber uintFromScriptValue(const QScriptValue& val); /** @see ParserUtils::intFromScriptValue() */ ParsedNumber uint64FromScriptValue(const QScriptValue& val); DataInformation::DataInformationEndianess byteOrderFromString(const QString& string, const LoggerWithContext& logger); QString byteOrderToString(DataInformation::DataInformationEndianess order); StringDataInformation::StringType toStringEncoding(const QString& str, const LoggerWithContext& logger); /** This essentially calls engine->evaluate(str), but ensures it can be a function (QTBUG-5757) */ QScriptValue functionSafeEval(QScriptEngine* engine, const QString& str); } #endif /* PARSERUTILS_H_ */ diff --git a/kasten/controllers/view/structures/parsers/scriptfileparser.cpp b/kasten/controllers/view/structures/parsers/scriptfileparser.cpp index 9b6796a5..92a7d68c 100644 --- a/kasten/controllers/view/structures/parsers/scriptfileparser.cpp +++ b/kasten/controllers/view/structures/parsers/scriptfileparser.cpp @@ -1,130 +1,130 @@ /* * This file is part of the Okteta Kasten Framework, made within the KDE community. * * Copyright 2010, 2011, 2012 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "scriptfileparser.h" #include "scriptvalueconverter.h" #include "parserutils.h" #include "../datatypes/topleveldatainformation.h" #include "../datatypes/dummydatainformation.h" #include "../script/scriptengineinitializer.h" #include "../script/scriptlogger.h" #include ScriptFileParser::ScriptFileParser(const QString& pluginName, const QString& absolutePath) : AbstractStructureParser(pluginName, absolutePath) { } ScriptFileParser::~ScriptFileParser() { } QStringList ScriptFileParser::parseStructureNames() const { return QStringList() << mPluginName; } QVector ScriptFileParser::parseStructures() const { QVector ret; QScriptEngine* engine = ScriptEngineInitializer::newEngine(); ScriptLogger* logger = new ScriptLogger(); QScriptValue value = loadScriptValue(logger, engine); DataInformation* dataInf; if (!value.isValid()) dataInf = new DummyDataInformation(0, mPluginName); else dataInf = ScriptValueConverter::convert(value, mPluginName, logger); if (!dataInf) dataInf = new DummyDataInformation(0, mPluginName); const QFileInfo fileInfo(mAbsolutePath); TopLevelDataInformation* top = new TopLevelDataInformation(dataInf, logger, engine, fileInfo); //handle default lock offset - QScriptValue lockOffset = value.property(ParserStrings::PROPERTY_DEFAULT_LOCK_OFFSET); + QScriptValue lockOffset = value.property(ParserStrings::PROPERTY_DEFAULT_LOCK_OFFSET()); if (lockOffset.isValid()) { ParsedNumber offset = ParserUtils::uint64FromScriptValue(lockOffset); if (!offset.isValid) dataInf->logError() << "Default lock offset is not a valid number:" << offset.string; else top->setDefaultLockOffset(offset.value); } ret.append(top); return ret; } QScriptValue ScriptFileParser::loadScriptValue(ScriptLogger* logger, QScriptEngine* engine) const { QFile scriptFile(mAbsolutePath); if (!scriptFile.open(QIODevice::ReadOnly)) { logger->error() << "Could not open file " << mAbsolutePath; return QScriptValue(); } QTextStream stream(&scriptFile); QString contents = stream.readAll(); scriptFile.close(); engine->evaluate(contents, mAbsolutePath); if (engine->hasUncaughtException()) { //check if it was a syntax error: QScriptSyntaxCheckResult syntaxError = QScriptEngine::checkSyntax(contents); if (syntaxError.state() == QScriptSyntaxCheckResult::Error) { //give a detailed syntax error message logger->error() << "Syntax error in script: " << syntaxError.errorMessage(); logger->error() << "Line number: " << syntaxError.errorLineNumber() << "Column:" << syntaxError.errorColumnNumber(); } else { //just print the generic exception message logger->error() << "Error evaluating script: " << engine->uncaughtException().toString(); logger->error() << "Line number: " << engine->uncaughtExceptionLineNumber(); logger->error() << "Backtrace: " << engine->uncaughtExceptionBacktrace(); } return QScriptValue(); } QScriptValue obj = engine->globalObject(); QScriptValue initMethod = obj.property(QStringLiteral("init")); if (!initMethod.isFunction()) { logger->error() << "Script has no 'init' function! Cannot evaluate script!"; return QScriptValue(); } QScriptValue thisObj = engine->newObject(); QScriptValueList args; QScriptValue result = initMethod.call(thisObj, args); if (result.isError()) { logger->error() << "Exception occurred while calling init():" << result.toString(); return QScriptValue(); } return result; } diff --git a/kasten/controllers/view/structures/parsers/scriptvalueconverter_p.cpp b/kasten/controllers/view/structures/parsers/scriptvalueconverter_p.cpp index 8d843727..1912b30c 100644 --- a/kasten/controllers/view/structures/parsers/scriptvalueconverter_p.cpp +++ b/kasten/controllers/view/structures/parsers/scriptvalueconverter_p.cpp @@ -1,319 +1,319 @@ /* * This file is part of the Okteta Kasten Framework, made within the KDE community. * * Copyright 2012 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "scriptvalueconverter.h" #include "scriptvalueconverter_p.h" #include "datainformationfactory.h" #include "parserutils.h" #include "../datatypes/uniondatainformation.h" #include "../datatypes/structuredatainformation.h" #include "../datatypes/strings/stringdata.h" #include "../datatypes/strings/stringdatainformation.h" #include "../script/scriptlogger.h" using namespace ParserStrings; namespace ScriptValueConverter { DataInformation* toDataInformation(const QScriptValue& value, const ParserInfo& oldInfo) { if (!value.isValid()) { oldInfo.error() << "invalid value passed!"; return 0; } ParserInfo info(oldInfo); - QString nameOverride = value.property(PROPERTY_NAME).toString(); + QString nameOverride = value.property(PROPERTY_NAME()).toString(); if (!nameOverride.isEmpty()) info.name = nameOverride; //check function array and date, since they are objects too if (value.isRegExp()) { //apparently regexp is a function info.error() << "Cannot convert a RegExp object to DataInformation!"; return 0; } if (value.isFunction()) { info.error() << "Cannot convert a Function object to DataInformation!"; return 0; } if (value.isArray()) { info.error() << "Cannot convert a Array object to DataInformation!"; return 0; } if (value.isDate()) { info.error() << "Cannot convert a Date object to DataInformation!"; return 0; } if (value.isError()) { info.error() << "Cannot convert a Error object to DataInformation!"; return 0; } //variant and qobject are also object types, however they cannot appear from user code, no need to check //if it is a string, we convert to primitive type, if not it has to be an object if (value.isString()) return toPrimitive(value, info); //a type string is also okay if (!value.isObject()) { if (value.isBool()) info.error() << "Cannot convert Boolean to DataInformation!"; else if (value.isNull()) info.error() << "Cannot convert null to DataInformation!"; else if (value.isUndefined()) info.error() << "Cannot convert undefined to DataInformation!"; else if (value.isNumber()) info.error() << "Cannot convert Number to DataInformation!"; else info.error() << "Cannot convert object of unknown type to DataInformation!"; return 0; //no point trying to convert } - QString type = value.property(PROPERTY_INTERNAL_TYPE).toString(); + QString type = value.property(PROPERTY_INTERNAL_TYPE()).toString(); if (type.isEmpty()) { info.error() << "Cannot convert object since type of object could not be determined!"; return 0; } DataInformation* returnVal = 0; - if (type == TYPE_ARRAY) + if (type == TYPE_ARRAY()) returnVal = toArray(value, info); - else if (type == TYPE_STRUCT) + else if (type == TYPE_STRUCT()) returnVal = toStruct(value, info); - else if (type == TYPE_UNION) + else if (type == TYPE_UNION()) returnVal = toUnion(value, info); - else if (type == TYPE_BITFIELD) + else if (type == TYPE_BITFIELD()) returnVal = toBitfield(value, info); - else if (type == TYPE_ENUM) + else if (type == TYPE_ENUM()) returnVal = toEnum(value, false, info); - else if (type == TYPE_FLAGS) + else if (type == TYPE_FLAGS()) returnVal = toEnum(value, true, info); - else if (type == TYPE_STRING) + else if (type == TYPE_STRING()) returnVal = toString(value, info); - else if (type == TYPE_POINTER) + else if (type == TYPE_POINTER()) returnVal = toPointer(value, info); - else if (type == TYPE_TAGGED_UNION) + else if (type == TYPE_TAGGED_UNION()) returnVal = toTaggedUnion(value, info); - else if (type == TYPE_PRIMITIVE) + else if (type == TYPE_PRIMITIVE()) returnVal = toPrimitive(value, info); else info.error() << "Unknown type:" << type; if (returnVal) { CommonParsedData cpd(info); - QString byteOrderStr = value.property(PROPERTY_BYTEORDER).toString(); + QString byteOrderStr = value.property(PROPERTY_BYTEORDER()).toString(); if (!byteOrderStr.isEmpty()) cpd.endianess = ParserUtils::byteOrderFromString(byteOrderStr, LoggerWithContext(info.logger, info.context())); - cpd.updateFunc = value.property(PROPERTY_UPDATE_FUNC); - cpd.validationFunc = value.property(PROPERTY_VALIDATION_FUNC); - cpd.toStringFunc = value.property(PROPERTY_TO_STRING_FUNC); - cpd.customTypeName = value.property(PROPERTY_CUSTOM_TYPE_NAME).toString(); + cpd.updateFunc = value.property(PROPERTY_UPDATE_FUNC()); + cpd.validationFunc = value.property(PROPERTY_VALIDATION_FUNC()); + cpd.toStringFunc = value.property(PROPERTY_TO_STRING_FUNC()); + cpd.customTypeName = value.property(PROPERTY_CUSTOM_TYPE_NAME()).toString(); if (!DataInformationFactory::commonInitialization(returnVal, cpd)) { delete returnVal; //error message has already been logged return 0; } } return returnVal; } ArrayDataInformation* toArray(const QScriptValue& value, const ParserInfo& info) { ArrayParsedData apd(info); - apd.length = value.property(PROPERTY_LENGTH); - QScriptValue childType = value.property(PROPERTY_TYPE); + apd.length = value.property(PROPERTY_LENGTH()); + QScriptValue childType = value.property(PROPERTY_TYPE()); ParserInfo childInfo(info); - DummyDataInformation dummy(info.parent, info.name + QLatin1Char('.') + NAME_ARRAY_TYPE); + DummyDataInformation dummy(info.parent, info.name + QLatin1Char('.') + NAME_ARRAY_TYPE()); childInfo.parent = &dummy; apd.arrayType = toDataInformation(childType, childInfo); return DataInformationFactory::newArray(apd); } AbstractBitfieldDataInformation* toBitfield(const QScriptValue& value, const ParserInfo& info) { BitfieldParsedData bpd(info); - bpd.type = value.property(PROPERTY_TYPE).toString(); - bpd.width = ParserUtils::intFromScriptValue(value.property(PROPERTY_WIDTH)); + bpd.type = value.property(PROPERTY_TYPE()).toString(); + bpd.width = ParserUtils::intFromScriptValue(value.property(PROPERTY_WIDTH())); return DataInformationFactory::newBitfield(bpd); } PrimitiveDataInformation* toPrimitive(const QScriptValue& value, const ParserInfo& info) { PrimitiveParsedData ppd(info); - ppd.type = value.isString() ? value.toString() : value.property(PROPERTY_TYPE).toString(); + ppd.type = value.isString() ? value.toString() : value.property(PROPERTY_TYPE()).toString(); return DataInformationFactory::newPrimitive(ppd); } StructureDataInformation* toStruct(const QScriptValue& value, const ParserInfo& info) { StructOrUnionParsedData supd(info); - supd.children.reset(new ScriptValueChildrenParser(info, value.property(PROPERTY_CHILDREN))); + supd.children.reset(new ScriptValueChildrenParser(info, value.property(PROPERTY_CHILDREN()))); return DataInformationFactory::newStruct(supd); } UnionDataInformation* toUnion(const QScriptValue& value, const ParserInfo& info) { StructOrUnionParsedData supd(info); - supd.children.reset(new ScriptValueChildrenParser(info, value.property(PROPERTY_CHILDREN))); + supd.children.reset(new ScriptValueChildrenParser(info, value.property(PROPERTY_CHILDREN()))); return DataInformationFactory::newUnion(supd);} PointerDataInformation* toPointer(const QScriptValue& value, const ParserInfo& info) { PointerParsedData ppd(info); ParserInfo childInfo(info); DummyDataInformation dummy(info.parent, info.name); childInfo.parent = &dummy; - childInfo.name = NAME_POINTER_TARGET; - ppd.pointerTarget = toDataInformation(value.property(PROPERTY_TARGET), childInfo); - childInfo.name = NAME_POINTER_VALUE_TYPE; - ppd.valueType = toDataInformation(value.property(PROPERTY_TYPE), childInfo); + childInfo.name = NAME_POINTER_TARGET(); + ppd.pointerTarget = toDataInformation(value.property(PROPERTY_TARGET()), childInfo); + childInfo.name = NAME_POINTER_VALUE_TYPE(); + ppd.valueType = toDataInformation(value.property(PROPERTY_TYPE()), childInfo); return DataInformationFactory::newPointer(ppd); } EnumDataInformation* toEnum(const QScriptValue& value, bool flags, const ParserInfo& info) { EnumParsedData epd(info); - QScriptValue enumType = value.property(PROPERTY_TYPE); + QScriptValue enumType = value.property(PROPERTY_TYPE()); if (enumType.isString()) epd.type = enumType.toString(); else if (enumType.isObject()) - epd.type = enumType.property(PROPERTY_TYPE).toString(); + epd.type = enumType.property(PROPERTY_TYPE()).toString(); //else it stays empty - epd.enumName = value.property(PROPERTY_ENUM_NAME).toString(); - epd.enumValuesObject = value.property(PROPERTY_ENUM_VALUES); + epd.enumName = value.property(PROPERTY_ENUM_NAME()).toString(); + epd.enumValuesObject = value.property(PROPERTY_ENUM_VALUES()); if (flags) return DataInformationFactory::newFlags(epd); else return DataInformationFactory::newEnum(epd); } StringDataInformation* toString(const QScriptValue& value, const ParserInfo& info) { StringParsedData spd(info); - spd.encoding = value.property(PROPERTY_ENCODING).toString(); - spd.termination = ParserUtils::uintFromScriptValue(value.property(PROPERTY_TERMINATED_BY)); - spd.maxByteCount = ParserUtils::uintFromScriptValue(value.property(PROPERTY_MAX_BYTE_COUNT)); - spd.maxCharCount = ParserUtils::uintFromScriptValue(value.property(PROPERTY_MAX_CHAR_COUNT)); + spd.encoding = value.property(PROPERTY_ENCODING()).toString(); + spd.termination = ParserUtils::uintFromScriptValue(value.property(PROPERTY_TERMINATED_BY())); + spd.maxByteCount = ParserUtils::uintFromScriptValue(value.property(PROPERTY_MAX_BYTE_COUNT())); + spd.maxCharCount = ParserUtils::uintFromScriptValue(value.property(PROPERTY_MAX_CHAR_COUNT())); return DataInformationFactory::newString(spd); } TaggedUnionDataInformation* toTaggedUnion(const QScriptValue& value, const ParserInfo& info) { TaggedUnionParsedData tpd(info); - QScriptValue alternatives = value.property(PROPERTY_ALTERNATIVES); + QScriptValue alternatives = value.property(PROPERTY_ALTERNATIVES()); if (!alternatives.isArray()) { info.error() << "Alternatives must be an array!"; return 0; } - int length = alternatives.property(PROPERTY_LENGTH).toInt32(); + int length = alternatives.property(PROPERTY_LENGTH()).toInt32(); for (int i = 0; i < length; ++i) { TaggedUnionParsedData::Alternatives alt; QScriptValue current = alternatives.property(i); - alt.name = current.property(PROPERTY_STRUCT_NAME).toString(); - alt.selectIf = current.property(PROPERTY_SELECT_IF); + alt.name = current.property(PROPERTY_STRUCT_NAME()).toString(); + alt.selectIf = current.property(PROPERTY_SELECT_IF()); alt.fields = QSharedPointer( - new ScriptValueChildrenParser(info, current.property(PROPERTY_CHILDREN))); + new ScriptValueChildrenParser(info, current.property(PROPERTY_CHILDREN()))); tpd.alternatives.append(alt); } - tpd.children.reset(new ScriptValueChildrenParser(info, value.property(PROPERTY_CHILDREN))); - tpd.defaultFields.reset(new ScriptValueChildrenParser(info, value.property(PROPERTY_DEFAULT_CHILDREN))); + tpd.children.reset(new ScriptValueChildrenParser(info, value.property(PROPERTY_CHILDREN()))); + tpd.defaultFields.reset(new ScriptValueChildrenParser(info, value.property(PROPERTY_DEFAULT_CHILDREN()))); return DataInformationFactory::newTaggedUnion(tpd); } } //namespace ScriptValueConverter ScriptValueConverter::ScriptValueChildrenParser::ScriptValueChildrenParser(const ParserInfo& info, const QScriptValue& children) : mValue(children), mIter(children), mInfo(info) { } ScriptValueConverter::ScriptValueChildrenParser::~ScriptValueChildrenParser() { } DataInformation* ScriptValueConverter::ScriptValueChildrenParser::next() { Q_ASSERT(hasNext()); mIter.next(); if (mValue.isArray() && mIter.name() == QStringLiteral("length")) mIter.next(); //skip length property mInfo.name = mIter.name(); return toDataInformation(mIter.value(), mInfo); } bool ScriptValueConverter::ScriptValueChildrenParser::hasNext() { if (!mIter.hasNext()) return false; if (mValue.isArray()) { //check if next element is length property mIter.next(); if (mIter.name() != QStringLiteral("length")) { mIter.previous(); //go back and return true return true; } else { return mIter.hasNext(); //skipped length } } else { return true; } } void ScriptValueConverter::ScriptValueChildrenParser::setParent(DataInformation* newParent) { mInfo.parent = newParent; } diff --git a/kasten/controllers/view/structures/script/classes/arrayscriptclass.cpp b/kasten/controllers/view/structures/script/classes/arrayscriptclass.cpp index e7d436f2..2486beba 100644 --- a/kasten/controllers/view/structures/script/classes/arrayscriptclass.cpp +++ b/kasten/controllers/view/structures/script/classes/arrayscriptclass.cpp @@ -1,174 +1,174 @@ /* * This file is part of the Okteta Kasten Framework, made within the KDE community. * * Copyright 2011, 2012 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "arrayscriptclass.h" #include "../../datatypes/array/arraydatainformation.h" #include "../../parsers/parserutils.h" #include "../../parsers/scriptvalueconverter.h" #include "../scriptlogger.h" #include "../../structlogging.h" ArrayScriptClass::ArrayScriptClass(QScriptEngine* engine, ScriptHandlerInfo* handlerInfo) : DefaultScriptClass(engine, handlerInfo) { - s_length = engine->toStringHandle(ParserStrings::PROPERTY_LENGTH); + s_length = engine->toStringHandle(ParserStrings::PROPERTY_LENGTH()); mIterableProperties.append(qMakePair(s_length, QScriptValue::PropertyFlags(QScriptValue::Undeletable))); s_childType = engine->toStringHandle(QStringLiteral("childType")); //the preferred property (the same as childType) - s_type = engine->toStringHandle(ParserStrings::PROPERTY_TYPE); + s_type = engine->toStringHandle(ParserStrings::PROPERTY_TYPE()); mIterableProperties.append(qMakePair(s_type, QScriptValue::PropertyFlags(QScriptValue::Undeletable))); mArrayPrototype = engine->newObject(); mArrayPrototype.setProperty(QStringLiteral("toString"), engine->newFunction(Array_proto_toString)); } ArrayScriptClass::~ArrayScriptClass() { } bool ArrayScriptClass::queryAdditionalProperty(const DataInformation* data, const QScriptString& name, QScriptClass::QueryFlags* flags, uint* id) { Q_UNUSED(data) //no need to modify flags since both read and write are handled if (name == s_length) return true; else if (name == s_type || name == s_childType) return true; else { bool isArrayIndex; quint32 pos = name.toArrayIndex(&isArrayIndex); if (isArrayIndex && pos <= data->childCount()) { *id = pos + 1; //add 1 to distinguish from the default value of 0 *flags &= ~HandlesWriteAccess; //writing is not yet supported return true; } } return false; //not found } bool ArrayScriptClass::additionalPropertyFlags(const DataInformation* data, const QScriptString& name, uint id, QScriptValue::PropertyFlags* flags) { Q_UNUSED(data) Q_UNUSED(name) if (name == s_childType) return true; //undeleteable is on by default if (id != 0) { *flags |= QScriptValue::ReadOnly; return true; } return false; } QScriptValue ArrayScriptClass::additionalProperty(const DataInformation* data, const QScriptString& name, uint id) { const ArrayDataInformation* aData = data->asArray(); if (id != 0) { quint32 pos = id - 1; if (pos >= data->childCount()) { aData->logError() << "attempting to access out of bounds child: index was" << pos << ", length is" << data->childCount(); return engine()->currentContext()->throwError(QScriptContext::RangeError, QString(QStringLiteral("Attempting to access array index %1, but length is %2")).arg( QString::number(pos), QString::number(data->childCount()))); } else { return aData->childToScriptValue(pos, engine(), mHandlerInfo); } } else if (name == s_length) return aData->length(); else if (name == s_type) return aData->childType(); else if (name == s_childType) { aData->logWarn() << "Using property 'childType' is deprecated, use the new name 'type' instead"; return aData->childType(); } return QScriptValue(); } bool ArrayScriptClass::setAdditionalProperty(DataInformation* data, const QScriptString& name, uint, const QScriptValue& value) { ArrayDataInformation* aData = data->asArray(); if (name == s_length) { if (value.isFunction()) { aData->setLengthFunction(value); } else { ParsedNumber newLength = ParserUtils::uintFromScriptValue(value); if (!newLength.isValid) { aData->logError() << "new length of array is invalid:" << newLength.string; aData->setArrayLength(0); } else { aData->setArrayLength(newLength.value); } } return true; } else if (name == s_type || name == s_childType) { if (name == s_childType) aData->logWarn() << "Using property 'childType' is deprecated, use the new name 'type' instead"; DataInformation* newChildType = ScriptValueConverter::convert(value, aData->name(), aData->logger(), aData); if (!newChildType) aData->logError() << "Failed to parse new child type:" << value.toString(); else aData->setArrayType(newChildType); return true; } return false; } QScriptValue ArrayScriptClass::prototype() const { return mArrayPrototype; } QScriptValue ArrayScriptClass::Array_proto_toString(QScriptContext* ctx, QScriptEngine* eng) { DataInformation* data = toDataInformation(ctx->thisObject()); if (!data) { qCWarning(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "could not cast data"; return eng->undefinedValue(); } return data->typeName(); } diff --git a/kasten/controllers/view/structures/script/classes/bitfieldscriptclass.cpp b/kasten/controllers/view/structures/script/classes/bitfieldscriptclass.cpp index 6164e34f..f5ea4090 100644 --- a/kasten/controllers/view/structures/script/classes/bitfieldscriptclass.cpp +++ b/kasten/controllers/view/structures/script/classes/bitfieldscriptclass.cpp @@ -1,83 +1,83 @@ /* * This file is part of the Okteta Kasten Framework, made within the KDE community. * * Copyright 2012 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "bitfieldscriptclass.h" #include "../../datatypes/primitive/bitfield/abstractbitfielddatainformation.h" #include "../../parsers/parserutils.h" BitfieldScriptClass::BitfieldScriptClass(QScriptEngine* engine, ScriptHandlerInfo* handlerInfo) : PrimitiveScriptClass(engine, handlerInfo) { - s_width = engine->toStringHandle(ParserStrings::PROPERTY_WIDTH); + s_width = engine->toStringHandle(ParserStrings::PROPERTY_WIDTH()); mIterableProperties.append(qMakePair(s_width, QScriptValue::PropertyFlags(QScriptValue::Undeletable))); } BitfieldScriptClass::~BitfieldScriptClass() { } QScriptValue BitfieldScriptClass::additionalProperty(const DataInformation* data, const QScriptString& name, uint id) { const AbstractBitfieldDataInformation* pData = data->asBitfield(); if (name == s_width) { return pData->width(); } else if (name == s_type) { return pData->typeName(); } return PrimitiveScriptClass::additionalProperty(data, name, id); } bool BitfieldScriptClass::queryAdditionalProperty(const DataInformation* data, const QScriptString& name, QScriptClass::QueryFlags* flags, uint* id) { if (name == s_width) { *flags = QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess; return true; } return PrimitiveScriptClass::queryAdditionalProperty(data, name, flags, id); } bool BitfieldScriptClass::setAdditionalProperty(DataInformation* data, const QScriptString& name, uint id, const QScriptValue& value) { if (name == s_width) { if (!value.isNumber()) { engine()->currentContext()->throwError(QScriptContext::TypeError, QStringLiteral("bitfield.width must be an integer!")); return true; } BitCount32 width = value.toUInt32(); if (width <= 0 || width > 64) { engine()->currentContext()->throwError(QScriptContext::RangeError, QString(QStringLiteral("bitfield.width must be between 1 and 64! Given: %1")).arg(width)); return true; } AbstractBitfieldDataInformation* pData = data->asBitfield(); pData->setWidth(width); return true; } return PrimitiveScriptClass::setAdditionalProperty(data, name, id, value); } diff --git a/kasten/controllers/view/structures/script/classes/defaultscriptclass.cpp b/kasten/controllers/view/structures/script/classes/defaultscriptclass.cpp index e4a4e85c..2c96e0e3 100644 --- a/kasten/controllers/view/structures/script/classes/defaultscriptclass.cpp +++ b/kasten/controllers/view/structures/script/classes/defaultscriptclass.cpp @@ -1,498 +1,498 @@ /* * This file is part of the Okteta Kasten Framework, made within the KDE community. * * Copyright 2011, 2012, 2013 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "defaultscriptclass.h" #include "../../datatypes/datainformation.h" #include "../../datatypes/topleveldatainformation.h" #include "../../datatypes/uniondatainformation.h" #include "../../datatypes/structuredatainformation.h" #include "../../datatypes/primitive/pointerdatainformation.h" #include "../../parsers/parserutils.h" #include "../../parsers/scriptvalueconverter.h" #include "../scriptlogger.h" #include "../scripthandlerinfo.h" #include "../safereference.h" #include "../../structlogging.h" DefaultScriptClass::DefaultScriptClass(QScriptEngine* engine, ScriptHandlerInfo* handlerInfo) : QScriptClass(engine), mHandlerInfo(handlerInfo) { - s_valid = engine->toStringHandle(ParserStrings::PROPERTY_VALID); - s_wasAbleToRead = engine->toStringHandle(ParserStrings::PROPERTY_ABLE_TO_READ); - s_validationError = engine->toStringHandle(ParserStrings::PROPERTY_VALIDATION_ERROR); - s_parent = engine->toStringHandle(ParserStrings::PROPERTY_PARENT); - s_byteOrder = engine->toStringHandle(ParserStrings::PROPERTY_BYTEORDER); - s_name = engine->toStringHandle(ParserStrings::PROPERTY_NAME); - s_datatype = engine->toStringHandle(ParserStrings::PROPERTY_DATATYPE); - s_updateFunc = engine->toStringHandle(ParserStrings::PROPERTY_UPDATE_FUNC); - s_validationFunc = engine->toStringHandle(ParserStrings::PROPERTY_VALIDATION_FUNC); - s_customTypeName = engine->toStringHandle(ParserStrings::PROPERTY_CUSTOM_TYPE_NAME); - s_asStringFunc = engine->toStringHandle(ParserStrings::PROPERTY_TO_STRING_FUNC); + s_valid = engine->toStringHandle(ParserStrings::PROPERTY_VALID()); + s_wasAbleToRead = engine->toStringHandle(ParserStrings::PROPERTY_ABLE_TO_READ()); + s_validationError = engine->toStringHandle(ParserStrings::PROPERTY_VALIDATION_ERROR()); + s_parent = engine->toStringHandle(ParserStrings::PROPERTY_PARENT()); + s_byteOrder = engine->toStringHandle(ParserStrings::PROPERTY_BYTEORDER()); + s_name = engine->toStringHandle(ParserStrings::PROPERTY_NAME()); + s_datatype = engine->toStringHandle(ParserStrings::PROPERTY_DATATYPE()); + s_updateFunc = engine->toStringHandle(ParserStrings::PROPERTY_UPDATE_FUNC()); + s_validationFunc = engine->toStringHandle(ParserStrings::PROPERTY_VALIDATION_FUNC()); + s_customTypeName = engine->toStringHandle(ParserStrings::PROPERTY_CUSTOM_TYPE_NAME()); + s_asStringFunc = engine->toStringHandle(ParserStrings::PROPERTY_TO_STRING_FUNC()); //TODO remove, every subclass should have proto mDefaultPrototype = engine->newObject(); mDefaultPrototype.setProperty(QStringLiteral("toString"), engine->newFunction(Default_proto_toString)); //add all our properties mIterableProperties.append(qMakePair(s_parent, QScriptValue::ReadOnly | QScriptValue::Undeletable)); mIterableProperties.append(qMakePair(s_name, QScriptValue::PropertyFlags(QScriptValue::Undeletable))); mIterableProperties.append(qMakePair(s_wasAbleToRead, QScriptValue::ReadOnly | QScriptValue::Undeletable)); mIterableProperties.append(qMakePair(s_byteOrder, QScriptValue::PropertyFlags(QScriptValue::Undeletable))); mIterableProperties.append(qMakePair(s_valid, QScriptValue::ReadOnly | QScriptValue::Undeletable)); mIterableProperties.append(qMakePair(s_validationError, QScriptValue::ReadOnly | QScriptValue::Undeletable)); mIterableProperties.append(qMakePair(s_validationFunc, QScriptValue::PropertyFlags(QScriptValue::Undeletable))); mIterableProperties.append(qMakePair(s_updateFunc, QScriptValue::PropertyFlags(QScriptValue::Undeletable))); mIterableProperties.append(qMakePair(s_datatype, QScriptValue::PropertyFlags(QScriptValue::Undeletable))); mIterableProperties.append(qMakePair(s_customTypeName, QScriptValue::PropertyFlags(QScriptValue::Undeletable))); mIterableProperties.append(qMakePair(s_asStringFunc, QScriptValue::PropertyFlags(QScriptValue::Undeletable))); } DefaultScriptClass::~DefaultScriptClass() { } DataInformation* DefaultScriptClass::toDataInformation(const QScriptValue& obj) { if (!obj.scriptClass()) return 0; Q_ASSERT(obj.data().isVariant()); const QVariant variant = obj.data().toVariant(); if (variant.isValid() && variant.canConvert() && variant.userType() == qMetaTypeId()) { const SafeReference& ref = *reinterpret_cast(variant.constData()); return ref.data(); } return 0; } QScriptClass::QueryFlags DefaultScriptClass::queryProperty(const QScriptValue& object, const QScriptString& name, QScriptClass::QueryFlags flags, uint* id) { const ScriptHandlerInfo::Mode mode = mHandlerInfo->mode(); Q_ASSERT(mode != ScriptHandlerInfo::None); DataInformation* data = toDataInformation(object); if (!data) { mHandlerInfo->logger()->error() << "could not cast data from" << object.data().toString(); engine()->currentContext()->throwError(QScriptContext::ReferenceError, QStringLiteral("Attempting to access an invalid object")); return 0; } if (name == s_valid || name == s_validationError) { return mode == ScriptHandlerInfo::Validating ? flags : flags & ~HandlesWriteAccess; } if (mode != ScriptHandlerInfo::Updating) { //the only properties that are possibly writable when not updating are valid and validationError //but we checked them before so we remove handlesWriteAccess from the flags flags &= ~HandlesWriteAccess; } if (name == s_byteOrder || name == s_name || name == s_updateFunc || name == s_validationFunc || name == s_datatype || name == s_customTypeName || name == s_asStringFunc) { return flags; } else if (name == s_wasAbleToRead || name == s_parent) { return flags & ~HandlesWriteAccess; } else if (queryAdditionalProperty(data, name, &flags, id)) { return flags; } else { data->logError() << "could not find property with name" << name.toString(); engine()->currentContext()->throwError(QScriptContext::ReferenceError, QStringLiteral("Could not find property with name ") + name.toString()); return 0; } } QScriptValue DefaultScriptClass::property(const QScriptValue& object, const QScriptString& name, uint id) { Q_ASSERT(mHandlerInfo->mode() != ScriptHandlerInfo::None); DataInformation* data = toDataInformation(object); if (!data) { mHandlerInfo->logger()->error() << "could not cast data from" << object.data().toString(); return engine()->currentContext()->throwError(QScriptContext::ReferenceError, QStringLiteral("Attempting to access an invalid object")); } if (name == s_valid) { return data->validationSuccessful(); } else if (name == s_wasAbleToRead) { return data->wasAbleToRead(); } else if (name == s_parent) { Q_CHECK_PTR(data->parent()); //parent() cannot be null if (data->parent()->isTopLevel()) return engine()->nullValue(); return data->parent()->asDataInformation()->toScriptValue(engine(), mHandlerInfo); } else if (name == s_datatype) { return data->typeName(); } else if (name == s_updateFunc) { return data->updateFunc(); } else if (name == s_validationFunc) { return data->validationFunc(); } else if (name == s_validationError) { return data->validationError(); } else if (name == s_byteOrder) { return ParserUtils::byteOrderToString(data->byteOrder()); } else if (name == s_name) { return data->name(); } else if (name == s_customTypeName) { return data->typeName(); } else if (name == s_asStringFunc) { return data->toStringFunction(); } QScriptValue other = additionalProperty(data, name, id); if (other.isValid()) return other; else { data->logError() << "could not find property with name" << name.toString(); return engine()->currentContext()->throwError(QScriptContext::ReferenceError, QStringLiteral("Cannot read property ") + name.toString()); } } void DefaultScriptClass::setDataType(const QScriptValue& value, DataInformation* data) { DataInformation* thisObj = toDataInformation(engine()->currentContext()->thisObject()); Q_CHECK_PTR(thisObj); const bool isThisObj = thisObj == data; //this object always has mHasBeenUpdated set just before calling updateFunc, so in that case it is okay if (data->hasBeenUpdated() && !isThisObj) { //this element has already been updated (and probably read, replacing it could cause crazy errors data->logError() << "Attempting to replace an already updated object. This could cause errors." "Current this object: " << (thisObj ? thisObj->fullObjectPath() : QString()); return; } //change the type of the underlying object DataInformation* newType = ScriptValueConverter::convert(value, data->name(), data->logger(), data); if (!newType) { data->logError() << "Failed to set new type, could not convert value!"; return; } DataInformationBase* parent = data->parent(); Q_CHECK_PTR(parent); TopLevelDataInformation* top = data->topLevelDataInformation(); Q_CHECK_PTR(top); //only if parent is toplevel, struct or union, can we replace bool replaced = false; if (parent->isTopLevel()) { Q_ASSERT(isThisObj); //we can only do this if we are currently at the top level element parent->asTopLevel()->setActualDataInformation(newType); replaced = true; } else if (parent->isStruct()) { StructureDataInformation* stru = parent->asStruct(); int index = stru->indexOf(data); Q_ASSERT(index != -1); Q_ASSERT(uint(index) < stru->childCount()); replaced = stru->replaceChildAt(index, newType); if (!replaced) stru->logError() << "failed to replace child at index" << index; } else if (parent->isUnion()) { UnionDataInformation* un = parent->asUnion(); int index = un->indexOf(data); Q_ASSERT(index != -1); Q_ASSERT(uint(index) < un->childCount()); replaced = un->replaceChildAt(index, newType); if (!replaced) un->logError() << "failed to replace child at index" << index; } else if (parent->isPointer()) { parent->asPointer()->setPointerTarget(newType); replaced = true; } else { data->logError() << "Failed to set data type since element is not toplevel and parent" " is neither struct nor union nor pointer."; } if (replaced) { top->setChildDataChanged(); //if the current object was "this" in javascript we have to replace it if (isThisObj) engine()->currentContext()->setThisObject(newType->toScriptValue(engine(), mHandlerInfo)); newType->mHasBeenUpdated = true; } else { delete newType; //could not set new type } } void DefaultScriptClass::setProperty(QScriptValue& object, const QScriptString& name, uint id, const QScriptValue& value) { const ScriptHandlerInfo::Mode mode = mHandlerInfo->mode(); Q_ASSERT(mode != ScriptHandlerInfo::None); DataInformation* data = toDataInformation(object); if (!data) { mHandlerInfo->logger()->error() << "could not cast data from" << object.data().toString(); engine()->currentContext()->throwError(QScriptContext::ReferenceError, QStringLiteral("Attempting to access an invalid object")); return; } if (mode == ScriptHandlerInfo::Validating) { //only way write access is allowed is when validating: valid and validationError if (data->hasBeenValidated()) data->logError() << "Cannot modify this object, it has already been validated!"; else if (name == s_valid) data->mValidationSuccessful = value.toBool(); else if (name == s_validationError) data->setValidationError(value.toString()); else data->logError() << "Cannot write to property" << name.toString() << "while validating!"; return; } if (mode != ScriptHandlerInfo::Updating) { data->logError() << "Writing to property" << name.toString() << "is only allowed when updating."; return; } Q_ASSERT(mode == ScriptHandlerInfo::Updating); if (name == s_byteOrder) { data->setByteOrder(ParserUtils::byteOrderFromString(value.toString(), LoggerWithContext(data->logger(), data->fullObjectPath()))); } else if (name == s_datatype) { //change the type of the underlying object setDataType(value, data); } else if (name == s_updateFunc) { data->setUpdateFunc(value); } else if (name == s_validationFunc) { data->setValidationFunc(value); } else if (name == s_name) { data->setName(value.toString()); } else if (name == s_customTypeName) { if (!value.isValid() || value.isNull() || value.isUndefined()) data->setCustomTypeName(QString()); //unset else data->setCustomTypeName(value.toString()); } else if (name == s_asStringFunc) { data->setToStringFunction(value); } else { bool setAdditional = setAdditionalProperty(data, name, id, value); if (setAdditional) return; else { data->logError() << "could not set property with name" << name.toString(); engine()->currentContext()->throwError(QScriptContext::ReferenceError, QStringLiteral("Cannot write property ") + name.toString()); } } } QScriptValue::PropertyFlags DefaultScriptClass::propertyFlags(const QScriptValue& object, const QScriptString& name, uint id) { QScriptValue::PropertyFlags result; const ScriptHandlerInfo::Mode mode = mHandlerInfo->mode(); Q_ASSERT(mode != ScriptHandlerInfo::None); DataInformation* data = toDataInformation(object); if (!data) { mHandlerInfo->logger()->error() << "could not cast data from" << object.data().toString(); engine()->currentContext()->throwError(QScriptContext::ReferenceError, QStringLiteral("Attempting to access an invalid object")); return 0; } if (name == s_valid || name == s_validationError) { if (mode != ScriptHandlerInfo::Validating) result |= QScriptValue::ReadOnly; } else if (mode != ScriptHandlerInfo::Updating) { result |= QScriptValue::ReadOnly; } for (int i = 0, size = mIterableProperties.size(); i < size; ++i) { if (mIterableProperties.at(i).first == name) return result | mIterableProperties.at(i).second; } if (additionalPropertyFlags(data, name, id, &result)) return result; //is a child element else { data->logError() << "could not find flags for property with name" << name.toString(); return 0; } } QScriptValue DefaultScriptClass::prototype() const { return mDefaultPrototype; } QScriptValue DefaultScriptClass::Default_proto_toString(QScriptContext* ctx, QScriptEngine* eng) { DataInformation* data = toDataInformation(ctx->thisObject()); if (!data) { qCWarning(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "could not cast data"; return eng->undefinedValue(); } return QString(data->typeName() + QLatin1Char(' ') + data->name()); } QScriptClassPropertyIterator* DefaultScriptClass::newIterator(const QScriptValue& object) { return new DefaultscriptClassIterator(object, this); } DefaultscriptClassIterator::DefaultscriptClassIterator(const QScriptValue& object, DefaultScriptClass* cls) : QScriptClassPropertyIterator(object), mCurrent(-1), mClass(cls) { DataInformation* data = DefaultScriptClass::toDataInformation(object); Q_CHECK_PTR(data); mData = data; } DefaultscriptClassIterator::~DefaultscriptClassIterator() { } bool DefaultscriptClassIterator::hasNext() const { return mCurrent < mClass->mIterableProperties.size() - 1; } bool DefaultscriptClassIterator::hasPrevious() const { return mCurrent > 0; } QScriptString DefaultscriptClassIterator::name() const { Q_ASSERT(mCurrent >= 0 && (uint)mCurrent < mClass->mIterableProperties.size() + mData->childCount()); if (mCurrent < 0 || (uint)mCurrent >= mClass->mIterableProperties.size() + mData->childCount()) return QScriptString(); if (mCurrent < mClass->mIterableProperties.size()) return mClass->mIterableProperties.at(mCurrent).first; int index = mCurrent - mClass->mIterableProperties.size(); Q_ASSERT(index >= 0); DataInformation* child = mData->childAt(index); return mClass->engine()->toStringHandle(child->name()); } QScriptValue::PropertyFlags DefaultscriptClassIterator::flags() const { Q_ASSERT(mCurrent >= 0 && (uint)mCurrent < mClass->mIterableProperties.size() + mData->childCount()); if (mCurrent < 0 || (uint)mCurrent >= mClass->mIterableProperties.size() + mData->childCount()) return 0; if (mCurrent < mClass->mIterableProperties.size()) return mClass->propertyFlags(object(), mClass->mIterableProperties.at(mCurrent).first, id()); return QScriptValue::ReadOnly; } uint DefaultscriptClassIterator::id() const { Q_ASSERT(mCurrent >= 0 && (uint)mCurrent < mClass->mIterableProperties.size() + mData->childCount()); if (mCurrent < 0 || (uint)mCurrent >= mClass->mIterableProperties.size() + mData->childCount()) return 0; //only children have an id assigned if (mCurrent < mClass->mIterableProperties.size()) return 0; return mCurrent - mClass->mIterableProperties.size() + 1; } void DefaultscriptClassIterator::next() { Q_ASSERT(mCurrent == -1 || (uint)mCurrent < mClass->mIterableProperties.size() + mData->childCount()); mCurrent++; } void DefaultscriptClassIterator::previous() { Q_ASSERT(mCurrent >= 0); mCurrent--; } void DefaultscriptClassIterator::toBack() { mCurrent = mClass->mIterableProperties.size() + mData->childCount(); } void DefaultscriptClassIterator::toFront() { mCurrent = -1; } diff --git a/kasten/controllers/view/structures/script/classes/enumscriptclass.cpp b/kasten/controllers/view/structures/script/classes/enumscriptclass.cpp index 9196c322..caf8b007 100644 --- a/kasten/controllers/view/structures/script/classes/enumscriptclass.cpp +++ b/kasten/controllers/view/structures/script/classes/enumscriptclass.cpp @@ -1,85 +1,85 @@ /* * This file is part of the Okteta Kasten Framework, made within the KDE community. * * Copyright 2012 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "enumscriptclass.h" #include "../../datatypes/primitive/enumdatainformation.h" #include "../../parsers/parserutils.h" #include "../scriptlogger.h" EnumScriptClass::EnumScriptClass(QScriptEngine* engine, ScriptHandlerInfo* handlerInfo) : PrimitiveScriptClass(engine, handlerInfo) { - s_values = engine->toStringHandle(ParserStrings::PROPERTY_ENUM_VALUES); + s_values = engine->toStringHandle(ParserStrings::PROPERTY_ENUM_VALUES()); mIterableProperties.append(qMakePair(s_values, QScriptValue::PropertyFlags(QScriptValue::Undeletable))); } EnumScriptClass::~EnumScriptClass() { } QScriptValue EnumScriptClass::additionalProperty(const DataInformation* data, const QScriptString& name, uint id) { if (name == s_values) { const EnumDataInformation* pData = data->asEnum(); QScriptValue ret = engine()->newObject(); QMapIterator it(pData-> enumValues()->values()); while(it.hasNext()) { it.next(); ret.setProperty(it.value(), QString::number(it.key().value())); //should always work } return ret; } else if (name == s_type) { return data->typeName(); } return PrimitiveScriptClass::additionalProperty(data, name, id); } bool EnumScriptClass::queryAdditionalProperty(const DataInformation* data, const QScriptString& name, QScriptClass::QueryFlags* flags, uint* id) { if (name == s_values) { *flags = QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess; return true; } return PrimitiveScriptClass::queryAdditionalProperty(data, name, flags, id); } bool EnumScriptClass::setAdditionalProperty(DataInformation* data, const QScriptString& name, uint id, const QScriptValue& value) { if (name == s_values) { EnumDataInformation* pData = data->asEnum(); QMap newValues = EnumDefinition::parseEnumValues(value, LoggerWithContext(pData->logger(), pData->fullObjectPath()) , pData->type()); if (newValues.isEmpty()) pData->logWarn() << "attempting to set empty list of enum values!"; pData->setEnumValues(newValues); return true; } return PrimitiveScriptClass::setAdditionalProperty(data, name, id, value); } diff --git a/kasten/controllers/view/structures/script/classes/pointerscriptclass.cpp b/kasten/controllers/view/structures/script/classes/pointerscriptclass.cpp index 449db139..f3c99562 100644 --- a/kasten/controllers/view/structures/script/classes/pointerscriptclass.cpp +++ b/kasten/controllers/view/structures/script/classes/pointerscriptclass.cpp @@ -1,94 +1,94 @@ /* * This file is part of the Okteta Kasten Framework, made within the KDE community. * * Copyright 2012 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "pointerscriptclass.h" #include "../../datatypes/primitive/pointerdatainformation.h" #include "../../parsers/parserutils.h" #include "../../parsers/scriptvalueconverter.h" PointerScriptClass::PointerScriptClass(QScriptEngine* engine, ScriptHandlerInfo* handlerInfo) : PrimitiveScriptClass(engine, handlerInfo) { - s_type = engine->toStringHandle(ParserStrings::PROPERTY_TYPE); + s_type = engine->toStringHandle(ParserStrings::PROPERTY_TYPE()); mIterableProperties.append(qMakePair(s_type, QScriptValue::PropertyFlags(QScriptValue::Undeletable))); - s_target = engine->toStringHandle(ParserStrings::PROPERTY_TARGET); + s_target = engine->toStringHandle(ParserStrings::PROPERTY_TARGET()); mIterableProperties.append(qMakePair(s_type, QScriptValue::PropertyFlags(QScriptValue::Undeletable))); } PointerScriptClass::~PointerScriptClass() { } QScriptValue PointerScriptClass::additionalProperty(const DataInformation* data, const QScriptString& name, uint id) { Q_ASSERT(data->isPointer()); if (name == s_type) { return PrimitiveType::standardTypeName(data->asPointer()->pointerType()->type()); } else if (name == s_target) { return data->asPointer()->pointerTarget()->toScriptValue(engine(), mHandlerInfo); } return PrimitiveScriptClass::additionalProperty(data, name, id); } bool PointerScriptClass::queryAdditionalProperty(const DataInformation* data, const QScriptString& name, QScriptClass::QueryFlags* flags, uint* id) { if (name == s_type || name == s_target) { *flags = QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess; return true; } return PrimitiveScriptClass::queryAdditionalProperty(data, name, flags, id); } bool PointerScriptClass::setAdditionalProperty(DataInformation* data, const QScriptString& name, uint id, const QScriptValue& value) { if (name == s_type) { DataInformation* newType = ScriptValueConverter::convert(value, QStringLiteral("(pointer value)"), data->logger(), data); if (!newType) data->logError() << "Could not set new pointer type."; else if (!data->asPointer()->setPointerType(newType)) delete newType; return true; } if (name == s_target) { DataInformation* newTarget = ScriptValueConverter::convert(value, QStringLiteral("(pointer value)"), data->logger(), data); if (!newTarget) data->logError() << "Could not set new pointer target."; else data->asPointer()->setPointerTarget(newTarget); return true; } return PrimitiveScriptClass::setAdditionalProperty(data, name, id, value); } diff --git a/kasten/controllers/view/structures/script/classes/stringscriptclass.cpp b/kasten/controllers/view/structures/script/classes/stringscriptclass.cpp index 7db037db..ba3fdf35 100644 --- a/kasten/controllers/view/structures/script/classes/stringscriptclass.cpp +++ b/kasten/controllers/view/structures/script/classes/stringscriptclass.cpp @@ -1,232 +1,232 @@ /* * This file is part of the Okteta Kasten Framework, made within the KDE community. * * Copyright 2011, 2012 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "stringscriptclass.h" #include "../../datatypes/strings/stringdatainformation.h" #include "../../parsers/parserutils.h" #include "../../structlogging.h" StringScriptClass::StringScriptClass(QScriptEngine* eng, ScriptHandlerInfo* handlerInfo) : DefaultScriptClass(eng, handlerInfo) { //read-only properties - s_lengthInCodepoints = eng->toStringHandle(ParserStrings::PROPERTY_CHAR_COUNT); + s_lengthInCodepoints = eng->toStringHandle(ParserStrings::PROPERTY_CHAR_COUNT()); mIterableProperties.append(qMakePair(s_lengthInCodepoints, QScriptValue::ReadOnly | QScriptValue::Undeletable)); - s_lengthInBytes = eng->toStringHandle(ParserStrings::PROPERTY_BYTE_COUNT); + s_lengthInBytes = eng->toStringHandle(ParserStrings::PROPERTY_BYTE_COUNT()); mIterableProperties.append(qMakePair(s_lengthInBytes, QScriptValue::ReadOnly | QScriptValue::Undeletable)); //read-write properties - s_maxByteCount = eng->toStringHandle(ParserStrings::PROPERTY_MAX_BYTE_COUNT); + s_maxByteCount = eng->toStringHandle(ParserStrings::PROPERTY_MAX_BYTE_COUNT()); mIterableProperties.append(qMakePair(s_maxByteCount, QScriptValue::PropertyFlags(QScriptValue::Undeletable))); - s_maxCharCount = eng->toStringHandle(ParserStrings::PROPERTY_MAX_CHAR_COUNT); + s_maxCharCount = eng->toStringHandle(ParserStrings::PROPERTY_MAX_CHAR_COUNT()); mIterableProperties.append(qMakePair(s_maxCharCount, QScriptValue::PropertyFlags(QScriptValue::Undeletable))); - s_terminatedBy = eng->toStringHandle(ParserStrings::PROPERTY_TERMINATED_BY); + s_terminatedBy = eng->toStringHandle(ParserStrings::PROPERTY_TERMINATED_BY()); mIterableProperties.append(qMakePair(s_terminatedBy, QScriptValue::PropertyFlags(QScriptValue::Undeletable))); - s_encoding = eng->toStringHandle(ParserStrings::PROPERTY_ENCODING); + s_encoding = eng->toStringHandle(ParserStrings::PROPERTY_ENCODING()); mIterableProperties.append(qMakePair(s_encoding, QScriptValue::PropertyFlags(QScriptValue::Undeletable))); mStringPrototype = eng->newObject(); mStringPrototype.setProperty(QStringLiteral("toString"), eng->newFunction(String_proto_toString)); } StringScriptClass::~StringScriptClass() { } bool StringScriptClass::queryAdditionalProperty(const DataInformation* data, const QScriptString& name, QScriptClass::QueryFlags* flags, uint* id) { Q_UNUSED(data) //no need to modify flags since both read and write are handled if (name == s_maxByteCount || name == s_maxCharCount || name == s_terminatedBy || name == s_encoding) return true; else if (name == s_lengthInCodepoints || name == s_lengthInBytes) { *flags &= ~HandlesWriteAccess; return true; } else { bool isArrayIndex; quint32 pos = name.toArrayIndex(&isArrayIndex); if (isArrayIndex && pos <= uint(data->asString()->stringLength())) { *id = pos + 1; //add 1 to distinguish from the default value of 0 *flags &= ~HandlesWriteAccess; //writing is not yet supported return true; } } return false; //not found } bool StringScriptClass::additionalPropertyFlags(const DataInformation* data, const QScriptString& name, uint id, QScriptValue::PropertyFlags* flags) { Q_UNUSED(data) Q_UNUSED(name) if (id != 0 ) { *flags |= QScriptValue::ReadOnly; return true; } return false; } QScriptValue StringScriptClass::additionalProperty(const DataInformation* data, const QScriptString& name, uint id) { const StringDataInformation* sData = data->asString(); if (id != 0) { quint32 pos = id - 1; if (pos >= uint(sData->stringLength())) { return engine()->currentContext()->throwError(QScriptContext::RangeError, QString(QStringLiteral("Attempting to access string index %1, but length is %2")).arg( QString::number(pos), QString::number(sData->stringLength()))); } else { return sData->valueAt(pos); } } else if (name == s_lengthInCodepoints) return sData->stringLength(); else if (name == s_lengthInBytes) return sData->stringByteLength(); else if (name == s_encoding) return stringEncodings[sData->encoding()]; else if (name == s_maxCharCount) return sData->maxCharCount(); else if (name == s_maxByteCount) return sData->maxByteCount(); else if (name == s_terminatedBy) return sData->terminationCodePoint(); return QScriptValue(); } bool StringScriptClass::setAdditionalProperty(DataInformation* data, const QScriptString& name, uint, const QScriptValue& value) { StringDataInformation* sData = data->asString(); if (name == s_maxCharCount) { if (value.isNull()) { sData->logInfo() << "Unsetting max char count."; sData->unsetTerminationMode(StringData::CharCount); } else { ParsedNumber result = ParserUtils::uintFromScriptValue(value); if (result.isValid) sData->setMaxCharCount(result.value); else sData->logError() << "Could not set maximum char count, invalid argument: " << value.toString(); } return true; } else if (name == s_maxByteCount) { if (value.isNull()) { sData->logInfo() << "Unsetting max byte count."; sData->unsetTerminationMode(StringData::ByteCount); } else { ParsedNumber result = ParserUtils::uintFromScriptValue(value); if (result.isValid) sData->setMaxByteCount(result.value); else sData->logError() << "Could not set maximum byte count, invalid argument: " << value.toString(); } return true; } else if (name == s_terminatedBy) { if (value.isNull()) { sData->logInfo() << "Unsetting termination character."; sData->unsetTerminationMode(StringData::Sequence); } else { if (value.isString()) { QString str = value.toString(); //we don't handle surrogate pairs, if you want to set that use a number instead. if (str.length() != 1) sData->logError() << "Setting termination char: expected one char or a code point number" ", got a string with length " << str.length(); else sData->setTerminationCodePoint(str[0].unicode()); } else { ParsedNumber result = ParserUtils::uintFromScriptValue(value); if (result.isValid) sData->setTerminationCodePoint(result.value); else sData->logError() << "Could not set maximum byte count, invalid argument: " << value.toString(); } } return true; } else if (name == s_encoding) { QString enc = value.toString(); StringDataInformation::StringType encoding = ParserUtils::toStringEncoding(enc, LoggerWithContext(sData->logger(), sData->fullObjectPath())); if (encoding == StringDataInformation::InvalidEncoding) sData->logError() << "Attempting to set invalid encoding:" << enc; else sData->setEncoding(encoding); return true; } return false; } QScriptValue StringScriptClass::prototype() const { return mStringPrototype; } QScriptValue StringScriptClass::String_proto_toString(QScriptContext* ctx, QScriptEngine* eng) { DataInformation* data = toDataInformation(ctx->thisObject().data()); if (!data) { qCWarning(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "could not cast data"; return eng->undefinedValue(); } return data->wasAbleToRead() ? data->valueString() : eng->undefinedValue(); } diff --git a/kasten/controllers/view/structures/script/classes/structunionscriptclass.cpp b/kasten/controllers/view/structures/script/classes/structunionscriptclass.cpp index ab2c8c28..535bd776 100644 --- a/kasten/controllers/view/structures/script/classes/structunionscriptclass.cpp +++ b/kasten/controllers/view/structures/script/classes/structunionscriptclass.cpp @@ -1,260 +1,260 @@ /* * This file is part of the Okteta Kasten Framework, made within the KDE community. * * Copyright 2011, 2012 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "structunionscriptclass.h" #include "../../datatypes/datainformationwithchildren.h" #include "../../datatypes/topleveldatainformation.h" #include "../../parsers/parserutils.h" #include "../scriptlogger.h" #include "../../structlogging.h" StructUnionScriptClass::StructUnionScriptClass(QScriptEngine* engine, ScriptHandlerInfo* handlerInfo) : DefaultScriptClass(engine, handlerInfo) { - s_childCount = engine->toStringHandle(ParserStrings::PROPERTY_CHILD_COUNT); //read-only + s_childCount = engine->toStringHandle(ParserStrings::PROPERTY_CHILD_COUNT()); //read-only mIterableProperties.append(qMakePair(s_childCount, QScriptValue::ReadOnly | QScriptValue::Undeletable)); - s_children = engine->toStringHandle(ParserStrings::PROPERTY_CHILDREN); //write-only + s_children = engine->toStringHandle(ParserStrings::PROPERTY_CHILDREN()); //write-only mStructUnionPrototype = engine->newObject(); mStructUnionPrototype.setProperty(QStringLiteral("toString"), engine->newFunction(StructUnion_proto_toString)); mStructUnionPrototype.setProperty(QStringLiteral("setChildren"), engine->newFunction(StructUnion_proto_setChildren)); mStructUnionPrototype.setProperty(QStringLiteral("child"), engine->newFunction(StructUnion_proto_child)); } StructUnionScriptClass::~StructUnionScriptClass() { } bool StructUnionScriptClass::queryAdditionalProperty(const DataInformation* data, const QScriptString& name, QScriptClass::QueryFlags* flags, uint* id) { Q_UNUSED(data) //no need to modify flags since both read and write are handled if (name == s_childCount) { *flags &= ~HandlesWriteAccess; return true; } else if (name == s_children) { *flags &= ~HandlesReadAccess; return true; } else { bool isArrayIndex; quint32 pos = name.toArrayIndex(&isArrayIndex); uint count = data->childCount(); bool isValidChild = false; if (isArrayIndex && pos < count) { isValidChild = true; } else { //compare name, names that match special properties/functions will be //hidden since these were checked before QString objName = name.toString(); for (uint i = 0 ; i < count; ++i) { if (objName == data->childAt(i)->name()) { isValidChild = true; pos = i; break; } } } if (isValidChild) { *id = pos + 1; //add 1 to distinguish from the default value of 0 *flags &= ~HandlesWriteAccess; //writing is not yet supported return true; } } return false; //not found } bool StructUnionScriptClass::additionalPropertyFlags(const DataInformation* data, const QScriptString& name, uint id, QScriptValue::PropertyFlags* flags) { Q_UNUSED(data) //no need to modify flags since both read and write are handled if (id != 0) { *flags |= QScriptValue::ReadOnly; return true; } //TODO is this necessary, will there be any way a child has no id set? //check named children QString objName = name.toString(); uint count = data->childCount(); for (uint i = 0 ; i < count; ++i) { DataInformation* child = data->childAt(i); Q_CHECK_PTR(child); if (objName == child->name()) { *flags |= QScriptValue::ReadOnly; return true; } } return false; } QScriptValue StructUnionScriptClass::additionalProperty(const DataInformation* data, const QScriptString& name, uint id) { const DataInformationWithChildren* dataW = static_cast(data); //do a dynamic cast in debug mode to ensure the static cast was valid Q_CHECK_PTR(dynamic_cast(dataW)); if (id != 0) { quint32 pos = id - 1; if (pos >= data->childCount()) { dataW->logError() << "attempting to access out of bounds child: index was" << pos << ", maximum is" << (data->childCount() - 1); return engine()->currentContext()->throwError(QScriptContext::RangeError, QString(QStringLiteral("Attempting to access struct index %1, but length is %2")).arg( QString::number(pos), QString::number(data->childCount()))); } else { Q_CHECK_PTR(data->childAt(pos)); return data->childAt(pos)->toScriptValue(engine(), mHandlerInfo); } } else if (name == s_childCount) return dataW->childCount(); else if (name == s_children) { dataW->logError() << "attempting to read read-only property" << s_children.toString(); return engine()->undefinedValue(); } else { //TODO is this necessary, will there be any way a child has no id set? //TODO testing seems to indicate this is not necessary, will leave it thought until I'm sure //check named children QString objName = name.toString(); uint count = data->childCount(); for (uint i = 0 ; i < count; ++i) { DataInformation* child = data->childAt(i); Q_CHECK_PTR(child); if (objName == child->name()) { return child->toScriptValue(engine(), mHandlerInfo); } } } return QScriptValue(); } bool StructUnionScriptClass::setAdditionalProperty(DataInformation* data, const QScriptString& name, uint, const QScriptValue& value) { DataInformationWithChildren* dataW = static_cast(data); //do a dynamic cast in debug mode to ensure the static cast was valid Q_CHECK_PTR(dynamic_cast(dataW)); if (name == s_children) { dataW->setChildren(value); return true; } //TODO set children!! return false; } QScriptValue StructUnionScriptClass::prototype() const { return mStructUnionPrototype; } QScriptValue StructUnionScriptClass::StructUnion_proto_toString(QScriptContext* ctx, QScriptEngine* eng) { DataInformation* data = toDataInformation(ctx->thisObject()); if (!data) { qCWarning(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "could not cast data"; return eng->undefinedValue(); } return data->typeName(); //TODO better toString } QScriptValue StructUnionScriptClass::StructUnion_proto_child(QScriptContext* ctx, QScriptEngine* eng) { if (ctx->argumentCount() < 1) { ctx->throwError(QScriptContext::RangeError, QStringLiteral("(struct/union).child(name) needs at least one argument")); return eng->undefinedValue(); } QScriptValue arg = ctx->argument(0); if (!arg.isString()) { ctx->throwError(QScriptContext::TypeError, QStringLiteral("(struct/union).child(name) argument has to be a string")); return QScriptValue::UndefinedValue; } DataInformation* data = toDataInformation(ctx->thisObject()); if (!data) { qCWarning(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "could not cast data"; return eng->undefinedValue(); } uint count = data->childCount(); QString name = arg.toString(); for (uint i = 0; i < count; i++) { DataInformation* child = data->childAt(i); if (child->name() == name) return child->toScriptValue(eng, data->topLevelDataInformation()->scriptHandler()->handlerInfo()); } return eng->nullValue(); } QScriptValue StructUnionScriptClass::StructUnion_proto_setChildren(QScriptContext* ctx, QScriptEngine* eng) { if (ctx->argumentCount() < 1) { return ctx->throwError(QScriptContext::RangeError, QStringLiteral("(struct/union).child(children) needs one argument")); } DataInformation* data = toDataInformation(ctx->thisObject()); if (!data) { qCWarning(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "could not cast data"; return eng->undefinedValue(); } DataInformationWithChildren* dataW = static_cast(data); //do a dynamic cast in debug mode to ensure the static cast was valid Q_CHECK_PTR(dynamic_cast(dataW)); dataW->setChildren(ctx->argument(0)); return eng->undefinedValue(); } diff --git a/kasten/controllers/view/structures/script/scriptengineinitializer.cpp b/kasten/controllers/view/structures/script/scriptengineinitializer.cpp index 2a884f4a..7ee16e0e 100644 --- a/kasten/controllers/view/structures/script/scriptengineinitializer.cpp +++ b/kasten/controllers/view/structures/script/scriptengineinitializer.cpp @@ -1,358 +1,358 @@ /* * This file is part of the Okteta Kasten Framework, made within the KDE community. * * Copyright 2010, 2011, 2012, 2013 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "scriptengineinitializer.h" #include "scriptutils.h" #include "../datatypes/primitivefactory.h" #include "../parsers/parserutils.h" #include #include #include #include #include #include #include namespace ScriptEngineInitializer { void addFuctionsToScriptEngine(QScriptEngine* engine) { engine->globalObject().setProperty(QStringLiteral("uint8"), engine->newFunction(Private::scriptNewUInt8)); engine->globalObject().setProperty(QStringLiteral("uint16"), engine->newFunction(Private::scriptNewUInt16)); engine->globalObject().setProperty(QStringLiteral("uint32"), engine->newFunction(Private::scriptNewUInt32)); engine->globalObject().setProperty(QStringLiteral("uint64"), engine->newFunction(Private::scriptNewUInt64)); engine->globalObject().setProperty(QStringLiteral("int8"), engine->newFunction(Private::scriptNewInt8)); engine->globalObject().setProperty(QStringLiteral("int16"), engine->newFunction(Private::scriptNewInt16)); engine->globalObject().setProperty(QStringLiteral("int32"), engine->newFunction(Private::scriptNewInt32)); engine->globalObject().setProperty(QStringLiteral("int64"), engine->newFunction(Private::scriptNewInt64)); engine->globalObject().setProperty(QStringLiteral("bool8"), engine->newFunction(Private::scriptNewBool8)); engine->globalObject().setProperty(QStringLiteral("bool16"), engine->newFunction(Private::scriptNewBool16)); engine->globalObject().setProperty(QStringLiteral("bool32"), engine->newFunction(Private::scriptNewBool32)); engine->globalObject().setProperty(QStringLiteral("bool64"), engine->newFunction(Private::scriptNewBool64)); engine->globalObject().setProperty(QStringLiteral("float"), engine->newFunction(Private::scriptNewFloat)); engine->globalObject().setProperty(QStringLiteral("double"), engine->newFunction(Private::scriptNewDouble)); engine->globalObject().setProperty(QStringLiteral("char"), engine->newFunction(Private::scriptNewChar)); engine->globalObject().setProperty(QStringLiteral("bitfield"), engine->newFunction(Private::scriptNewBitfield)); engine->globalObject().setProperty(QStringLiteral("array"), engine->newFunction(Private::scriptNewArray)); engine->globalObject().setProperty(QStringLiteral("struct"), engine->newFunction(Private::scriptNewStruct)); engine->globalObject().setProperty(QStringLiteral("union"), engine->newFunction(Private::scriptNewUnion)); //enum is a reserved keyword in JavaScript, cannot use it engine->globalObject().setProperty(QStringLiteral("enumeration"), engine->newFunction(Private::scriptNewEnum)); engine->globalObject().setProperty(QStringLiteral("flags"), engine->newFunction(Private::scriptNewFlags)); engine->globalObject().setProperty(QStringLiteral("string"), engine->newFunction(Private::scriptNewString)); engine->globalObject().setProperty(QStringLiteral("pointer"), engine->newFunction(Private::scriptNewPointer)); engine->globalObject().setProperty(QStringLiteral("taggedUnion"), engine->newFunction(Private::scriptNewTaggedUnion)); engine->globalObject().setProperty(QStringLiteral("alternative"), engine->newFunction(Private::alternativeFunc)); engine->globalObject().setProperty(QStringLiteral("importScript"), engine->newFunction(Private::importScriptFunc)); } QScriptEngine* newEngine() { QScriptEngine* ret = new QScriptEngine(); addFuctionsToScriptEngine(ret); return ret; } namespace Private { -static const QString setUpdatePropertyString = QStringLiteral("setUpdate"); -static const QString setValidationPropertyString = QStringLiteral("setValidation"); -static const QString setPropertyString = QStringLiteral("set"); +QString setUpdatePropertyName() { return QStringLiteral("setUpdate"); } +QString setValidationPropertyName() { return QStringLiteral("setValidation"); } +QString setPropertyName() { return QStringLiteral("set"); } namespace { QScriptValue scriptNewCommon(QScriptContext* ctx, QScriptEngine* eng, const QString& typeName) { QScriptValue object = ctx->isCalledAsConstructor() ? ctx->thisObject() : eng->newObject(); - object.setProperty(ParserStrings::PROPERTY_INTERNAL_TYPE, typeName); + object.setProperty(ParserStrings::PROPERTY_INTERNAL_TYPE(), typeName); //add the setUpdate() and setValidation() functions - object.setProperty(setUpdatePropertyString, eng->newFunction(addUpdateFunc, 1)); - object.setProperty(setValidationPropertyString, eng->newFunction(addValidationFunc, 1)); - object.setProperty(setPropertyString, eng->newFunction(addCustomPropertiesFunc, 1)); + object.setProperty(setUpdatePropertyName(), eng->newFunction(addUpdateFunc, 1)); + object.setProperty(setValidationPropertyName(), eng->newFunction(addValidationFunc, 1)); + object.setProperty(setPropertyName(), eng->newFunction(addCustomPropertiesFunc, 1)); return object; } /** create a new primitive of type @p type */ QScriptValue primitiveConstructor(QScriptContext* ctx, QScriptEngine* eng, const QString& type) { - QScriptValue object = scriptNewCommon(ctx, eng, ParserStrings::TYPE_PRIMITIVE); - object.setProperty(ParserStrings::PROPERTY_TYPE, type); + QScriptValue object = scriptNewCommon(ctx, eng, ParserStrings::TYPE_PRIMITIVE()); + object.setProperty(ParserStrings::PROPERTY_TYPE(), type); return object; } } #define PRIMITIVE_CONSTRUCTOR(type) QScriptValue scriptNew##type(QScriptContext* ctx, QScriptEngine* eng) \ { return primitiveConstructor(ctx, eng, QStringLiteral(#type)); } PRIMITIVE_CONSTRUCTOR(UInt8) PRIMITIVE_CONSTRUCTOR(UInt16) PRIMITIVE_CONSTRUCTOR(UInt32) PRIMITIVE_CONSTRUCTOR(UInt64) PRIMITIVE_CONSTRUCTOR(Int8) PRIMITIVE_CONSTRUCTOR(Int16) PRIMITIVE_CONSTRUCTOR(Int32) PRIMITIVE_CONSTRUCTOR(Int64) PRIMITIVE_CONSTRUCTOR(Bool8) PRIMITIVE_CONSTRUCTOR(Bool16) PRIMITIVE_CONSTRUCTOR(Bool32) PRIMITIVE_CONSTRUCTOR(Bool64) PRIMITIVE_CONSTRUCTOR(Float) PRIMITIVE_CONSTRUCTOR(Double) PRIMITIVE_CONSTRUCTOR(Char) #undef PRIMITIVE_CONSTRUCTOR QScriptValue scriptNewBitfield(QScriptContext* ctx, QScriptEngine* eng) { - QScriptValue object = scriptNewCommon(ctx, eng, ParserStrings::TYPE_BITFIELD); + QScriptValue object = scriptNewCommon(ctx, eng, ParserStrings::TYPE_BITFIELD()); - object.setProperty(ParserStrings::PROPERTY_TYPE, ctx->argument(0)); //first argument is type - object.setProperty(ParserStrings::PROPERTY_WIDTH, ctx->argument(1)); //second argument is width + object.setProperty(ParserStrings::PROPERTY_TYPE(), ctx->argument(0)); //first argument is type + object.setProperty(ParserStrings::PROPERTY_WIDTH(), ctx->argument(1)); //second argument is width return object; } //with children: QScriptValue scriptNewStruct(QScriptContext* ctx, QScriptEngine* eng) { - QScriptValue object = scriptNewCommon(ctx, eng, ParserStrings::TYPE_STRUCT); - object.setProperty(ParserStrings::PROPERTY_CHILD, eng->newFunction(getChild)); + QScriptValue object = scriptNewCommon(ctx, eng, ParserStrings::TYPE_STRUCT()); + object.setProperty(ParserStrings::PROPERTY_CHILD(), eng->newFunction(getChild)); - object.setProperty(ParserStrings::PROPERTY_CHILDREN, ctx->argument(0)); //first argument is children + object.setProperty(ParserStrings::PROPERTY_CHILDREN(), ctx->argument(0)); //first argument is children return object; } QScriptValue scriptNewUnion(QScriptContext* ctx, QScriptEngine* eng) { - QScriptValue object = scriptNewCommon(ctx, eng, ParserStrings::TYPE_UNION); - object.setProperty(ParserStrings::PROPERTY_TYPE, eng->newFunction(getChild)); + QScriptValue object = scriptNewCommon(ctx, eng, ParserStrings::TYPE_UNION()); + object.setProperty(ParserStrings::PROPERTY_TYPE(), eng->newFunction(getChild)); - object.setProperty(ParserStrings::PROPERTY_CHILDREN, ctx->argument(0)); //first argument is children + object.setProperty(ParserStrings::PROPERTY_CHILDREN(), ctx->argument(0)); //first argument is children return object; } QScriptValue scriptNewArray(QScriptContext* ctx, QScriptEngine* eng) { - QScriptValue object = scriptNewCommon(ctx, eng, ParserStrings::TYPE_ARRAY); + QScriptValue object = scriptNewCommon(ctx, eng, ParserStrings::TYPE_ARRAY()); - object.setProperty(ParserStrings::PROPERTY_TYPE, ctx->argument(0)); //first argument is child type - object.setProperty(ParserStrings::PROPERTY_LENGTH, ctx->argument(1)); //second argument is length + object.setProperty(ParserStrings::PROPERTY_TYPE(), ctx->argument(0)); //first argument is child type + object.setProperty(ParserStrings::PROPERTY_LENGTH(), ctx->argument(1)); //second argument is length return object; } QScriptValue createEnumObject(QScriptContext* ctx, QScriptEngine* eng, const QString& typeName) { QScriptValue object = scriptNewCommon(ctx, eng, typeName); - object.setProperty(ParserStrings::PROPERTY_ENUM_NAME, ctx->argument(0)); //first argument is the name of the underlying enum - object.setProperty(ParserStrings::PROPERTY_TYPE, ctx->argument(1)); //second argument is the type of the enum - object.setProperty(ParserStrings::PROPERTY_ENUM_VALUES, ctx->argument(2)); //third argument is the enum values + object.setProperty(ParserStrings::PROPERTY_ENUM_NAME(), ctx->argument(0)); //first argument is the name of the underlying enum + object.setProperty(ParserStrings::PROPERTY_TYPE(), ctx->argument(1)); //second argument is the type of the enum + object.setProperty(ParserStrings::PROPERTY_ENUM_VALUES(), ctx->argument(2)); //third argument is the enum values return object; } QScriptValue scriptNewEnum(QScriptContext* ctx, QScriptEngine* eng) { - return createEnumObject(ctx, eng, ParserStrings::TYPE_ENUM); + return createEnumObject(ctx, eng, ParserStrings::TYPE_ENUM()); } QScriptValue scriptNewFlags(QScriptContext* ctx, QScriptEngine* eng) { - return createEnumObject(ctx, eng, ParserStrings::TYPE_FLAGS); + return createEnumObject(ctx, eng, ParserStrings::TYPE_FLAGS()); } QScriptValue scriptNewString(QScriptContext* ctx, QScriptEngine* eng) { - QScriptValue object = scriptNewCommon(ctx, eng, ParserStrings::TYPE_STRING); + QScriptValue object = scriptNewCommon(ctx, eng, ParserStrings::TYPE_STRING()); - object.setProperty(ParserStrings::PROPERTY_ENCODING, ctx->argument(0)); + object.setProperty(ParserStrings::PROPERTY_ENCODING(), ctx->argument(0)); return object; } QScriptValue scriptNewPointer(QScriptContext* ctx, QScriptEngine* eng) { - QScriptValue object = scriptNewCommon(ctx, eng, ParserStrings::TYPE_POINTER); + QScriptValue object = scriptNewCommon(ctx, eng, ParserStrings::TYPE_POINTER()); - object.setProperty(ParserStrings::PROPERTY_TYPE, ctx->argument(0)); - object.setProperty(ParserStrings::PROPERTY_TARGET, ctx->argument(1)); + object.setProperty(ParserStrings::PROPERTY_TYPE(), ctx->argument(0)); + object.setProperty(ParserStrings::PROPERTY_TARGET(), ctx->argument(1)); return object; } QScriptValue scriptNewTaggedUnion(QScriptContext* ctx, QScriptEngine* eng) { - QScriptValue object = scriptNewCommon(ctx, eng, ParserStrings::TYPE_TAGGED_UNION); - object.setProperty(ParserStrings::PROPERTY_CHILD, eng->newFunction(getChild)); + QScriptValue object = scriptNewCommon(ctx, eng, ParserStrings::TYPE_TAGGED_UNION()); + object.setProperty(ParserStrings::PROPERTY_CHILD(), eng->newFunction(getChild)); - object.setProperty(ParserStrings::PROPERTY_CHILDREN, ctx->argument(0)); - object.setProperty(ParserStrings::PROPERTY_ALTERNATIVES, ctx->argument(1)); - object.setProperty(ParserStrings::PROPERTY_DEFAULT_CHILDREN, ctx->argument(2)); + object.setProperty(ParserStrings::PROPERTY_CHILDREN(), ctx->argument(0)); + object.setProperty(ParserStrings::PROPERTY_ALTERNATIVES(), ctx->argument(1)); + object.setProperty(ParserStrings::PROPERTY_DEFAULT_CHILDREN(), ctx->argument(2)); return object; } QScriptValue getChild(QScriptContext* ctx, QScriptEngine* eng) { Q_UNUSED(eng) if (ctx->argumentCount() < 1) return ctx->throwError(QStringLiteral("child(): name of child must be passed as first parameter")); QString nameString = ctx->argument(0).toString(); - QScriptValue ret = ctx->thisObject().property(ParserStrings::PROPERTY_CHILDREN).property(nameString); + QScriptValue ret = ctx->thisObject().property(ParserStrings::PROPERTY_CHILDREN()).property(nameString); if (ret.isValid()) return ret; else return ctx->throwError( QString(QStringLiteral("child(): could not find child with name=") + nameString)); } QScriptValue addUpdateFunc(QScriptContext* ctx, QScriptEngine*) { if (ctx->argumentCount() != 1) return ctx->throwError(QStringLiteral("setUpdate(): needs one argument!")); QScriptValue thisObj = ctx->thisObject(); Q_ASSERT(thisObj.isValid()); QScriptValue func = ctx->argument(0); if (!func.isFunction()) { return ctx->throwError(QScriptContext::TypeError, QStringLiteral("setUpdate(): argument must be a function!")); } - thisObj.setProperty(ParserStrings::PROPERTY_UPDATE_FUNC, func); + thisObj.setProperty(ParserStrings::PROPERTY_UPDATE_FUNC(), func); return thisObj; } QScriptValue addValidationFunc(QScriptContext* ctx, QScriptEngine*) { if (ctx->argumentCount() != 1) return ctx->throwError(QStringLiteral("setValidation(): needs one argument!")); QScriptValue thisObj = ctx->thisObject(); Q_ASSERT(thisObj.isValid()); QScriptValue func = ctx->argument(0); if (!func.isFunction()) { return ctx->throwError(QScriptContext::TypeError, QStringLiteral("setValidation(): argument must be a function!")); } - thisObj.setProperty(ParserStrings::PROPERTY_VALIDATION_FUNC, func); + thisObj.setProperty(ParserStrings::PROPERTY_VALIDATION_FUNC(), func); return thisObj; } QScriptValue addCustomPropertiesFunc(QScriptContext* ctx, QScriptEngine*) { if (ctx->argumentCount() != 1) return ctx->throwError(QStringLiteral("set(): needs one argument!")); QScriptValue thisObj = ctx->thisObject(); Q_ASSERT(thisObj.isValid()); QScriptValue arg = ctx->argument(0); if (!arg.isValid() || !arg.isObject()) return ctx->throwError(QScriptContext::TypeError, QStringLiteral("set(): argument must be an object!")); int count = 0; QScriptValueIterator it(arg); while (it.hasNext()) { it.next(); thisObj.setProperty(it.scriptName(), it.value()); count++; } if (count == 0) return ctx->throwError(QStringLiteral("set(): must set at least one property!")); return thisObj; } QScriptValue alternativeFunc(QScriptContext* ctx, QScriptEngine* eng) { if (ctx->argumentCount() < 2) return ctx->throwError(QStringLiteral("alternative(): needs at least 2 arguments!")); QScriptValue object = ctx->isCalledAsConstructor() ? ctx->thisObject() : eng->newObject(); - object.setProperty(ParserStrings::PROPERTY_SELECT_IF, ctx->argument(0)); - object.setProperty(ParserStrings::PROPERTY_CHILDREN, ctx->argument(1)); + object.setProperty(ParserStrings::PROPERTY_SELECT_IF(), ctx->argument(0)); + object.setProperty(ParserStrings::PROPERTY_CHILDREN(), ctx->argument(1)); if (ctx->argumentCount() > 2) - object.setProperty(ParserStrings::PROPERTY_STRUCT_NAME, ctx->argument(2)); + object.setProperty(ParserStrings::PROPERTY_STRUCT_NAME(), ctx->argument(2)); return object; } QScriptValue importScriptFunc(QScriptContext* ctx, QScriptEngine* eng) { if (ctx->argumentCount() != 1) return ctx->throwError(QStringLiteral("importScript(): expected one argument!")); QString arg = ctx->argument(0).toString(); if (arg.contains(QStringLiteral(".."))) return ctx->throwError(QStringLiteral("importScript(): You may only access installed structure files! Path traversal detected.")); const QString fileName = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("okteta/structures/") + arg); if (fileName.isEmpty()) return ctx->throwError(QStringLiteral("importScript(): could not find file to import!")); QFile file(fileName); if (!file.open(QFile::ReadOnly)) return ctx->throwError(QStringLiteral("importScript(): failed to open file!")); QTextStream s(&file); QString code = s.readAll(); file.close(); //now push context so that we don't conflict with the current execution QScriptContext* newCtx = eng->pushContext(); QScriptValue result = eng->evaluate(code); if (result.isError()) result = QScriptValue(QStringLiteral("importScript(): failed due to exception: ") + result.toString()); else result = newCtx->activationObject(); eng->popContext(); return result; } } //namespace Private } //namespace ScriptEngine Initializer diff --git a/kasten/controllers/view/structures/script/scriptengineinitializer.h b/kasten/controllers/view/structures/script/scriptengineinitializer.h index 823df8fa..0f5adfdd 100644 --- a/kasten/controllers/view/structures/script/scriptengineinitializer.h +++ b/kasten/controllers/view/structures/script/scriptengineinitializer.h @@ -1,165 +1,164 @@ /* * This file is part of the Okteta Kasten Framework, made within the KDE community. * * Copyright 2010, 2011, 2012 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #ifndef SCRIPTENGINEINITIALIZER_H_ #define SCRIPTENGINEINITIALIZER_H_ class QScriptEngine; class QScriptContext; class QScriptValue; -class QStringLiteral; /** This class adds all functions to the scriptengine that are needed for the scripts. * * For example this allows developers to write something like. * @code * var teststructure = struct({ * // now the members * member1 : uint8(), * member2 : array(uint16(),12), * member3 : bitfield("bool",1), * member4 : bitfield("unsigned", 12), * }) * @endcode * @note */ namespace ScriptEngineInitializer { /** @return a new QScriptEngine with the functions added to the global object */ QScriptEngine* newEngine(); /** add the necessary functions to the QScriptEngine */ void addFuctionsToScriptEngine(QScriptEngine* engine); namespace Private { /** create a new enum: * first parameter is the type, second parameter is a list of name - value pairs */ QScriptValue scriptNewEnum(QScriptContext* ctx, QScriptEngine* eng); /** create a new flag value: * first parameter is the type, second parameter is a list of name - value pairs */ QScriptValue scriptNewFlags(QScriptContext* ctx, QScriptEngine* eng); /** this script constructors/initializer takes no parameters */ QScriptValue scriptNewUInt8(QScriptContext* ctx, QScriptEngine* eng); /** this script constructors/initializer takes no parameters */ QScriptValue scriptNewUInt16(QScriptContext* ctx, QScriptEngine* eng); /** this script constructors/initializer takes no parameters */ QScriptValue scriptNewUInt32(QScriptContext* ctx, QScriptEngine* eng); /** this script constructors/initializer takes no parameters */ QScriptValue scriptNewUInt64(QScriptContext* ctx, QScriptEngine* eng); /** this script constructors/initializer takes no parameters */ QScriptValue scriptNewInt8(QScriptContext* ctx, QScriptEngine* eng); /** this script constructors/initializer takes no parameters */ QScriptValue scriptNewInt16(QScriptContext* ctx, QScriptEngine* eng); /** this script constructors/initializer takes no parameters */ QScriptValue scriptNewInt32(QScriptContext* ctx, QScriptEngine* eng); /** this script constructors/initializer takes no parameters */ QScriptValue scriptNewInt64(QScriptContext* ctx, QScriptEngine* eng); /** this script constructors/initializer takes no parameters */ QScriptValue scriptNewBool8(QScriptContext* ctx, QScriptEngine* eng); /** this script constructors/initializer takes no parameters */ QScriptValue scriptNewBool16(QScriptContext* ctx, QScriptEngine* eng); /** this script constructors/initializer takes no parameters */ QScriptValue scriptNewBool32(QScriptContext* ctx, QScriptEngine* eng); /** this script constructors/initializer takes no parameters */ QScriptValue scriptNewBool64(QScriptContext* ctx, QScriptEngine* eng); /** this script constructors/initializer takes no parameters */ QScriptValue scriptNewFloat(QScriptContext* ctx, QScriptEngine* eng); /** this script constructors/initializer takes no parameters */ QScriptValue scriptNewDouble(QScriptContext* ctx, QScriptEngine* eng); /** this script constructors/initializer takes no parameters */ QScriptValue scriptNewChar(QScriptContext* ctx, QScriptEngine* eng); /** this script constructor/initializer function takes 2 arguments: *
* -the first is the type of the bitfield: "signed", "bool" or "unsigned"
* -the second is the width (in bits) of the bitfield) */ QScriptValue scriptNewBitfield(QScriptContext* ctx, QScriptEngine* eng); /** this script constructor/initializer function takes 1 argument and returns a struct object:
* an object (hierarchy), which represents the children.
* An example would be: * @code * var obj = struct({ * member1 : uint8(), * member2 : int32(), * member3 : union({ * first : uint32(), * second: float(), * }), * member4 : double(), * }) * @endcode */ QScriptValue scriptNewStruct(QScriptContext* ctx, QScriptEngine* eng); /** this script constructor/initializer function takes 1 argument and returns a union object:
* an object (hierarchy), which represents the children.
* An example would be: * @code * var obj = union({ * member1 : uint8(), * member2 : int32(), * member3 : struct({ * first : uint32(), * second: float(), * }), * member4 : double(), * }) * @endcode */ QScriptValue scriptNewUnion(QScriptContext* ctx, QScriptEngine* eng); /** this constructor/initializer function takes 2 arguments and returns an array:
* -the first is an object of the type of the array (can also be a struct or a union or even another array)
* -the second is the length of the array
*/ QScriptValue scriptNewArray(QScriptContext* ctx, QScriptEngine* eng); /** this constructor takes one argument, the encoding of the string (as a string) */ QScriptValue scriptNewString(QScriptContext* ctx, QScriptEngine* eng); /** this constructor takes two arguments: 1. type of the pointer and 2. the target type */ QScriptValue scriptNewPointer(QScriptContext* ctx, QScriptEngine* eng); /** this constructor takes three arguments: 1. initial fields 2. the alternatives 3. (optional) default fields */ QScriptValue scriptNewTaggedUnion(QScriptContext* ctx, QScriptEngine* eng); QScriptValue getChild(QScriptContext* ctx, QScriptEngine* eng); QScriptValue addUpdateFunc(QScriptContext* ctx, QScriptEngine* eng); QScriptValue addValidationFunc(QScriptContext* ctx, QScriptEngine* eng); QScriptValue alternativeFunc(QScriptContext* ctx, QScriptEngine* eng); QScriptValue importScriptFunc(QScriptContext* ctx, QScriptEngine* eng); /** this allows you to write e.g. * return struct({foo : uint8() }) * .set({ updateFunc : ..., * name : "something"}) * */ QScriptValue addCustomPropertiesFunc(QScriptContext* ctx, QScriptEngine* eng); } } #endif /* SCRIPTENGINEINITIALIZER_H_ */ diff --git a/kasten/gui/system/bytearrayviewprofilemanager.cpp b/kasten/gui/system/bytearrayviewprofilemanager.cpp index 8caa5a93..7cb67e7f 100644 --- a/kasten/gui/system/bytearrayviewprofilemanager.cpp +++ b/kasten/gui/system/bytearrayviewprofilemanager.cpp @@ -1,598 +1,597 @@ /* This file is part of the Okteta Kasten module, made within the KDE community. Copyright 2010,2012 Friedrich W. H. Kossebau This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "bytearrayviewprofilemanager.h" // library #include "bytearrayviewprofilelock.h" #include // KF5 #include #include #include // Qt #include #include #include namespace Kasten { -static const QStringList viewProfileFileNameFilter = - QStringList() << QStringLiteral( "*.obavp" ) << QStringLiteral( "*.olock" ); -static const QString viewProfileFileSuffix = QStringLiteral( ".obavp" ); -static const QString viewProfileDirSubPath = QStringLiteral( "/okteta/viewprofiles" ); -static const QString defaultViewProfileFileSubPath = QStringLiteral( "/okteta/defaultviewprofile" ); +QStringList viewProfileFileNameFilter() { return QStringList() << QStringLiteral( "*.obavp" ) << QStringLiteral( "*.olock" ); } +static const QLatin1String viewProfileFileSuffix = QLatin1String( ".obavp" ); +static const QLatin1String viewProfileDirSubPath = QLatin1String( "/okteta/viewprofiles" ); +static const QLatin1String defaultViewProfileFileSubPath = QLatin1String( "/okteta/defaultviewprofile" ); static const int DefaultNoOfBytesPerLine = 16; static const int DefaultNoOfBytesPerGroup = 4; static const int DefaultLayoutStyle = 0; static const int DefaultViewModus = 0; static const int DefaultVisibleByteArrayCodings = 3; static const int DefaultOffsetCoding = 0; static const int DefaultValueCoding = 0; -static const QString DefaultCharCoding; +QString DefaultCharCoding() { return QString(); } static QList lockedViewProfileIds( const ByteArrayViewProfileFileInfoLookup& viewProfileFileInfoLookup ) { QList result; ByteArrayViewProfileFileInfoLookup::ConstIterator end = viewProfileFileInfoLookup.constEnd(); for( ByteArrayViewProfileFileInfoLookup::ConstIterator it = viewProfileFileInfoLookup.constBegin(); it != end; ++it ) { if( it.value().isLocked() ) result.append( it.key() ); } return result; } static void updateLockStatus( ByteArrayViewProfileFileInfoLookup& viewProfileFileInfoLookup, const QList& lockedViewProfileIds, const QList& unlockedViewProfileIds ) { if( lockedViewProfileIds.isEmpty() && unlockedViewProfileIds.isEmpty() ) return; ByteArrayViewProfileFileInfoLookup::Iterator end = viewProfileFileInfoLookup.end(); for( ByteArrayViewProfileFileInfoLookup::Iterator it = viewProfileFileInfoLookup.begin(); it != end; ++it ) { bool isLocked; if( lockedViewProfileIds.contains(it.key()) ) isLocked = true; else if( unlockedViewProfileIds.contains(it.key()) ) isLocked = false; else continue; it.value().setLocked( isLocked ); } } static QString defaultViewProfileFilePath() { return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + defaultViewProfileFileSubPath; } static QString viewProfileFilePath( const ByteArrayViewProfile::Id& viewProfileId ) { return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + viewProfileDirSubPath + QLatin1Char('/') + viewProfileId + viewProfileFileSuffix; } static QString viewProfileFileName( const ByteArrayViewProfile::Id& viewProfileId ) { return viewProfileId + viewProfileFileSuffix; } // TODO: add global lock // TODO: make calls async // TODO: only load view profiles on demand ByteArrayViewProfileManager::ByteArrayViewProfileManager() { mViewProfileFileWatcher = new KDirWatch( this ); connect( mViewProfileFileWatcher, &KDirWatch::dirty, this, &ByteArrayViewProfileManager::onViewProfilesFolderChanged ); // get all folder where viewProfiles could be stored const QStringList dataFolderPaths = QStandardPaths::standardLocations( QStandardPaths::GenericDataLocation ); foreach( const QString& dataFolderPath, dataFolderPaths ) { const QString viewProfileFolderPath = dataFolderPath + viewProfileDirSubPath; // watch folder for changes mViewProfileFileWatcher->addDir( viewProfileFolderPath, KDirWatch::WatchDirOnly ); // read current files onViewProfilesFolderChanged( viewProfileFolderPath ); } // default view profile // While there is no proper config syncing offer in the used frameworks, use a // single file with the id as content as workaround and watch for it changing KDirWatch* defaultViewProfileWatcher = new KDirWatch( this ); connect( defaultViewProfileWatcher, &KDirWatch::created, this, &ByteArrayViewProfileManager::onDefaultViewProfileChanged ); connect( defaultViewProfileWatcher, &KDirWatch::dirty, this, &ByteArrayViewProfileManager::onDefaultViewProfileChanged ); const QString _defaultViewProfileFilePath = defaultViewProfileFilePath(); defaultViewProfileWatcher->addFile( _defaultViewProfileFilePath ); onDefaultViewProfileChanged( _defaultViewProfileFilePath ); // report any problems with existing view profiles? } int ByteArrayViewProfileManager::viewProfilesCount() const { return mViewProfiles.count(); } QList ByteArrayViewProfileManager::viewProfiles() const { return mViewProfiles; } ByteArrayViewProfile ByteArrayViewProfileManager::viewProfile( const ByteArrayViewProfile::Id& viewProfileId ) const { ByteArrayViewProfile result; foreach( const ByteArrayViewProfile& viewProfile, mViewProfiles ) { if( viewProfile.id() == viewProfileId ) { result = viewProfile; break; } } return result; } ByteArrayViewProfile::Id ByteArrayViewProfileManager::defaultViewProfileId() const { return mDefaultViewProfileId; } ByteArrayViewProfile ByteArrayViewProfileManager::defaultViewProfile() const { return viewProfile( mDefaultViewProfileId ); } bool ByteArrayViewProfileManager::isViewProfileLocked( const ByteArrayViewProfile::Id& viewProfileId ) const { bool result = false; // search in all folders for the info foreach( const ByteArrayViewProfileFileInfoLookup& viewProfileFileInfoLookup, mViewProfileFileInfoLookupPerFolder ) { ByteArrayViewProfileFileInfoLookup::ConstIterator it = viewProfileFileInfoLookup.find( viewProfileId ); if( it != viewProfileFileInfoLookup.constEnd() ) { result = it->isLocked(); break; } } return result; } void ByteArrayViewProfileManager::saveViewProfiles( QList& viewProfiles ) { //TODO: do not save if locked by someone else -> needs passing of our lock? or just registering our own and check? // create and set unique id for( QList::Iterator it = viewProfiles.begin(); it != viewProfiles.end(); ++it ) { ByteArrayViewProfile& viewProfile = *it; const ByteArrayViewProfile::Id viewProfileId = viewProfile.id(); const ByteArrayViewProfile::Id oldViewProfileId = viewProfile.id(); bool needsId = true; if( ! viewProfileId.isEmpty() ) { // already existing? QList::ConstIterator existingIt = mViewProfiles.constBegin(); QList::ConstIterator existingEnd = mViewProfiles.constEnd(); for( ; existingIt != existingEnd; ++existingIt ) { if( viewProfileId == existingIt->id() ) { needsId = false; break; } } } // set new uuid for non-existing if( needsId ) viewProfile.setId( QUuid::createUuid().toString() ); saveViewProfile( viewProfile ); } } void ByteArrayViewProfileManager::removeViewProfiles( const QList& viewProfileIds ) { foreach( const ByteArrayViewProfile::Id& viewProfileId, viewProfileIds ) { removeViewProfile( viewProfileId ); } } void ByteArrayViewProfileManager::setDefaultViewProfile( const ByteArrayViewProfile::Id& viewProfileId ) { QFile defaultViewProfileFile( defaultViewProfileFilePath() ); defaultViewProfileFile.open( QIODevice::WriteOnly ); defaultViewProfileFile.write( viewProfileId.toUtf8() ); defaultViewProfileFile.close(); } ByteArrayViewProfileLock ByteArrayViewProfileManager::createLock( const ByteArrayViewProfile::Id& viewProfileId ) { const QString viewProfileFilePath = filePathOfViewProfile( viewProfileId ); return ByteArrayViewProfileLock( viewProfileFilePath, viewProfileId ); } /* bool ByteArrayViewProfileManager::lockViewProfile( const Kasten::ByteArrayViewProfile::Id& viewProfileId ) { bool isSuccessfull; const QString viewProfileFilePath = filePathOfViewProfile( viewProfileId ); // viewProfile known if( not viewProfileFilePath.isEmpty() ) { const QString lockFilePath = viewProfileFileLockPath( viewProfileFilePath ); KLockFile::Ptr lock = new KLockFile( lockFilePath ); const KLockFile::LockResult lockResult = lock->lock(KLockFile::NoBlockFlag | KLockFile::ForceFlag); isSuccessfull = (lockResult == KLockFile::LockOK ); } // if found // try to create lock file return isSuccessfull; } */ // bool // ByteArrayViewProfileManager::unlockViewProfile( const Kasten::ByteArrayViewProfile::Id& viewProfileId ) // { // const QString filePath = filePathOfViewProfile( viewProfileId ); // // if( filePath.isEmpty() ) // return false; // } ByteArrayViewProfile ByteArrayViewProfileManager::loadViewProfile( const QString& absoluteFilePath ) const { ByteArrayViewProfile result; KConfig configFile( absoluteFilePath, KConfig::SimpleConfig ); // check version KConfigGroup formatConfigGroup = configFile.group( "OBAVP" ); const QString formatVersion = formatConfigGroup.readEntry( "Version" ); if( ! formatVersion.startsWith(QStringLiteral( "1." )) ) { return result; } result.setId( QFileInfo(absoluteFilePath).baseName() ); KConfigGroup generalConfigGroup = configFile.group( "General" ); result.setViewProfileTitle( generalConfigGroup.readEntry("Title") ); KConfigGroup layoutConfigGroup = configFile.group( "Layout" ); result.setNoOfBytesPerLine( layoutConfigGroup.readEntry("NoOfBytesPerLine", DefaultNoOfBytesPerLine) ); result.setNoOfGroupedBytes( layoutConfigGroup.readEntry("NoOfBytesPerGroup", DefaultNoOfBytesPerGroup) ); result.setLayoutStyle( layoutConfigGroup.readEntry("LayoutStyle", DefaultLayoutStyle) ); KConfigGroup displayConfigGroup = configFile.group( "Display" ); result.setOffsetColumnVisible( displayConfigGroup.readEntry("OffsetColumnVisible", true) ); result.setOffsetCoding( displayConfigGroup.readEntry("OffsetCoding", DefaultOffsetCoding) ); result.setViewModus( displayConfigGroup.readEntry("ViewModus", DefaultViewModus) ); result.setVisibleByteArrayCodings( displayConfigGroup.readEntry("VisibleByteArrayCodings", DefaultVisibleByteArrayCodings) ); KConfigGroup interpretationConfigGroup = configFile.group( "Interpretation" ); KConfigGroup valuesConfigGroup = interpretationConfigGroup.group( "Values" ); result.setValueCoding( valuesConfigGroup.readEntry("Coding", DefaultValueCoding) ); KConfigGroup charsConfigGroup = interpretationConfigGroup.group( "Chars" ); - result.setCharCoding( charsConfigGroup.readEntry("Coding", DefaultCharCoding) ); + result.setCharCoding( charsConfigGroup.readEntry("Coding", DefaultCharCoding()) ); result.setShowsNonprinting( charsConfigGroup.readEntry("NonprintingShown", false) ); result.setSubstituteChar( charsConfigGroup.readEntry("SubstituteChar", ".").at(0) ); result.setUndefinedChar( charsConfigGroup.readEntry("UndefinedChar", "?").at(0) ); return result; } void ByteArrayViewProfileManager::saveViewProfile( const ByteArrayViewProfile& viewProfile ) const { const QString fileName = viewProfileFilePath( viewProfile.id() ); KConfig configFile( fileName, KConfig::SimpleConfig ); KConfigGroup formatConfigGroup = configFile.group( "OBAVP" ); formatConfigGroup.writeEntry( "Version", "1.1" ); KConfigGroup generalConfigGroup = configFile.group( "General" ); generalConfigGroup.writeEntry( "Title", viewProfile.viewProfileTitle() ); KConfigGroup layoutConfigGroup = configFile.group( "Layout" ); layoutConfigGroup.writeEntry( "NoOfBytesPerLine", viewProfile.noOfBytesPerLine() ); layoutConfigGroup.writeEntry( "NoOfBytesPerGroup", viewProfile.noOfGroupedBytes() ); layoutConfigGroup.writeEntry( "LayoutStyle", viewProfile.layoutStyle() ); KConfigGroup displayConfigGroup = configFile.group( "Display" ); displayConfigGroup.writeEntry( "OffsetColumnVisible", viewProfile.offsetColumnVisible() ); displayConfigGroup.writeEntry( "OffsetCoding", viewProfile.offsetCoding() ); displayConfigGroup.writeEntry( "ViewModus", viewProfile.viewModus() ); displayConfigGroup.writeEntry( "VisibleByteArrayCodings", viewProfile.visibleByteArrayCodings() ); KConfigGroup interpretationConfigGroup = configFile.group( "Interpretation" ); KConfigGroup valuesConfigGroup = interpretationConfigGroup.group( "Values" ); valuesConfigGroup.writeEntry( "Coding", viewProfile.valueCoding() ); KConfigGroup charsConfigGroup = interpretationConfigGroup.group( "Chars" ); charsConfigGroup.writeEntry( "Coding", viewProfile.charCodingName() ); charsConfigGroup.writeEntry( "NonprintingShown", viewProfile.showsNonprinting() ); charsConfigGroup.writeEntry( "SubstituteChar", QString(viewProfile.substituteChar()) ); charsConfigGroup.writeEntry( "UndefinedChar", QString(viewProfile.undefinedChar()) ); } void ByteArrayViewProfileManager::removeViewProfile( const ByteArrayViewProfile::Id& viewProfileId ) { const QString filePath = filePathOfViewProfile( viewProfileId ); if( ! filePath.isEmpty() ) QFile::remove( filePath ); } QString ByteArrayViewProfileManager::filePathOfViewProfile( const ByteArrayViewProfile::Id& viewProfileId ) const { QString result; for( QHash::ConstIterator foldersIt = mViewProfileFileInfoLookupPerFolder.constBegin(); foldersIt != mViewProfileFileInfoLookupPerFolder.constEnd() && result.isEmpty(); ++foldersIt ) { const ByteArrayViewProfileFileInfoLookup& fileInfoList = foldersIt.value(); for( ByteArrayViewProfileFileInfoLookup::ConstIterator folderIt = fileInfoList.constBegin(); folderIt != fileInfoList.constEnd(); ++folderIt ) { if( folderIt.key() == viewProfileId ) { result = foldersIt.key() + QLatin1Char('/') + viewProfileFileName( viewProfileId ); break; } } } return result; } void ByteArrayViewProfileManager::onViewProfilesFolderChanged( const QString& viewProfileFolderPath ) { ByteArrayViewProfileFileInfoLookup& viewProfileFileInfoLookup = mViewProfileFileInfoLookupPerFolder[viewProfileFolderPath]; // TODO: reparse for new, removed and changed files // assume all are removed and unlocked in the beginning QList removedViewProfileIds = viewProfileFileInfoLookup.keys(); QList newViewProfiles; QList changedViewProfiles; QList newUnlockedViewProfileIds = lockedViewProfileIds(viewProfileFileInfoLookup); QList newLockedViewProfileIds; // iterate all files in folder const QFileInfoList viewProfileFileInfoList = - QDir( viewProfileFolderPath ).entryInfoList( viewProfileFileNameFilter, QDir::Files ); + QDir( viewProfileFolderPath ).entryInfoList( viewProfileFileNameFilter(), QDir::Files ); foreach( const QFileInfo& viewProfileFileInfo, viewProfileFileInfoList ) { // a lock file ? if( viewProfileFileInfo.suffix() == QStringLiteral("olock") ) { const ByteArrayViewProfile::Id lockedViewProfileId = viewProfileFileInfo.baseName(); // if not in old locks, is a new lock if( ! newUnlockedViewProfileIds.removeOne(lockedViewProfileId) ) newLockedViewProfileIds.append( lockedViewProfileId ); continue; } // not a viewprofile file ? if( viewProfileFileInfo.suffix() != QStringLiteral("obavp") ) continue; // all other files assumed to be viewProfile files const ByteArrayViewProfile::Id viewProfileId = viewProfileFileInfo.baseName(); // load file const ByteArrayViewProfile viewProfile = loadViewProfile( viewProfileFileInfo.absoluteFilePath() ); // loading failed? Treat as not existing if( viewProfile.id().isEmpty() ) continue; const ByteArrayViewProfileFileInfoLookup::Iterator infoIt = viewProfileFileInfoLookup.find( viewProfileId ); const bool isKnown = ( infoIt != viewProfileFileInfoLookup.end() ); const QDateTime fileInfoLastModified = viewProfileFileInfo.lastModified(); // is known? if( isKnown ) { removedViewProfileIds.removeOne( viewProfileId ); // check timestamp if( fileInfoLastModified == infoIt->lastModified() ) continue; // update timestamp infoIt->setLastModified( fileInfoLastModified ); } else { ByteArrayViewProfileFileInfo info( fileInfoLastModified, false ); viewProfileFileInfoLookup.insert( viewProfileId, info ); } if( isKnown ) { QList::Iterator it = mViewProfiles.begin(); QList::Iterator end = mViewProfiles.end(); for( ; it != end; ++it ) { if( it->id() == viewProfileId ) { *it = viewProfile; break; } } } else newViewProfiles.append( viewProfile ); changedViewProfiles.append( viewProfile ); } // remove all removed viewprofiles { QList::Iterator it = mViewProfiles.begin(); while( it != mViewProfiles.end() ) { // contained in removed? if( removedViewProfileIds.contains(it->id()) ) it = mViewProfiles.erase(it); else ++it; } } foreach( const ByteArrayViewProfile::Id& viewProfileId, removedViewProfileIds ) { viewProfileFileInfoLookup.remove( viewProfileId ); if( viewProfileId == mDefaultViewProfileId ) mDefaultViewProfileId.clear(); // TODO: how to select new one? } // add new viewprofiles mViewProfiles.append( newViewProfiles ); // if there was no default viewprofile before, set default to first const bool isDefaultViewProfileChanged = ( mDefaultViewProfileId.isEmpty() && ! mViewProfiles.isEmpty() ); if( isDefaultViewProfileChanged ) mDefaultViewProfileId = mViewProfiles.at(0).id(); // update lock info updateLockStatus( viewProfileFileInfoLookup, newLockedViewProfileIds, newUnlockedViewProfileIds ); // signal changes if( ! changedViewProfiles.isEmpty() ) emit viewProfilesChanged( changedViewProfiles ); if( ! removedViewProfileIds.isEmpty() ) emit viewProfilesRemoved( removedViewProfileIds ); if( ! newUnlockedViewProfileIds.isEmpty() ) emit viewProfilesUnlocked( newUnlockedViewProfileIds ); if( ! newLockedViewProfileIds.isEmpty() ) emit viewProfilesLocked( newLockedViewProfileIds ); if( isDefaultViewProfileChanged ) emit defaultViewProfileChanged( mDefaultViewProfileId ); } void ByteArrayViewProfileManager::onDefaultViewProfileChanged( const QString& path ) { QFile defaultViewProfileFile( path ); if ( !defaultViewProfileFile.open( QIODevice::ReadOnly ) ) { qCDebug(LOG_KASTEN_OKTETA_GUI) << "Failed to open view profiles file " << path; return; } const QByteArray fileContent = defaultViewProfileFile.readAll(); const QString viewProfileId = QString::fromUtf8( fileContent ); defaultViewProfileFile.close(); // no id set? if( viewProfileId.isEmpty() ) return; // no change? if( mDefaultViewProfileId == viewProfileId ) return; bool isExisting = false; foreach( const ByteArrayViewProfile& viewProfile, mViewProfiles ) { if( viewProfile.id() == viewProfileId ) { isExisting = true; break; } } if( isExisting ) { mDefaultViewProfileId = viewProfileId; emit defaultViewProfileChanged( mDefaultViewProfileId ); } } ByteArrayViewProfileManager::~ByteArrayViewProfileManager() { } } diff --git a/kasten/gui/view/bytearrayviewprofile.cpp b/kasten/gui/view/bytearrayviewprofile.cpp index 570b92eb..ffac4372 100644 --- a/kasten/gui/view/bytearrayviewprofile.cpp +++ b/kasten/gui/view/bytearrayviewprofile.cpp @@ -1,141 +1,141 @@ /* This file is part of the Okteta Kasten module, made within the KDE community. Copyright 2010,2012 Friedrich W. H. Kossebau This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "bytearrayviewprofile.h" // Okteta Gui #include // Qt #include namespace Kasten { class ByteArrayViewProfilePrivate : public QSharedData { public: ByteArrayViewProfilePrivate(); public: QString mId; QString mViewProfileTitle; int mOffsetCoding; QString mCharCodingName; int mValueCoding; bool mOffsetColumnVisible; int mVisibleByteArrayCodings; int mNoOfBytesPerLine; int mLayoutStyle; QChar mSubstituteChar; QChar mUndefinedChar; bool mShowsNonprinting; int mNoOfGroupedBytes; int mViewModus; }; -static const QString DefaultViewProfileCharCodingName = QStringLiteral("ISO-8859-1"); +QString DefaultViewProfileCharCodingName() { return QStringLiteral("ISO-8859-1"); } static const bool DefaultViewProfileShowingNonprinting = false; static const QChar DefaultViewProfileSubstituteChar = QLatin1Char( '.' ); static const QChar DefaultViewProfileUndefinedChar = QChar( QChar::ReplacementCharacter ); static const int DefaultViewProfileNoOfGroupedBytes = 4; static const int DefaultViewProfileNoOfBytesPerLine = 16; static const Okteta::AbstractByteArrayView::OffsetCoding DefaultViewProfileOffsetCoding = Okteta::AbstractByteArrayView::HexadecimalOffset; static const Okteta::AbstractByteArrayView::ValueCoding DefaultViewProfileValueCoding = Okteta::AbstractByteArrayView::HexadecimalCoding; static const Okteta::AbstractByteArrayView::LayoutStyle DefaultViewProfileResizeStyle = Okteta::AbstractByteArrayView::FixedLayoutStyle; static const Okteta::AbstractByteArrayView::CodingTypes DefaultViewProfileVisibleByteArrayCodings = Okteta::AbstractByteArrayView::ValueAndCharCodings; ByteArrayViewProfilePrivate::ByteArrayViewProfilePrivate() : QSharedData() , mOffsetCoding( DefaultViewProfileOffsetCoding ) - , mCharCodingName( DefaultViewProfileCharCodingName ) + , mCharCodingName( DefaultViewProfileCharCodingName() ) , mValueCoding( DefaultViewProfileValueCoding ) , mOffsetColumnVisible( true ) , mVisibleByteArrayCodings( DefaultViewProfileVisibleByteArrayCodings ) , mNoOfBytesPerLine( DefaultViewProfileNoOfBytesPerLine ) , mLayoutStyle( DefaultViewProfileResizeStyle ) , mSubstituteChar( DefaultViewProfileSubstituteChar ) , mUndefinedChar( DefaultViewProfileUndefinedChar ) , mShowsNonprinting( DefaultViewProfileShowingNonprinting ) , mNoOfGroupedBytes( DefaultViewProfileNoOfGroupedBytes ) , mViewModus( 0 ) { } ByteArrayViewProfile::ByteArrayViewProfile() : d( new ByteArrayViewProfilePrivate ) { } ByteArrayViewProfile::ByteArrayViewProfile( const ByteArrayViewProfile& other ) : d( other.d ) { } ByteArrayViewProfile& ByteArrayViewProfile::operator=( const ByteArrayViewProfile& other ) { d = other.d; return *this; } ByteArrayViewProfile::Id ByteArrayViewProfile::id() const { return d->mId; } QString ByteArrayViewProfile::viewProfileTitle() const { return d->mViewProfileTitle; } int ByteArrayViewProfile::offsetCoding() const { return d->mOffsetCoding; } QString ByteArrayViewProfile::charCodingName() const { return d->mCharCodingName; } int ByteArrayViewProfile::valueCoding() const { return d->mValueCoding; } bool ByteArrayViewProfile::offsetColumnVisible() const { return d->mOffsetColumnVisible; } int ByteArrayViewProfile::visibleByteArrayCodings() const { return d->mVisibleByteArrayCodings; } int ByteArrayViewProfile::noOfBytesPerLine() const { return d->mNoOfBytesPerLine; } int ByteArrayViewProfile::layoutStyle() const { return d->mLayoutStyle; } QChar ByteArrayViewProfile::substituteChar() const { return d->mSubstituteChar; } QChar ByteArrayViewProfile::undefinedChar() const { return d->mUndefinedChar; } bool ByteArrayViewProfile::showsNonprinting() const { return d->mShowsNonprinting; } int ByteArrayViewProfile::noOfGroupedBytes() const { return d->mNoOfGroupedBytes; } int ByteArrayViewProfile::viewModus() const { return d->mViewModus; } void ByteArrayViewProfile::setId( const Id& id ) { d->mId = id; } void ByteArrayViewProfile::setViewProfileTitle( const QString& title ) { d->mViewProfileTitle = title; } void ByteArrayViewProfile::setOffsetCoding( int offsetCoding ) { d->mOffsetCoding = offsetCoding; } void ByteArrayViewProfile::setValueCoding( int valueCoding ) { d->mValueCoding = valueCoding; } void ByteArrayViewProfile::setCharCoding( const QString& charCodingName ) { d->mCharCodingName = charCodingName; } void ByteArrayViewProfile::setSubstituteChar( const QChar& substituteChar ) { d->mSubstituteChar = substituteChar; } void ByteArrayViewProfile::setUndefinedChar( const QChar& undefinedChar ) { d->mUndefinedChar = undefinedChar; } void ByteArrayViewProfile::setOffsetColumnVisible( bool visible ) { d->mOffsetColumnVisible = visible; } void ByteArrayViewProfile::setVisibleByteArrayCodings( int columns ) { d->mVisibleByteArrayCodings = columns; } void ByteArrayViewProfile::setLayoutStyle( int layoutStyle ) { d->mLayoutStyle = layoutStyle; } void ByteArrayViewProfile::setNoOfBytesPerLine( int noOfBytesPerLine ) { d->mNoOfBytesPerLine = noOfBytesPerLine; } void ByteArrayViewProfile::setShowsNonprinting( bool showsNonprinting ) { d->mShowsNonprinting = showsNonprinting; } void ByteArrayViewProfile::setNoOfGroupedBytes( int noOfGroupedBytes ) { d->mNoOfGroupedBytes = noOfGroupedBytes; } void ByteArrayViewProfile::setViewModus( int viewModus ) { d->mViewModus = viewModus; } ByteArrayViewProfile::~ByteArrayViewProfile() {} }