diff --git a/src/msgpack.cpp b/src/msgpack.cpp index fdd413d..d9fe7a8 100644 --- a/src/msgpack.cpp +++ b/src/msgpack.cpp @@ -4,6 +4,7 @@ #include "private/pack_p.h" #include "private/qt_types_p.h" #include "private/sysdep.h" +#include QVariant MsgPack::unpack(const QByteArray &data) { @@ -16,13 +17,14 @@ QVariant MsgPack::unpack(const QByteArray &data) QByteArray MsgPack::pack(const QVariant &variant) { quint8 *p = 0; - quint8 *end = MsgPackPrivate::pack(variant, p, false); + QVector user_data; + quint8 *end = MsgPackPrivate::pack(variant, p, false, user_data); quint32 size = end - p; //qDebug() << "size probe:" << size; QByteArray arr; arr.resize(size); - end = MsgPackPrivate::pack(variant, (quint8 *)arr.data(), true); + end = MsgPackPrivate::pack(variant, (quint8 *)arr.data(), true, user_data); return arr; } diff --git a/src/msgpack_common.h b/src/msgpack_common.h index bb36a16..e8cf602 100644 --- a/src/msgpack_common.h +++ b/src/msgpack_common.h @@ -10,14 +10,14 @@ namespace MsgPack { /** - * pack some variant to byte array data - * when write == false only calculates and returns size - * when write == true writes bytes to data, and returns the same size - * return type size + * @brief pack user type to byte array data + * @arg variant user type, must be registered first + * @return array with user data only, all other fields will be added automatically */ -typedef quint32 (*pack_user_f)(const QVariant &variant, QByteArray &data, bool write); +typedef QByteArray (*pack_user_f)(const QVariant &variant); /** - * unpack user type to QVariant + * @brief unpack user type to QVariant + * @arg data only user data, without size and messagepack type */ typedef QVariant (*unpack_user_f)(const QByteArray &data); /** diff --git a/src/private/pack_p.cpp b/src/private/pack_p.cpp index 0793d1f..c94b989 100644 --- a/src/private/pack_p.cpp +++ b/src/private/pack_p.cpp @@ -16,7 +16,7 @@ QHash MsgPackPrivate::user_packers; bool MsgPackPrivate::compatibilityMode = false; QReadWriteLock MsgPackPrivate::packers_lock; -quint8 *MsgPackPrivate::pack(const QVariant &v, quint8 *p, bool wr) +quint8 *MsgPackPrivate::pack(const QVariant &v, quint8 *p, bool wr, QVector &user_data) { QMetaType::Type t = (QMetaType::Type)v.type(); if (t == QMetaType::Int) @@ -28,7 +28,7 @@ quint8 *MsgPackPrivate::pack(const QVariant &v, quint8 *p, bool 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); + 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) @@ -40,7 +40,7 @@ quint8 *MsgPackPrivate::pack(const QVariant &v, quint8 *p, bool 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); + p = pack_map(v.toMap(), p, wr, user_data); else { if (t == QMetaType::User) t = (QMetaType::Type)v.userType(); @@ -48,7 +48,7 @@ quint8 *MsgPackPrivate::pack(const QVariant &v, quint8 *p, bool wr) bool has_packer = user_packers.contains(t); locker.unlock(); if (has_packer) - p = pack_user(v, p, wr); + p = pack_user(v, p, wr, user_data); else qWarning() << "MsgPack::pack can't pack type:" << t; } @@ -157,12 +157,12 @@ quint8 *MsgPackPrivate::pack_arraylen(quint32 len, quint8 *p, bool wr) return p; } -quint8 *MsgPackPrivate::pack_array(const QVariantList &list, quint8 *p, bool wr) +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); + p = pack(item, p, wr, user_data); return p; } @@ -246,7 +246,7 @@ quint8 *MsgPackPrivate::pack_bin(const QByteArray &arr, quint8 *p, bool wr) } -quint8 *MsgPackPrivate::pack_map(const QVariantMap &map, quint8 *p, bool wr) +quint8 *MsgPackPrivate::pack_map(const QVariantMap &map, quint8 *p, bool wr, QVector &user_data) { QMapIterator it(map); int len = 0; @@ -272,8 +272,8 @@ quint8 *MsgPackPrivate::pack_map(const QVariantMap &map, quint8 *p, bool wr) it.toFront(); while (it.hasNext()) { it.next(); - p = pack(it.key(), p, wr); - p = pack(it.value(), p, wr); + p = pack(it.key(), p, wr, user_data); + p = pack(it.value(), p, wr, user_data); } return p; } @@ -296,15 +296,25 @@ bool MsgPackPrivate::register_packer(QMetaType::Type q_type, qint8 msgpack_type, return true; } -quint8 *MsgPackPrivate::pack_user(const QVariant &v, quint8 *p, bool wr) +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(); - QByteArray data; QReadLocker locker(&packers_lock); packer_t pt = user_packers[t]; locker.unlock(); - quint32 len = pt.packer(v, data, wr); + + 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++; diff --git a/src/private/pack_p.h b/src/private/pack_p.h index 4ef57f4..d3afda4 100644 --- a/src/private/pack_p.h +++ b/src/private/pack_p.h @@ -23,7 +23,7 @@ extern QHash user_packers; extern QReadWriteLock packers_lock; extern bool compatibilityMode; -quint8 * pack(const QVariant &v, quint8 *p, bool wr); +quint8 * pack(const QVariant &v, quint8 *p, bool wr, QVector &user_data); quint8 * pack_int(qint32 i, quint8 *p, bool wr); quint8 * pack_uint(quint32 i, quint8 *p, bool wr); @@ -33,14 +33,14 @@ quint8 * pack_ulonglong(quint64 i, quint8 *p, bool wr); quint8 * pack_bool(const QVariant &v, quint8 *p, bool wr); quint8 * pack_arraylen(quint32 len, quint8 *p, bool wr); -quint8 * pack_array(const QVariantList &list, quint8 *p, bool wr); +quint8 * pack_array(const QVariantList &list, quint8 *p, bool wr, QVector &user_data); quint8 * pack_stringlist(const QStringList &list, quint8 *p, bool wr); quint8 * pack_string(const QString &str, quint8 *p, bool wr); quint8 * pack_double(double i, quint8 *p, bool wr); quint8 * pack_bin(const QByteArray &arr, quint8 *p, bool wr); -quint8 * pack_map(const QVariantMap &map, quint8 *p, bool wr); -quint8 * pack_user(const QVariant &v, quint8 *p, bool wr); +quint8 * pack_map(const QVariantMap &map, quint8 *p, bool wr, QVector &user_data); +quint8 * pack_user(const QVariant &v, quint8 *p, bool wr, QVector &user_data); } #endif // PACK_P_H diff --git a/src/private/qt_types_p.cpp b/src/private/qt_types_p.cpp index da3d260..5975429 100644 --- a/src/private/qt_types_p.cpp +++ b/src/private/qt_types_p.cpp @@ -46,18 +46,17 @@ bool MsgPackPrivate::register_qtype(QMetaType::Type q_type, quint8 msgpack_type) } #ifdef QT_GUI_LIB -quint32 MsgPackPrivate::pack_qcolor(const QVariant &variant, QByteArray &data, bool write) +QByteArray MsgPackPrivate::pack_qcolor(const QVariant &variant) { - if (write) { - QColor color = variant.value(); - data.resize(4); - quint8 *p = (quint8 *)data.data(); - p[0] = color.red(); - p[1] = color.green(); - p[2] = color.blue(); - p[3] = color.alpha(); - } - return 4; // 4 bytes: r,g,b,a + QByteArray data; + data.resize(4); + QColor color = variant.value(); + quint8 *p = (quint8 *)data.data(); + p[0] = color.red(); + p[1] = color.green(); + p[2] = color.blue(); + p[3] = color.alpha(); + return data; } QVariant MsgPackPrivate::unpack_qcolor(const QByteArray &data) @@ -96,15 +95,14 @@ QTime MsgPackPrivate::unpack_qtime_raw(quint8 *p, bool with_ms) return QTime(h, m, s, ms); } -quint32 MsgPackPrivate::pack_qtime(const QVariant &variant, QByteArray &data, bool write) +QByteArray MsgPackPrivate::pack_qtime(const QVariant &variant) { QTime time = variant.toTime(); quint8 size = time.msec() == 0 ? 2 : 4; - if (write) { - data.resize(size); - pack_qtime_raw(time, (quint8 *)data.data()); - } - return size; + QByteArray data; + data.resize(size); + pack_qtime_raw(time, (quint8 *)data.data()); + return data; } QVariant MsgPackPrivate::unpack_qtime(const QByteArray &data) @@ -134,13 +132,12 @@ QDate MsgPackPrivate::unpack_qdate_raw(quint8 *p) return QDate(year, month, day); } -quint32 MsgPackPrivate::pack_qdate(const QVariant &variant, QByteArray &data, bool write) +QByteArray MsgPackPrivate::pack_qdate(const QVariant &variant) { - if (write) { - data.resize(3); - pack_qdate_raw(variant.toDate(), (quint8 *)data.data()); - } - return 3; + QByteArray data; + data.resize(3); + pack_qdate_raw(variant.toDate(), (quint8 *)data.data()); + return data; } QVariant MsgPackPrivate::unpack_qdate(const QByteArray &data) @@ -148,18 +145,17 @@ QVariant MsgPackPrivate::unpack_qdate(const QByteArray &data) return unpack_qdate_raw((quint8 *)data.data()); } -quint32 MsgPackPrivate::pack_qdatetime(const QVariant &variant, QByteArray &data, bool write) +QByteArray MsgPackPrivate::pack_qdatetime(const QVariant &variant) { QDateTime dt = variant.toDateTime(); quint8 time_size = dt.time().msec() == 0 ? 2 : 4; - if (write) { - data.resize(3 + time_size); - quint8 *p = (quint8 *)data.data(); - pack_qdate_raw(dt.date(), p); - p += 3; - pack_qtime_raw(dt.time(), p); - } - return 3 + time_size; // 3 for date, 4 for time + QByteArray data; + data.resize(3 + time_size); + quint8 *p = (quint8 *)data.data(); + pack_qdate_raw(dt.date(), p); + p += 3; + pack_qtime_raw(dt.time(), p); + return data; } QVariant MsgPackPrivate::unpack_qdatetime(const QByteArray &data) @@ -171,20 +167,7 @@ QVariant MsgPackPrivate::unpack_qdatetime(const QByteArray &data) } // Points and Vectors -quint8 MsgPackPrivate::pack_two_integers(qint32 a, qint32 b, quint8 *to, bool write) -{ - quint8 *p = 0; - p = MsgPackPrivate::pack_int(a, p, false); - p = MsgPackPrivate::pack_int(b, p, false); - quint8 size = p - (quint8 *)0; - if (write) { - to = MsgPackPrivate::pack_int(a, to, true); - MsgPackPrivate::pack_int(b, to, true); - } - return size; -} - -quint32 MsgPackPrivate::pack_qpoint(const QVariant &variant, QByteArray &data, bool write) +QByteArray MsgPackPrivate::pack_qpoint(const QVariant &variant) { // QPoint pt = variant.toPoint(); // quint8 size = pack_two_integers(pt.x(), pt.y(), 0, false); @@ -208,7 +191,7 @@ QVariant MsgPackPrivate::unpack_qpoint(const QByteArray &data) // return pt; } -quint32 MsgPackPrivate::pack_qsize(const QVariant &variant, QByteArray &data, bool write) +QByteArray MsgPackPrivate::pack_qsize(const QVariant &variant) { // QSize sz = variant.toSize(); // quint8 size = pack_two_integers(sz.width(), sz.height(), 0, false); @@ -232,7 +215,7 @@ QVariant MsgPackPrivate::unpack_qsize(const QByteArray &data) // return sz; } -quint32 MsgPackPrivate::pack_qrect(const QVariant &variant, QByteArray &data, bool write) +QByteArray MsgPackPrivate::pack_qrect(const QVariant &variant) { // QRect rect = variant.toRect(); // QPoint pt1 = rect.topLeft(); diff --git a/src/private/qt_types_p.h b/src/private/qt_types_p.h index 9c90c3e..e0fbc9c 100644 --- a/src/private/qt_types_p.h +++ b/src/private/qt_types_p.h @@ -9,7 +9,7 @@ namespace MsgPackPrivate bool register_qtype(QMetaType::Type q_type, quint8 msgpack_type); #ifdef QT_GUI_LIB -quint32 pack_qcolor(const QVariant &variant, QByteArray &data, bool write); +QByteArray pack_qcolor(const QVariant &variant); QVariant unpack_qcolor(const QByteArray &data); #endif //QT_GUI_LIB @@ -28,7 +28,7 @@ void pack_qtime_raw(const QTime &time, quint8 *p); // return 2 - without ms, 4 w * @return QTime */ QTime unpack_qtime_raw(quint8 *p, bool with_ms); -quint32 pack_qtime(const QVariant &variant, QByteArray &data, bool write); +QByteArray pack_qtime(const QVariant &variant); QVariant unpack_qtime(const QByteArray &data); /** @@ -40,19 +40,18 @@ QVariant unpack_qtime(const QByteArray &data); void pack_qdate_raw(const QDate &date, quint8 *p); /// @brief internal: unpack bytes to QDate QDate unpack_qdate_raw(quint8 *p); -quint32 pack_qdate(const QVariant &variant, QByteArray &data, bool write); +QByteArray pack_qdate(const QVariant &variant); QVariant unpack_qdate(const QByteArray &data); -quint32 pack_qdatetime(const QVariant &variant, QByteArray &data, bool write); +QByteArray pack_qdatetime(const QVariant &variant); QVariant unpack_qdatetime(const QByteArray &data); // Points and Vectors -quint8 pack_two_integers(qint32 a, qint32 b, quint8 *to, bool write); -quint32 pack_qpoint(const QVariant &variant, QByteArray &data, bool write); +QByteArray pack_qpoint(const QVariant &variant); QVariant unpack_qpoint(const QByteArray &data); -quint32 pack_qsize(const QVariant &variant, QByteArray &data, bool write); +QByteArray pack_qsize(const QVariant &variant); QVariant unpack_qsize(const QByteArray &data); -quint32 pack_qrect(const QVariant &variant, QByteArray &data, bool write); +QByteArray pack_qrect(const QVariant &variant); QVariant unpack_qrect(const QByteArray &data); } // MsgPackPrivate diff --git a/src/stream.cpp b/src/stream.cpp index b13ea69..71b6f72 100644 --- a/src/stream.cpp +++ b/src/stream.cpp @@ -3,6 +3,7 @@ #include "private/sysdep.h" #include "private/pack_p.h" #include "msgpack_common.h" +#include #include #undef CHECK_STREAM_PRECOND @@ -106,35 +107,98 @@ MsgPackStream &MsgPackStream::operator>>(bool &b) MsgPackStream &MsgPackStream::operator >>(quint8 &u8) { - CHECK_STREAM_PRECOND(*this) - char c; - if (!dev->getChar(&c)) { - u8 = 0; + CHECK_STREAM_PRECOND(*this); + quint8 p; + if (dev->read((char *)&p, 1) != 1) { setStatus(ReadPastEnd); - } else { - u8 = quint8(c); + return *this; } + unpack_upto_quint8(u8, &p); return *this; } MsgPackStream &MsgPackStream::operator>>(quint16 &u16) { CHECK_STREAM_PRECOND(*this); - quint8 p[3]; - if (dev->read((char *)p, 3) != 3) { - u16 = 0; + quint8 p; + if (dev->read((char *)&p, 1) != 1) { setStatus(ReadPastEnd); - } else { - if (p[0] != MsgPack::FirstByte::UINT16) - setStatus(ReadCorruptData); - u16 = _msgpack_load16(quint16, (p + 1)); + return *this; } + unpack_upto_quint16(u16, &p); return *this; } MsgPackStream &MsgPackStream::operator>>(quint32 &u32) { + CHECK_STREAM_PRECOND(*this); + quint8 p; + if (dev->read((char *)&p, 1) != 1) { + setStatus(ReadPastEnd); + return *this; + } + unpack_upto_quint32(u32, &p); + return *this; +} +MsgPackStream &MsgPackStream::operator>>(quint64 &u64) +{ + CHECK_STREAM_PRECOND(*this); + quint8 p; + if (dev->read((char *)&p, 1) != 1) { + setStatus(ReadPastEnd); + return *this; + } + unpack_upto_quint64(u64, &p); + return *this; +} + +MsgPackStream &MsgPackStream::operator>>(qint8 &i8) +{ + CHECK_STREAM_PRECOND(*this); + quint8 p; + if (dev->read((char *)&p, 1) != 1) { + setStatus(ReadPastEnd); + return *this; + } + unpack_upto_qint8(i8, &p); + return *this; +} + +MsgPackStream &MsgPackStream::operator>>(qint16 &i16) +{ + CHECK_STREAM_PRECOND(*this); + quint8 p; + if (dev->read((char *)&p, 1) != 1) { + setStatus(ReadPastEnd); + return *this; + } + unpack_upto_qint16(i16, &p); + return *this; +} + +MsgPackStream &MsgPackStream::operator>>(qint32 &i32) +{ + CHECK_STREAM_PRECOND(*this); + quint8 p; + if (dev->read((char *)&p, 1) != 1) { + setStatus(ReadPastEnd); + return *this; + } + unpack_upto_qint32(i32, &p); + return *this; +} + +MsgPackStream &MsgPackStream::operator>>(qint64 &i64) +{ + CHECK_STREAM_PRECOND(*this); + quint8 p; + if (dev->read((char *)&p, 1) != 1) { + setStatus(ReadPastEnd); + return *this; + } + unpack_upto_qint64(i64, &p); + return *this; } MsgPackStream &MsgPackStream::operator>>(QString &str) @@ -179,7 +243,17 @@ MsgPackStream &MsgPackStream::operator<<(quint32 u32) CHECK_STREAM_WRITE_PRECOND(*this); quint8 p[5]; quint8 sz = MsgPackPrivate::pack_uint(u32, p, true) - p; - if (!dev->write((char *)p, sz) != sz) + if (dev->write((char *)p, sz) != sz) + setStatus(WriteFailed); + return *this; +} + +MsgPackStream &MsgPackStream::operator<<(quint64 u64) +{ + CHECK_STREAM_WRITE_PRECOND(*this); + quint8 p[9]; + quint8 sz = MsgPackPrivate::pack_ulonglong(u64, p, true) - p; + if (dev->write((char *)p, sz) != sz) setStatus(WriteFailed); return *this; } @@ -188,8 +262,18 @@ MsgPackStream &MsgPackStream::operator<<(qint32 i32) { CHECK_STREAM_WRITE_PRECOND(*this); quint8 p[5]; - quint8 sz = MsgPackPrivate::pack_uint(i32, p, true) - p; - if (!dev->write((char *)p, sz) != sz) + quint8 sz = MsgPackPrivate::pack_int(i32, p, true) - p; + if (dev->write((char *)p, sz) != sz) + setStatus(WriteFailed); + return *this; +} + +MsgPackStream &MsgPackStream::operator<<(qint64 i64) +{ + CHECK_STREAM_WRITE_PRECOND(*this); + quint8 p[9]; + quint8 sz = MsgPackPrivate::pack_longlong(i64, p, true) - p; + if (dev->write((char *)p, sz) != sz) setStatus(WriteFailed); return *this; } @@ -200,7 +284,8 @@ MsgPackStream &MsgPackStream::operator<<(QString str) quint8 *p = (quint8 *)0; quint32 sz = MsgPackPrivate::pack_string(str, p, false) - p; quint8 *data = new quint8[sz]; - MsgPackPrivate::pack(str, data, true); + QVector user_data; + MsgPackPrivate::pack(str, data, true, user_data); if (dev->write((char *)data, sz) != sz) setStatus(WriteFailed); delete[] data; @@ -211,3 +296,175 @@ MsgPackStream &MsgPackStream::operator<<(const char *str) { } + + +bool MsgPackStream::unpack_upto_quint8(quint8 &u8, quint8 *p) +{ + if (*p <= MsgPack::FirstByte::POSITIVE_FIXINT) { + u8 = *p; + } else if (*p == MsgPack::FirstByte::UINT8) { + if (dev->read((char* )&u8, 1) != 1) { + setStatus(ReadPastEnd); + return false; + } + } else { + setStatus(ReadCorruptData); + return false; + } + return true; +} + +bool MsgPackStream::unpack_upto_quint16(quint16 &u16, quint8 *p) +{ + if (*p == MsgPack::FirstByte::UINT16) { + quint8 d[2]; + if (dev->read((char *)d, 2) != 2) { + setStatus(ReadPastEnd); + return false; + } + u16 = _msgpack_load16(quint16, d); + } else { + quint8 u8; + bool ok = unpack_upto_quint8(u8, p); + u16 = u8; + return ok; + } +} + +bool MsgPackStream::unpack_upto_quint32(quint32 &u32, quint8 *p) +{ + if (*p == MsgPack::FirstByte::UINT32) { + quint8 d[4]; + if (dev->read((char *)d, 4) != 4) { + setStatus(ReadPastEnd); + return false; + } + u32 = _msgpack_load32(quint32, d); + return true; + } else { + quint16 u16; + bool ok = unpack_upto_quint16(u16, p); + u32 = u16; + return ok; + } +} + +bool MsgPackStream::unpack_upto_quint64(quint64 &u64, quint8 *p) +{ + if (*p == MsgPack::FirstByte::UINT64) { + quint8 d[8]; + if (dev->read((char *)d, 8) != 8) { + setStatus(ReadPastEnd); + return false; + } + u64 = _msgpack_load64(quint64, d); + return true; + } else { + quint32 u32; + bool ok = unpack_upto_quint32(u32, p); + u64 = u32; + return ok; + } +} + +bool MsgPackStream::unpack_upto_qint8(qint8 &i8, quint8 *p) +{ + if (*p >= MsgPack::FirstByte::NEGATIVE_FIXINT) { + i8 = *p; + } else if (*p == MsgPack::FirstByte::INT8) { + if (dev->read((char *)&i8, 1) != 1) { + setStatus(ReadPastEnd); + return false; + } + } else { + quint8 u8; + bool ok = unpack_upto_quint8(u8, p); + if (u8 > std::numeric_limits::max()) + setStatus(ReadCorruptData); + else + i8 = u8; + return ok; + } + return true; +} + +bool MsgPackStream::unpack_upto_qint16(qint16 &i16, quint8 *p) +{ + if (*p == MsgPack::FirstByte::INT16) { + quint8 d[2]; + if (dev->read((char *)d, 2) != 2) { + setStatus(ReadPastEnd); + return false; + } + i16 = _msgpack_load16(qint16, d); + return true; + } else { + qint8 i8; + bool ok = unpack_upto_qint8(i8, p); + if (ok) { + i16 = i8; + } else { + quint16 u16; + bool ok = unpack_upto_quint16(u16, p); + if (u16 <= std::numeric_limits::max()) + i16 = u16; + else + setStatus(ReadCorruptData); + return ok; + } + } +} + +bool MsgPackStream::unpack_upto_qint32(qint32 &i32, quint8 *p) +{ + if(*p == MsgPack::FirstByte::INT32) { + quint8 d[4]; + if (dev->read((char *)d, 4) != 4) { + setStatus(ReadPastEnd); + return false; + } + i32 = _msgpack_load32(qint32, d); + return true; + } else { + qint16 i16; + bool ok = unpack_upto_qint16(i16, p); + if (ok) { + i32 = i16; + } else { + quint32 u32; + bool ok = unpack_upto_quint32(u32, p); + if (u32 <= std::numeric_limits::max()) + i32 = u32; + else + setStatus(ReadCorruptData); + return ok; + } + } +} + +bool MsgPackStream::unpack_upto_qint64(qint64 &i64, quint8 *p) +{ + if(*p == MsgPack::FirstByte::INT64) { + quint8 d[8]; + if (dev->read((char *)d, 8) != 8) { + setStatus(ReadPastEnd); + return false; + } + i64 = _msgpack_load64(qint64, d); + return true; + } else { + qint32 i32; + bool ok = unpack_upto_qint32(i32, p); + if (ok) { + i64 = i32; + } else { + quint64 u64; + bool ok = unpack_upto_quint64(u64, p); + if (u64 <= std::numeric_limits::max()) + i64 = u64; + else + setStatus(ReadCorruptData); + return ok; + } + } +} diff --git a/src/stream.h b/src/stream.h index 816011c..e4aa849 100644 --- a/src/stream.h +++ b/src/stream.h @@ -58,6 +58,15 @@ private: Status q_status; MsgPackStream &operator<<(const char *str); // use QStringLiteral instead + + bool unpack_upto_quint8(quint8 &u8, quint8 *p); + bool unpack_upto_quint16(quint16 &u16, quint8 *p); + bool unpack_upto_quint32(quint32 &u32, quint8 *p); + bool unpack_upto_quint64(quint64 &u64, quint8 *p); + bool unpack_upto_qint8(qint8 &i8, quint8 *p); + bool unpack_upto_qint16(qint16 &i16, quint8 *p); + bool unpack_upto_qint32(qint32 &i32, quint8 *p); + bool unpack_upto_qint64(qint64 &i64, quint8 *p); }; #endif // STREAM_H diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 385f69b..9e74114 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -8,7 +8,7 @@ if (Qt5Core_FOUND) set(TEST_LIBRARIES ${Qt5Test_LIBRARIES}) endif () -set(TEST_SUBDIRS pack unpack mixed qttypes) +set(TEST_SUBDIRS pack unpack mixed qttypes stream) foreach(subdir ${TEST_SUBDIRS}) add_subdirectory(${subdir}) diff --git a/tests/mixed/mixed_test.cpp b/tests/mixed/mixed_test.cpp index 1debc23..2f9ea1b 100644 --- a/tests/mixed/mixed_test.cpp +++ b/tests/mixed/mixed_test.cpp @@ -66,17 +66,15 @@ private: Q_DECLARE_METATYPE(CustomType) -quint32 pack_custom_type(const QVariant &variant, QByteArray &data, bool write) +QByteArray pack_custom_type(const QVariant &variant) { CustomType ct = variant.value(); - if (write) { - data.resize(ct.size()); - quint8 *p = (quint8 *)data.data(); - for (int i = 0; i < ct.size(); ++i) - p[i] = 7; - } - - return ct.size(); + QByteArray data; + data.resize(ct.size()); + quint8 *p = (quint8 *)data.data(); + for (int i = 0; i < ct.size(); ++i) + p[i] = 7; + return data; } QVariant unpack_custom_type(const QByteArray &data) diff --git a/tests/stream/CMakeLists.txt b/tests/stream/CMakeLists.txt new file mode 100644 index 0000000..0ba81a3 --- /dev/null +++ b/tests/stream/CMakeLists.txt @@ -0,0 +1,24 @@ +set(QT_USE_QTTEST TRUE) + +if (NOT Qt5Core_FOUND) + include( ${QT_USE_FILE} ) +endif() + +include(AddFileDependencies) + +include_directories(../../src ${CMAKE_CURRENT_BINARY_DIR}) + +set(UNIT_TESTS stream_test) + +foreach(test ${UNIT_TESTS}) + message(status "Building ${test}") + add_executable(${test} ${test}.cpp) + + target_link_libraries(${test} + ${QT_LIBRARIES} + ${TEST_LIBRARIES} + qmsgpack + ) + + add_test(${test} ${test}) +endforeach() \ No newline at end of file diff --git a/tests/stream/stream_test.cpp b/tests/stream/stream_test.cpp new file mode 100644 index 0000000..a389512 --- /dev/null +++ b/tests/stream/stream_test.cpp @@ -0,0 +1,141 @@ +#include +#include +#include +#include +#include +#include + +class StreamTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void test_unpack_integers(); + void test_pack_integers(); + +}; + +void StreamTest::test_unpack_integers() +{ + QByteArray ints = QByteArray::fromBase64("AH//4cyAzP/Q39CAzQEAzf//0f9/0YAAz" + "gABAADO/////9L//3//0oAAAADPAAAAAQ" + "AAAADP///////////T/////3/////TgAA" + "AAAAAAAA="); + MsgPackStream stream(ints); + quint8 u8; + quint16 u16; + quint32 u32; + quint64 u64; + qint8 i8; + qint16 i16; + qint32 i32; + qint64 i64; + + stream >> u8; + QVERIFY(stream.status() == MsgPackStream::Ok); + QVERIFY(u8 == 0); + stream >> u8; + QVERIFY(stream.status() == MsgPackStream::Ok); + QVERIFY(u8 == 127); + stream >> i8; + QVERIFY(stream.status() == MsgPackStream::Ok); + QVERIFY(i8 == -1); + stream >> i8; + QVERIFY(stream.status() == MsgPackStream::Ok); + QVERIFY(i8 == -31); + stream >> u8; + QVERIFY(stream.status() == MsgPackStream::Ok); + QVERIFY(u8 == 128); + stream >> u8; + QVERIFY(stream.status() == MsgPackStream::Ok); + QVERIFY(u8 == 255); + stream >> i8; + QVERIFY(stream.status() == MsgPackStream::Ok); + QVERIFY(i8 == -33); + stream >> i8; + QVERIFY(stream.status() == MsgPackStream::Ok); + QVERIFY(i8 == -128); + stream >> u16; + QVERIFY(stream.status() == MsgPackStream::Ok); + QVERIFY(u16 == 256); + stream >> u32; + QVERIFY(stream.status() == MsgPackStream::Ok); + QVERIFY(u32 == 65535); + stream >> i16; + QVERIFY(stream.status() == MsgPackStream::Ok); + QVERIFY(i16 == -129); + stream >> i16; + QVERIFY(stream.status() == MsgPackStream::Ok); + QVERIFY(i16 == -32768); + stream >> u32; + QVERIFY(stream.status() == MsgPackStream::Ok); + QVERIFY(u32 == 65536); + stream >> u32; + QVERIFY(stream.status() == MsgPackStream::Ok); + QVERIFY(u32 == 4294967295); + stream >> i32; + QVERIFY(stream.status() == MsgPackStream::Ok); + QVERIFY(i32 == -32769); + stream >> i32; + QVERIFY(stream.status() == MsgPackStream::Ok); + QVERIFY(i32 == -2147483648); + stream >> u64; + QVERIFY(stream.status() == MsgPackStream::Ok); + QVERIFY(u64 == 4294967296); + stream >> u64; + QVERIFY(stream.status() == MsgPackStream::Ok); + QVERIFY(u64 == std::numeric_limits::max()); + stream >> i64; + QVERIFY(stream.status() == MsgPackStream::Ok); + QVERIFY(i64 == -2147483649); + stream >> i64; + QVERIFY(stream.status() == MsgPackStream::Ok); + QVERIFY(i64 == std::numeric_limits::min()); +} + +void StreamTest::test_pack_integers() +{ + QByteArray packed; + MsgPackStream stream(&packed, QIODevice::WriteOnly); + stream << 0 << 127 << -1 << -31 << 128 << 255 << -33 << -128 << 256; + QVERIFY(stream.status() == MsgPackStream::Ok); + stream << 65535 << -129 << -32768 << 65536; + QVERIFY(stream.status() == MsgPackStream::Ok); + stream << (quint32)4294967295 << -32769 << (qint32)-2147483648; + QVERIFY(stream.status() == MsgPackStream::Ok); + stream << (quint64)4294967296; + QVERIFY(stream.status() == MsgPackStream::Ok); + stream << std::numeric_limits::max(); + QVERIFY(stream.status() == MsgPackStream::Ok); + stream << (qint64)-2147483649; + QVERIFY(stream.status() == MsgPackStream::Ok); + stream << std::numeric_limits::min(); + QVERIFY(stream.status() == MsgPackStream::Ok); + + QVariantList l = MsgPack::unpack(packed).toList(); + QVERIFY(l[0].toInt() == 0); + QVERIFY(l[1].toInt() == 127); + QVERIFY(l[2].toInt() == -1); + QVERIFY(l[3].toInt() == -31); + QVERIFY(l[4].toInt() == 128); + QVERIFY(l[5].toInt() == 255); + QVERIFY(l[6].toInt() == -33); + QVERIFY(l[7].toInt() == -128); + QVERIFY(l[8].toInt() == 256); + QVERIFY(l[9].toInt() == 65535); + QVERIFY(l[10].toInt() == -129); + QVERIFY(l[11].toInt() == -32768); + QVERIFY(l[12].toInt() == 65536); + QVERIFY(l[13].toUInt() == 4294967295); + QVERIFY(l[14].toInt() == -32769); + QVERIFY(l[15].toInt() == -2147483648); + QVERIFY(l[16].toLongLong() == 4294967296); + QVERIFY(l[17].toULongLong() == std::numeric_limits::max()); + QVERIFY(l[18].toLongLong() == -2147483649); + QVERIFY(l[19].toLongLong() == std::numeric_limits::min()); +} + + +QTEST_APPLESS_MAIN(StreamTest) + +#include "stream_test.moc"