From 02a248c9c57714d4ad1ba775d9e60a7f286f10c6 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Thu, 1 Oct 2009 18:52:53 +1000 Subject: Prevent writes to the global object Also add toString() method to qobjects --- demos/declarative/samegame/content/samegame.js | 28 ++++---- src/declarative/qml/qml.pri | 6 +- src/declarative/qml/qmlengine.cpp | 16 +++-- src/declarative/qml/qmlengine_p.h | 2 + src/declarative/qml/qmlglobalscriptclass.cpp | 94 ++++++++++++++++++++++++++ src/declarative/qml/qmlglobalscriptclass_p.h | 81 ++++++++++++++++++++++ src/declarative/qml/qmlobjectscriptclass.cpp | 83 +++++++++++++---------- src/declarative/qml/qmlobjectscriptclass_p.h | 8 +++ 8 files changed, 260 insertions(+), 58 deletions(-) create mode 100644 src/declarative/qml/qmlglobalscriptclass.cpp create mode 100644 src/declarative/qml/qmlglobalscriptclass_p.h diff --git a/demos/declarative/samegame/content/samegame.js b/demos/declarative/samegame/content/samegame.js index 4a9179b..09057eb 100755 --- a/demos/declarative/samegame/content/samegame.js +++ b/demos/declarative/samegame/content/samegame.js @@ -24,7 +24,7 @@ function timeStr(msecs) { function initBoard() { - for(i = 0; i= maxX || xIdx < 0 || yIdx >= maxY || yIdx < 0) return; if(board[index(xIdx, yIdx)] == null) @@ -105,14 +105,14 @@ function floodFill(xIdx,yIdx,type) function shuffleDown() { //Fall down - for(xIdx=0; xIdx=0; yIdx--){ + for(var xIdx=0; xIdx=0; yIdx--){ if(board[index(xIdx,yIdx)] == null){ fallDist += 1; }else{ if(fallDist > 0){ - obj = board[index(xIdx,yIdx)]; + var obj = board[index(xIdx,yIdx)]; obj.targetY += fallDist * tileSize; board[index(xIdx,yIdx+fallDist)] = obj; board[index(xIdx,yIdx)] = null; @@ -143,8 +143,8 @@ function shuffleDown() function victoryCheck() { //awards bonuses for no tiles left - deservesBonus = true; - for(xIdx=maxX-1; xIdx>=0; xIdx--) + var deservesBonus = true; + for(var xIdx=maxX-1; xIdx>=0; xIdx--) if(board[index(xIdx, maxY - 1)] != null) deservesBonus = false; if(deservesBonus) @@ -166,7 +166,7 @@ function floodMoveCheck(xIdx, yIdx, type) return false; if(board[index(xIdx, yIdx)] == null) return false; - myType = board[index(xIdx, yIdx)].type; + var myType = board[index(xIdx, yIdx)].type; if(type == myType) return true; return floodMoveCheck(xIdx + 1, yIdx, myType) || @@ -174,7 +174,7 @@ function floodMoveCheck(xIdx, yIdx, type) } function createBlock(xIdx,yIdx){ - if(component==null) + if(component==null) component = createComponent(tileSrc); // Note that we don't wait for the component to become ready. This will @@ -182,7 +182,7 @@ function createBlock(xIdx,yIdx){ // not be ready immediately. There is a statusChanged signal on the // component you could use if you want to wait to load remote files. if(component.isReady){ - dynamicObject = component.createObject(); + var dynamicObject = component.createObject(); if(dynamicObject == null){ print("error creating block"); print(component.errorsString()); diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri index 1a6dad3..eb761e3 100644 --- a/src/declarative/qml/qml.pri +++ b/src/declarative/qml/qml.pri @@ -38,7 +38,8 @@ SOURCES += qml/qmlparser.cpp \ qml/qmlpropertycache.cpp \ qml/qmlintegercache.cpp \ qml/qmlobjectscriptclass.cpp \ - qml/qmlcontextscriptclass.cpp + qml/qmlcontextscriptclass.cpp \ + qml/qmlglobalscriptclass.cpp HEADERS += qml/qmlparser_p.h \ qml/qmlinstruction_p.h \ @@ -94,7 +95,8 @@ HEADERS += qml/qmlparser_p.h \ qml/qmlpropertycache_p.h \ qml/qmlintegercache_p.h \ qml/qmlobjectscriptclass_p.h \ - qml/qmlcontextscriptclass_p.h + qml/qmlcontextscriptclass_p.h \ + qml/qmlglobalscriptclass_p.h # for qtscript debugger contains(QT_CONFIG, scripttools):QT += scripttools diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index d680fa1..4afd245 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #ifdef QT_SCRIPTTOOLS_LIB #include @@ -156,7 +157,7 @@ static QString userLocalDataPath(const QString& app) QmlEnginePrivate::QmlEnginePrivate(QmlEngine *e) : rootContext(0), currentExpression(0), - isDebugging(false), contextClass(0), objectClass(0), valueTypeClass(0), + isDebugging(false), contextClass(0), objectClass(0), valueTypeClass(0), globalClass(0), nodeListClass(0), namedNodeMapClass(0), sqlQueryClass(0), scriptEngine(this), rootComponent(0), networkAccessManager(0), typeManager(e), uniqueId(1) { @@ -183,6 +184,14 @@ QmlEnginePrivate::QmlEnginePrivate(QmlEngine *e) qtObject.setProperty(QLatin1String("lighter"), scriptEngine.newFunction(QmlEnginePrivate::lighter, 1)); qtObject.setProperty(QLatin1String("darker"), scriptEngine.newFunction(QmlEnginePrivate::darker, 1)); qtObject.setProperty(QLatin1String("tint"), scriptEngine.newFunction(QmlEnginePrivate::tint, 2)); + + scriptEngine.globalObject().setProperty(QLatin1String("createQmlObject"), + scriptEngine.newFunction(QmlEnginePrivate::createQmlObject, 1)); + scriptEngine.globalObject().setProperty(QLatin1String("createComponent"), + scriptEngine.newFunction(QmlEnginePrivate::createComponent, 1)); + + //scriptEngine.globalObject().setScriptClass(new QmlGlobalScriptClass(&scriptEngine)); + globalClass = new QmlGlobalScriptClass(&scriptEngine); } QmlEnginePrivate::~QmlEnginePrivate() @@ -250,11 +259,6 @@ void QmlEnginePrivate::init() } #endif - scriptEngine.globalObject().setProperty(QLatin1String("createQmlObject"), - scriptEngine.newFunction(QmlEnginePrivate::createQmlObject, 1)); - scriptEngine.globalObject().setProperty(QLatin1String("createComponent"), - scriptEngine.newFunction(QmlEnginePrivate::createComponent, 1)); - if (QCoreApplication::instance()->thread() == q->thread() && QmlEngineDebugServer::isDebuggingEnabled()) { qmlEngineDebugServer(); diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h index 764cc6c..231388d 100644 --- a/src/declarative/qml/qmlengine_p.h +++ b/src/declarative/qml/qmlengine_p.h @@ -151,6 +151,8 @@ public: QmlObjectScriptClass *objectClass; QmlValueTypeScriptClass *valueTypeClass; QmlTypeNameScriptClass *typeNameClass; + // Global script class + QScriptClass *globalClass; // Used by DOM Core 3 API QScriptClass *nodeListClass; QScriptClass *namedNodeMapClass; diff --git a/src/declarative/qml/qmlglobalscriptclass.cpp b/src/declarative/qml/qmlglobalscriptclass.cpp new file mode 100644 index 0000000..0ade5ee --- /dev/null +++ b/src/declarative/qml/qmlglobalscriptclass.cpp @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlglobalscriptclass_p.h" +#include +#include +#include + +QT_BEGIN_NAMESPACE + +/* + Used to prevent any writes to the global object. +*/ +QmlGlobalScriptClass::QmlGlobalScriptClass(QScriptEngine *engine) +: QScriptClass(engine) +{ + QScriptValue v = engine->newObject(); + globalObject = engine->globalObject(); + + QScriptValueIterator iter(globalObject); + while (iter.hasNext()) { + iter.next(); + v.setProperty(iter.scriptName(), iter.value()); + } + + v.setScriptClass(this); + engine->setGlobalObject(v); +} + +QScriptClass::QueryFlags +QmlGlobalScriptClass::queryProperty(const QScriptValue &object, + const QScriptString &name, + QueryFlags flags, uint *id) +{ + return HandlesReadAccess | HandlesWriteAccess; +} + +QScriptValue +QmlGlobalScriptClass::property(const QScriptValue &object, + const QScriptString &name, + uint id) +{ + return engine()->undefinedValue(); +} + +void QmlGlobalScriptClass::setProperty(QScriptValue &object, + const QScriptString &name, + uint id, const QScriptValue &value) +{ + QString error = QLatin1String("Invalid write to global property \"") + + name.toString() + QLatin1String("\""); + engine()->currentContext()->throwError(error); +} + +QT_END_NAMESPACE + diff --git a/src/declarative/qml/qmlglobalscriptclass_p.h b/src/declarative/qml/qmlglobalscriptclass_p.h new file mode 100644 index 0000000..1b58f1e --- /dev/null +++ b/src/declarative/qml/qmlglobalscriptclass_p.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLGLOBALSCRIPTCLASS_P_H +#define QMLGLOBALSCRIPTCLASS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QmlGlobalScriptClass : public QScriptClass +{ +public: + QmlGlobalScriptClass(QScriptEngine *); + + virtual QueryFlags queryProperty(const QScriptValue &object, + const QScriptString &name, + QueryFlags flags, uint *id); + + virtual QScriptValue property(const QScriptValue &object, + const QScriptString &name, uint id); + + virtual void setProperty(QScriptValue &object, const QScriptString &name, + uint id, const QScriptValue &value); + +private: + QScriptValue globalObject; +}; + +QT_END_NAMESPACE + +#endif // QMLGLOBALSCRIPTCLASS_P_H diff --git a/src/declarative/qml/qmlobjectscriptclass.cpp b/src/declarative/qml/qmlobjectscriptclass.cpp index 28a808a..bb5f191 100644 --- a/src/declarative/qml/qmlobjectscriptclass.cpp +++ b/src/declarative/qml/qmlobjectscriptclass.cpp @@ -51,40 +51,6 @@ struct ObjectData { QGuard object; }; -static QScriptValue QmlObjectToString(QScriptContext *context, QScriptEngine *engine) -{ - QObject* obj = context->thisObject().data().toQObject(); - QString ret = QLatin1String("Qml Object, "); - if(obj){ - //###Should this be designer or developer details? Dev for now. - //TODO: Can we print the id too? - ret += QLatin1String("\""); - ret += obj->objectName(); - ret += QLatin1String("\" "); - ret += QLatin1String(obj->metaObject()->className()); - ret += QLatin1String("(0x"); - ret += QString::number((quintptr)obj,16); - ret += QLatin1String(")"); - }else{ - ret += QLatin1String("null"); - } - return engine->newVariant(ret); -} - -static QScriptValue QmlObjectDestroy(QScriptContext *context, QScriptEngine *engine) -{ - QObject* obj = context->thisObject().toQObject(); - if(obj){ - int delay = 0; - if(context->argumentCount() > 0) - delay = context->argument(0).toInt32(); - obj->deleteLater(); - //### Should this be delayed as well? - context->thisObject().setData(QScriptValue(engine, 0)); - } - return engine->nullValue(); -} - /* The QmlObjectScriptClass handles property access for QObjects via QtScript. It is also used to provide a more useful API in @@ -97,8 +63,10 @@ QmlObjectScriptClass::QmlObjectScriptClass(QmlEngine *bindEngine) engine = bindEngine; QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(bindEngine); - m_destroy = scriptEngine->newFunction(QmlObjectDestroy); + m_destroy = scriptEngine->newFunction(destroy); m_destroyId = createPersistentIdentifier(QLatin1String("destroy")); + m_toString = scriptEngine->newFunction(tostring); + m_toStringId = createPersistentIdentifier(QLatin1String("toString")); } QmlObjectScriptClass::~QmlObjectScriptClass() @@ -132,7 +100,8 @@ QmlObjectScriptClass::queryProperty(QObject *obj, const Identifier &name, Q_UNUSED(flags); lastData = 0; - if (name == m_destroyId->identifier) + if (name == m_destroyId->identifier || + name == m_toStringId->identifier) return QScriptClass::HandlesReadAccess; if (!obj) @@ -173,6 +142,8 @@ QScriptValue QmlObjectScriptClass::property(QObject *obj, const Identifier &name { if (name == m_destroyId->identifier) return m_destroy; + else if (name == m_toStringId->identifier) + return m_toString; Q_ASSERT(lastData); Q_ASSERT(obj); @@ -240,4 +211,44 @@ void QmlObjectScriptClass::destroyed(const Object &object) delete data; } +QScriptValue QmlObjectScriptClass::tostring(QScriptContext *context, QScriptEngine *engine) +{ + QObject* obj = context->thisObject().toQObject(); + + QString ret; + if(obj){ + QString objectName = obj->objectName(); + + ret += QLatin1String(obj->metaObject()->className()); + ret += QLatin1String("(0x"); + ret += QString::number((quintptr)obj,16); + + if (!objectName.isEmpty()) { + ret += QLatin1String(", \""); + ret += objectName; + ret += QLatin1String("\""); + } + + ret += QLatin1String(")"); + }else{ + ret += QLatin1String("null"); + } + return QScriptValue(ret); +} + +QScriptValue QmlObjectScriptClass::destroy(QScriptContext *context, QScriptEngine *engine) +{ + QObject* obj = context->thisObject().toQObject(); + if(obj){ + int delay = 0; + if(context->argumentCount() > 0) + delay = context->argument(0).toInt32(); + obj->deleteLater(); + //### Should this be delayed as well? + context->thisObject().setData(QScriptValue(engine, 0)); + } + return engine->nullValue(); +} + + QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlobjectscriptclass_p.h b/src/declarative/qml/qmlobjectscriptclass_p.h index f126192..cd67fac 100644 --- a/src/declarative/qml/qmlobjectscriptclass_p.h +++ b/src/declarative/qml/qmlobjectscriptclass_p.h @@ -60,6 +60,8 @@ QT_BEGIN_NAMESPACE class QmlEngine; +class QScriptContext; +class QScriptEngine; class QmlObjectScriptClass : public QScriptDeclarativeClass { public: @@ -90,7 +92,13 @@ private: struct Dummy {}; PersistentIdentifier *m_destroyId; + PersistentIdentifier *m_toStringId; QScriptValue m_destroy; + QScriptValue m_toString; + + static QScriptValue tostring(QScriptContext *context, QScriptEngine *engine); + static QScriptValue destroy(QScriptContext *context, QScriptEngine *engine); + QmlEngine *engine; }; -- cgit v0.12