#include "pack_p.h" #include "private/sysdep.h" #include #include #include #include #include #include #include #include QHash MsgPackPrivate::user_packers; bool MsgPackPrivate::compatibilityMode = false; QReadWriteLock MsgPackPrivate::packers_lock; quint8 *MsgPackPrivate::pack(const QVariant &v, quint8 *p, bool wr, QVector &user_data) { QMetaType::Type t = (QMetaType::Type)v.type(); if (t == QMetaType::Int) p = pack_int(v.toInt(), p, wr); else if (t == QMetaType::UInt) p = pack_uint(v.toUInt(), p, wr); else if (t == QMetaType::Bool) p = pack_bool(v, p, wr); else if (t == QMetaType::QString) p = pack_string(v.toString(), p, wr); else if (t == QMetaType::QVariantList) p = pack_array(v.toList(), p, wr, user_data); else if (t == QMetaType::QStringList) p = pack_stringlist(v.toStringList(), p, wr); else if (t == QMetaType::LongLong) p = pack_longlong(v.toLongLong(), p, wr); else if (t == QMetaType::ULongLong) p = pack_ulonglong(v.toULongLong(), p, wr); else if (t == QMetaType::Double) p = pack_double(v.toDouble(), p, wr); else if (t == QMetaType::Float) p = pack_float(v.toFloat(), p, wr); else if (t == QMetaType::QByteArray) p = pack_bin(v.toByteArray(), p, wr); else if (t == QMetaType::QVariantMap) p = pack_map(v.toMap(), p, wr, user_data); else { if (t == QMetaType::User) t = (QMetaType::Type)v.userType(); QReadLocker locker(&packers_lock); bool has_packer = user_packers.contains(t); locker.unlock(); if (has_packer) p = pack_user(v, p, wr, user_data); else qWarning() << "MsgPack::pack can't pack type:" << t; } return p; } quint8 *MsgPackPrivate::pack_int(qint32 i, quint8 *p, bool wr) { if (i >= -32 && i <= 127) { qint32 val = _msgpack_be32(i); if (wr) *p = *( (quint8 *)&val + 3 ); p++; } else if (i >= std::numeric_limits::min() && i <= std::numeric_limits::max()) { if (wr) *p = i > 0 ? 0xcc : 0xd0; p++; if (wr) *p = i; p++; } else if (i >= std::numeric_limits::min() && i <= std::numeric_limits::max()) { if (wr) *p = i > 0 ? 0xcd : 0xd1; p++; if (wr) _msgpack_store16(p, i); p += 2; } else { if (wr) *p = i > 0 ? 0xce : 0xd2; p++; if (wr) _msgpack_store32(p, i); p += 4; } return p; } quint8 *MsgPackPrivate::pack_uint(quint32 i, quint8 *p, bool wr) { if (i <= 127) { qint32 val = _msgpack_be32(i); if (wr) *p = *( (quint8 *)&val + 3 ); p++; } else if (i <= std::numeric_limits::max()) { if (wr) *p = 0xcc; p++; if (wr) *p = i; p++; } else if (i <= std::numeric_limits::max()) { if (wr) *p = 0xcd; p++; if (wr) _msgpack_store16(p, i); p += 2; } else { if (wr) *p = 0xce; p++; if (wr) _msgpack_store32(p, i); p += 4; } return p; } quint8 *MsgPackPrivate::pack_longlong(qint64 i, quint8 *p, bool wr) { if (i >= std::numeric_limits::min() && i <= std::numeric_limits::max()) return p = pack_int(i, p, wr); if (wr) *p = 0xd3; p++; if (wr) _msgpack_store64(p, i); return p + 8; } quint8 *MsgPackPrivate::pack_ulonglong(quint64 i, quint8 *p, bool wr) { if (i <= std::numeric_limits::max()) return pack_uint(i, p, wr); if (wr) *p = 0xcf; p++; if (wr) _msgpack_store64(p, i); return p + 8; } quint8 *MsgPackPrivate::pack_bool(const QVariant &v, quint8 *p, bool wr) { if (wr) *p = v.toBool() ? 0xc3 : 0xc2; return p + 1; } quint8 *MsgPackPrivate::pack_arraylen(quint32 len, quint8 *p, bool wr) { if (len <= 15) { if (wr) *p = 0x90 | len; p++; } else if (len <= std::numeric_limits::max()) { if (wr) *p = 0xdc; p++; if (wr) _msgpack_store16(p, len); p += 2; } else { if (wr) *p = 0xdd; p++; if (wr) _msgpack_store32(p, len); p += 4; } return p; } quint8 *MsgPackPrivate::pack_array(const QVariantList &list, quint8 *p, bool wr, QVector &user_data) { int len = list.length(); p = pack_arraylen(len, p, wr); foreach (QVariant item, list) p = pack(item, p, wr, user_data); return p; } quint8 *MsgPackPrivate::pack_stringlist(const QStringList &list, quint8 *p, bool wr) { int len = list.length(); p = pack_arraylen(len, p, wr); foreach (QString item, list) p = pack_string(item, p, wr); return p; } quint8 *MsgPackPrivate::pack_string_raw(const char *str, quint32 len, quint8 *p, bool wr) { if (len <= 31) { if (wr) *p = 0xa0 | len; p++; } else if (len <= std::numeric_limits::max() && compatibilityMode == false) { if (wr) *p = 0xd9; p++; if (wr) *p = len; p++; } else if (len <= std::numeric_limits::max()) { if (wr) *p = 0xda; p++; if (wr) _msgpack_store16(p, len); p += 2; } else { if (wr) *p = 0xdb; p++; if (wr) _msgpack_store32(p, len); p += 4; } if (wr) memcpy(p, str, len); return p + len; } quint8 *MsgPackPrivate::pack_string(const QString &str, quint8 *p, bool wr) { QByteArray str_data = str.toUtf8(); quint32 str_len = str_data.length(); return pack_string_raw(str_data.data(), str_len, p, wr); } quint8 *MsgPackPrivate::pack_float(float f, quint8 *p, bool wr) { if (wr) *p = 0xca; p++; if (wr) { quint8 *d = (quint8 *)&i; #ifdef __LITTLE_ENDIAN__ for (int i = 0; i < 4; ++i) *(p + 3 - i) = *(d + i); #else for (int i = 0; i < 4; ++i) *(p + i) = *(d + i); #endif } return p + 8; } quint8 *MsgPackPrivate::pack_double(double i, quint8 *p, bool wr) { if (wr) *p = 0xcb; p++; if (wr) { quint8 *d = (quint8 *)&i; #ifdef __LITTLE_ENDIAN__ for (int i = 0; i < 8; ++i) *(p + 7 - i) = *(d + i); #else for (int i = 0; i < 8; ++i) *(p + i) = *(d + i); #endif } return p + 8; } quint8 *MsgPackPrivate::pack_bin(const QByteArray &arr, quint8 *p, bool wr) { int len = arr.length(); if (len <= std::numeric_limits::max()) { if (wr) *p = compatibilityMode ? 0xd9 : 0xc4; p++; if (wr) *p = len; p++; } else if (len <= std::numeric_limits::max()) { if (wr) *p = compatibilityMode ? 0xda : 0xc5; p++; if (wr) _msgpack_store16(p, len); p += 2; } else { if (wr) *p = compatibilityMode ? 0xdb : 0xc6; p++; if (wr) _msgpack_store32(p, len); p += 4; } if (wr) memcpy(p, arr.data(), len); p += len; return p; } quint8 *MsgPackPrivate::pack_map(const QVariantMap &map, quint8 *p, bool wr, QVector &user_data) { QMapIterator it(map); int len = 0; while (it.hasNext()) { it.next(); len++; } if (len <= 15) { if (wr) *p = 0x80 | len; p++; } else if (len <= std::numeric_limits::max()) { if (wr) *p = 0xde; p++; if (wr) _msgpack_store16(p, len); p += 2; } else { if (wr) *p = 0xdf; p++; if (wr) _msgpack_store32(p, len); p += 4; } it.toFront(); while (it.hasNext()) { it.next(); p = pack(it.key(), p, wr, user_data); p = pack(it.value(), p, wr, user_data); } return p; } bool MsgPackPrivate::register_packer(QMetaType::Type q_type, qint8 msgpack_type, MsgPack::pack_user_f packer) { if (packer == 0) { qWarning() << "MsgPack::packer for qtype" << q_type << "is invalid"; return false; } QWriteLocker locker(&packers_lock); if (user_packers.contains(q_type)) { qWarning() << "MsgPack::packer for qtype" << q_type << "already exist"; return false; } packer_t p; p.packer = packer; p.type = msgpack_type; user_packers.insert(q_type, p); return true; } quint8 *MsgPackPrivate::pack_user(const QVariant &v, quint8 *p, bool wr, QVector &user_data) { QMetaType::Type t = (QMetaType::Type)v.type() == QMetaType::User ? (QMetaType::Type)v.userType() : (QMetaType::Type)v.type(); QReadLocker locker(&packers_lock); packer_t pt = user_packers[t]; locker.unlock(); QByteArray data; if (wr) { data = user_data.front(); user_data.pop_front(); } else { data = pt.packer(v); user_data.push_back(data); } quint32 len = data.size(); if (len == 1) { if (wr) *p = 0xd4; p++; } else if (len == 2) { if (wr) *p = 0xd5; p++; } else if (len == 4) { if (wr) *p = 0xd6; p++; } else if (len == 8) { if (wr) *p = 0xd7; p++; } else if (len == 16) { if (wr) *p = 0xd8; p++; } else if (len <= std::numeric_limits::max()) { if (wr) *p = 0xc7; p++; if (wr) *p = len; p++; } else if (len <= std::numeric_limits::max()) { if (wr) *p = 0xc8; p++; if (wr) _msgpack_store16(p, len); p += 2; } else { if (wr) *p = 0xc9; p++; if (wr) _msgpack_store32(p, len); p += 4; } if (wr) *p = pt.type; p++; if (wr) memcpy(p, data.data(), len); return p += len; }