From: Janne Koschinski Date: Mon, 2 Apr 2018 20:26:34 +0000 (+0200) Subject: Implement custom deserializer to add our own sanity checks X-Git-Tag: travis-deploy-test~134 X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=commitdiff_plain;h=2b777e99fc9f74d4ed21491710260664a1721d1f Implement custom deserializer to add our own sanity checks This is a rough first implementation in preparation of writing proper serializers independently of QDataStream. Thanks to @chaign_c (https://twitter.com/chaign_c/) for finding issues with QDataStream that prompted this change. --- diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 1deac520..b5efb4a6 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -40,6 +40,8 @@ set(SOURCES transfermanager.cpp util.cpp + serializers/serializers.cpp + protocols/datastream/datastreampeer.cpp protocols/legacy/legacypeer.cpp diff --git a/src/common/protocols/datastream/datastreampeer.cpp b/src/common/protocols/datastream/datastreampeer.cpp index 5c524cef..240560da 100644 --- a/src/common/protocols/datastream/datastreampeer.cpp +++ b/src/common/protocols/datastream/datastreampeer.cpp @@ -25,6 +25,7 @@ #include "datastreampeer.h" #include "quassel.h" +#include "serializers/serializers.h" using namespace Protocol; @@ -59,7 +60,8 @@ void DataStreamPeer::processMessage(const QByteArray &msg) QDataStream stream(msg); stream.setVersion(QDataStream::Qt_4_2); QVariantList list; - stream >> list; + if (!Serializers::deserialize(stream, features(), list)) + close("Peer sent corrupt data, closing down!"); if (stream.status() != QDataStream::Ok) { close("Peer sent corrupt data, closing down!"); return; diff --git a/src/common/protocols/legacy/legacypeer.cpp b/src/common/protocols/legacy/legacypeer.cpp index 19806742..caf1bb22 100644 --- a/src/common/protocols/legacy/legacypeer.cpp +++ b/src/common/protocols/legacy/legacypeer.cpp @@ -24,6 +24,7 @@ #include "legacypeer.h" #include "quassel.h" +#include "serializers/serializers.h" /* version.inc is no longer used for this */ const uint protocolVersion = 10; @@ -63,7 +64,10 @@ void LegacyPeer::processMessage(const QByteArray &msg) QVariant item; if (_useCompression) { QByteArray rawItem; - stream >> rawItem; + if (!Serializers::deserialize(stream, features(), rawItem)) { + close("Peer sent corrupt data: unable to load QVariant!"); + return; + } int nbytes = rawItem.size(); if (nbytes <= 4) { @@ -78,10 +82,15 @@ void LegacyPeer::processMessage(const QByteArray &msg) QDataStream itemStream(&rawItem, QIODevice::ReadOnly); itemStream.setVersion(QDataStream::Qt_4_2); - itemStream >> item; - } - else { - stream >> item; + if (!Serializers::deserialize(itemStream, features(), item)) { + close("Peer sent corrupt data: unable to load QVariant!"); + return; + } + } else { + if (!Serializers::deserialize(stream, features(), item)) { + close("Peer sent corrupt data: unable to load QVariant!"); + return; + } } if (stream.status() != QDataStream::Ok || !item.isValid()) { diff --git a/src/common/serializers/serializers.cpp b/src/common/serializers/serializers.cpp new file mode 100644 index 00000000..f0df398b --- /dev/null +++ b/src/common/serializers/serializers.cpp @@ -0,0 +1,707 @@ +/*************************************************************************** + * Copyright (C) 2005-2018 by the Quassel Project * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) version 3. * + * * + * This program 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include "serializers.h" + +bool checkStreamValid(QDataStream &stream) +{ + if (stream.status() != QDataStream::Ok) { + qWarning() << "Peer sent corrupt data"; + return false; + } + + return true; +} + +bool Serializers::deserialize(QDataStream &stream, const Quassel::Features &features, QVariantList &data) +{ + uint32_t size; + if (!deserialize(stream, features, size)) + return false; + if (size > 4 * 1024 * 1024) { + qWarning() << "Peer sent too large QVariantList: " << size; + return false; + } + for (uint32_t i = 0; i < size; i++) { + QVariant element; + if (!deserialize(stream, features, element)) + return false; + data << element; + } + return checkStreamValid(stream); +} + +bool Serializers::deserialize(QDataStream &stream, const Quassel::Features &features, QVariantMap &data) +{ + uint32_t size; + if (!deserialize(stream, features, size)) + return false; + if (size > 4 * 1024 * 1024) { + qWarning() << "Peer sent too large QVariantMap: " << size; + return false; + } + for (uint32_t i = 0; i < size; i++) { + QString key; + QVariant value; + if (!deserialize(stream, features, key)) + return false; + if (!deserialize(stream, features, value)) + return false; + data[key] = value; + } + return checkStreamValid(stream); +} + +bool Serializers::deserialize(QDataStream &stream, const Quassel::Features &features, QVariant &data) +{ + Types::VariantType type; + int8_t isNull; + if (!deserialize(stream, features, type)) + return false; + if (!deserialize(stream, features, isNull)) + return false; + if (type == Types::VariantType::UserType) { + QByteArray name; + if (!deserialize(stream, features, name)) + return false; + while (name.length() > 0 && name.at(name.length() - 1) == 0) + name.chop(1); + if (!deserialize(stream, features, data, Types::fromName(name))) + return false; + } else { + if (!deserialize(stream, features, data, type)) + return false; + } + return checkStreamValid(stream); +} + +bool Serializers::deserialize(QDataStream &stream, const Quassel::Features &features, QVariant &data, Types::VariantType type) +{ + switch (type) { + case Types::VariantType::Void: { + return true; + } + case Types::VariantType::Bool: { + bool content; + if (!deserialize(stream, features, content)) + return false; + data = QVariant(content); + return true; + } + case Types::VariantType::Int: { + int32_t content; + if (!deserialize(stream, features, content)) + return false; + data = QVariant(content); + return true; + } + case Types::VariantType::UInt: { + uint32_t content; + if (!deserialize(stream, features, content)) + return false; + data = QVariant(content); + return true; + } + case Types::VariantType::QChar: { + QChar content; + if (!deserialize(stream, features, content)) + return false; + data = QVariant(content); + return true; + } + case Types::VariantType::QVariantMap: { + QVariantMap content; + if (!deserialize(stream, features, content)) + return false; + data = QVariant(content); + return true; + } + case Types::VariantType::QVariantList: { + QVariantList content; + if (!deserialize(stream, features, content)) + return false; + data = QVariant(content); + return true; + } + case Types::VariantType::QString: { + QString content; + if (!deserialize(stream, features, content)) + return false; + data = QVariant(content); + return true; + } + case Types::VariantType::QStringList: { + QStringList content; + if (!deserialize(stream, features, content)) + return false; + data = QVariant(content); + return true; + } + case Types::VariantType::QByteArray: { + QByteArray content; + if (!deserialize(stream, features, content)) + return false; + data = QVariant(content); + return true; + } + case Types::VariantType::QDate: { + QDate content; + if (!deserialize(stream, features, content)) + return false; + data = QVariant(content); + return true; + } + case Types::VariantType::QTime: { + QTime content; + if (!deserialize(stream, features, content)) + return false; + data = QVariant(content); + return true; + } + case Types::VariantType::QDateTime: { + QDateTime content; + if (!deserialize(stream, features, content)) + return false; + data = QVariant(content); + return true; + } + case Types::VariantType::Long: { + qlonglong content; + if (!deserialize(stream, features, content)) + return false; + data = QVariant(content); + return true; + } + case Types::VariantType::Short: { + int16_t content; + if (!deserialize(stream, features, content)) + return false; + data = QVariant(content); + return true; + } + case Types::VariantType::Char: { + int8_t content; + if (!deserialize(stream, features, content)) + return false; + data = QVariant(content); + return true; + } + case Types::VariantType::ULong: { + qulonglong content; + if (!deserialize(stream, features, content)) + return false; + data = QVariant(content); + return true; + } + case Types::VariantType::UShort: { + uint16_t content; + if (!deserialize(stream, features, content)) + return false; + data = QVariant(content); + return true; + } + case Types::VariantType::UChar: { + uint8_t content; + if (!deserialize(stream, features, content)) + return false; + data = QVariant(content); + return true; + } + case Types::VariantType::QVariant: { + QVariant content; + if (!deserialize(stream, features, content)) + return false; + data = QVariant(content); + return true; + } + default: { + qWarning() << "Usertype should have been caught earlier already"; + return false; + } + } +} + +bool Serializers::deserialize(QDataStream &stream, const Quassel::Features &features, QVariant &data, Types::QuasselType type) +{ + switch (type) { + case Types::QuasselType::BufferId: { + BufferId content; + if (!deserialize(stream, features, content)) + return false; + data = qVariantFromValue(content); + return true; + } + case Types::QuasselType::BufferInfo: { + BufferInfo content; + if (!deserialize(stream, features, content)) + return false; + data = qVariantFromValue(content); + return true; + } + case Types::QuasselType::Identity: { + Identity content; + if (!deserialize(stream, features, content)) + return false; + data = qVariantFromValue(content); + return true; + } + case Types::QuasselType::IdentityId: { + IdentityId content; + if (!deserialize(stream, features, content)) + return false; + data = qVariantFromValue(content); + return true; + } + case Types::QuasselType::Message: { + Message content; + if (!deserialize(stream, features, content)) + return false; + data = qVariantFromValue(content); + return true; + } + case Types::QuasselType::MsgId: { + MsgId content; + if (!deserialize(stream, features, content)) + return false; + data = qVariantFromValue(content); + return true; + } + case Types::QuasselType::NetworkId: { + NetworkId content; + if (!deserialize(stream, features, content)) + return false; + data = qVariantFromValue(content); + return true; + } + case Types::QuasselType::NetworkInfo: { + NetworkInfo content; + if (!deserialize(stream, features, content)) + return false; + data = qVariantFromValue(content); + return true; + } + case Types::QuasselType::Network_Server: { + Network::Server content; + if (!deserialize(stream, features, content)) + return false; + data = qVariantFromValue(content); + return true; + } + case Types::QuasselType::PeerPtr: { + PeerPtr content; + if (!deserialize(stream, features, content)) + return false; + data = qVariantFromValue(content); + return true; + } + default: { + qWarning() << "Invalid QType"; + return false; + } + } +} + +bool Serializers::deserialize(QDataStream &stream, const Quassel::Features &features, Types::VariantType &data) +{ + uint32_t raw; + if (!deserialize(stream, features, raw)) + return false; + data = static_cast(raw); + return checkStreamValid(stream); +} + +bool Serializers::deserialize(QDataStream &stream, const Quassel::Features &features, QStringList &data) +{ + uint32_t size; + if (!deserialize(stream, features, size)) + return false; + for (uint32_t i = 0; i < size; i++) { + QString element; + if (!deserialize(stream, features, element)) + return false; + data << element; + } + return checkStreamValid(stream); +} + +bool Serializers::deserialize(QDataStream &stream, const Quassel::Features &features, Network::Server &server) +{ + Q_UNUSED(features); + QVariantMap serverMap; + if (!deserialize(stream, features, serverMap)) + return false; + server.host = serverMap["Host"].toString(); + server.port = serverMap["Port"].toUInt(); + server.password = serverMap["Password"].toString(); + server.useSsl = serverMap["UseSSL"].toBool(); + server.sslVerify = serverMap["sslVerify"].toBool(); + server.sslVersion = serverMap["sslVersion"].toInt(); + server.useProxy = serverMap["UseProxy"].toBool(); + server.proxyType = serverMap["ProxyType"].toInt(); + server.proxyHost = serverMap["ProxyHost"].toString(); + server.proxyPort = serverMap["ProxyPort"].toUInt(); + server.proxyUser = serverMap["ProxyUser"].toString(); + server.proxyPass = serverMap["ProxyPass"].toString(); + return checkStreamValid(stream); +} + +bool Serializers::deserialize(QDataStream &stream, const Quassel::Features &features, Identity &data) +{ + Q_UNUSED(features); + QVariantMap raw; + if (!deserialize(stream, features, raw)) + return false; + data.fromVariantMap(raw); + return checkStreamValid(stream); +} + +bool Serializers::deserialize(QDataStream &stream, const Quassel::Features &features, NetworkInfo &info) +{ + Q_UNUSED(features); + QVariantMap i; + if (!deserialize(stream, features, i)) + return false; + info.networkId = i["NetworkId"].value(); + info.networkName = i["NetworkName"].toString(); + info.identity = i["Identity"].value(); + info.codecForServer = i["CodecForServer"].toByteArray(); + info.codecForEncoding = i["CodecForEncoding"].toByteArray(); + info.codecForDecoding = i["CodecForDecoding"].toByteArray(); + info.serverList = fromVariantList(i["ServerList"].toList()); + info.useRandomServer = i["UseRandomServer"].toBool(); + info.perform = i["Perform"].toStringList(); + info.useAutoIdentify = i["UseAutoIdentify"].toBool(); + info.autoIdentifyService = i["AutoIdentifyService"].toString(); + info.autoIdentifyPassword = i["AutoIdentifyPassword"].toString(); + info.useSasl = i["UseSasl"].toBool(); + info.saslAccount = i["SaslAccount"].toString(); + info.saslPassword = i["SaslPassword"].toString(); + info.useAutoReconnect = i["UseAutoReconnect"].toBool(); + info.autoReconnectInterval = i["AutoReconnectInterval"].toUInt(); + info.autoReconnectRetries = i["AutoReconnectRetries"].toInt(); + info.unlimitedReconnectRetries = i["UnlimitedReconnectRetries"].toBool(); + info.rejoinChannels = i["RejoinChannels"].toBool(); + // Custom rate limiting + info.useCustomMessageRate = i["UseCustomMessageRate"].toBool(); + info.messageRateBurstSize = i["MessageRateBurstSize"].toUInt(); + info.messageRateDelay = i["MessageRateDelay"].toUInt(); + info.unlimitedMessageRate = i["UnlimitedMessageRate"].toBool(); + return checkStreamValid(stream); +} + +bool Serializers::deserialize(QDataStream &stream, const Quassel::Features &features, PeerPtr &data) +{ + Q_UNUSED(features); + stream >> data; + return checkStreamValid(stream); +} + +bool Serializers::deserialize(QDataStream &stream, const Quassel::Features &features, QByteArray &data) +{ + Q_UNUSED(features); + data.clear(); + uint32_t length; + if (!deserialize(stream, features, length)) + return false; + // -1 - or 0xffffffff - is used for an empty byte array + if (length == 0xffffffff) { + return true; + } + + // 64 MB should be enough + if (length > 64 * 1024 * 1024) { + qWarning() << "Peer sent too large QByteArray: " << length; + return false; + } + + const uint32_t Step = 1024 * 1024; + uint32_t allocated = 0; + do { + int blockSize = std::min(Step, length - allocated); + data.resize(allocated + blockSize); + if (stream.readRawData(data.data() + allocated, blockSize) != blockSize) { + data.clear(); + qWarning() << "BufferUnderFlow while reading QByteArray"; + return false; + } + allocated += blockSize; + } while (allocated < length); + return checkStreamValid(stream); +} + +bool Serializers::deserialize(QDataStream &stream, const Quassel::Features &features, QString &data) +{ + Q_UNUSED(features); + uint32_t bytes = 0; + // read size of string + if (!deserialize(stream, features, bytes)) + return false; + + // empty string + if (bytes == 0) { + return true; + } + + // null string + if (bytes == 0xffffffff) { + data.clear(); + return true; + } + + // 64 MB should be enough + if (bytes > 64 * 1024 * 1024) { + qWarning() << "Peer sent too large QString: " << bytes; + return false; + } + + if (bytes & 0x1) { + data.clear(); + qWarning() << "Read corrupted data: UTF-6 String with odd length: " << bytes; + return false; + } + const uint32_t step = 1024 * 1024; + uint32_t length = bytes / 2; + uint32_t allocated = 0; + while (allocated < length) { + int blockSize = std::min(step, length - allocated); + data.resize(allocated + blockSize); + if (stream.readRawData(reinterpret_cast(data.data()) + allocated * 2, blockSize * 2) != blockSize * 2) { + data.clear(); + qWarning() << "BufferUnderFlow while reading QString"; + return false; + } + allocated += blockSize; + } + if ((stream.byteOrder() == QDataStream::BigEndian) != (QSysInfo::ByteOrder == QSysInfo::BigEndian)) { + uint16_t *rawData = reinterpret_cast(data.data()); + while (length--) { + *rawData = qbswap(*rawData); + ++rawData; + } + } + return checkStreamValid(stream); +} + +bool Serializers::deserialize(QDataStream &stream, const Quassel::Features &features, QChar &data) +{ + Q_UNUSED(features); + stream >> data; + return checkStreamValid(stream); +} + +bool Serializers::deserialize(QDataStream &stream, const Quassel::Features &features, QDate &data) +{ + Q_UNUSED(features); + stream >> data; + return checkStreamValid(stream); +} + +bool Serializers::deserialize(QDataStream &stream, const Quassel::Features &features, QTime &data) +{ + Q_UNUSED(features); + stream >> data; + return checkStreamValid(stream); +} + +bool Serializers::deserialize(QDataStream &stream, const Quassel::Features &features, QDateTime &data) +{ + Q_UNUSED(features); + stream >> data; + return checkStreamValid(stream); +} + +bool Serializers::deserialize(QDataStream &stream, const Quassel::Features &features, int32_t &data) +{ + Q_UNUSED(features); + stream >> data; + return checkStreamValid(stream); +} + +bool Serializers::deserialize(QDataStream &stream, const Quassel::Features &features, uint32_t &data) +{ + Q_UNUSED(features); + stream >> data; + return checkStreamValid(stream); +} + +bool Serializers::deserialize(QDataStream &stream, const Quassel::Features &features, int16_t &data) +{ + Q_UNUSED(features); + stream >> data; + return checkStreamValid(stream); +} + +bool Serializers::deserialize(QDataStream &stream, const Quassel::Features &features, uint16_t &data) +{ + Q_UNUSED(features); + stream >> data; + return checkStreamValid(stream); +} + +bool Serializers::deserialize(QDataStream &stream, const Quassel::Features &features, int8_t &data) +{ + Q_UNUSED(features); + stream >> data; + return checkStreamValid(stream); +} + +bool Serializers::deserialize(QDataStream &stream, const Quassel::Features &features, uint8_t &data) +{ + Q_UNUSED(features); + stream >> data; + return checkStreamValid(stream); +} + +bool Serializers::deserialize(QDataStream &stream, const Quassel::Features &features, qlonglong &data) +{ + Q_UNUSED(features); + stream >> data; + return checkStreamValid(stream); +} + +bool Serializers::deserialize(QDataStream &stream, const Quassel::Features &features, qulonglong &data) +{ + Q_UNUSED(features); + stream >> data; + return checkStreamValid(stream); +} + +bool Serializers::deserialize(QDataStream &stream, const Quassel::Features &features, bool &data) +{ + Q_UNUSED(features); + stream >> data; + return checkStreamValid(stream); +} + +bool Serializers::deserialize(QDataStream &stream, const Quassel::Features &features, BufferInfo &data) +{ + Q_UNUSED(features); + stream >> data; + return checkStreamValid(stream); +} + +bool Serializers::deserialize(QDataStream &stream, const Quassel::Features &features, Message &data) +{ + Q_UNUSED(features); + stream >> data; + return checkStreamValid(stream); +} + +bool Serializers::deserialize(QDataStream &stream, const Quassel::Features &features, NetworkId &data) +{ + Q_UNUSED(features); + stream >> data; + return checkStreamValid(stream); +} + +bool Serializers::deserialize(QDataStream &stream, const Quassel::Features &features, IdentityId &data) +{ + Q_UNUSED(features); + stream >> data; + return checkStreamValid(stream); +} + +bool Serializers::deserialize(QDataStream &stream, const Quassel::Features &features, BufferId &data) +{ + Q_UNUSED(features); + stream >> data; + return checkStreamValid(stream); +} + +bool Serializers::deserialize(QDataStream &stream, const Quassel::Features &features, MsgId &data) +{ + Q_UNUSED(features); + stream >> data; + return checkStreamValid(stream); +} + +Serializers::Types::VariantType Serializers::Types::variantType(Serializers::Types::QuasselType type) +{ + switch (type) { + case QuasselType::BufferId: + return VariantType::UserType; + case QuasselType::BufferInfo: + return VariantType::UserType; + case QuasselType::Identity: + return VariantType::UserType; + case QuasselType::IdentityId: + return VariantType::UserType; + case QuasselType::Message: + return VariantType::UserType; + case QuasselType::MsgId: + return VariantType::UserType; + case QuasselType::NetworkId: + return VariantType::UserType; + case QuasselType::NetworkInfo: + return VariantType::UserType; + case QuasselType::Network_Server: + return VariantType::UserType; + case QuasselType::PeerPtr: + return VariantType::Long; + default: + return VariantType::UserType; + } +} + +QString Serializers::Types::toName(Serializers::Types::QuasselType type) +{ + switch (type) { + case QuasselType::BufferId: + return QString("BufferId"); + case QuasselType::BufferInfo: + return QString("BufferInfo"); + case QuasselType::Identity: + return QString("Identity"); + case QuasselType::IdentityId: + return QString("IdentityId"); + case QuasselType::Message: + return QString("Message"); + case QuasselType::MsgId: + return QString("MsgId"); + case QuasselType::NetworkId: + return QString("NetworkId"); + case QuasselType::NetworkInfo: + return QString("NetworkInfo"); + case QuasselType::Network_Server: + return QString("Network::Server"); + case QuasselType::PeerPtr: + return QString("PeerPtr"); + default: + return QString("Invalid Type"); + } +} + +Serializers::Types::QuasselType Serializers::Types::fromName(::QByteArray &name) +{ + if (qstrcmp(name, "BufferId") == 0) return QuasselType::BufferId; + else if (qstrcmp(name, "BufferInfo") == 0) return QuasselType::BufferInfo; + else if (qstrcmp(name, "Identity") == 0) return QuasselType::Identity; + else if (qstrcmp(name, "IdentityId") == 0) return QuasselType::IdentityId; + else if (qstrcmp(name, "Message") == 0) return QuasselType::Message; + else if (qstrcmp(name, "MsgId") == 0) return QuasselType::MsgId; + else if (qstrcmp(name, "NetworkId") == 0) return QuasselType::NetworkId; + else if (qstrcmp(name, "NetworkInfo") == 0) return QuasselType::NetworkInfo; + else if (qstrcmp(name, "Network::Server") == 0) return QuasselType::Network_Server; + else if (qstrcmp(name, "PeerPtr") == 0) return QuasselType::PeerPtr; + else { + qWarning() << "Type name is not valid: " << name; + return QuasselType::Invalid; + } +} diff --git a/src/common/serializers/serializers.h b/src/common/serializers/serializers.h new file mode 100644 index 00000000..b3c0aa04 --- /dev/null +++ b/src/common/serializers/serializers.h @@ -0,0 +1,117 @@ +/*************************************************************************** + * Copyright (C) 2005-2018 by the Quassel Project * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) version 3. * + * * + * This program 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#pragma once + +#include +#include +#include +#include +#include + +#include "bufferinfo.h" +#include "identity.h" +#include "message.h" +#include "network.h" +#include "peer.h" + +namespace Serializers { + namespace Types { + enum class VariantType : quint32 { + Void = 0, + Bool = 1, + Int = 2, + UInt = 3, + + QChar = 7, + QVariantMap = 8, + QVariantList = 9, + QString = 10, + QStringList = 11, + QByteArray = 12, + + QDate = 14, + QTime = 15, + QDateTime = 16, + + Long = 129, + Short = 130, + Char = 131, + ULong = 132, + UShort = 133, + UChar = 134, + + QVariant = 138, + + UserType = 127 + }; + + enum class QuasselType { + Invalid, + BufferId, + BufferInfo, + Identity, + IdentityId, + Message, + MsgId, + NetworkId, + NetworkInfo, + Network_Server, + PeerPtr + }; + + VariantType variantType(QuasselType type); + QString toName(QuasselType type); + Types::QuasselType fromName(::QByteArray &name); + } + + bool deserialize(QDataStream &stream, const Quassel::Features &features, QVariant &data); + bool deserialize(QDataStream &stream, const Quassel::Features &features, QVariantList &list); + bool deserialize(QDataStream &stream, const Quassel::Features &features, QVariantMap &data); + bool deserialize(QDataStream &stream, const Quassel::Features &features, QVariant &data, Types::VariantType type); + bool deserialize(QDataStream &stream, const Quassel::Features &features, QVariant &data, Types::QuasselType type); + bool deserialize(QDataStream &stream, const Quassel::Features &features, bool &data); + bool deserialize(QDataStream &stream, const Quassel::Features &features, int8_t &data); + bool deserialize(QDataStream &stream, const Quassel::Features &features, uint8_t &data); + bool deserialize(QDataStream &stream, const Quassel::Features &features, int16_t &data); + bool deserialize(QDataStream &stream, const Quassel::Features &features, uint16_t &data); + bool deserialize(QDataStream &stream, const Quassel::Features &features, int32_t &data); + bool deserialize(QDataStream &stream, const Quassel::Features &features, uint32_t &data); + bool deserialize(QDataStream &stream, const Quassel::Features &features, qlonglong &data); + bool deserialize(QDataStream &stream, const Quassel::Features &features, qulonglong &data); + bool deserialize(QDataStream &stream, const Quassel::Features &features, Types::VariantType &data); + bool deserialize(QDataStream &stream, const Quassel::Features &features, QChar &data); + bool deserialize(QDataStream &stream, const Quassel::Features &features, QString &data); + bool deserialize(QDataStream &stream, const Quassel::Features &features, QTime &data); + bool deserialize(QDataStream &stream, const Quassel::Features &features, QDate &data); + bool deserialize(QDataStream &stream, const Quassel::Features &features, QDateTime &data); + bool deserialize(QDataStream &stream, const Quassel::Features &features, QByteArray &data); + bool deserialize(QDataStream &stream, const Quassel::Features &features, QStringList &data); + bool deserialize(QDataStream &stream, const Quassel::Features &features, Message &data); + bool deserialize(QDataStream &stream, const Quassel::Features &features, BufferInfo &data); + bool deserialize(QDataStream &stream, const Quassel::Features &features, BufferId &data); + bool deserialize(QDataStream &stream, const Quassel::Features &features, IdentityId &data); + bool deserialize(QDataStream &stream, const Quassel::Features &features, NetworkId &data); + bool deserialize(QDataStream &stream, const Quassel::Features &features, MsgId &data); + bool deserialize(QDataStream &stream, const Quassel::Features &features, PeerPtr &data); + bool deserialize(QDataStream &stream, const Quassel::Features &features, NetworkInfo &data); + bool deserialize(QDataStream &stream, const Quassel::Features &features, Identity &data); + bool deserialize(QDataStream &stream, const Quassel::Features &features, Network::Server &data); +};