diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index 40c87b98e8..c2688e7607 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -107,6 +107,14 @@ Bitstream::Bitstream(QDataStream& underlying, MetadataType metadataType, QObject _sharedObjectStreamer(*this) { } +void Bitstream::addMetaObjectSubstitution(const QByteArray& className, const QMetaObject* metaObject) { + _metaObjectSubstitutions.insert(className, metaObject); +} + +void Bitstream::addTypeSubstitution(const QByteArray& typeName, int type) { + _typeStreamerSubstitutions.insert(typeName, getTypeStreamers().value(type)); +} + const int LAST_BIT_POSITION = BITS_IN_BYTE - 1; Bitstream& Bitstream::write(const void* data, int bits, int offset) { @@ -496,7 +504,10 @@ Bitstream& Bitstream::operator>(ObjectReader& objectReader) { objectReader = ObjectReader(); return *this; } - const QMetaObject* metaObject = getMetaObjects().value(className); + const QMetaObject* metaObject = _metaObjectSubstitutions.value(className); + if (!metaObject) { + metaObject = getMetaObjects().value(className); + } if (!metaObject) { qWarning() << "Unknown class name: " << className << "\n"; } @@ -523,6 +534,7 @@ Bitstream& Bitstream::operator>(ObjectReader& objectReader) { // for hash metadata, check the names/types of the properties as well as the name hash against our own class if (_metadataType == HASH_METADATA) { QCryptographicHash hash(QCryptographicHash::Md5); + bool matches = true; if (metaObject) { int propertyIndex = 0; for (int i = 0; i < metaObject->propertyCount(); i++) { @@ -536,21 +548,20 @@ Bitstream& Bitstream::operator>(ObjectReader& objectReader) { } if (propertyIndex >= properties.size() || !properties.at(propertyIndex).getReader().matchesExactly(typeStreamer)) { - objectReader = ObjectReader(className, metaObject, properties); - return *this; + matches = false; + break; } hash.addData(property.name(), strlen(property.name()) + 1); propertyIndex++; } if (propertyIndex != properties.size()) { - objectReader = ObjectReader(className, metaObject, properties); - return *this; + matches = false; } } QByteArray localHashResult = hash.result(); QByteArray remoteHashResult(localHashResult.size(), 0); read(remoteHashResult.data(), remoteHashResult.size() * BITS_IN_BYTE); - if (metaObject && localHashResult == remoteHashResult) { + if (metaObject && matches && localHashResult == remoteHashResult) { objectReader = ObjectReader(className, metaObject, getPropertyReaders(metaObject)); return *this; } @@ -589,7 +600,10 @@ Bitstream& Bitstream::operator<(const TypeStreamer* streamer) { Bitstream& Bitstream::operator>(TypeReader& reader) { QByteArray typeName; *this >> typeName; - const TypeStreamer* streamer = getTypeStreamers().value(QMetaType::type(typeName.constData())); + const TypeStreamer* streamer = _typeStreamerSubstitutions.value(typeName); + if (!streamer) { + streamer = getTypeStreamers().value(QMetaType::type(typeName.constData())); + } if (!streamer) { qWarning() << "Unknown type name: " << typeName << "\n"; } diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index 78bc125841..b51bee3a25 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -222,6 +222,12 @@ public: /// Creates a new bitstream. Note: the stream may be used for reading or writing, but not both. Bitstream(QDataStream& underlying, MetadataType metadataType = NO_METADATA, QObject* parent = NULL); + /// Substitutes the supplied metaobject for the given class name's default mapping. + void addMetaObjectSubstitution(const QByteArray& className, const QMetaObject* metaObject); + + /// Substitutes the supplied type for the given type name's default mapping. + void addTypeSubstitution(const QByteArray& typeName, int type); + /// Writes a set of bits to the underlying stream. /// \param bits the number of bits to write /// \param offset the offset of the first bit @@ -363,6 +369,9 @@ private: WeakSharedObjectHash _weakSharedObjectHash; + QHash _metaObjectSubstitutions; + QHash _typeStreamerSubstitutions; + static QHash& getMetaObjects(); static QMultiHash& getMetaObjectSubClasses(); static QHash& getTypeStreamers(); diff --git a/tests/metavoxels/src/MetavoxelTests.cpp b/tests/metavoxels/src/MetavoxelTests.cpp index 9de48364b6..a178215fbc 100644 --- a/tests/metavoxels/src/MetavoxelTests.cpp +++ b/tests/metavoxels/src/MetavoxelTests.cpp @@ -34,23 +34,65 @@ static int streamedBytesReceived = 0; static int sharedObjectsCreated = 0; static int sharedObjectsDestroyed = 0; +static QByteArray createRandomBytes(int minimumSize, int maximumSize) { + QByteArray bytes(randIntInRange(minimumSize, maximumSize), 0); + for (int i = 0; i < bytes.size(); i++) { + bytes[i] = rand(); + } + return bytes; +} + +static QByteArray createRandomBytes() { + const int MIN_BYTES = 4; + const int MAX_BYTES = 16; + return createRandomBytes(MIN_BYTES, MAX_BYTES); +} + static bool testSerialization(Bitstream::MetadataType metadataType) { QByteArray array; QDataStream outStream(&array, QIODevice::WriteOnly); Bitstream out(outStream, metadataType); - SharedObjectPointer testObjectWritten = new TestSharedObjectA(randFloat()); - out << testObjectWritten; + SharedObjectPointer testObjectWrittenA = new TestSharedObjectA(randFloat()); + out << testObjectWrittenA; + SharedObjectPointer testObjectWrittenB = new TestSharedObjectB(randFloat(), createRandomBytes()); + out << testObjectWrittenB; + QByteArray endWritten = "end"; + out << endWritten; out.flush(); QDataStream inStream(array); Bitstream in(inStream, metadataType); - SharedObjectPointer testObjectRead; - in >> testObjectRead; + in.addMetaObjectSubstitution("TestSharedObjectA", &TestSharedObjectB::staticMetaObject); + in.addMetaObjectSubstitution("TestSharedObjectB", &TestSharedObjectA::staticMetaObject); + SharedObjectPointer testObjectReadA, testObjectReadB; + in >> testObjectReadA >> testObjectReadB; - if (!testObjectWritten->equals(testObjectRead)) { - QDebug debug = qDebug() << "Read/write mismatch"; - testObjectWritten->dump(debug); - testObjectRead->dump(debug); + if (!testObjectReadA || testObjectReadA->metaObject() != &TestSharedObjectB::staticMetaObject) { + qDebug() << "Wrong class for A" << testObjectReadA << metadataType; + return true; + } + if (metadataType == Bitstream::FULL_METADATA && static_cast(testObjectWrittenA.data())->getFoo() != + static_cast(testObjectReadA.data())->getFoo()) { + QDebug debug = qDebug() << "Failed to transfer shared field from A to B"; + testObjectWrittenA->dump(debug); + testObjectReadA->dump(debug); + } + + if (!testObjectReadB || testObjectReadB->metaObject() != &TestSharedObjectA::staticMetaObject) { + qDebug() << "Wrong class for B" << testObjectReadB << metadataType; + return true; + } + if (metadataType == Bitstream::FULL_METADATA && static_cast(testObjectWrittenB.data())->getFoo() != + static_cast(testObjectReadB.data())->getFoo()) { + QDebug debug = qDebug() << "Failed to transfer shared field from B to A"; + testObjectWrittenB->dump(debug); + testObjectReadB->dump(debug); + } + + QByteArray endRead; + in >> endRead; + if (endWritten != endRead) { + qDebug() << "End tag mismatch." << endRead; return true; } @@ -100,20 +142,6 @@ bool MetavoxelTests::run() { return false; } -static QByteArray createRandomBytes(int minimumSize, int maximumSize) { - QByteArray bytes(randIntInRange(minimumSize, maximumSize), 0); - for (int i = 0; i < bytes.size(); i++) { - bytes[i] = rand(); - } - return bytes; -} - -static QByteArray createRandomBytes() { - const int MIN_BYTES = 4; - const int MAX_BYTES = 16; - return createRandomBytes(MIN_BYTES, MAX_BYTES); -} - static SharedObjectPointer createRandomSharedObject() { switch (randIntInRange(0, 2)) { case 0: return new TestSharedObjectA(randFloat()); @@ -354,7 +382,9 @@ void TestSharedObjectA::setFoo(float foo) { } } -TestSharedObjectB::TestSharedObjectB() { +TestSharedObjectB::TestSharedObjectB(float foo, const QByteArray& bar) : + _foo(foo), + _bar(bar) { sharedObjectsCreated++; } diff --git a/tests/metavoxels/src/MetavoxelTests.h b/tests/metavoxels/src/MetavoxelTests.h index 3b69c28f79..22a680acbb 100644 --- a/tests/metavoxels/src/MetavoxelTests.h +++ b/tests/metavoxels/src/MetavoxelTests.h @@ -89,11 +89,24 @@ private: /// Another simple shared object. class TestSharedObjectB : public SharedObject { Q_OBJECT + Q_PROPERTY(float foo READ getFoo WRITE setFoo) + Q_PROPERTY(QByteArray bar READ getBar WRITE setBar) public: - Q_INVOKABLE TestSharedObjectB(); + Q_INVOKABLE TestSharedObjectB(float foo = 0.0f, const QByteArray& bar = QByteArray()); virtual ~TestSharedObjectB(); + + void setFoo(float foo) { _foo = foo; } + float getFoo() const { return _foo; } + + void setBar(const QByteArray& bar) { _bar = bar; } + const QByteArray& getBar() const { return _bar; } + +private: + + float _foo; + QByteArray _bar; }; /// A simple test message.