diff options
author | Simon Hausmann <simon.hausmann@qt.io> | 2016-07-28 17:40:21 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@qt.io> | 2016-08-01 15:28:04 +0000 |
commit | 143f22babb43d50dd5ee99f73f04016c84d6171a (patch) | |
tree | cbb7f02861d503aa3f85cc68450f7fa43746c439 | |
parent | 897eb7f1290428dcc257e999b099d0ef14349e35 (diff) |
Add a checksum to QQmlPropertyCache
By running an md5 hash over the meta-object data and string tables this will
allow us to detect changes to meta-objects and invalidate QML disk caches.
Change-Id: I15b92de4cdf0cb525281b86e1c7b8ba0b11347a0
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
-rw-r--r-- | src/qml/qml/qqmlpropertycache.cpp | 42 | ||||
-rw-r--r-- | src/qml/qml/qqmlpropertycache_p.h | 5 | ||||
-rw-r--r-- | tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp | 38 |
3 files changed, 85 insertions, 0 deletions
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index 01be38ada1..322e519706 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -1413,6 +1413,48 @@ bool QQmlPropertyCache::determineMetaObjectSizes(const QMetaObject &mo, int *fie return true; } +bool QQmlPropertyCache::addToHash(QCryptographicHash &hash, const QMetaObject &mo) +{ + int fieldCount = 0; + int stringCount = 0; + if (!determineMetaObjectSizes(mo, &fieldCount, &stringCount)) { + return false; + } + + hash.addData(reinterpret_cast<const char *>(mo.d.data), fieldCount * sizeof(uint)); + for (int i = 0; i < stringCount; ++i) { + const QByteArrayDataPtr data = { const_cast<QByteArrayData*>(&mo.d.stringdata[i]) }; + hash.addData(QByteArray(data)); + } + + return true; +} + +QByteArray QQmlPropertyCache::checksum(bool *ok) +{ + if (!_checksum.isEmpty()) { + *ok = true; + return _checksum; + } + + QCryptographicHash hash(QCryptographicHash::Md5); + + if (_parent) { + hash.addData(_parent->checksum(ok)); + if (!*ok) + return QByteArray(); + } + + if (!addToHash(hash, *createMetaObject())) { + *ok = false; + return QByteArray(); + } + + _checksum = hash.result(); + *ok = !_checksum.isEmpty(); + return _checksum; +} + /*! \internal \a index MUST be in the signal index range (see QObjectPrivate::signalIndex()). This is different from QMetaMethod::methodIndex(). diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h index fd29cc8e6a..750537e707 100644 --- a/src/qml/qml/qqmlpropertycache_p.h +++ b/src/qml/qml/qqmlpropertycache_p.h @@ -65,6 +65,7 @@ QT_BEGIN_NAMESPACE +class QCryptographicHash; class QMetaProperty; class QQmlEngine; class QJSEngine; @@ -367,6 +368,9 @@ public: void toMetaObjectBuilder(QMetaObjectBuilder &); static bool determineMetaObjectSizes(const QMetaObject &mo, int *fieldCount, int *stringCount); + static bool addToHash(QCryptographicHash &hash, const QMetaObject &mo); + + QByteArray checksum(bool *ok); protected: virtual void destroy(); @@ -437,6 +441,7 @@ private: QByteArray _dynamicStringData; QString _defaultPropertyName; QQmlPropertyCacheMethodArguments *argumentsCache; + QByteArray _checksum; }; // QQmlMetaObject serves as a wrapper around either QMetaObject or QQmlPropertyCache. diff --git a/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp b/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp index acc68befb5..2916d8455c 100644 --- a/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp +++ b/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp @@ -31,6 +31,7 @@ #include <QtQml/qqmlengine.h> #include <private/qv8engine_p.h> #include <private/qmetaobjectbuilder_p.h> +#include <QCryptographicHash> #include "../../shared/util.h" class tst_qqmlpropertycache : public QObject @@ -48,6 +49,7 @@ private slots: void signalHandlersDerived(); void metaObjectSize_data(); void metaObjectSize(); + void metaObjectChecksum(); private: QQmlEngine engine; @@ -361,4 +363,40 @@ void tst_qqmlpropertycache::metaObjectSize() QCOMPARE(stringDataSize, expectedStringCount); } +void tst_qqmlpropertycache::metaObjectChecksum() +{ + QMetaObjectBuilder builder; + builder.setClassName("Test"); + builder.addClassInfo("foo", "bar"); + + QCryptographicHash hash(QCryptographicHash::Md5); + + QScopedPointer<QMetaObject, QScopedPointerPodDeleter> mo(builder.toMetaObject()); + QVERIFY(!mo.isNull()); + + QVERIFY(QQmlPropertyCache::addToHash(hash, *mo.data())); + QByteArray initialHash = hash.result(); + QVERIFY(!initialHash.isEmpty()); + hash.reset(); + + { + QVERIFY(QQmlPropertyCache::addToHash(hash, *mo.data())); + QByteArray nextHash = hash.result(); + QVERIFY(!nextHash.isEmpty()); + hash.reset(); + QCOMPARE(initialHash, nextHash); + } + + builder.addProperty("testProperty", "int", -1); + + mo.reset(builder.toMetaObject()); + { + QVERIFY(QQmlPropertyCache::addToHash(hash, *mo.data())); + QByteArray nextHash = hash.result(); + QVERIFY(!nextHash.isEmpty()); + hash.reset(); + QVERIFY(initialHash != nextHash); + } +} + QTEST_MAIN(tst_qqmlpropertycache) |