// This is an open source non-commercial project. Dear PVS-Studio, please check it. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com #include "unpack_p.h" #include "../endianhelper.h" #include #include #include #include #include MsgPackPrivate::type_parser_f MsgPackPrivate::unpackers[32] = { MsgPackPrivate::unpack_nil, MsgPackPrivate::unpack_never_used, MsgPackPrivate::unpack_false, MsgPackPrivate::unpack_true, MsgPackPrivate::unpack_bin8, MsgPackPrivate::unpack_bin16, MsgPackPrivate::unpack_bin32, MsgPackPrivate::unpack_ext8, MsgPackPrivate::unpack_ext16, MsgPackPrivate::unpack_ext32, MsgPackPrivate::unpack_float32, MsgPackPrivate::unpack_float64, MsgPackPrivate::unpack_uint8, MsgPackPrivate::unpack_uint16, MsgPackPrivate::unpack_uint32, MsgPackPrivate::unpack_uint64, MsgPackPrivate::unpack_int8, MsgPackPrivate::unpack_int16, MsgPackPrivate::unpack_int32, MsgPackPrivate::unpack_int64, MsgPackPrivate::unpack_fixext1, MsgPackPrivate::unpack_fixext2, MsgPackPrivate::unpack_fixext4, MsgPackPrivate::unpack_fixext8, MsgPackPrivate::unpack_fixext16, MsgPackPrivate::unpack_str8, MsgPackPrivate::unpack_str16, MsgPackPrivate::unpack_str32, MsgPackPrivate::unpack_array16, MsgPackPrivate::unpack_array32, MsgPackPrivate::unpack_map16, MsgPackPrivate::unpack_map32 }; QHash MsgPackPrivate::user_unpackers; QReadWriteLock MsgPackPrivate::unpackers_lock; QVariant MsgPackPrivate::unpack(const quint8 *p, const quint8 *end) { QVariantList d; QVariant v; quint8* pos = const_cast(p); // FIXME while (pos <= end) { pos = unpack_type(v, pos); d.append(v); } if (pos - end > 1) return QVariant(); if (d.length() == 1) return d[0]; return d; } quint8 *MsgPackPrivate::unpack_type(QVariant &v, quint8 *p) { if (*p <= 127) { // positive fixint 0x00 - 0x7f p = unpack_positive_fixint(v, p); } else if (*p >= 0xe0) { // negative fixint 0xe0 - 0xff p = unpack_negative_fixint(v, p); } else if (*p >= 0x80 && *p <= 0x8f) { // fixmap 1000xxxx 0x80 - 0x8f p = unpack_fixmap(v, p); } else if (*p >= 0x90 && *p <= 0x9f) { // fixarray 1001xxxx 0x90 - 0x9f p = unpack_fixarray(v, p); } else if (*p >= 0xa0 && *p <= 0xbf) { // fixstr 101xxxxx 0xa0 - 0xbf p = unpack_fixstr(v, p); } else { // all other types p = (unpackers[*p - 0xc0])(v, p); } //qDebug() << "unpack type res:" << d << sz; return p; } quint8 * MsgPackPrivate::unpack_nil(QVariant &v, quint8 *p) { Q_UNUSED(p) Q_UNUSED(v) v = QVariant(); return p + 1; } quint8 * MsgPackPrivate::unpack_never_used(QVariant &v, quint8 *p) { Q_UNUSED(p) Q_UNUSED(v) v = QVariant(); return p + 1; } quint8 * MsgPackPrivate::unpack_false(QVariant &v, quint8 *p) { Q_UNUSED(p) v = false; return p + 1; } quint8 * MsgPackPrivate::unpack_true(QVariant &v, quint8 *p) { Q_UNUSED(p) v = true; return p + 1; } quint8 * MsgPackPrivate::unpack_positive_fixint(QVariant &v, quint8 *p) { v = static_cast(*p); return p + 1; } quint8 * MsgPackPrivate::unpack_negative_fixint(QVariant &v, quint8 *p) { v = static_cast(*p); return p + 1; } quint8 * MsgPackPrivate::unpack_uint8(QVariant &v, quint8 *p) { v = static_cast(*(++p)); return p + 1; } quint8 * MsgPackPrivate::unpack_uint16(QVariant &v, quint8 *p) { p++; v = static_cast(_msgpack_load16(quint16, p)); return p + 2; } quint8 * MsgPackPrivate::unpack_uint32(QVariant &v, quint8 *p) { p++; v = _msgpack_load32(quint32, p); return p + 4; } quint8 * MsgPackPrivate::unpack_uint64(QVariant &v, quint8 *p) { p++; v = _msgpack_load64(quint64, p); return p + 8; } quint8 * MsgPackPrivate::unpack_int8(QVariant &v, quint8 *p) { v = static_cast(*(++p)); return p + 1; } quint8 * MsgPackPrivate::unpack_int16(QVariant &v, quint8 *p) { p++; v = _msgpack_load16(qint16, p); return p + 2; } quint8 * MsgPackPrivate::unpack_int32(QVariant &v, quint8 *p) { p++; v = _msgpack_load32(qint32, p); return p + 4; } quint8 * MsgPackPrivate::unpack_int64(QVariant &v, quint8 *p) { p++; v = _msgpack_load64(qint64, p); return p + 8; } quint8 * MsgPackPrivate::unpack_float32(QVariant &v, quint8 *p) { float f; quint8 *fp = reinterpret_cast(&f); p++; #ifdef __LITTLE_ENDIAN__ for (int i = 0; i < 4; ++i) *(fp + 3 - i) = *(p + i); #else for (int i = 0; i < 4; ++i) *(fp + i) = *(p + i); #endif v = f; return p + 4; } quint8 * MsgPackPrivate::unpack_float64(QVariant &v, quint8 *p) { double d; quint8 *fd = reinterpret_cast(&d); p++; #ifdef __LITTLE_ENDIAN__ for (int i = 0; i < 8; ++i) *(fd + 7 - i) = *(p + i); #else for (int i = 0; i < 8; ++i) *(fp + i) = *(p + i); #endif v = d; return p + 8; } quint8 * MsgPackPrivate::unpack_fixstr(QVariant &v, quint8 *p) { int len = (*p) & 0x1f; // 0b00011111 p++; v = QString::fromUtf8(reinterpret_cast(p), len); return p + len; } quint8 * MsgPackPrivate::unpack_str8(QVariant &v, quint8 *p) { int len = *(++p); v = QString::fromUtf8(reinterpret_cast((++p)), len); return p + len; } quint8 * MsgPackPrivate::unpack_str16(QVariant &v, quint8 *p) { p++; int len = _msgpack_load16(int, p); p += 2; v = QString::fromUtf8(reinterpret_cast(p), len); return p + len; } quint8 * MsgPackPrivate::unpack_str32(QVariant &v, quint8 *p) { p++; int len = _msgpack_load32(int, p); p += 4; v = QString::fromUtf8(reinterpret_cast(p), len); return p + len; } quint8 * MsgPackPrivate::unpack_bin8(QVariant &v, quint8 *p) { int len = *(++p); v = QByteArray(reinterpret_cast((++p)), len); return p + len; } quint8 * MsgPackPrivate::unpack_bin16(QVariant &v, quint8 *p) { p++; int len = _msgpack_load16(int, p); p += 2; v = QByteArray(reinterpret_cast(p), len); return p + len; } quint8 * MsgPackPrivate::unpack_bin32(QVariant &v, quint8 *p) { p++; int len = _msgpack_load32(int, p); p += 4; v = QByteArray(reinterpret_cast(p), len); return p + len; } quint8 * MsgPackPrivate::unpack_array_len(QVariant &v, quint8 *p, quint32 len) { QVariantList arr; QVariant vu; for (quint32 i = 0; i < len; ++i) { p = unpack_type(vu, p); arr.append(vu); } v = arr; return p; } quint8 * MsgPackPrivate::unpack_fixarray(QVariant &v, quint8 *p) { quint32 len = (*p++) & 0x0f; // 0b00001111 return unpack_array_len(v, p, len); } quint8 * MsgPackPrivate::unpack_array16(QVariant &v, quint8 *p) { p++; quint32 len = _msgpack_load16(quint32, p); return unpack_array_len(v, p + 2, len); } quint8 * MsgPackPrivate::unpack_array32(QVariant &v, quint8 *p) { p++; quint32 len = _msgpack_load32(quint32, p); return unpack_array_len(v, p + 4, len); } quint8 * MsgPackPrivate::unpack_map_len(QVariant &v, quint8 *p, quint32 len) { QMap map; QVariant key, val; for (quint32 i = 0; i < len; ++i) { p = unpack_type(key, p); p = unpack_type(val, p); map.insert(key.toString(), val); } v = map; return p; } quint8 * MsgPackPrivate::unpack_fixmap(QVariant &v, quint8 *p) { quint32 len = (*p++) & 0x0f; // 0b00001111 return unpack_map_len(v, p ,len); } quint8 * MsgPackPrivate::unpack_map16(QVariant &v, quint8 *p) { p++; quint32 len = _msgpack_load16(quint32, p); return unpack_map_len(v, p + 2, len); } quint8 * MsgPackPrivate::unpack_map32(QVariant &v, quint8 *p) { p++; quint32 len = _msgpack_load32(quint32, p); return unpack_map_len(v, p + 4, len); } quint8 *MsgPackPrivate::unpack_ext(QVariant &v, quint8 *p, qint8 type, quint32 len) { QReadLocker locker(&unpackers_lock); if (!user_unpackers.contains(type)) { qWarning() << "MsgPack::unpack() unpacker for type" << type << "doesn't exist"; return p + len; } QByteArray data(reinterpret_cast(p), static_cast(len)); v = user_unpackers[type](data); return p + len; } quint8 * MsgPackPrivate::unpack_fixext1(QVariant &v, quint8 *p) { qint8 type = static_cast(*(++p)); return unpack_ext(v, p + 1, type, 1); } quint8 * MsgPackPrivate::unpack_fixext2(QVariant &v, quint8 *p) { qint8 type = static_cast(*(++p)); return unpack_ext(v, p + 1, type, 2); } quint8 * MsgPackPrivate::unpack_fixext4(QVariant &v, quint8 *p) { qint8 type = static_cast(*(++p)); return unpack_ext(v, p + 1, type, 4); } quint8 * MsgPackPrivate::unpack_fixext8(QVariant &v, quint8 *p) { qint8 type = static_cast(*(++p)); return unpack_ext(v, p + 1, type, 8); } quint8 * MsgPackPrivate::unpack_fixext16(QVariant &v, quint8 *p) { qint8 type = static_cast(*(++p)); return unpack_ext(v, p + 1, type, 16); } quint8 * MsgPackPrivate::unpack_ext8(QVariant &v, quint8 *p) { p++; quint32 len = *(p); p += 1; qint8 type = static_cast(*p); return unpack_ext(v, p + 1, type, len); } quint8 * MsgPackPrivate::unpack_ext16(QVariant &v, quint8 *p) { p++; quint32 len = _msgpack_load16(quint32, p); p += 2; qint8 type = static_cast(*p); return unpack_ext(v, p + 1, type, len); } quint8 * MsgPackPrivate::unpack_ext32(QVariant &v, quint8 *p) { p++; quint32 len = _msgpack_load32(quint32, p); p += 4; qint8 type = static_cast(*p); return unpack_ext(v, p + 1, type, len); } bool MsgPackPrivate::register_unpacker(qint8 msgpack_type, MsgPack::unpack_user_f unpacker) { if (unpacker == nullptr) { qWarning() << "MsgPack::unpacker for type" << msgpack_type << "is invalid"; return false; } QWriteLocker locker(&unpackers_lock); if (user_unpackers.contains(msgpack_type)) { qWarning() << "MsgPack::unpacker for type" << msgpack_type << "already exists"; return false; } user_unpackers.insert(msgpack_type, unpacker); return true; }