From e7c0ee2387554cafee66f5df3dce3a6a00729b05 Mon Sep 17 00:00:00 2001 From: Roman Date: Sat, 11 Apr 2015 22:11:44 +0300 Subject: [PATCH 01/22] Started working on Qt types packers/unpackers QColor implemented cmake will fail with Qt4 for now --- CMakeLists.txt | 17 ++++++++++++++ src/CMakeLists.txt | 6 ++++- src/msgpack-qt.pro | 8 ++++--- src/msgpack.cpp | 6 +++++ src/msgpack.h | 8 +++---- src/msgpack_common.h | 45 ++++++++++++++++++++++++++++++++++++- src/msgpack_common.h.in | 45 ++++++++++++++++++++++++++++++++++++- src/private/qt_types_p.cpp | 46 ++++++++++++++++++++++++++++++++++++++ src/private/qt_types_p.h | 18 +++++++++++++++ 9 files changed, 189 insertions(+), 10 deletions(-) create mode 100644 src/private/qt_types_p.cpp create mode 100644 src/private/qt_types_p.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 307146b..6f09424 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,6 +39,23 @@ else () set(PC_Requires "QtCore") endif () +option (QTGUI_TYPES "Build with support for QtGui types") +if (QTGUI_TYPES) + if (QT4_BUILD) + find_package(Qt4 QTGUI) + else () + find_package(Qt5Gui QUIET) + endif () +endif () + +if (Qt5Gui_FOUND) + message("Qt5Gui found") + include_directories(${Qt5Gui_INCLUDE_DIRS}) + add_definitions(${Qt5Gui_DEFINITIONS}) +else () + message("Qt5Gui not found") +endif () + if (NOT WIN32) set(QT_DONT_USE_QTGUI TRUE) endif () diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e82a68b..7ac4d56 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,4 +1,4 @@ -set(qmsgpack_srcs msgpack.cpp msgpack_common.cpp private/pack_p.cpp private/unpack_p.cpp) +set(qmsgpack_srcs msgpack.cpp msgpack_common.cpp private/pack_p.cpp private/unpack_p.cpp private/qt_types_p.cpp) set(qmsgpack_headers msgpack.h msgpack_common.h msgpack_export.h) add_library(qmsgpack SHARED ${qmsgpack_srcs} ${qmsgpack_headers}) @@ -9,6 +9,10 @@ else () target_link_libraries(qmsgpack ${QT_LIBRARIES}) endif () +if (Qt5Gui_FOUND) + target_link_libraries(qmsgpack Qt5::Gui) +endif () + configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/msgpack_common.h.in" "${CMAKE_CURRENT_SOURCE_DIR}/msgpack_common.h" diff --git a/src/msgpack-qt.pro b/src/msgpack-qt.pro index f1c6d18..97ddb4b 100644 --- a/src/msgpack-qt.pro +++ b/src/msgpack-qt.pro @@ -6,7 +6,7 @@ QT += core -QT -= gui +QT += gui TARGET = qmsgpack CONFIG -= app_bundle @@ -26,7 +26,8 @@ CONFIG(debug, debug|release) { SOURCES += msgpack.cpp \ msgpack_common.cpp \ private/pack_p.cpp \ - private/unpack_p.cpp + private/unpack_p.cpp \ + private/qt_types_p.cpp HEADERS += \ msgpack.h \ @@ -34,4 +35,5 @@ HEADERS += \ private/unpack_p.h \ private/sysdep.h \ msgpack_common.h \ - msgpack_export.h + msgpack_export.h \ + private/qt_types_p.h diff --git a/src/msgpack.cpp b/src/msgpack.cpp index 36e011e..0ab84cd 100644 --- a/src/msgpack.cpp +++ b/src/msgpack.cpp @@ -2,6 +2,7 @@ #include "msgpack_common.h" #include "private/unpack_p.h" #include "private/pack_p.h" +#include "private/qt_types_p.h" QVariant MsgPack::unpack(const QByteArray &data) { @@ -35,6 +36,11 @@ bool MsgPack::registerUnpacker(qint8 msgpackType, MsgPack::unpack_user_f unpacke return MsgPackPrivate::register_unpacker(msgpackType, unpacker); } +bool MsgPack::registerType(QMetaType::Type qType, quint8 msgpackType) +{ + return MsgPackPrivate::register_qtype(qType, msgpackType); +} + void MsgPack::setCompatibilityModeEnabled(bool enabled) { MsgPackPrivate::compatibilityMode = enabled; diff --git a/src/msgpack.h b/src/msgpack.h index cf4c540..4d3e603 100644 --- a/src/msgpack.h +++ b/src/msgpack.h @@ -1,12 +1,10 @@ #ifndef MSGPACK_H #define MSGPACK_H - +#include +#include #include "msgpack_common.h" #include "msgpack_export.h" -#include -#include - namespace MsgPack { MSGPACK_EXPORT QVariant unpack(const QByteArray &data); @@ -15,6 +13,8 @@ namespace MsgPack MSGPACK_EXPORT QByteArray pack(const QVariant &variant); MSGPACK_EXPORT bool registerPacker(QMetaType::Type qType, qint8 msgpackType, pack_user_f packer); + MSGPACK_EXPORT bool registerType(QMetaType::Type qType, quint8 msgpackType); + MSGPACK_EXPORT void setCompatibilityModeEnabled(bool enabled); } diff --git a/src/msgpack_common.h b/src/msgpack_common.h index 3c62f7c..7311e7a 100644 --- a/src/msgpack_common.h +++ b/src/msgpack_common.h @@ -2,6 +2,7 @@ #define COMMON_H #include +#include #define MSGPACK_MAJOR 0 #define MSGPACK_MINOR 1 @@ -24,6 +25,48 @@ typedef QVariant (*unpack_user_f)(const QByteArray &data); * @return current version */ QString version(); +/** + * @brief The FirstByte enum + * From Message Pack spec + */ +namespace FirstByte { +const quint8 POSITIVE_FIXINT = 0x00; +const quint8 FIXMAP = 0x80; +const quint8 FIXARRAY = 0x90; +const quint8 FIXSTR = 0xa0; +const quint8 NIL = 0xc0; +const quint8 NEVER_USED = 0xc1; +const quint8 FALSE = 0xc2; +const quint8 TRUE = 0xc3; +const quint8 BIN8 = 0xc4; +const quint8 BIN16 = 0xc5; +const quint8 BIN32 = 0xc6; +const quint8 EXT8 = 0xc7; +const quint8 EXT16 = 0xc8; +const quint8 EXT32 = 0xc9; +const quint8 FLOAT32 = 0xca; +const quint8 FLOAT64 = 0xcb; +const quint8 UINT8 = 0xcc; +const quint8 UINT16 = 0xcd; +const quint8 UINT32 = 0xce; +const quint8 UINT64 = 0xcf; +const quint8 INT8 = 0xd0; +const quint8 INT16 = 0xd1; +const quint8 INT32 = 0xd2; +const quint8 INT64 = 0xd3; +const quint8 FIXEXT1 = 0xd4; +const quint8 FIXEXT2 = 0xd5; +const quint8 FIXEXT4 = 0xd6; +const quint8 FIXEXT8 = 0xd7; +const quint8 FIXEX16 = 0xd8; +const quint8 STR8 = 0xd9; +const quint8 STR16 = 0xda; +const quint8 STR32 = 0xdb; +const quint8 ARRAY8 = 0xdc; +const quint8 ARRAY16 = 0xdd; +const quint8 MAP16 = 0xde; +const quint8 MAP32 = 0xdf; +const quint8 NEGATIVE_FIXINT = 0xe0; +} } - #endif // COMMON_H diff --git a/src/msgpack_common.h.in b/src/msgpack_common.h.in index 9e140bc..fbf906d 100644 --- a/src/msgpack_common.h.in +++ b/src/msgpack_common.h.in @@ -2,6 +2,7 @@ #define COMMON_H #include +#include #define MSGPACK_MAJOR @QMSGPACK_MAJOR@ #define MSGPACK_MINOR @QMSGPACK_MINOR@ @@ -24,6 +25,48 @@ typedef QVariant (*unpack_user_f)(const QByteArray &data); * @return current version */ QString version(); +/** + * @brief The FirstByte enum + * From Message Pack spec + */ +namespace FirstByte { +const quint8 POSITIVE_FIXINT = 0x00; +const quint8 FIXMAP = 0x80; +const quint8 FIXARRAY = 0x90; +const quint8 FIXSTR = 0xa0; +const quint8 NIL = 0xc0; +const quint8 NEVER_USED = 0xc1; +const quint8 FALSE = 0xc2; +const quint8 TRUE = 0xc3; +const quint8 BIN8 = 0xc4; +const quint8 BIN16 = 0xc5; +const quint8 BIN32 = 0xc6; +const quint8 EXT8 = 0xc7; +const quint8 EXT16 = 0xc8; +const quint8 EXT32 = 0xc9; +const quint8 FLOAT32 = 0xca; +const quint8 FLOAT64 = 0xcb; +const quint8 UINT8 = 0xcc; +const quint8 UINT16 = 0xcd; +const quint8 UINT32 = 0xce; +const quint8 UINT64 = 0xcf; +const quint8 INT8 = 0xd0; +const quint8 INT16 = 0xd1; +const quint8 INT32 = 0xd2; +const quint8 INT64 = 0xd3; +const quint8 FIXEXT1 = 0xd4; +const quint8 FIXEXT2 = 0xd5; +const quint8 FIXEXT4 = 0xd6; +const quint8 FIXEXT8 = 0xd7; +const quint8 FIXEX16 = 0xd8; +const quint8 STR8 = 0xd9; +const quint8 STR16 = 0xda; +const quint8 STR32 = 0xdb; +const quint8 ARRAY8 = 0xdc; +const quint8 ARRAY16 = 0xdd; +const quint8 MAP16 = 0xde; +const quint8 MAP32 = 0xdf; +const quint8 NEGATIVE_FIXINT = 0xe0; +} } - #endif // COMMON_H diff --git a/src/private/qt_types_p.cpp b/src/private/qt_types_p.cpp new file mode 100644 index 0000000..0bac757 --- /dev/null +++ b/src/private/qt_types_p.cpp @@ -0,0 +1,46 @@ +#include "qt_types_p.h" +#include "pack_p.h" +#include "unpack_p.h" + +#include + +#ifdef QT_GUI_LIB +#include +#endif +#define NO_QTGUI_WARNING "Library built without QtGui, hence some types are not available" + +bool MsgPackPrivate::register_qtype(QMetaType::Type q_type, quint8 msgpack_type) +{ + if (q_type == QMetaType::QColor) { + #ifdef QT_GUI_LIB + qRegisterMetaType("QColor"); + MsgPackPrivate::register_packer((QMetaType::Type)qMetaTypeId(), msgpack_type, pack_qcolor); + MsgPackPrivate::register_unpacker(msgpack_type, unpack_qcolor); + return true; + #else + qWarning() << NO_QTGUI_WARNING; + return false; + #endif //QT_GUI_LIB + } +} + +#ifdef QT_GUI_LIB +quint32 MsgPackPrivate::pack_qcolor(const QVariant &variant, QByteArray &data, bool write) +{ + if (write) { + QColor color = variant.value(); + data.resize(4); + data[0] = color.red(); + data[1] = color.green(); + data[2] = color.blue(); + data[3] = color.alpha(); + } + return 4; // 4 bytes: r,g,b,a +} + +QVariant MsgPackPrivate::unpack_qcolor(const QByteArray &data) +{ + return QColor((quint8)data[0], (quint8)data[1], + (quint8)data[2], (quint8)data[3]); +} +#endif //MsgPackPrivate diff --git a/src/private/qt_types_p.h b/src/private/qt_types_p.h new file mode 100644 index 0000000..a83d2e1 --- /dev/null +++ b/src/private/qt_types_p.h @@ -0,0 +1,18 @@ +#ifndef QT_TYPES_P_H +#define QT_TYPES_P_H + +#include +#include + +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); +QVariant unpack_qcolor(const QByteArray &data); +#endif //QT_GUI_LIB + +} // MsgPackPrivate + +#endif // QT_TYPES_P_H \ No newline at end of file From dd24abd0b71053673c300bded7b334bb2a4fd331 Mon Sep 17 00:00:00 2001 From: Roman Date: Sun, 12 Apr 2015 13:43:14 +0300 Subject: [PATCH 02/22] QTime, QDate, QDateTime added --- src/private/qt_types_p.cpp | 96 ++++++++++++++++++++++++++++++++++++-- src/private/qt_types_p.h | 17 ++++++- 2 files changed, 108 insertions(+), 5 deletions(-) diff --git a/src/private/qt_types_p.cpp b/src/private/qt_types_p.cpp index 0bac757..5545dcf 100644 --- a/src/private/qt_types_p.cpp +++ b/src/private/qt_types_p.cpp @@ -1,6 +1,7 @@ #include "qt_types_p.h" #include "pack_p.h" #include "unpack_p.h" +#include "sysdep.h" #include @@ -9,19 +10,29 @@ #endif #define NO_QTGUI_WARNING "Library built without QtGui, hence some types are not available" +#include + bool MsgPackPrivate::register_qtype(QMetaType::Type q_type, quint8 msgpack_type) { if (q_type == QMetaType::QColor) { #ifdef QT_GUI_LIB - qRegisterMetaType("QColor"); - MsgPackPrivate::register_packer((QMetaType::Type)qMetaTypeId(), msgpack_type, pack_qcolor); + MsgPackPrivate::register_packer(q_type, msgpack_type, pack_qcolor); MsgPackPrivate::register_unpacker(msgpack_type, unpack_qcolor); - return true; #else qWarning() << NO_QTGUI_WARNING; return false; #endif //QT_GUI_LIB - } + } else if (q_type == QMetaType::QTime) { + MsgPackPrivate::register_packer(q_type, msgpack_type, pack_qtime); + MsgPackPrivate::register_unpacker(msgpack_type, unpack_qtime); + } else if (q_type == QMetaType::QDate) { + MsgPackPrivate::register_packer(q_type, msgpack_type, pack_qdate); + MsgPackPrivate::register_unpacker(msgpack_type, unpack_qdate); + } else if (q_type == QMetaType::QDateTime) { + MsgPackPrivate::register_packer(q_type, msgpack_type, pack_qdatetime); + MsgPackPrivate::register_unpacker(msgpack_type, unpack_qdatetime); + } + return true; } #ifdef QT_GUI_LIB @@ -44,3 +55,80 @@ QVariant MsgPackPrivate::unpack_qcolor(const QByteArray &data) (quint8)data[2], (quint8)data[3]); } #endif //MsgPackPrivate + +// Date and Time +void MsgPackPrivate::pack_qtime_raw(const QTime &time, quint8 *p) +{ + quint32 t = time.msecsSinceStartOfDay(); + _msgpack_store32(p, t); +} + +QTime MsgPackPrivate::unpack_qtime_raw(quint8 *p) +{ + quint32 t = _msgpack_load32(quint32, p); + return QTime::fromMSecsSinceStartOfDay(t); +} + +quint32 MsgPackPrivate::pack_qtime(const QVariant &variant, QByteArray &data, bool write) +{ + if (write) + pack_qtime_raw(variant.toTime(), (quint8 *)data.data()); + return 4; // 24h*60m*60s*1000ms = max 27 bits +} + +QVariant MsgPackPrivate::unpack_qtime(const QByteArray &data) +{ + return unpack_qtime_raw((quint8 *)data.data()); +} + +void MsgPackPrivate::pack_qdate_raw(const QDate &date, quint8 *p) +{ + quint16 year = date.year(); + quint8 month = date.month(); + quint8 day = date.day(); + quint16 dy = year | (day & 0x80); + quint8 md = (month << 4) | (day & 0xf); + _msgpack_store16(p, dy); + p[2] = md; +} + +QDate MsgPackPrivate::unpack_qdate_raw(quint8 *p) +{ + quint16 year = _msgpack_load16(quint16, p); + quint8 month = (p[2] & 0xf0) >> 4; + quint8 day = p[2] & 0xf; + day |= (quint8)((year & 0x8000) >> 11); + year &= 0x7fff; + return QDate(year, month, day); +} + +quint32 MsgPackPrivate::pack_qdate(const QVariant &variant, QByteArray &data, bool write) +{ + if (write) + pack_qdate_raw(variant.toDate(), (quint8 *)data.data()); + return 3; // d(5th bit)xyyyyyyyyyyyyyy, mmmmdddd +} + +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) +{ + if (write) { + quint8 *p = (quint8 *)data.data(); + QDateTime dt = variant.toDateTime(); + pack_qdate_raw(dt.date(), p); + pack_qtime_raw(dt.time(), p + 3); + } + return 7; // 3 for date, 4 for time +} + +QVariant MsgPackPrivate::unpack_qdatetime(const QByteArray &data) +{ + quint8 *p = (quint8 *)data.data(); + QDate d = unpack_qdate_raw(p); + QTime t = unpack_qtime_raw(p + 3); + return QDateTime(d, t); +} diff --git a/src/private/qt_types_p.h b/src/private/qt_types_p.h index a83d2e1..b3d50c1 100644 --- a/src/private/qt_types_p.h +++ b/src/private/qt_types_p.h @@ -13,6 +13,21 @@ quint32 pack_qcolor(const QVariant &variant, QByteArray &data, bool write); QVariant unpack_qcolor(const QByteArray &data); #endif //QT_GUI_LIB +// Date and Time +void pack_qtime_raw(const QTime &time, quint8 *p); +QTime unpack_qtime_raw(quint8 *p); +quint32 pack_qtime(const QVariant &variant, QByteArray &data, bool write); +QVariant unpack_qtime(const QByteArray &data); + +void pack_qdate_raw(const QDate &date, quint8 *p); +QDate unpack_qdate_raw(quint8 *p); +quint32 pack_qdate(const QVariant &variant, QByteArray &data, bool write); +QVariant unpack_qdate(const QByteArray &data); + +quint32 pack_qdatetime(const QVariant &variant, QByteArray &data, bool write); +QVariant unpack_qdatetime(const QByteArray &data); + + } // MsgPackPrivate -#endif // QT_TYPES_P_H \ No newline at end of file +#endif // QT_TYPES_P_H From e7c6afcd4940952a915b640125089e31d45f78c1 Mon Sep 17 00:00:00 2001 From: Roman Date: Tue, 14 Apr 2015 22:50:20 +0300 Subject: [PATCH 03/22] Thread safety implemented for registerPacker and registerUnpacker --- src/private/pack_p.cpp | 23 ++++++++++++++++------- src/private/pack_p.h | 2 ++ src/private/unpack_p.cpp | 14 ++++++++++---- src/private/unpack_p.h | 2 ++ tests/mixed/mixed_test.cpp | 6 ++++-- 5 files changed, 34 insertions(+), 13 deletions(-) diff --git a/src/private/pack_p.cpp b/src/private/pack_p.cpp index 7e759d1..da38357 100644 --- a/src/private/pack_p.cpp +++ b/src/private/pack_p.cpp @@ -11,6 +11,7 @@ QHash MsgPackPrivate::user_packers; bool MsgPackPrivate::compatibilityMode = false; +QReadWriteLock MsgPackPrivate::packers_lock; quint8 *MsgPackPrivate::pack(const QVariant &v, quint8 *p, bool wr) { @@ -38,7 +39,12 @@ quint8 *MsgPackPrivate::pack(const QVariant &v, quint8 *p, bool wr) else if (t == QMetaType::QVariantMap) p = pack_map(v.toMap(), p, wr); else { - if (user_packers.contains(t)) + if (t == QMetaType::User) + t = (QMetaType::Type)v.userType(); + packers_lock.lockForRead(); + bool has_packer = user_packers.contains(t); + packers_lock.unlock(); + if (has_packer) p = pack_user(v, p, wr); else qWarning() << "MsgPack::pack can't pack type:" << t; @@ -269,21 +275,23 @@ quint8 *MsgPackPrivate::pack_map(const QVariantMap &map, quint8 *p, bool wr) return p; } - bool MsgPackPrivate::register_packer(QMetaType::Type q_type, qint8 msgpack_type, MsgPack::pack_user_f packer) { - if (user_packers.contains(q_type)) { - qWarning() << "MsgPack::packer for qtype" << q_type << "already exist"; - return false; - } if (packer == 0) { qWarning() << "MsgPack::packer for qtype" << q_type << "is invalid"; return false; } + packers_lock.lockForWrite(); + if (user_packers.contains(q_type)) { + qWarning() << "MsgPack::packer for qtype" << q_type << "already exist"; + packers_lock.unlock(); + return false; + } packer_t p; p.packer = packer; p.type = msgpack_type; user_packers.insert(q_type, p); + packers_lock.unlock(); return true; } @@ -292,7 +300,9 @@ quint8 *MsgPackPrivate::pack_user(const QVariant &v, quint8 *p, bool wr) QMetaType::Type t = (QMetaType::Type)v.type() == QMetaType::User ? (QMetaType::Type)v.userType() : (QMetaType::Type)v.type(); QByteArray data; + packers_lock.lockForRead(); packer_t pt = user_packers[t]; + packers_lock.unlock(); quint32 len = pt.packer(v, data, wr); if (len == 1) { if (wr) *p = 0xd4; @@ -331,4 +341,3 @@ quint8 *MsgPackPrivate::pack_user(const QVariant &v, quint8 *p, bool wr) memcpy(p, data.data(), len); return p += len; } - diff --git a/src/private/pack_p.h b/src/private/pack_p.h index b29f971..4ef57f4 100644 --- a/src/private/pack_p.h +++ b/src/private/pack_p.h @@ -5,6 +5,7 @@ #include #include +#include class QByteArray; class QString; @@ -19,6 +20,7 @@ typedef struct { } packer_t; bool register_packer(QMetaType::Type q_type, qint8 msgpack_type, MsgPack::pack_user_f packer); extern QHash user_packers; +extern QReadWriteLock packers_lock; extern bool compatibilityMode; quint8 * pack(const QVariant &v, quint8 *p, bool wr); diff --git a/src/private/unpack_p.cpp b/src/private/unpack_p.cpp index 511bd4a..4983d02 100644 --- a/src/private/unpack_p.cpp +++ b/src/private/unpack_p.cpp @@ -21,6 +21,7 @@ MsgPackPrivate::type_parser_f MsgPackPrivate::unpackers[32] = { }; QHash MsgPackPrivate::user_unpackers; +QReadWriteLock MsgPackPrivate::unpackers_lock; QVariant MsgPackPrivate::unpack(quint8 *p, quint8 *end) { @@ -314,12 +315,14 @@ quint8 * MsgPackPrivate::unpack_map32(QVariant &v, quint8 *p) quint8 *MsgPackPrivate::unpack_ext(QVariant &v, quint8 *p, qint8 type, quint32 len) { + unpackers_lock.lockForRead(); if (!user_unpackers.contains(type)) { qWarning() << "MsgPack::unpack() unpacker for type" << type << "doesn't exist"; return p + len; } QByteArray data((char *)p, len); v = user_unpackers[type](data); + unpackers_lock.unlock(); return p + len; } @@ -382,14 +385,17 @@ quint8 * MsgPackPrivate::unpack_ext32(QVariant &v, quint8 *p) bool MsgPackPrivate::register_unpacker(qint8 msgpack_type, MsgPack::unpack_user_f unpacker) { - if (user_unpackers.contains(msgpack_type)) { - qWarning() << "MsgPack::unpacker for type" << msgpack_type << "already exists"; - return false; - } if (unpacker == 0) { qWarning() << "MsgPack::unpacker for type" << msgpack_type << "is invalid"; return false; } + unpackers_lock.lockForWrite(); + if (user_unpackers.contains(msgpack_type)) { + qWarning() << "MsgPack::unpacker for type" << msgpack_type << "already exists"; + unpackers_lock.unlock(); + return false; + } user_unpackers.insert(msgpack_type, unpacker); + unpackers_lock.unlock(); return true; } diff --git a/src/private/unpack_p.h b/src/private/unpack_p.h index ed8b323..ae85648 100644 --- a/src/private/unpack_p.h +++ b/src/private/unpack_p.h @@ -5,6 +5,7 @@ #include #include +#include namespace MsgPackPrivate { @@ -19,6 +20,7 @@ extern type_parser_f unpackers[32]; bool register_unpacker(qint8 msgpack_type, MsgPack::unpack_user_f unpacker); extern QHash user_unpackers; +extern QReadWriteLock unpackers_lock; // goes from p to end unpacking types with unpack_type function below QVariant unpack(quint8 *p, quint8 *end); diff --git a/tests/mixed/mixed_test.cpp b/tests/mixed/mixed_test.cpp index 1976483..1debc23 100644 --- a/tests/mixed/mixed_test.cpp +++ b/tests/mixed/mixed_test.cpp @@ -90,9 +90,11 @@ void MixedTest::test_ext() QVariant custom; custom.setValue(ct); - MsgPack::registerPacker((QMetaType::Type)qMetaTypeId(), + bool packer_registered = MsgPack::registerPacker((QMetaType::Type)qMetaTypeId(), 3, pack_custom_type); - MsgPack::registerUnpacker(3, unpack_custom_type); + QVERIFY(packer_registered); + bool unpacker_registered = MsgPack::registerUnpacker(3, unpack_custom_type); + QVERIFY(unpacker_registered); QByteArray arr = MsgPack::pack(custom); QVERIFY(arr.size() == 2 + ct.size()); From 906c48b9b6b7396d82f4df10a2c6b1f2f42cb62e Mon Sep 17 00:00:00 2001 From: Roman Date: Tue, 14 Apr 2015 23:03:04 +0300 Subject: [PATCH 04/22] QReadLocker / QWriteLocker instead manual lock() unlock() for safety (e.g. exception before unlock()) master ahead manual fix --- .travis.yml | 1 - src/msgpack.h | 6 ++++-- src/private/pack_p.cpp | 15 ++++++++------- src/private/unpack_p.cpp | 12 ++++++------ 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0f35ef4..b37d3ee 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,6 @@ language: cpp compiler: - gcc - - clang env: - QT4_BUILD=ON diff --git a/src/msgpack.h b/src/msgpack.h index 4d3e603..ba95663 100644 --- a/src/msgpack.h +++ b/src/msgpack.h @@ -1,10 +1,12 @@ #ifndef MSGPACK_H #define MSGPACK_H -#include -#include + #include "msgpack_common.h" #include "msgpack_export.h" +#include +#include + namespace MsgPack { MSGPACK_EXPORT QVariant unpack(const QByteArray &data); diff --git a/src/private/pack_p.cpp b/src/private/pack_p.cpp index da38357..0793d1f 100644 --- a/src/private/pack_p.cpp +++ b/src/private/pack_p.cpp @@ -9,6 +9,9 @@ #include +#include +#include + QHash MsgPackPrivate::user_packers; bool MsgPackPrivate::compatibilityMode = false; QReadWriteLock MsgPackPrivate::packers_lock; @@ -41,9 +44,9 @@ quint8 *MsgPackPrivate::pack(const QVariant &v, quint8 *p, bool wr) else { if (t == QMetaType::User) t = (QMetaType::Type)v.userType(); - packers_lock.lockForRead(); + QReadLocker locker(&packers_lock); bool has_packer = user_packers.contains(t); - packers_lock.unlock(); + locker.unlock(); if (has_packer) p = pack_user(v, p, wr); else @@ -281,17 +284,15 @@ bool MsgPackPrivate::register_packer(QMetaType::Type q_type, qint8 msgpack_type, qWarning() << "MsgPack::packer for qtype" << q_type << "is invalid"; return false; } - packers_lock.lockForWrite(); + QWriteLocker locker(&packers_lock); if (user_packers.contains(q_type)) { qWarning() << "MsgPack::packer for qtype" << q_type << "already exist"; - packers_lock.unlock(); return false; } packer_t p; p.packer = packer; p.type = msgpack_type; user_packers.insert(q_type, p); - packers_lock.unlock(); return true; } @@ -300,9 +301,9 @@ quint8 *MsgPackPrivate::pack_user(const QVariant &v, quint8 *p, bool wr) QMetaType::Type t = (QMetaType::Type)v.type() == QMetaType::User ? (QMetaType::Type)v.userType() : (QMetaType::Type)v.type(); QByteArray data; - packers_lock.lockForRead(); + QReadLocker locker(&packers_lock); packer_t pt = user_packers[t]; - packers_lock.unlock(); + locker.unlock(); quint32 len = pt.packer(v, data, wr); if (len == 1) { if (wr) *p = 0xd4; diff --git a/src/private/unpack_p.cpp b/src/private/unpack_p.cpp index 4983d02..cc3c0ed 100644 --- a/src/private/unpack_p.cpp +++ b/src/private/unpack_p.cpp @@ -5,6 +5,9 @@ #include #include +#include +#include + MsgPackPrivate::type_parser_f MsgPackPrivate::unpackers[32] = { unpack_nil, unpack_never_used, @@ -315,14 +318,13 @@ quint8 * MsgPackPrivate::unpack_map32(QVariant &v, quint8 *p) quint8 *MsgPackPrivate::unpack_ext(QVariant &v, quint8 *p, qint8 type, quint32 len) { - unpackers_lock.lockForRead(); + QReadLocker locker(&unpackers_lock); if (!user_unpackers.contains(type)) { qWarning() << "MsgPack::unpack() unpacker for type" << type << "doesn't exist"; return p + len; } QByteArray data((char *)p, len); - v = user_unpackers[type](data); - unpackers_lock.unlock(); + v = user_unpackers[type](data);s return p + len; } @@ -389,13 +391,11 @@ bool MsgPackPrivate::register_unpacker(qint8 msgpack_type, MsgPack::unpack_user_ qWarning() << "MsgPack::unpacker for type" << msgpack_type << "is invalid"; return false; } - unpackers_lock.lockForWrite(); + QWriteLocker locker(&unpackers_lock); if (user_unpackers.contains(msgpack_type)) { qWarning() << "MsgPack::unpacker for type" << msgpack_type << "already exists"; - unpackers_lock.unlock(); return false; } user_unpackers.insert(msgpack_type, unpacker); - unpackers_lock.unlock(); return true; } From cb0ed45ea1a8288c99769a8064d38cc966a7717e Mon Sep 17 00:00:00 2001 From: Roman Date: Tue, 14 Apr 2015 23:52:52 +0300 Subject: [PATCH 05/22] typo --- src/private/unpack_p.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/private/unpack_p.cpp b/src/private/unpack_p.cpp index cc3c0ed..4570b3d 100644 --- a/src/private/unpack_p.cpp +++ b/src/private/unpack_p.cpp @@ -324,7 +324,7 @@ quint8 *MsgPackPrivate::unpack_ext(QVariant &v, quint8 *p, qint8 type, quint32 l return p + len; } QByteArray data((char *)p, len); - v = user_unpackers[type](data);s + v = user_unpackers[type](data); return p + len; } From 6cf1e17492ae48980dc2070743a6e57fba41ebfc Mon Sep 17 00:00:00 2001 From: Isaikin Roman Date: Wed, 15 Apr 2015 19:13:54 +0300 Subject: [PATCH 06/22] 1/2 QPoint --- src/private/qt_types_p.cpp | 25 +++++++++++++++++++++++++ src/private/qt_types_p.h | 4 ++++ 2 files changed, 29 insertions(+) diff --git a/src/private/qt_types_p.cpp b/src/private/qt_types_p.cpp index 5545dcf..67b6a0d 100644 --- a/src/private/qt_types_p.cpp +++ b/src/private/qt_types_p.cpp @@ -132,3 +132,28 @@ QVariant MsgPackPrivate::unpack_qdatetime(const QByteArray &data) QTime t = unpack_qtime_raw(p + 3); return QDateTime(d, t); } + +// Points and Vectors +quint32 MsgPackPrivate::pack_qpoint(const QVariant &variant, QByteArray &data, bool write) +{ + QPoint pt = variant.toPoint(); + quint8 *p = 0; + if (write) { + p = (quint8 *)data.data(); + p = MsgPackPrivate::pack_int(pt.x(), p, false); + p = MsgPackPrivate::pack_int(pt.y(), p, false); + return data.size(); // ok since it already resized + } else { + p = MsgPackPrivate::pack_int(pt.x(), p, false); + p = MsgPackPrivate::pack_int(pt.y(), p, false); + return p - (quint8 *)0; + } +} + +QVariant MsgPackPrivate::unpack_qpoint(const QByteArray &data) +{ + quint8 *p = (quint8 *)data.data(); + QVariant v; + p = (MsgPackPrivate::unpackers[*p - 0xc0])(v, p); + +} \ No newline at end of file diff --git a/src/private/qt_types_p.h b/src/private/qt_types_p.h index b3d50c1..725a3b6 100644 --- a/src/private/qt_types_p.h +++ b/src/private/qt_types_p.h @@ -27,6 +27,10 @@ QVariant unpack_qdate(const QByteArray &data); quint32 pack_qdatetime(const QVariant &variant, QByteArray &data, bool write); QVariant unpack_qdatetime(const QByteArray &data); +// Points and Vectors +quint32 pack_qpoint(const QVariant &variant, QByteArray &data, bool write); +QVariant unpack_qpoint(const QByteArray &data); + } // MsgPackPrivate From 6d04bc66c60bbecbb9118ea24e906a8d00106a0e Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 15 Apr 2015 22:59:59 +0300 Subject: [PATCH 07/22] ExtHelpers added --- src/msgpack.cpp | 138 +++++++++++++++++++++++++++++++++++++ src/msgpack.h | 15 +++- src/msgpack_common.h | 2 +- src/msgpack_common.h.in | 2 +- src/private/qt_types_p.cpp | 3 +- src/private/unpack_p.cpp | 2 +- 6 files changed, 157 insertions(+), 5 deletions(-) diff --git a/src/msgpack.cpp b/src/msgpack.cpp index 0ab84cd..fed3bba 100644 --- a/src/msgpack.cpp +++ b/src/msgpack.cpp @@ -3,6 +3,7 @@ #include "private/unpack_p.h" #include "private/pack_p.h" #include "private/qt_types_p.h" +#include "private/sysdep.h" QVariant MsgPack::unpack(const QByteArray &data) { @@ -45,3 +46,140 @@ void MsgPack::setCompatibilityModeEnabled(bool enabled) { MsgPackPrivate::compatibilityMode = enabled; } + +quint8 * MsgPack::ExtHelpers::unpack_upto_quint8(quint8 *to, quint8 *p, bool *success) +{ + if (*p <= MsgPack::FirstByte::POSITIVE_FIXINT) { + *to = *(p++); + } else if (*p == MsgPack::FirstByte::UINT8) { + *to = *(++p); + } else { + *success = false; + return p; + } + *success = true; + return p; +} + +quint8 *MsgPack::ExtHelpers::unpack_upto_quint16(quint16 *to, quint8 *p, bool *success) +{ + if (*p == MsgPack::FirstByte::UINT16) { + *to = _msgpack_load16(quint16, p); + *success = true; + return p + 2; + } else { + quint8 u8; + p = unpack_upto_quint8(&u8, p, success); + *to = u8; + return p; + } +} + +quint8 *MsgPack::ExtHelpers::unpack_upto_quint32(quint32 *to, quint8 *p, bool *success) +{ + if (*p == MsgPack::FirstByte::UINT32) { + *to = _msgpack_load32(quint32, p); + *success = true; + return p + 4; + } else { + quint16 u16; + p = unpack_upto_quint16(&u16, p, success); + *to = u16; + return p; + } +} + +quint8 *MsgPack::ExtHelpers::unpack_upto_quint64(quint64 *to, quint8 *p, bool *success) +{ + if (*p == MsgPack::FirstByte::UINT64) { + *to = _msgpack_load64(quint64, p); + *success = true; + return p + 8; + } else { + quint32 u32; + p = unpack_upto_quint32(&u32, p, success); + *to = u32; + return p; + } +} + +quint8 *MsgPack::ExtHelpers::unpack_upto_qint8(qint8 *to, quint8 *p, bool *success) +{ + if (*p >= MsgPack::FirstByte::NEGATIVE_FIXINT) { + *to = *p; + *success = true; + return p + 1; + } else if (*p == MsgPack::FirstByte::INT8) { + *to = (qint8) *(++p); + *success = true; + return p + 1; + } else { + quint8 u8; + p = unpack_upto_quint8(&u8, p, success); + *to = u8; + return p; + } +} + +quint8 *MsgPack::ExtHelpers::unpack_upto_qint16(qint16 *to, quint8 *p, bool *success) +{ + if (*p == MsgPack::FirstByte::INT16) { + *to = _msgpack_load16(qint16, p); + *success = true; + return p + 2; + } else { + qint8 i8; + p = unpack_upto_qint8(&i8, p, success); + *to = i8; + if (*success) { + return p; + } else { + quint16 u16; + p = unpack_upto_quint16(&u16, p, success); + *to = u16; + return p; + } + } +} + +quint8 *MsgPack::ExtHelpers::unpack_upto_qint32(qint32 *to, quint8 *p, bool *success) +{ + if(*p == MsgPack::FirstByte::INT32) { + *to = _msgpack_load32(qint32, p); + *success = true; + return p + 4; + } else { + qint16 i16; + p = unpack_upto_qint16(&i16, p, success); + *to = i16; + if (*success) { + return p; + } else { + quint32 u32; + p = unpack_upto_quint32(&u32, p, success); + *to = u32; + return p; + } + } +} + +quint8 *MsgPack::ExtHelpers::unpack_upto_qint64(qint64 *to, quint8 *p, bool *success) +{ + if(*p == MsgPack::FirstByte::INT64) { + *to = _msgpack_load64(qint64, p); + *success = true; + return p + 8; + } else { + qint32 i32; + p = unpack_upto_qint32(&i32, p, success); + *to = i32; + if (*success) { + return p; + } else { + quint64 u64; + p = unpack_upto_quint64(&u64, p, success); + *to = u64; + return p; + } + } +} diff --git a/src/msgpack.h b/src/msgpack.h index ba95663..e90cc44 100644 --- a/src/msgpack.h +++ b/src/msgpack.h @@ -18,6 +18,19 @@ namespace MsgPack MSGPACK_EXPORT bool registerType(QMetaType::Type qType, quint8 msgpackType); MSGPACK_EXPORT void setCompatibilityModeEnabled(bool enabled); -} + + namespace ExtHelpers { + quint8 * unpack_upto_quint8(quint8 *to, quint8 *from, bool *success); + quint8 * unpack_upto_quint16(quint16 *to, quint8 *from, bool *success); + quint8 * unpack_upto_quint32(quint32 *to, quint8 *from, bool *success); + quint8 * unpack_upto_quint64(quint64 *to, quint8 *from, bool *success); + quint8 * unpack_upto_qint8(qint8 *to, quint8 *from, bool *success); + quint8 * unpack_upto_qint16(qint16 *to, quint8 *from, bool *success); + quint8 * unpack_upto_qint32(qint32 *to, quint8 *from, bool *success); + quint8 * unpack_upto_qint64(qint64 *to, quint8 *from, bool *success); + quint8 * unpack_float(float *to, quint8 *from, bool *success); + quint8 * unpack_double(double *to, quint8 *from, bool *success); + } // ExtHelpers +} // MsgPack #endif // MSGPACK_H diff --git a/src/msgpack_common.h b/src/msgpack_common.h index 7311e7a..bb36a16 100644 --- a/src/msgpack_common.h +++ b/src/msgpack_common.h @@ -30,7 +30,7 @@ QString version(); * From Message Pack spec */ namespace FirstByte { -const quint8 POSITIVE_FIXINT = 0x00; +const quint8 POSITIVE_FIXINT = 0x7f; const quint8 FIXMAP = 0x80; const quint8 FIXARRAY = 0x90; const quint8 FIXSTR = 0xa0; diff --git a/src/msgpack_common.h.in b/src/msgpack_common.h.in index fbf906d..af55f1f 100644 --- a/src/msgpack_common.h.in +++ b/src/msgpack_common.h.in @@ -30,7 +30,7 @@ QString version(); * From Message Pack spec */ namespace FirstByte { -const quint8 POSITIVE_FIXINT = 0x00; +const quint8 POSITIVE_FIXINT = 0x7f; const quint8 FIXMAP = 0x80; const quint8 FIXARRAY = 0x90; const quint8 FIXSTR = 0xa0; diff --git a/src/private/qt_types_p.cpp b/src/private/qt_types_p.cpp index 67b6a0d..6c550b4 100644 --- a/src/private/qt_types_p.cpp +++ b/src/private/qt_types_p.cpp @@ -11,6 +11,7 @@ #define NO_QTGUI_WARNING "Library built without QtGui, hence some types are not available" #include +#include bool MsgPackPrivate::register_qtype(QMetaType::Type q_type, quint8 msgpack_type) { @@ -156,4 +157,4 @@ QVariant MsgPackPrivate::unpack_qpoint(const QByteArray &data) QVariant v; p = (MsgPackPrivate::unpackers[*p - 0xc0])(v, p); -} \ No newline at end of file +} diff --git a/src/private/unpack_p.cpp b/src/private/unpack_p.cpp index 4570b3d..6a09c48 100644 --- a/src/private/unpack_p.cpp +++ b/src/private/unpack_p.cpp @@ -147,7 +147,7 @@ quint8 * MsgPackPrivate::unpack_int16(QVariant &v, quint8 *p) quint8 * MsgPackPrivate::unpack_int32(QVariant &v, quint8 *p) { p++; - v = _msgpack_load32(quint32, p); + v = _msgpack_load32(qint32, p); return p + 4; } From 3b0d6e3c3180ec24c8f01b2369ea02a0155ce1c8 Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 22 Apr 2015 23:47:31 +0300 Subject: [PATCH 08/22] Work on QTime, QDate, QDateTime, QSize, QPoint, QRect unpack_upto_ added for user packer / unpacker functions --- src/CMakeLists.txt | 4 +- src/msgpack-qt.pro | 6 +- src/msgpack.cpp | 137 ----------------------- src/msgpack_ext.cpp | 146 +++++++++++++++++++++++++ src/msgpack_ext.h | 20 ++++ src/private/qt_types_p.cpp | 192 ++++++++++++++++++++++++++------- src/private/qt_types_p.h | 29 ++++- tests/CMakeLists.txt | 2 +- tests/ext/CMakeLists.txt | 24 +++++ tests/ext/ext_test.cpp | 149 +++++++++++++++++++++++++ tests/qttypes/CMakeLists.txt | 24 +++++ tests/qttypes/qttypes_test.cpp | 124 +++++++++++++++++++++ 12 files changed, 674 insertions(+), 183 deletions(-) create mode 100644 src/msgpack_ext.cpp create mode 100644 src/msgpack_ext.h create mode 100644 tests/ext/CMakeLists.txt create mode 100644 tests/ext/ext_test.cpp create mode 100644 tests/qttypes/CMakeLists.txt create mode 100644 tests/qttypes/qttypes_test.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7ac4d56..59c05cf 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,5 @@ -set(qmsgpack_srcs msgpack.cpp msgpack_common.cpp private/pack_p.cpp private/unpack_p.cpp private/qt_types_p.cpp) -set(qmsgpack_headers msgpack.h msgpack_common.h msgpack_export.h) +set(qmsgpack_srcs msgpack.cpp msgpack_common.cpp msgpack_ext.cpp private/pack_p.cpp private/unpack_p.cpp private/qt_types_p.cpp) +set(qmsgpack_headers msgpack.h msgpack_common.h msgpack_ext.h msgpack_export.h) add_library(qmsgpack SHARED ${qmsgpack_srcs} ${qmsgpack_headers}) diff --git a/src/msgpack-qt.pro b/src/msgpack-qt.pro index 97ddb4b..544eecc 100644 --- a/src/msgpack-qt.pro +++ b/src/msgpack-qt.pro @@ -27,7 +27,8 @@ SOURCES += msgpack.cpp \ msgpack_common.cpp \ private/pack_p.cpp \ private/unpack_p.cpp \ - private/qt_types_p.cpp + private/qt_types_p.cpp \ + msgpack_ext.cpp HEADERS += \ msgpack.h \ @@ -36,4 +37,5 @@ HEADERS += \ private/sysdep.h \ msgpack_common.h \ msgpack_export.h \ - private/qt_types_p.h + private/qt_types_p.h \ + msgpack_ext.h diff --git a/src/msgpack.cpp b/src/msgpack.cpp index fed3bba..fdd413d 100644 --- a/src/msgpack.cpp +++ b/src/msgpack.cpp @@ -46,140 +46,3 @@ void MsgPack::setCompatibilityModeEnabled(bool enabled) { MsgPackPrivate::compatibilityMode = enabled; } - -quint8 * MsgPack::ExtHelpers::unpack_upto_quint8(quint8 *to, quint8 *p, bool *success) -{ - if (*p <= MsgPack::FirstByte::POSITIVE_FIXINT) { - *to = *(p++); - } else if (*p == MsgPack::FirstByte::UINT8) { - *to = *(++p); - } else { - *success = false; - return p; - } - *success = true; - return p; -} - -quint8 *MsgPack::ExtHelpers::unpack_upto_quint16(quint16 *to, quint8 *p, bool *success) -{ - if (*p == MsgPack::FirstByte::UINT16) { - *to = _msgpack_load16(quint16, p); - *success = true; - return p + 2; - } else { - quint8 u8; - p = unpack_upto_quint8(&u8, p, success); - *to = u8; - return p; - } -} - -quint8 *MsgPack::ExtHelpers::unpack_upto_quint32(quint32 *to, quint8 *p, bool *success) -{ - if (*p == MsgPack::FirstByte::UINT32) { - *to = _msgpack_load32(quint32, p); - *success = true; - return p + 4; - } else { - quint16 u16; - p = unpack_upto_quint16(&u16, p, success); - *to = u16; - return p; - } -} - -quint8 *MsgPack::ExtHelpers::unpack_upto_quint64(quint64 *to, quint8 *p, bool *success) -{ - if (*p == MsgPack::FirstByte::UINT64) { - *to = _msgpack_load64(quint64, p); - *success = true; - return p + 8; - } else { - quint32 u32; - p = unpack_upto_quint32(&u32, p, success); - *to = u32; - return p; - } -} - -quint8 *MsgPack::ExtHelpers::unpack_upto_qint8(qint8 *to, quint8 *p, bool *success) -{ - if (*p >= MsgPack::FirstByte::NEGATIVE_FIXINT) { - *to = *p; - *success = true; - return p + 1; - } else if (*p == MsgPack::FirstByte::INT8) { - *to = (qint8) *(++p); - *success = true; - return p + 1; - } else { - quint8 u8; - p = unpack_upto_quint8(&u8, p, success); - *to = u8; - return p; - } -} - -quint8 *MsgPack::ExtHelpers::unpack_upto_qint16(qint16 *to, quint8 *p, bool *success) -{ - if (*p == MsgPack::FirstByte::INT16) { - *to = _msgpack_load16(qint16, p); - *success = true; - return p + 2; - } else { - qint8 i8; - p = unpack_upto_qint8(&i8, p, success); - *to = i8; - if (*success) { - return p; - } else { - quint16 u16; - p = unpack_upto_quint16(&u16, p, success); - *to = u16; - return p; - } - } -} - -quint8 *MsgPack::ExtHelpers::unpack_upto_qint32(qint32 *to, quint8 *p, bool *success) -{ - if(*p == MsgPack::FirstByte::INT32) { - *to = _msgpack_load32(qint32, p); - *success = true; - return p + 4; - } else { - qint16 i16; - p = unpack_upto_qint16(&i16, p, success); - *to = i16; - if (*success) { - return p; - } else { - quint32 u32; - p = unpack_upto_quint32(&u32, p, success); - *to = u32; - return p; - } - } -} - -quint8 *MsgPack::ExtHelpers::unpack_upto_qint64(qint64 *to, quint8 *p, bool *success) -{ - if(*p == MsgPack::FirstByte::INT64) { - *to = _msgpack_load64(qint64, p); - *success = true; - return p + 8; - } else { - qint32 i32; - p = unpack_upto_qint32(&i32, p, success); - *to = i32; - if (*success) { - return p; - } else { - quint64 u64; - p = unpack_upto_quint64(&u64, p, success); - *to = u64; - return p; - } - } -} diff --git a/src/msgpack_ext.cpp b/src/msgpack_ext.cpp new file mode 100644 index 0000000..5a4f094 --- /dev/null +++ b/src/msgpack_ext.cpp @@ -0,0 +1,146 @@ +#include "msgpack_ext.h" +#include "msgpack_common.h" +#include "private/sysdep.h" + +quint8 * MsgPack::Ext::unpack_upto_quint8(quint8 *to, quint8 *p, bool *success) +{ + if (*p <= MsgPack::FirstByte::POSITIVE_FIXINT) { + *to = *(p++); + } else if (*p == MsgPack::FirstByte::UINT8) { + *to = *(++p); + } else { + *success = false; + return p; + } + *success = true; + return p; +} + +quint8 *MsgPack::Ext::unpack_upto_quint16(quint16 *to, quint8 *p, bool *success) +{ + if (*p == MsgPack::FirstByte::UINT16) { + p++; + *to = _msgpack_load16(quint16, p); + *success = true; + return p + 2; + } else { + quint8 u8; + p = unpack_upto_quint8(&u8, p, success); + *to = u8; + return p; + } +} + +quint8 *MsgPack::Ext::unpack_upto_quint32(quint32 *to, quint8 *p, bool *success) +{ + if (*p == MsgPack::FirstByte::UINT32) { + p++; + *to = _msgpack_load32(quint32, p); + *success = true; + return p + 4; + } else { + quint16 u16; + p = unpack_upto_quint16(&u16, p, success); + *to = u16; + return p; + } +} + +quint8 *MsgPack::Ext::unpack_upto_quint64(quint64 *to, quint8 *p, bool *success) +{ + if (*p == MsgPack::FirstByte::UINT64) { + p++; + *to = _msgpack_load64(quint64, p); + *success = true; + return p + 8; + } else { + quint32 u32; + p = unpack_upto_quint32(&u32, p, success); + *to = u32; + return p; + } +} + +quint8 *MsgPack::Ext::unpack_upto_qint8(qint8 *to, quint8 *p, bool *success) +{ + if (*p >= MsgPack::FirstByte::NEGATIVE_FIXINT) { + *to = *p; + *success = true; + return p + 1; + } else if (*p == MsgPack::FirstByte::INT8) { + *to = (qint8) *(++p); + *success = true; + return p + 1; + } else { + quint8 u8; + p = unpack_upto_quint8(&u8, p, success); + *to = u8; + return p; + } +} + +quint8 *MsgPack::Ext::unpack_upto_qint16(qint16 *to, quint8 *p, bool *success) +{ + if (*p == MsgPack::FirstByte::INT16) { + p++; + *to = _msgpack_load16(qint16, p); + *success = true; + return p + 2; + } else { + qint8 i8; + p = unpack_upto_qint8(&i8, p, success); + *to = i8; + if (*success) { + return p; + } else { + quint16 u16; + p = unpack_upto_quint16(&u16, p, success); + *to = u16; + return p; + } + } +} + +quint8 *MsgPack::Ext::unpack_upto_qint32(qint32 *to, quint8 *p, bool *success) +{ + if(*p == MsgPack::FirstByte::INT32) { + p++; + *to = _msgpack_load32(qint32, p); + *success = true; + return p + 4; + } else { + qint16 i16; + p = unpack_upto_qint16(&i16, p, success); + *to = i16; + if (*success) { + return p; + } else { + quint32 u32; + p = unpack_upto_quint32(&u32, p, success); + *to = u32; + return p; + } + } +} + +quint8 *MsgPack::Ext::unpack_upto_qint64(qint64 *to, quint8 *p, bool *success) +{ + if(*p == MsgPack::FirstByte::INT64) { + p++; + *to = _msgpack_load64(qint64, p); + *success = true; + return p + 8; + } else { + qint32 i32; + p = unpack_upto_qint32(&i32, p, success); + *to = i32; + if (*success) { + return p; + } else { + quint64 u64; + p = unpack_upto_quint64(&u64, p, success); + *to = u64; + return p; + } + } +} diff --git a/src/msgpack_ext.h b/src/msgpack_ext.h new file mode 100644 index 0000000..c36c789 --- /dev/null +++ b/src/msgpack_ext.h @@ -0,0 +1,20 @@ +#ifndef MSGPACK_EXT_H +#define MSGPACK_EXT_H +#include + +namespace MsgPack +{ + namespace Ext { + quint8 * unpack_upto_quint8(quint8 *to, quint8 *from, bool *success); + quint8 * unpack_upto_quint16(quint16 *to, quint8 *from, bool *success); + quint8 * unpack_upto_quint32(quint32 *to, quint8 *from, bool *success); + quint8 * unpack_upto_quint64(quint64 *to, quint8 *from, bool *success); + quint8 * unpack_upto_qint8(qint8 *to, quint8 *from, bool *success); + quint8 * unpack_upto_qint16(qint16 *to, quint8 *from, bool *success); + quint8 * unpack_upto_qint32(qint32 *to, quint8 *from, bool *success); + quint8 * unpack_upto_qint64(qint64 *to, quint8 *from, bool *success); + quint8 * unpack_float(float *to, quint8 *from, bool *success); + quint8 * unpack_double(double *to, quint8 *from, bool *success); + } // ExtHelpers +} // MsgPack +#endif // MSGPACK_EXT_H diff --git a/src/private/qt_types_p.cpp b/src/private/qt_types_p.cpp index 6c550b4..8491ab1 100644 --- a/src/private/qt_types_p.cpp +++ b/src/private/qt_types_p.cpp @@ -2,6 +2,7 @@ #include "pack_p.h" #include "unpack_p.h" #include "sysdep.h" +#include "../msgpack_ext.h" #include @@ -11,7 +12,7 @@ #define NO_QTGUI_WARNING "Library built without QtGui, hence some types are not available" #include -#include +#include bool MsgPackPrivate::register_qtype(QMetaType::Type q_type, quint8 msgpack_type) { @@ -20,7 +21,7 @@ bool MsgPackPrivate::register_qtype(QMetaType::Type q_type, quint8 msgpack_type) MsgPackPrivate::register_packer(q_type, msgpack_type, pack_qcolor); MsgPackPrivate::register_unpacker(msgpack_type, unpack_qcolor); #else - qWarning() << NO_QTGUI_WARNING; + qWarning() << NO_QTGUI_WARNING; return false; #endif //QT_GUI_LIB } else if (q_type == QMetaType::QTime) { @@ -32,6 +33,15 @@ bool MsgPackPrivate::register_qtype(QMetaType::Type q_type, quint8 msgpack_type) } else if (q_type == QMetaType::QDateTime) { MsgPackPrivate::register_packer(q_type, msgpack_type, pack_qdatetime); MsgPackPrivate::register_unpacker(msgpack_type, unpack_qdatetime); + } else if (q_type == QMetaType::QPoint) { + MsgPackPrivate::register_packer(q_type, msgpack_type, pack_qpoint); + MsgPackPrivate::register_unpacker(msgpack_type, unpack_qpoint); + } else if (q_type == QMetaType::QSize) { + MsgPackPrivate::register_packer(q_type, msgpack_type, pack_qsize); + MsgPackPrivate::register_unpacker(msgpack_type, unpack_qsize); + } else if (q_type == QMetaType::QRect) { + MsgPackPrivate::register_packer(q_type, msgpack_type, pack_qrect); + MsgPackPrivate::register_unpacker(msgpack_type, unpack_qrect); } return true; } @@ -42,44 +52,65 @@ quint32 MsgPackPrivate::pack_qcolor(const QVariant &variant, QByteArray &data, b if (write) { QColor color = variant.value(); data.resize(4); - data[0] = color.red(); - data[1] = color.green(); - data[2] = color.blue(); - data[3] = color.alpha(); + 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 } QVariant MsgPackPrivate::unpack_qcolor(const QByteArray &data) { - return QColor((quint8)data[0], (quint8)data[1], - (quint8)data[2], (quint8)data[3]); + quint8 *p = (quint8 *)data.data(); + return QColor(p[0], p[1], p[2], p[3]); } -#endif //MsgPackPrivate +#endif // QT_GUI_LIB // Date and Time void MsgPackPrivate::pack_qtime_raw(const QTime &time, quint8 *p) { - quint32 t = time.msecsSinceStartOfDay(); - _msgpack_store32(p, t); + quint8 hm, ms; + hm = (quint8)time.hour() << 4; + hm |= (quint8)time.minute() >> 2; + ms = ((quint8)time.minute() << 6) & 0xc0; // 11000000 + ms |= (quint8)time.second(); + p[0] = hm; p[1] = ms; + + if (time.msec() != 0) { + p[2] = (quint8)( (quint16)time.msec() >> 8 ); + p[3] = (quint8)time.msec(); + } } -QTime MsgPackPrivate::unpack_qtime_raw(quint8 *p) +QTime MsgPackPrivate::unpack_qtime_raw(quint8 *p, bool with_ms) { - quint32 t = _msgpack_load32(quint32, p); - return QTime::fromMSecsSinceStartOfDay(t); + quint8 h, m, s; + quint16 ms = 0; + h = p[0] >> 4; + m = (p[0] << 2) | (p[1] >> 6); + m &= 0x3f; // 00111111 + s = p[1] & 0x3f; + if (with_ms) + ms = (p[2] << 8) | p[3]; + return QTime(h, m, s, ms); } quint32 MsgPackPrivate::pack_qtime(const QVariant &variant, QByteArray &data, bool write) { - if (write) - pack_qtime_raw(variant.toTime(), (quint8 *)data.data()); - return 4; // 24h*60m*60s*1000ms = max 27 bits + 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; } QVariant MsgPackPrivate::unpack_qtime(const QByteArray &data) { - return unpack_qtime_raw((quint8 *)data.data()); + return unpack_qtime_raw((quint8 *)data.data(), data.size() == 4); } void MsgPackPrivate::pack_qdate_raw(const QDate &date, quint8 *p) @@ -87,9 +118,10 @@ void MsgPackPrivate::pack_qdate_raw(const QDate &date, quint8 *p) quint16 year = date.year(); quint8 month = date.month(); quint8 day = date.day(); - quint16 dy = year | (day & 0x80); + if (day > 15) + year |= 0x8000; quint8 md = (month << 4) | (day & 0xf); - _msgpack_store16(p, dy); + _msgpack_store16(p, year); p[2] = md; } @@ -105,9 +137,11 @@ QDate MsgPackPrivate::unpack_qdate_raw(quint8 *p) quint32 MsgPackPrivate::pack_qdate(const QVariant &variant, QByteArray &data, bool write) { - if (write) + if (write) { + data.resize(3); pack_qdate_raw(variant.toDate(), (quint8 *)data.data()); - return 3; // d(5th bit)xyyyyyyyyyyyyyy, mmmmdddd + } + return 3; } QVariant MsgPackPrivate::unpack_qdate(const QByteArray &data) @@ -117,44 +151,126 @@ QVariant MsgPackPrivate::unpack_qdate(const QByteArray &data) quint32 MsgPackPrivate::pack_qdatetime(const QVariant &variant, QByteArray &data, bool write) { + 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(); - QDateTime dt = variant.toDateTime(); pack_qdate_raw(dt.date(), p); - pack_qtime_raw(dt.time(), p + 3); + p += 3; + pack_qtime_raw(dt.time(), p); } - return 7; // 3 for date, 4 for time + return 3 + time_size; // 3 for date, 4 for time } QVariant MsgPackPrivate::unpack_qdatetime(const QByteArray &data) { quint8 *p = (quint8 *)data.data(); QDate d = unpack_qdate_raw(p); - QTime t = unpack_qtime_raw(p + 3); + QTime t = unpack_qtime_raw(p + 3, data.size() == 7); return QDateTime(d, t); } // 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) { QPoint pt = variant.toPoint(); - quint8 *p = 0; + quint8 size = pack_two_integers(pt.x(), pt.y(), 0, false); if (write) { - p = (quint8 *)data.data(); - p = MsgPackPrivate::pack_int(pt.x(), p, false); - p = MsgPackPrivate::pack_int(pt.y(), p, false); - return data.size(); // ok since it already resized - } else { - p = MsgPackPrivate::pack_int(pt.x(), p, false); - p = MsgPackPrivate::pack_int(pt.y(), p, false); - return p - (quint8 *)0; + data.resize(size); + pack_two_integers(pt.x(), pt.y(), (quint8 *)data.data(), true); } + return size; } QVariant MsgPackPrivate::unpack_qpoint(const QByteArray &data) { quint8 *p = (quint8 *)data.data(); - QVariant v; - p = (MsgPackPrivate::unpackers[*p - 0xc0])(v, p); - + qint32 x; + bool ok; + p = MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); + QPoint pt; + pt.setX(x); + MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); + pt.setY(x); + return pt; } + +quint32 MsgPackPrivate::pack_qsize(const QVariant &variant, QByteArray &data, bool write) +{ + QSize sz = variant.toSize(); + quint8 size = pack_two_integers(sz.width(), sz.height(), 0, false); + if (write) { + data.resize(size); + pack_two_integers(sz.width(), sz.height(), (quint8 *)data.data(), true); + } + return size; +} + +QVariant MsgPackPrivate::unpack_qsize(const QByteArray &data) +{ + quint8 *p = (quint8 *)data.data(); + qint32 x; + bool ok; + p = MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); + QSize sz; + sz.setWidth(x); + MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); + sz.setHeight(x); + return sz; +} + +quint32 MsgPackPrivate::pack_qrect(const QVariant &variant, QByteArray &data, bool write) +{ + QRect rect = variant.toRect(); + QPoint pt1 = rect.topLeft(); + QPoint pt2 = rect.bottomRight(); + quint8 size = pack_two_integers(pt1.x(), pt1.y(), 0, false); + size += pack_two_integers(pt2.x(), pt2.y(), 0, false); + if (write) { + data.resize(size); + quint8 *p = (quint8 *)data.data(); + p += pack_two_integers(pt1.x(), pt1.y(), p, true); + pack_two_integers(pt2.x(), pt2.y(), p, true); + } + return size; +} + +QVariant MsgPackPrivate::unpack_qrect(const QByteArray &data) +{ + quint8 *p = (quint8 *)data.data(); + qint32 x; + bool ok; + + p = MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); + QPoint pt; + pt.setX(x); + p = MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); + pt.setY(x); + + QRect rect; + rect.setTopLeft(pt); + + p = MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); + pt.setX(x); + p = MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); + pt.setY(x); + + rect.setBottomRight(pt); + + return rect; +} + diff --git a/src/private/qt_types_p.h b/src/private/qt_types_p.h index 725a3b6..9c90c3e 100644 --- a/src/private/qt_types_p.h +++ b/src/private/qt_types_p.h @@ -14,12 +14,31 @@ QVariant unpack_qcolor(const QByteArray &data); #endif //QT_GUI_LIB // Date and Time -void pack_qtime_raw(const QTime &time, quint8 *p); -QTime unpack_qtime_raw(quint8 *p); +/** + * @brief pack_qtime_raw internal: packs QTime to 4 or 2 bytes (with or without ms) + * @param time QTime to pack + * @param p pointer to preallocated array + * format: (bits) hhhhmmmm mmssssss [------ms msmsmsms] + */ +void pack_qtime_raw(const QTime &time, quint8 *p); // return 2 - without ms, 4 with ms +/** + * @brief unpack_qtime_raw internal: unpack 2 or 4 bytes to QTime + * @param p data to unpack + * @param with_ms true if array is 4 bytes (i.e. unpack with ms) + * @return QTime + */ +QTime unpack_qtime_raw(quint8 *p, bool with_ms); quint32 pack_qtime(const QVariant &variant, QByteArray &data, bool write); QVariant unpack_qtime(const QByteArray &data); +/** + * @brief pack_qdate_raw internal: pack QDate to 3 bytes + * @param date QDate to pack + * @param p pointer to preallocated array + * format: (bits) d(5th bit)xyyyyyyyyyyyyyy, mmmmdddd + */ 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); QVariant unpack_qdate(const QByteArray &data); @@ -28,9 +47,13 @@ quint32 pack_qdatetime(const QVariant &variant, QByteArray &data, bool write); 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); QVariant unpack_qpoint(const QByteArray &data); - +quint32 pack_qsize(const QVariant &variant, QByteArray &data, bool write); +QVariant unpack_qsize(const QByteArray &data); +quint32 pack_qrect(const QVariant &variant, QByteArray &data, bool write); +QVariant unpack_qrect(const QByteArray &data); } // MsgPackPrivate diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 18f82e5..856446b 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) +set(TEST_SUBDIRS pack unpack mixed qttypes ext) foreach(subdir ${TEST_SUBDIRS}) add_subdirectory(${subdir}) diff --git a/tests/ext/CMakeLists.txt b/tests/ext/CMakeLists.txt new file mode 100644 index 0000000..e5ca9c1 --- /dev/null +++ b/tests/ext/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 ext_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/ext/ext_test.cpp b/tests/ext/ext_test.cpp new file mode 100644 index 0000000..6455f49 --- /dev/null +++ b/tests/ext/ext_test.cpp @@ -0,0 +1,149 @@ +#include +#include +#include +#include +#include +#include + +class ExtText : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void test_upto_quint(); + void test_upto_qint(); + void test_upto_qint_to_quint(); + void test_fail(); +}; + +void ExtText::test_upto_quint() +{ + QByteArray packed; + bool success; + quint8 u8; + quint16 u16; + quint32 u32; + quint64 u64; + + packed = MsgPack::pack(0); + MsgPack::Ext::unpack_upto_quint8(&u8, (quint8 *)packed.data(), &success); + QVERIFY(u8 == 0); + QVERIFY(success); + MsgPack::Ext::unpack_upto_quint16(&u16, (quint8 *)packed.data(), &success); + QVERIFY(u16 == 0); + QVERIFY(success); + MsgPack::Ext::unpack_upto_quint32(&u32, (quint8 *)packed.data(), &success); + QVERIFY(u32 == 0); + QVERIFY(success); + MsgPack::Ext::unpack_upto_quint64(&u64, (quint8 *)packed.data(), &success); + QVERIFY(u64 == 0); + QVERIFY(success); + + packed = MsgPack::pack(std::numeric_limits::max()); + MsgPack::Ext::unpack_upto_quint8(&u8, (quint8 *)packed.data(), &success); + QVERIFY(u8 == std::numeric_limits::max()); + QVERIFY(success); + + packed = MsgPack::pack(std::numeric_limits::max()); + MsgPack::Ext::unpack_upto_quint16(&u16, (quint8 *)packed.data(), &success); + QVERIFY(u16 == std::numeric_limits::max()); + QVERIFY(success); + + packed = MsgPack::pack(std::numeric_limits::max()); + MsgPack::Ext::unpack_upto_quint32(&u32, (quint8 *)packed.data(), &success); + QVERIFY(u32 == std::numeric_limits::max()); + QVERIFY(success); + + packed = MsgPack::pack(std::numeric_limits::max()); + MsgPack::Ext::unpack_upto_quint64(&u64, (quint8 *)packed.data(), &success); + QVERIFY(u64 == std::numeric_limits::max()); + QVERIFY(success); +} + +void ExtText::test_upto_qint() +{ + QByteArray packed; + bool success; + qint8 i8; + qint16 i16; + qint32 i32; + qint64 i64; + + packed = MsgPack::pack(-32); + MsgPack::Ext::unpack_upto_qint8(&i8, (quint8 *)packed.data(), &success); + QVERIFY(i8 == -32); + QVERIFY(success); + MsgPack::Ext::unpack_upto_qint16(&i16, (quint8 *)packed.data(), &success); + QVERIFY(i16 == -32); + QVERIFY(success); + MsgPack::Ext::unpack_upto_qint32(&i32, (quint8 *)packed.data(), &success); + QVERIFY(i32 == -32); + QVERIFY(success); + MsgPack::Ext::unpack_upto_qint64(&i64, (quint8 *)packed.data(), &success); + QVERIFY(i64 == -32); + QVERIFY(success); + + packed = MsgPack::pack(std::numeric_limits::min() - 1); + MsgPack::Ext::unpack_upto_qint8(&i8, (quint8 *)packed.data(), &success); + QVERIFY(i8 == std::numeric_limits::min() - 1); + QVERIFY(success); + + packed = MsgPack::pack(std::numeric_limits::min() - 1); + MsgPack::Ext::unpack_upto_qint16(&i16, (quint8 *)packed.data(), &success); + QVERIFY(i16 == std::numeric_limits::min() - 1); + QVERIFY(success); + + packed = MsgPack::pack(std::numeric_limits::min() - 1); + MsgPack::Ext::unpack_upto_qint32(&i32, (quint8 *)packed.data(), &success); + QVERIFY(i32 == std::numeric_limits::min() - 1); + QVERIFY(success); + + packed = MsgPack::pack(std::numeric_limits::min() - 1); + MsgPack::Ext::unpack_upto_qint64(&i64, (quint8 *)packed.data(), &success); + QVERIFY(i64 == std::numeric_limits::min() - 1); + QVERIFY(success); +} + +void ExtText::test_upto_qint_to_quint() +{ + QByteArray packed; + bool success; + qint8 i8; + qint16 i16; + qint32 i32; + qint64 i64; + + packed = MsgPack::pack(std::numeric_limits::max()); + MsgPack::Ext::unpack_upto_qint8(&i8, (quint8 *)packed.data(), &success); + QVERIFY(i8 == std::numeric_limits::max()); + QVERIFY(success); + + packed = MsgPack::pack(std::numeric_limits::max()); + MsgPack::Ext::unpack_upto_qint16(&i16, (quint8 *)packed.data(), &success); + QVERIFY(i16 == std::numeric_limits::max()); + QVERIFY(success); + + packed = MsgPack::pack(std::numeric_limits::max()); + MsgPack::Ext::unpack_upto_qint32(&i32, (quint8 *)packed.data(), &success); + QVERIFY(i32 == std::numeric_limits::max()); + QVERIFY(success); + + packed = MsgPack::pack(std::numeric_limits::max()); + MsgPack::Ext::unpack_upto_qint64(&i64, (quint8 *)packed.data(), &success); + QVERIFY(i64 == std::numeric_limits::max()); + QVERIFY(success); +} + +void ExtText::test_fail() +{ + quint8 p[] = {0xd9}; + quint8 u8; + bool ok; + quint8 *p2 = MsgPack::Ext::unpack_upto_quint8(&u8, p, &ok); + QVERIFY(!ok); + QVERIFY(p2 - p == 0); +} + +QTEST_APPLESS_MAIN(ExtText) + +#include "ext_test.moc" diff --git a/tests/qttypes/CMakeLists.txt b/tests/qttypes/CMakeLists.txt new file mode 100644 index 0000000..9f37e5b --- /dev/null +++ b/tests/qttypes/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 qttypes_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/qttypes/qttypes_test.cpp b/tests/qttypes/qttypes_test.cpp new file mode 100644 index 0000000..ebcaa28 --- /dev/null +++ b/tests/qttypes/qttypes_test.cpp @@ -0,0 +1,124 @@ +#include +#include +#include +#include +#include + +class QtTypesTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void test_qtime(); + void test_qdate(); + void test_qpoint(); + void test_qsize(); + void test_qrect(); +}; + +void QtTypesTest::test_qtime() +{ + MsgPack::registerType(QMetaType::QTime, 0x77); + QTime t(0, 0, 0, 0); + QByteArray packed = MsgPack::pack(t); + QTime t2 = MsgPack::unpack(packed).toTime(); + QVERIFY(t == t2); + QVERIFY(packed.size() == 4); + + t = QTime(12, 01, 01, 0); + packed = MsgPack::pack(t); + t2 = MsgPack::unpack(packed).toTime(); + QVERIFY(t == t2); + QVERIFY(packed.size() == 4); + + t = QTime(12, 59, 59, 0); + packed = MsgPack::pack(t); + t2 = MsgPack::unpack(packed).toTime(); + QVERIFY(t == t2); + QVERIFY(packed.size() == 4); + + t = QTime(12, 34, 56, 999); + packed = MsgPack::pack(t); + t2 = MsgPack::unpack(packed).toTime(); + QVERIFY(t == t2); + QVERIFY(packed.size() == 6); +} + +void QtTypesTest::test_qdate() +{ + MsgPack::registerType(QMetaType::QDate, 0x78); + QDate d; + QByteArray packed = MsgPack::pack(d); + QDate d2 = MsgPack::unpack(packed).toDate(); + QVERIFY(d == d2); + QVERIFY(packed.size() == 6); + + d = QDate(1234, 12, 1); + packed = MsgPack::pack(d); + d2 = MsgPack::unpack(packed).toDate(); + QVERIFY(d == d2); + + d = QDate(9999, 1, 31); + packed = MsgPack::pack(d); + d2 = MsgPack::unpack(packed).toDate(); + QVERIFY(d == d2); +} + +void QtTypesTest::test_qpoint() +{ + MsgPack::registerType(QMetaType::QPoint, 0x79); + QPoint pt(1, 2); + QByteArray packed = MsgPack::pack(pt); + QVERIFY(packed.size() == 4); + QPoint pt2 = MsgPack::unpack(packed).toPoint(); + QVERIFY(pt == pt2); + + pt = QPoint(1234, 5678); + packed = MsgPack::pack(pt); + QVERIFY(packed.size() == 9); + pt2 = MsgPack::unpack(packed).toPoint(); + QVERIFY(pt == pt2); + + pt = QPoint(std::numeric_limits::max(), std::numeric_limits::max()); + packed = MsgPack::pack(pt); + QVERIFY(packed.size() == 13); + pt2 = MsgPack::unpack(packed).toPoint(); + QVERIFY(pt == pt2); +} + +void QtTypesTest::test_qsize() +{ + MsgPack::registerType(QMetaType::QSize, 80); + QSize sz(1, 2); + QByteArray packed = MsgPack::pack(sz); + QVERIFY(packed.size() == 4); + QSize sz2 = MsgPack::unpack(packed).toSize(); + QVERIFY(sz == sz2); + + sz = QSize(1234, 5678); + packed = MsgPack::pack(sz); + QVERIFY(packed.size() == 9); + sz2 = MsgPack::unpack(packed).toSize(); + QVERIFY(sz == sz2); +} + +void QtTypesTest::test_qrect() +{ + MsgPack::registerType(QMetaType::QRect, 81); + QRect r(1, 2, 3, 4); + QByteArray packed = MsgPack::pack(r); + QVERIFY(packed.size() == 6); + QRect r2 = MsgPack::unpack(packed).toRect(); + QVERIFY(r == r2); + + qint32 max = std::numeric_limits::max(); + r = QRect(0, 0, max, max); + packed = MsgPack::pack(r); + QVERIFY(packed.size() == 15); + r2 = MsgPack::unpack(packed).toRect(); + QVERIFY(r == r2); +} + +QTEST_APPLESS_MAIN(QtTypesTest) + +#include "qttypes_test.moc" From 1ae96715cf7c654729edba36b014f4d4adce0d8e Mon Sep 17 00:00:00 2001 From: Roman Date: Sat, 2 May 2015 00:06:35 +0300 Subject: [PATCH 09/22] Started work on MsgPackStream --- src/CMakeLists.txt | 4 +- src/msgpack-qt.pro | 6 +- src/msgpack_ext.cpp | 146 -------------------------------------- src/msgpack_ext.h | 20 ------ src/stream.cpp | 98 +++++++++++++++++++++++++ src/stream.h | 49 +++++++++++++ tests/CMakeLists.txt | 2 +- tests/ext/CMakeLists.txt | 24 ------- tests/ext/ext_test.cpp | 149 --------------------------------------- 9 files changed, 154 insertions(+), 344 deletions(-) delete mode 100644 src/msgpack_ext.cpp delete mode 100644 src/msgpack_ext.h create mode 100644 src/stream.cpp create mode 100644 src/stream.h delete mode 100644 tests/ext/CMakeLists.txt delete mode 100644 tests/ext/ext_test.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 59c05cf..ed4735d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,5 @@ -set(qmsgpack_srcs msgpack.cpp msgpack_common.cpp msgpack_ext.cpp private/pack_p.cpp private/unpack_p.cpp private/qt_types_p.cpp) -set(qmsgpack_headers msgpack.h msgpack_common.h msgpack_ext.h msgpack_export.h) +set(qmsgpack_srcs msgpack.cpp msgpack_common.cpp stream.cpp private/pack_p.cpp private/unpack_p.cpp private/qt_types_p.cpp) +set(qmsgpack_headers msgpack.h stream.h msgpack_common.h msgpack_export.h) add_library(qmsgpack SHARED ${qmsgpack_srcs} ${qmsgpack_headers}) diff --git a/src/msgpack-qt.pro b/src/msgpack-qt.pro index 544eecc..2e187fd 100644 --- a/src/msgpack-qt.pro +++ b/src/msgpack-qt.pro @@ -28,7 +28,8 @@ SOURCES += msgpack.cpp \ private/pack_p.cpp \ private/unpack_p.cpp \ private/qt_types_p.cpp \ - msgpack_ext.cpp + msgpack_ext.cpp \ + stream.cpp HEADERS += \ msgpack.h \ @@ -38,4 +39,5 @@ HEADERS += \ msgpack_common.h \ msgpack_export.h \ private/qt_types_p.h \ - msgpack_ext.h + msgpack_ext.h \ + stream.h diff --git a/src/msgpack_ext.cpp b/src/msgpack_ext.cpp deleted file mode 100644 index 5a4f094..0000000 --- a/src/msgpack_ext.cpp +++ /dev/null @@ -1,146 +0,0 @@ -#include "msgpack_ext.h" -#include "msgpack_common.h" -#include "private/sysdep.h" - -quint8 * MsgPack::Ext::unpack_upto_quint8(quint8 *to, quint8 *p, bool *success) -{ - if (*p <= MsgPack::FirstByte::POSITIVE_FIXINT) { - *to = *(p++); - } else if (*p == MsgPack::FirstByte::UINT8) { - *to = *(++p); - } else { - *success = false; - return p; - } - *success = true; - return p; -} - -quint8 *MsgPack::Ext::unpack_upto_quint16(quint16 *to, quint8 *p, bool *success) -{ - if (*p == MsgPack::FirstByte::UINT16) { - p++; - *to = _msgpack_load16(quint16, p); - *success = true; - return p + 2; - } else { - quint8 u8; - p = unpack_upto_quint8(&u8, p, success); - *to = u8; - return p; - } -} - -quint8 *MsgPack::Ext::unpack_upto_quint32(quint32 *to, quint8 *p, bool *success) -{ - if (*p == MsgPack::FirstByte::UINT32) { - p++; - *to = _msgpack_load32(quint32, p); - *success = true; - return p + 4; - } else { - quint16 u16; - p = unpack_upto_quint16(&u16, p, success); - *to = u16; - return p; - } -} - -quint8 *MsgPack::Ext::unpack_upto_quint64(quint64 *to, quint8 *p, bool *success) -{ - if (*p == MsgPack::FirstByte::UINT64) { - p++; - *to = _msgpack_load64(quint64, p); - *success = true; - return p + 8; - } else { - quint32 u32; - p = unpack_upto_quint32(&u32, p, success); - *to = u32; - return p; - } -} - -quint8 *MsgPack::Ext::unpack_upto_qint8(qint8 *to, quint8 *p, bool *success) -{ - if (*p >= MsgPack::FirstByte::NEGATIVE_FIXINT) { - *to = *p; - *success = true; - return p + 1; - } else if (*p == MsgPack::FirstByte::INT8) { - *to = (qint8) *(++p); - *success = true; - return p + 1; - } else { - quint8 u8; - p = unpack_upto_quint8(&u8, p, success); - *to = u8; - return p; - } -} - -quint8 *MsgPack::Ext::unpack_upto_qint16(qint16 *to, quint8 *p, bool *success) -{ - if (*p == MsgPack::FirstByte::INT16) { - p++; - *to = _msgpack_load16(qint16, p); - *success = true; - return p + 2; - } else { - qint8 i8; - p = unpack_upto_qint8(&i8, p, success); - *to = i8; - if (*success) { - return p; - } else { - quint16 u16; - p = unpack_upto_quint16(&u16, p, success); - *to = u16; - return p; - } - } -} - -quint8 *MsgPack::Ext::unpack_upto_qint32(qint32 *to, quint8 *p, bool *success) -{ - if(*p == MsgPack::FirstByte::INT32) { - p++; - *to = _msgpack_load32(qint32, p); - *success = true; - return p + 4; - } else { - qint16 i16; - p = unpack_upto_qint16(&i16, p, success); - *to = i16; - if (*success) { - return p; - } else { - quint32 u32; - p = unpack_upto_quint32(&u32, p, success); - *to = u32; - return p; - } - } -} - -quint8 *MsgPack::Ext::unpack_upto_qint64(qint64 *to, quint8 *p, bool *success) -{ - if(*p == MsgPack::FirstByte::INT64) { - p++; - *to = _msgpack_load64(qint64, p); - *success = true; - return p + 8; - } else { - qint32 i32; - p = unpack_upto_qint32(&i32, p, success); - *to = i32; - if (*success) { - return p; - } else { - quint64 u64; - p = unpack_upto_quint64(&u64, p, success); - *to = u64; - return p; - } - } -} diff --git a/src/msgpack_ext.h b/src/msgpack_ext.h deleted file mode 100644 index c36c789..0000000 --- a/src/msgpack_ext.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef MSGPACK_EXT_H -#define MSGPACK_EXT_H -#include - -namespace MsgPack -{ - namespace Ext { - quint8 * unpack_upto_quint8(quint8 *to, quint8 *from, bool *success); - quint8 * unpack_upto_quint16(quint16 *to, quint8 *from, bool *success); - quint8 * unpack_upto_quint32(quint32 *to, quint8 *from, bool *success); - quint8 * unpack_upto_quint64(quint64 *to, quint8 *from, bool *success); - quint8 * unpack_upto_qint8(qint8 *to, quint8 *from, bool *success); - quint8 * unpack_upto_qint16(qint16 *to, quint8 *from, bool *success); - quint8 * unpack_upto_qint32(qint32 *to, quint8 *from, bool *success); - quint8 * unpack_upto_qint64(qint64 *to, quint8 *from, bool *success); - quint8 * unpack_float(float *to, quint8 *from, bool *success); - quint8 * unpack_double(double *to, quint8 *from, bool *success); - } // ExtHelpers -} // MsgPack -#endif // MSGPACK_EXT_H diff --git a/src/stream.cpp b/src/stream.cpp new file mode 100644 index 0000000..d90bbe6 --- /dev/null +++ b/src/stream.cpp @@ -0,0 +1,98 @@ +#include "stream.h" +#include + +#undef CHECK_STREAM_PRECOND +#ifndef QT_NO_DEBUG +#define CHECK_STREAM_PRECOND(retVal) \ + if (!dev) { \ + qWarning("msgpack::Stream: No device"); \ + return retVal; \ + } +#else +#define CHECK_STREAM_PRECOND(retVal) \ + if (!dev) { \ + return retVal; \ + } +#endif + +#define CHECK_STREAM_WRITE_PRECOND(retVal) \ + CHECK_STREAM_PRECOND(retVal) \ + if (q_status != Ok) \ + return retVal; + +MsgPackStream::MsgPackStream() : + dev(0), compatibility(false), owndev(false), q_status(Ok) +{ } + +MsgPackStream::MsgPackStream(QIODevice *d) : + dev(d), compatibility(false), owndev(false) +{ } + +MsgPackStream::MsgPackStream(QByteArray *a, QIODevice::OpenMode mode) : + compatibility(false), owndev(true), q_status(Ok) +{ + QBuffer *buf = new QBuffer(a); + buf->open(mode); + dev = buf; +} + +MsgPackStream::MsgPackStream(const QByteArray &a) : + compatibility(false), owndev(true), q_status(Ok) +{ + QBuffer *buf = new QBuffer(); + buf->setData(a); + buf->open(QIODevice::ReadOnly); + dev = buf; +} + +MsgPackStream::~MsgPackStream() +{ + if (owndev) + delete dev; +} + +void MsgPackStream::setDevice(QIODevice *d) +{ + if (owndev) + delete dev; + dev = d; + owndev = false; +} + +bool MsgPackStream::atEnd() const +{ + return dev ? dev->atEnd() : true; +} + +void MsgPackStream::setCompatibility(bool isEnabled) +{ + compatibility = isEnabled; +} + +MsgPackStream::Status MsgPackStream::status() const +{ + return q_status; +} + +void MsgPackStream::resetStatus() +{ + q_status = Ok; +} + +void MsgPackStream::setStatus(Status status) +{ + q_status = status; +} + +MsgPackStream &MsgPackStream::operator >>(quint8 &u8) +{ + u8 = 0; + CHECK_STREAM_PRECOND(*this) + char c; + if (!dev->getChar(&c)) + setStatus(ReadPastEnd); + else + u8 = quint8(c); + return *this; +} + diff --git a/src/stream.h b/src/stream.h new file mode 100644 index 0000000..d272841 --- /dev/null +++ b/src/stream.h @@ -0,0 +1,49 @@ +#ifndef STREAM_H +#define STREAM_H +#include + +class MsgPackStream +{ +public: + MsgPackStream(); + MsgPackStream(QIODevice *d); + MsgPackStream(QByteArray *a, QIODevice::OpenMode mode); + MsgPackStream(const QByteArray &a); + virtual ~MsgPackStream(); + + void setDevice(QIODevice *d); + QIODevice *device() const; + bool atEnd() const; + + void setCompatibility(bool isEnabled); + + enum Status {Ok, ReadPastEnd, ReadCorruptData, WriteFailed}; + Status status() const; + void resetStatus(); + void setStatus(Status status); + + MsgPackStream &operator>>(bool &b); + MsgPackStream &operator>>(quint8 &u8); + MsgPackStream &operator>>(quint16 &u16); + MsgPackStream &operator>>(quint32 &u32); + MsgPackStream &operator>>(quint64 &u64); + MsgPackStream &operator>>(qint8 &i8); + MsgPackStream &operator>>(qint16 &i16); + MsgPackStream &operator>>(qint32 &i32); + MsgPackStream &operator>>(qint64 &i64); + MsgPackStream &operator>>(float &f); + MsgPackStream &operator>>(double &d); + MsgPackStream &operator>>(QString &str); + MsgPackStream &operator>>(QByteArray &array); + MsgPackStream &operator>>(QVariantList &list); + MsgPackStream &operator>>(QVariantMap &map); + + +private: + QIODevice *dev; + bool compatibility; + bool owndev; + Status q_status; +}; + +#endif // STREAM_H diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 856446b..385f69b 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 ext) +set(TEST_SUBDIRS pack unpack mixed qttypes) foreach(subdir ${TEST_SUBDIRS}) add_subdirectory(${subdir}) diff --git a/tests/ext/CMakeLists.txt b/tests/ext/CMakeLists.txt deleted file mode 100644 index e5ca9c1..0000000 --- a/tests/ext/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -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 ext_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/ext/ext_test.cpp b/tests/ext/ext_test.cpp deleted file mode 100644 index 6455f49..0000000 --- a/tests/ext/ext_test.cpp +++ /dev/null @@ -1,149 +0,0 @@ -#include -#include -#include -#include -#include -#include - -class ExtText : public QObject -{ - Q_OBJECT - -private Q_SLOTS: - void test_upto_quint(); - void test_upto_qint(); - void test_upto_qint_to_quint(); - void test_fail(); -}; - -void ExtText::test_upto_quint() -{ - QByteArray packed; - bool success; - quint8 u8; - quint16 u16; - quint32 u32; - quint64 u64; - - packed = MsgPack::pack(0); - MsgPack::Ext::unpack_upto_quint8(&u8, (quint8 *)packed.data(), &success); - QVERIFY(u8 == 0); - QVERIFY(success); - MsgPack::Ext::unpack_upto_quint16(&u16, (quint8 *)packed.data(), &success); - QVERIFY(u16 == 0); - QVERIFY(success); - MsgPack::Ext::unpack_upto_quint32(&u32, (quint8 *)packed.data(), &success); - QVERIFY(u32 == 0); - QVERIFY(success); - MsgPack::Ext::unpack_upto_quint64(&u64, (quint8 *)packed.data(), &success); - QVERIFY(u64 == 0); - QVERIFY(success); - - packed = MsgPack::pack(std::numeric_limits::max()); - MsgPack::Ext::unpack_upto_quint8(&u8, (quint8 *)packed.data(), &success); - QVERIFY(u8 == std::numeric_limits::max()); - QVERIFY(success); - - packed = MsgPack::pack(std::numeric_limits::max()); - MsgPack::Ext::unpack_upto_quint16(&u16, (quint8 *)packed.data(), &success); - QVERIFY(u16 == std::numeric_limits::max()); - QVERIFY(success); - - packed = MsgPack::pack(std::numeric_limits::max()); - MsgPack::Ext::unpack_upto_quint32(&u32, (quint8 *)packed.data(), &success); - QVERIFY(u32 == std::numeric_limits::max()); - QVERIFY(success); - - packed = MsgPack::pack(std::numeric_limits::max()); - MsgPack::Ext::unpack_upto_quint64(&u64, (quint8 *)packed.data(), &success); - QVERIFY(u64 == std::numeric_limits::max()); - QVERIFY(success); -} - -void ExtText::test_upto_qint() -{ - QByteArray packed; - bool success; - qint8 i8; - qint16 i16; - qint32 i32; - qint64 i64; - - packed = MsgPack::pack(-32); - MsgPack::Ext::unpack_upto_qint8(&i8, (quint8 *)packed.data(), &success); - QVERIFY(i8 == -32); - QVERIFY(success); - MsgPack::Ext::unpack_upto_qint16(&i16, (quint8 *)packed.data(), &success); - QVERIFY(i16 == -32); - QVERIFY(success); - MsgPack::Ext::unpack_upto_qint32(&i32, (quint8 *)packed.data(), &success); - QVERIFY(i32 == -32); - QVERIFY(success); - MsgPack::Ext::unpack_upto_qint64(&i64, (quint8 *)packed.data(), &success); - QVERIFY(i64 == -32); - QVERIFY(success); - - packed = MsgPack::pack(std::numeric_limits::min() - 1); - MsgPack::Ext::unpack_upto_qint8(&i8, (quint8 *)packed.data(), &success); - QVERIFY(i8 == std::numeric_limits::min() - 1); - QVERIFY(success); - - packed = MsgPack::pack(std::numeric_limits::min() - 1); - MsgPack::Ext::unpack_upto_qint16(&i16, (quint8 *)packed.data(), &success); - QVERIFY(i16 == std::numeric_limits::min() - 1); - QVERIFY(success); - - packed = MsgPack::pack(std::numeric_limits::min() - 1); - MsgPack::Ext::unpack_upto_qint32(&i32, (quint8 *)packed.data(), &success); - QVERIFY(i32 == std::numeric_limits::min() - 1); - QVERIFY(success); - - packed = MsgPack::pack(std::numeric_limits::min() - 1); - MsgPack::Ext::unpack_upto_qint64(&i64, (quint8 *)packed.data(), &success); - QVERIFY(i64 == std::numeric_limits::min() - 1); - QVERIFY(success); -} - -void ExtText::test_upto_qint_to_quint() -{ - QByteArray packed; - bool success; - qint8 i8; - qint16 i16; - qint32 i32; - qint64 i64; - - packed = MsgPack::pack(std::numeric_limits::max()); - MsgPack::Ext::unpack_upto_qint8(&i8, (quint8 *)packed.data(), &success); - QVERIFY(i8 == std::numeric_limits::max()); - QVERIFY(success); - - packed = MsgPack::pack(std::numeric_limits::max()); - MsgPack::Ext::unpack_upto_qint16(&i16, (quint8 *)packed.data(), &success); - QVERIFY(i16 == std::numeric_limits::max()); - QVERIFY(success); - - packed = MsgPack::pack(std::numeric_limits::max()); - MsgPack::Ext::unpack_upto_qint32(&i32, (quint8 *)packed.data(), &success); - QVERIFY(i32 == std::numeric_limits::max()); - QVERIFY(success); - - packed = MsgPack::pack(std::numeric_limits::max()); - MsgPack::Ext::unpack_upto_qint64(&i64, (quint8 *)packed.data(), &success); - QVERIFY(i64 == std::numeric_limits::max()); - QVERIFY(success); -} - -void ExtText::test_fail() -{ - quint8 p[] = {0xd9}; - quint8 u8; - bool ok; - quint8 *p2 = MsgPack::Ext::unpack_upto_quint8(&u8, p, &ok); - QVERIFY(!ok); - QVERIFY(p2 - p == 0); -} - -QTEST_APPLESS_MAIN(ExtText) - -#include "ext_test.moc" From 87bd3dedb148569bc1e00058ab83f867f63925fd Mon Sep 17 00:00:00 2001 From: Roman Date: Fri, 15 May 2015 22:49:39 +0300 Subject: [PATCH 10/22] MsgPackStream work (now working now) --- src/msgpack-qt.pro | 2 - src/private/qt_types_p.cpp | 121 ++++++++++++++++++------------------- src/stream.cpp | 52 ++++++++++++++-- 3 files changed, 106 insertions(+), 69 deletions(-) diff --git a/src/msgpack-qt.pro b/src/msgpack-qt.pro index 2e187fd..d69ffaf 100644 --- a/src/msgpack-qt.pro +++ b/src/msgpack-qt.pro @@ -28,7 +28,6 @@ SOURCES += msgpack.cpp \ private/pack_p.cpp \ private/unpack_p.cpp \ private/qt_types_p.cpp \ - msgpack_ext.cpp \ stream.cpp HEADERS += \ @@ -39,5 +38,4 @@ HEADERS += \ msgpack_common.h \ msgpack_export.h \ private/qt_types_p.h \ - msgpack_ext.h \ stream.h diff --git a/src/private/qt_types_p.cpp b/src/private/qt_types_p.cpp index 8491ab1..da3d260 100644 --- a/src/private/qt_types_p.cpp +++ b/src/private/qt_types_p.cpp @@ -2,7 +2,6 @@ #include "pack_p.h" #include "unpack_p.h" #include "sysdep.h" -#include "../msgpack_ext.h" #include @@ -187,90 +186,90 @@ quint8 MsgPackPrivate::pack_two_integers(qint32 a, qint32 b, quint8 *to, bool wr quint32 MsgPackPrivate::pack_qpoint(const QVariant &variant, QByteArray &data, bool write) { - QPoint pt = variant.toPoint(); - quint8 size = pack_two_integers(pt.x(), pt.y(), 0, false); - if (write) { - data.resize(size); - pack_two_integers(pt.x(), pt.y(), (quint8 *)data.data(), true); - } - return size; + // QPoint pt = variant.toPoint(); + // quint8 size = pack_two_integers(pt.x(), pt.y(), 0, false); + // if (write) { + // data.resize(size); + // pack_two_integers(pt.x(), pt.y(), (quint8 *)data.data(), true); + // } + // return size; } QVariant MsgPackPrivate::unpack_qpoint(const QByteArray &data) { - quint8 *p = (quint8 *)data.data(); - qint32 x; - bool ok; - p = MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); - QPoint pt; - pt.setX(x); - MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); - pt.setY(x); - return pt; + // quint8 *p = (quint8 *)data.data(); + // qint32 x; + // bool ok; + // p = MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); + // QPoint pt; + // pt.setX(x); + // MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); + // pt.setY(x); + // return pt; } quint32 MsgPackPrivate::pack_qsize(const QVariant &variant, QByteArray &data, bool write) { - QSize sz = variant.toSize(); - quint8 size = pack_two_integers(sz.width(), sz.height(), 0, false); - if (write) { - data.resize(size); - pack_two_integers(sz.width(), sz.height(), (quint8 *)data.data(), true); - } - return size; + // QSize sz = variant.toSize(); + // quint8 size = pack_two_integers(sz.width(), sz.height(), 0, false); + // if (write) { + // data.resize(size); + // pack_two_integers(sz.width(), sz.height(), (quint8 *)data.data(), true); + // } + // return size; } QVariant MsgPackPrivate::unpack_qsize(const QByteArray &data) { - quint8 *p = (quint8 *)data.data(); - qint32 x; - bool ok; - p = MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); - QSize sz; - sz.setWidth(x); - MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); - sz.setHeight(x); - return sz; + // quint8 *p = (quint8 *)data.data(); + // qint32 x; + // bool ok; + // p = MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); + // QSize sz; + // sz.setWidth(x); + // MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); + // sz.setHeight(x); + // return sz; } quint32 MsgPackPrivate::pack_qrect(const QVariant &variant, QByteArray &data, bool write) { - QRect rect = variant.toRect(); - QPoint pt1 = rect.topLeft(); - QPoint pt2 = rect.bottomRight(); - quint8 size = pack_two_integers(pt1.x(), pt1.y(), 0, false); - size += pack_two_integers(pt2.x(), pt2.y(), 0, false); - if (write) { - data.resize(size); - quint8 *p = (quint8 *)data.data(); - p += pack_two_integers(pt1.x(), pt1.y(), p, true); - pack_two_integers(pt2.x(), pt2.y(), p, true); - } - return size; + // QRect rect = variant.toRect(); + // QPoint pt1 = rect.topLeft(); + // QPoint pt2 = rect.bottomRight(); + // quint8 size = pack_two_integers(pt1.x(), pt1.y(), 0, false); + // size += pack_two_integers(pt2.x(), pt2.y(), 0, false); + // if (write) { + // data.resize(size); + // quint8 *p = (quint8 *)data.data(); + // p += pack_two_integers(pt1.x(), pt1.y(), p, true); + // pack_two_integers(pt2.x(), pt2.y(), p, true); + // } + // return size; } QVariant MsgPackPrivate::unpack_qrect(const QByteArray &data) { - quint8 *p = (quint8 *)data.data(); - qint32 x; - bool ok; + // quint8 *p = (quint8 *)data.data(); + // qint32 x; + // bool ok; - p = MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); - QPoint pt; - pt.setX(x); - p = MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); - pt.setY(x); + // p = MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); + // QPoint pt; + // pt.setX(x); + // p = MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); + // pt.setY(x); - QRect rect; - rect.setTopLeft(pt); + // QRect rect; + // rect.setTopLeft(pt); - p = MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); - pt.setX(x); - p = MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); - pt.setY(x); + // p = MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); + // pt.setX(x); + // p = MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); + // pt.setY(x); - rect.setBottomRight(pt); + // rect.setBottomRight(pt); - return rect; + // return rect; } diff --git a/src/stream.cpp b/src/stream.cpp index d90bbe6..8e9ce3e 100644 --- a/src/stream.cpp +++ b/src/stream.cpp @@ -1,5 +1,8 @@ #include "stream.h" #include +#include "private/sysdep.h" +#include "msgpack_common.h" +#include #undef CHECK_STREAM_PRECOND #ifndef QT_NO_DEBUG @@ -84,15 +87,52 @@ void MsgPackStream::setStatus(Status status) q_status = status; } -MsgPackStream &MsgPackStream::operator >>(quint8 &u8) +MsgPackStream &MsgPackStream::operator>>(bool &b) { - u8 = 0; CHECK_STREAM_PRECOND(*this) - char c; - if (!dev->getChar(&c)) + quint8 p[1]; + if (!dev->getChar((char *)p)) { + b = false; setStatus(ReadPastEnd); - else - u8 = quint8(c); + } else { + if (p[0] != MsgPack::FirstByte::TRUE || + p[0] != MsgPack::FirstByte::FALSE) + setStatus(ReadCorruptData); + b = (p[0] == MsgPack::FirstByte::TRUE); + } return *this; } +MsgPackStream &MsgPackStream::operator >>(quint8 &u8) +{ + CHECK_STREAM_PRECOND(*this) + char c; + if (!dev->getChar(&c)) { + u8 = 0; + setStatus(ReadPastEnd); + } else { + u8 = quint8(c); + } + return *this; +} + +MsgPackStream &MsgPackStream::operator>>(quint16 &u16) +{ + CHECK_STREAM_PRECOND(*this); + quint8 p[3]; + if (dev->read((char *)p, 3) != 3) { + u16 = 0; + setStatus(ReadPastEnd); + } else { + if (p[0] != MsgPack::FirstByte::UINT16) + setStatus(ReadCorruptData); + u16 = _msgpack_load16(quint16, (p + 1)); + } + return *this; +} + +MsgPackStream &MsgPackStream::operator>>(quint32 &u32) +{ + +} + From 32b04745eec06a1f8400d6b3843ff0a371f6a274 Mon Sep 17 00:00:00 2001 From: Isaikin Roman Date: Sat, 16 May 2015 12:07:10 +0300 Subject: [PATCH 11/22] MsgPackStream work --- src/private/unpack_p.cpp | 2 +- src/stream.cpp | 75 ++++++++++++++++++++++++++++++++++++++++ src/stream.h | 14 ++++++++ 3 files changed, 90 insertions(+), 1 deletion(-) diff --git a/src/private/unpack_p.cpp b/src/private/unpack_p.cpp index 6a09c48..5901e9b 100644 --- a/src/private/unpack_p.cpp +++ b/src/private/unpack_p.cpp @@ -183,7 +183,7 @@ quint8 * MsgPackPrivate::unpack_float64(QVariant &v, quint8 *p) for (int i = 0; i < 8; ++i) *(fd + 7 - i) = *(p + i); #else - for (int i = 0; i < 4; ++i) + for (int i = 0; i < 8; ++i) *(fp + i) = *(p + i); #endif v = d; diff --git a/src/stream.cpp b/src/stream.cpp index 8e9ce3e..b13ea69 100644 --- a/src/stream.cpp +++ b/src/stream.cpp @@ -1,6 +1,7 @@ #include "stream.h" #include #include "private/sysdep.h" +#include "private/pack_p.h" #include "msgpack_common.h" #include @@ -136,3 +137,77 @@ MsgPackStream &MsgPackStream::operator>>(quint32 &u32) } +MsgPackStream &MsgPackStream::operator>>(QString &str) +{ + CHECK_STREAM_PRECOND(*this); + quint8 p[5]; + if (dev->read((char *)p, 1) != 1) { + setStatus(ReadPastEnd); + return *this; + } + + int len = 0; + if (*p >= 0xa0 && *p <= 0xbf) { // fixstr + len = (*p) & 0x1f; // 0b00011111 + } else if (*p == MsgPack::FirstByte::STR8) { + if (dev->read((char *)p + 1, 1) == 1) + len = p[1]; + } else if (*p == MsgPack::FirstByte::STR16) { + if (dev->read((char *)p + 1, 2) == 2) + len = _msgpack_load16(int, &p[1]); + } else if (*p == MsgPack::FirstByte::STR32) { + if (dev->read((char *)p + 1, 4) == 4) + len = _msgpack_load32(int, &p[1]); + } else { + setStatus(ReadCorruptData); + return *this; + } +} + +MsgPackStream &MsgPackStream::operator<<(bool b) +{ + CHECK_STREAM_WRITE_PRECOND(*this); + quint8 m = b == true ? + MsgPack::FirstByte::TRUE : MsgPack::FirstByte::FALSE; + if (dev->write((char *)&m, 1) != 1) + setStatus(WriteFailed); + return *this; +} + +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) + setStatus(WriteFailed); + return *this; +} + +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) + setStatus(WriteFailed); + return *this; +} + +MsgPackStream &MsgPackStream::operator<<(QString str) +{ + CHECK_STREAM_WRITE_PRECOND(*this); + quint8 *p = (quint8 *)0; + quint32 sz = MsgPackPrivate::pack_string(str, p, false) - p; + quint8 *data = new quint8[sz]; + MsgPackPrivate::pack(str, data, true); + if (dev->write((char *)data, sz) != sz) + setStatus(WriteFailed); + delete[] data; + return *this; +} + +MsgPackStream &MsgPackStream::operator<<(const char *str) +{ + +} diff --git a/src/stream.h b/src/stream.h index d272841..816011c 100644 --- a/src/stream.h +++ b/src/stream.h @@ -38,12 +38,26 @@ public: MsgPackStream &operator>>(QVariantList &list); MsgPackStream &operator>>(QVariantMap &map); + MsgPackStream &operator<<(bool b); + MsgPackStream &operator<<(quint32 u32); + MsgPackStream &operator<<(quint64 u64); + MsgPackStream &operator<<(qint32 i32); + MsgPackStream &operator<<(qint64 i64); + MsgPackStream &operator<<(float f); + MsgPackStream &operator<<(double d); + MsgPackStream &operator<<(QString str); + + MsgPackStream &operator<<(QByteArray array); + MsgPackStream &operator<<(QVariantList list); + MsgPackStream &operator<<(QVariantMap map); private: QIODevice *dev; bool compatibility; bool owndev; Status q_status; + + MsgPackStream &operator<<(const char *str); // use QStringLiteral instead }; #endif // STREAM_H From b7fbf6413e58e32735b2551e40050cd799686ba2 Mon Sep 17 00:00:00 2001 From: Roman Date: Sat, 16 May 2015 21:45:33 +0300 Subject: [PATCH 12/22] MsgPackStream integers pack and unpack User types packers now called only once, and return QByteArray --- src/msgpack.cpp | 6 +- src/msgpack_common.h | 12 +- src/private/pack_p.cpp | 34 ++-- src/private/pack_p.h | 8 +- src/private/qt_types_p.cpp | 79 ++++------ src/private/qt_types_p.h | 15 +- src/stream.cpp | 291 +++++++++++++++++++++++++++++++++-- src/stream.h | 9 ++ tests/CMakeLists.txt | 2 +- tests/mixed/mixed_test.cpp | 16 +- tests/stream/CMakeLists.txt | 24 +++ tests/stream/stream_test.cpp | 141 +++++++++++++++++ 12 files changed, 530 insertions(+), 107 deletions(-) create mode 100644 tests/stream/CMakeLists.txt create mode 100644 tests/stream/stream_test.cpp 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" From f978fb0d783dfe48e9a9ef71b3c60ec0e407ac09 Mon Sep 17 00:00:00 2001 From: Roman Date: Tue, 19 May 2015 22:41:22 +0300 Subject: [PATCH 13/22] MsgPackStream QString and const char * added Qt types: QPoint, QSize, QRect implemented using MsgPackStream MsgPackStream QString tests added --- .gitignore | 2 +- src/msgpack_common.h | 10 +-- src/msgpack_common.h.in | 12 ++-- src/private/pack_p.cpp | 12 +++- src/private/pack_p.h | 1 + src/private/qt_types_p.cpp | 100 +++++++++++------------------- src/stream.cpp | 109 ++++++++++++++++++--------------- src/stream.h | 7 +-- tests/pack/pack_test.cpp | 8 +-- tests/qttypes/qttypes_test.cpp | 2 + tests/stream/stream_test.cpp | 68 ++++++++++++++++++++ 11 files changed, 190 insertions(+), 141 deletions(-) diff --git a/.gitignore b/.gitignore index 33c5afb..ab6317a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -*.pro.user +*.pro.user* build lib Makefile diff --git a/src/msgpack_common.h b/src/msgpack_common.h index e8cf602..17f713b 100644 --- a/src/msgpack_common.h +++ b/src/msgpack_common.h @@ -10,14 +10,14 @@ namespace MsgPack { /** - * @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 + * 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 */ typedef QByteArray (*pack_user_f)(const QVariant &variant); /** - * @brief unpack user type to QVariant - * @arg data only user data, without size and messagepack type + * unpack user type to QVariant */ typedef QVariant (*unpack_user_f)(const QByteArray &data); /** diff --git a/src/msgpack_common.h.in b/src/msgpack_common.h.in index af55f1f..3d43993 100644 --- a/src/msgpack_common.h.in +++ b/src/msgpack_common.h.in @@ -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 c94b989..7fa5166 100644 --- a/src/private/pack_p.cpp +++ b/src/private/pack_p.cpp @@ -175,9 +175,8 @@ quint8 *MsgPackPrivate::pack_stringlist(const QStringList &list, quint8 *p, bool return p; } -quint8 *MsgPackPrivate::pack_string(const QString &str, quint8 *p, bool wr) +quint8 *MsgPackPrivate::pack_string_raw(const char *str, quint32 len, quint8 *p, bool wr) { - int len = str.length(); if (len <= 31) { if (wr) *p = 0xa0 | len; p++; @@ -198,11 +197,18 @@ quint8 *MsgPackPrivate::pack_string(const QString &str, quint8 *p, bool wr) if (wr) _msgpack_store32(p, len); p += 4; } - if (wr) memcpy(p, str.toUtf8().data(), len); + 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_double(double i, quint8 *p, bool wr) { if (wr) *p = 0xcb; diff --git a/src/private/pack_p.h b/src/private/pack_p.h index d3afda4..d16d81b 100644 --- a/src/private/pack_p.h +++ b/src/private/pack_p.h @@ -36,6 +36,7 @@ quint8 * pack_arraylen(quint32 len, 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_raw(const char *str, quint32 len, 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); diff --git a/src/private/qt_types_p.cpp b/src/private/qt_types_p.cpp index 5975429..5630d12 100644 --- a/src/private/qt_types_p.cpp +++ b/src/private/qt_types_p.cpp @@ -1,6 +1,7 @@ #include "qt_types_p.h" #include "pack_p.h" #include "unpack_p.h" +#include "stream.h" #include "sysdep.h" #include @@ -169,90 +170,59 @@ QVariant MsgPackPrivate::unpack_qdatetime(const QByteArray &data) // Points and Vectors QByteArray MsgPackPrivate::pack_qpoint(const QVariant &variant) { - // QPoint pt = variant.toPoint(); - // quint8 size = pack_two_integers(pt.x(), pt.y(), 0, false); - // if (write) { - // data.resize(size); - // pack_two_integers(pt.x(), pt.y(), (quint8 *)data.data(), true); - // } - // return size; + QByteArray packed; + MsgPackStream stream(&packed, QIODevice::WriteOnly); + QPoint pt = variant.toPoint(); + stream << pt.x() << pt.y(); + return packed; } QVariant MsgPackPrivate::unpack_qpoint(const QByteArray &data) { - // quint8 *p = (quint8 *)data.data(); - // qint32 x; - // bool ok; - // p = MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); - // QPoint pt; - // pt.setX(x); - // MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); - // pt.setY(x); - // return pt; + MsgPackStream stream(data); + qint32 x, y; + stream >> x >> y; + qDebug() << "unpack qpoint stream" << (stream.status() == MsgPackStream::Ok); + return QPoint(x, y); } QByteArray MsgPackPrivate::pack_qsize(const QVariant &variant) { - // QSize sz = variant.toSize(); - // quint8 size = pack_two_integers(sz.width(), sz.height(), 0, false); - // if (write) { - // data.resize(size); - // pack_two_integers(sz.width(), sz.height(), (quint8 *)data.data(), true); - // } - // return size; + QByteArray packed; + MsgPackStream stream(&packed, QIODevice::WriteOnly); + QSize sz = variant.toSize(); + stream << sz.width() << sz.height(); + return packed; } QVariant MsgPackPrivate::unpack_qsize(const QByteArray &data) { - // quint8 *p = (quint8 *)data.data(); - // qint32 x; - // bool ok; - // p = MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); - // QSize sz; - // sz.setWidth(x); - // MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); - // sz.setHeight(x); - // return sz; + MsgPackStream stream(data); + qint32 width, height; + stream >> width >> height; + return QSize(width, height); } QByteArray MsgPackPrivate::pack_qrect(const QVariant &variant) { - // QRect rect = variant.toRect(); - // QPoint pt1 = rect.topLeft(); - // QPoint pt2 = rect.bottomRight(); - // quint8 size = pack_two_integers(pt1.x(), pt1.y(), 0, false); - // size += pack_two_integers(pt2.x(), pt2.y(), 0, false); - // if (write) { - // data.resize(size); - // quint8 *p = (quint8 *)data.data(); - // p += pack_two_integers(pt1.x(), pt1.y(), p, true); - // pack_two_integers(pt2.x(), pt2.y(), p, true); - // } - // return size; + QRect rect = variant.toRect(); + QPoint pt1 = rect.topLeft(); + QPoint pt2 = rect.bottomRight(); + QByteArray packed; + MsgPackStream stream(&packed, QIODevice::WriteOnly); + stream << pt1.x() << pt1.y() << pt2.x() << pt2.y(); + return packed; } QVariant MsgPackPrivate::unpack_qrect(const QByteArray &data) { - // quint8 *p = (quint8 *)data.data(); - // qint32 x; - // bool ok; - - // p = MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); - // QPoint pt; - // pt.setX(x); - // p = MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); - // pt.setY(x); - - // QRect rect; - // rect.setTopLeft(pt); - - // p = MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); - // pt.setX(x); - // p = MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); - // pt.setY(x); - - // rect.setBottomRight(pt); - - // return rect; + MsgPackStream stream(data); + qint32 x, y; + stream >> x >> y; + QRect rect; + rect.setTopLeft(QPoint(x, y)); + stream >> x >> y; + rect.setBottomRight(QPoint(x, y)); + return rect; } diff --git a/src/stream.cpp b/src/stream.cpp index 71b6f72..3c59216 100644 --- a/src/stream.cpp +++ b/src/stream.cpp @@ -26,15 +26,15 @@ return retVal; MsgPackStream::MsgPackStream() : - dev(0), compatibility(false), owndev(false), q_status(Ok) + dev(0), owndev(false), q_status(Ok) { } MsgPackStream::MsgPackStream(QIODevice *d) : - dev(d), compatibility(false), owndev(false) + dev(d), owndev(false) { } MsgPackStream::MsgPackStream(QByteArray *a, QIODevice::OpenMode mode) : - compatibility(false), owndev(true), q_status(Ok) + owndev(true), q_status(Ok) { QBuffer *buf = new QBuffer(a); buf->open(mode); @@ -42,7 +42,7 @@ MsgPackStream::MsgPackStream(QByteArray *a, QIODevice::OpenMode mode) : } MsgPackStream::MsgPackStream(const QByteArray &a) : - compatibility(false), owndev(true), q_status(Ok) + owndev(true), q_status(Ok) { QBuffer *buf = new QBuffer(); buf->setData(a); @@ -69,11 +69,6 @@ bool MsgPackStream::atEnd() const return dev ? dev->atEnd() : true; } -void MsgPackStream::setCompatibility(bool isEnabled) -{ - compatibility = isEnabled; -} - MsgPackStream::Status MsgPackStream::status() const { return q_status; @@ -113,7 +108,8 @@ MsgPackStream &MsgPackStream::operator >>(quint8 &u8) setStatus(ReadPastEnd); return *this; } - unpack_upto_quint8(u8, &p); + if (!unpack_upto_quint8(u8, &p)) + setStatus(ReadCorruptData); return *this; } @@ -125,7 +121,8 @@ MsgPackStream &MsgPackStream::operator>>(quint16 &u16) setStatus(ReadPastEnd); return *this; } - unpack_upto_quint16(u16, &p); + if (!unpack_upto_quint16(u16, &p { + setStatus(ReadCorruptData); return *this; } @@ -137,7 +134,8 @@ MsgPackStream &MsgPackStream::operator>>(quint32 &u32) setStatus(ReadPastEnd); return *this; } - unpack_upto_quint32(u32, &p); + if (!unpack_upto_quint32(u32, &p { + setStatus(ReadCorruptData); return *this; } @@ -149,7 +147,8 @@ MsgPackStream &MsgPackStream::operator>>(quint64 &u64) setStatus(ReadPastEnd); return *this; } - unpack_upto_quint64(u64, &p); + if (!unpack_upto_quint64(u64, &p { + setStatus(ReadCorruptData); return *this; } @@ -161,7 +160,7 @@ MsgPackStream &MsgPackStream::operator>>(qint8 &i8) setStatus(ReadPastEnd); return *this; } - unpack_upto_qint8(i8, &p); + if (!unpack_upto_qint8(i8, &p)) setStatus(ReadCorruptData); return *this; } @@ -173,7 +172,8 @@ MsgPackStream &MsgPackStream::operator>>(qint16 &i16) setStatus(ReadPastEnd); return *this; } - unpack_upto_qint16(i16, &p); + if (!unpack_upto_qint16(i16, &p){ + setStatus(ReadCorruptData); return *this; } @@ -185,7 +185,8 @@ MsgPackStream &MsgPackStream::operator>>(qint32 &i32) setStatus(ReadPastEnd); return *this; } - unpack_upto_qint32(i32, &p); + if (!unpack_upto_qint32(i32, &p){ + setStatus(ReadCorruptData); return *this; } @@ -197,7 +198,8 @@ MsgPackStream &MsgPackStream::operator>>(qint64 &i64) setStatus(ReadPastEnd); return *this; } - unpack_upto_qint64(i64, &p); + if (!unpack_upto_qint64(i64, &p){ + setStatus(ReadCorruptData); return *this; } @@ -226,6 +228,14 @@ MsgPackStream &MsgPackStream::operator>>(QString &str) setStatus(ReadCorruptData); return *this; } + quint8 *data = new quint8[len]; + if (dev->read((char *)data, len) != len) { + setStatus(ReadPastEnd); + delete[] data; + return *this; + } + str = QString::fromUtf8((const char*) data, len); + delete[] data; } MsgPackStream &MsgPackStream::operator<<(bool b) @@ -284,8 +294,7 @@ MsgPackStream &MsgPackStream::operator<<(QString str) quint8 *p = (quint8 *)0; quint32 sz = MsgPackPrivate::pack_string(str, p, false) - p; quint8 *data = new quint8[sz]; - QVector user_data; - MsgPackPrivate::pack(str, data, true, user_data); + MsgPackPrivate::pack_string(str, data, true); if (dev->write((char *)data, sz) != sz) setStatus(WriteFailed); delete[] data; @@ -294,21 +303,26 @@ MsgPackStream &MsgPackStream::operator<<(QString str) MsgPackStream &MsgPackStream::operator<<(const char *str) { - + CHECK_STREAM_WRITE_PRECOND(*this); + quint8 *p = (quint8 *)0; + quint32 str_len = strlen(str); + quint32 sz = MsgPackPrivate::pack_string_raw(str, str_len, p, false) - p; + quint8 *data = new quint8[sz]; + MsgPackPrivate::pack_string_raw(str, str_len, data, true); + if (dev->write((char *)data, sz) != sz) + setStatus(WriteFailed); + delete[] data; + return *this; } - 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); + if (dev->read((char* )&u8, 1) != 1) return false; - } } else { - setStatus(ReadCorruptData); return false; } return true; @@ -318,10 +332,8 @@ 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); + if (dev->read((char *)d, 2) != 2) return false; - } u16 = _msgpack_load16(quint16, d); } else { quint8 u8; @@ -329,16 +341,15 @@ bool MsgPackStream::unpack_upto_quint16(quint16 &u16, quint8 *p) u16 = u8; return ok; } + return true; } 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); + if (dev->read((char *)d, 4) != 4) return false; - } u32 = _msgpack_load32(quint32, d); return true; } else { @@ -347,6 +358,7 @@ bool MsgPackStream::unpack_upto_quint32(quint32 &u32, quint8 *p) u32 = u16; return ok; } + return true; } bool MsgPackStream::unpack_upto_quint64(quint64 &u64, quint8 *p) @@ -354,7 +366,6 @@ 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); @@ -373,14 +384,13 @@ bool MsgPackStream::unpack_upto_qint8(qint8 &i8, quint8 *p) 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); + return false; else i8 = u8; return ok; @@ -393,11 +403,9 @@ 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; + i16 = _msgpack_load16(qint16, d); } else { qint8 i8; bool ok = unpack_upto_qint8(i8, p); @@ -406,13 +414,14 @@ bool MsgPackStream::unpack_upto_qint16(qint16 &i16, quint8 *p) } else { quint16 u16; bool ok = unpack_upto_quint16(u16, p); - if (u16 <= std::numeric_limits::max()) - i16 = u16; + if (u16 > std::numeric_limits::max()) + return false; else - setStatus(ReadCorruptData); + i16 = u16; return ok; } } + return true; } bool MsgPackStream::unpack_upto_qint32(qint32 &i32, quint8 *p) @@ -420,11 +429,9 @@ 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); @@ -433,23 +440,22 @@ bool MsgPackStream::unpack_upto_qint32(qint32 &i32, quint8 *p) } else { quint32 u32; bool ok = unpack_upto_quint32(u32, p); - if (u32 <= std::numeric_limits::max()) - i32 = u32; + if (u32 > std::numeric_limits::max()) + return false; else - setStatus(ReadCorruptData); + i32 = u32; return ok; } } + return true; } 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); + if (dev->read((char *)d, 8) != 8) return false; - } i64 = _msgpack_load64(qint64, d); return true; } else { @@ -460,11 +466,12 @@ bool MsgPackStream::unpack_upto_qint64(qint64 &i64, quint8 *p) } else { quint64 u64; bool ok = unpack_upto_quint64(u64, p); - if (u64 <= std::numeric_limits::max()) - i64 = u64; + if (u64 > std::numeric_limits::max()) + return false; else - setStatus(ReadCorruptData); + i64 = u64; return ok; } } + return true; } diff --git a/src/stream.h b/src/stream.h index e4aa849..545973d 100644 --- a/src/stream.h +++ b/src/stream.h @@ -15,8 +15,6 @@ public: QIODevice *device() const; bool atEnd() const; - void setCompatibility(bool isEnabled); - enum Status {Ok, ReadPastEnd, ReadCorruptData, WriteFailed}; Status status() const; void resetStatus(); @@ -46,19 +44,16 @@ public: MsgPackStream &operator<<(float f); MsgPackStream &operator<<(double d); MsgPackStream &operator<<(QString str); - + MsgPackStream &operator<<(const char *str); MsgPackStream &operator<<(QByteArray array); MsgPackStream &operator<<(QVariantList list); MsgPackStream &operator<<(QVariantMap map); private: QIODevice *dev; - bool compatibility; bool owndev; 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); diff --git a/tests/pack/pack_test.cpp b/tests/pack/pack_test.cpp index 70b2963..8d01fc2 100644 --- a/tests/pack/pack_test.cpp +++ b/tests/pack/pack_test.cpp @@ -216,14 +216,14 @@ void PackTest::test_float() void PackTest::test_str() { - QString str = QString::fromUtf8("msgpack rocks"); + QString str = QStringLiteral("msgpack rocks"); QByteArray arr = MsgPack::pack(str); QVERIFY(arr.size() == 14); quint8 *p = (quint8 *)arr.data(); QVERIFY(p[0] == (0xa0 | str.length())); QVERIFY(memcmp(p + 1, str.toUtf8().data(), str.size()) == 0); - str = QString::fromUtf8(QByteArray(32, 'm')); + str = QString(QByteArray(32, 'm')); arr = MsgPack::pack(str); QVERIFY(arr.size() == 32 + 2); p = (quint8 *)arr.data(); @@ -231,7 +231,7 @@ void PackTest::test_str() QVERIFY(p[1] == 32); QVERIFY(memcmp(p + 2, str.toUtf8().data(), str.size()) == 0); - str = QString::fromUtf8(QByteArray(256, 's')); + str = QString(QByteArray(256, 's')); arr = MsgPack::pack(str); QVERIFY(arr.size() == 256 + 3); p = (quint8 *)arr.data(); @@ -240,7 +240,7 @@ void PackTest::test_str() QVERIFY(p[2] == 0x00); QVERIFY(memcmp(p + 3, str.toUtf8().data(), str.size()) == 0); - str = QString::fromUtf8(QByteArray(65536, 'g')); + str = QString(QByteArray(65536, 'g')); arr = MsgPack::pack(str); QVERIFY(arr.size() == 65536 + 5); p = (quint8 *)arr.data(); diff --git a/tests/qttypes/qttypes_test.cpp b/tests/qttypes/qttypes_test.cpp index ebcaa28..9f4d31f 100644 --- a/tests/qttypes/qttypes_test.cpp +++ b/tests/qttypes/qttypes_test.cpp @@ -77,6 +77,8 @@ void QtTypesTest::test_qpoint() packed = MsgPack::pack(pt); QVERIFY(packed.size() == 9); pt2 = MsgPack::unpack(packed).toPoint(); + qDebug() << pt << pt2; + qDebug() << packed.toHex() << packed.size(); QVERIFY(pt == pt2); pt = QPoint(std::numeric_limits::max(), std::numeric_limits::max()); diff --git a/tests/stream/stream_test.cpp b/tests/stream/stream_test.cpp index a389512..29662b3 100644 --- a/tests/stream/stream_test.cpp +++ b/tests/stream/stream_test.cpp @@ -12,6 +12,8 @@ class StreamTest : public QObject private Q_SLOTS: void test_unpack_integers(); void test_pack_integers(); + void test_unpack_string(); + void test_pack_string(); }; @@ -135,6 +137,72 @@ void StreamTest::test_pack_integers() QVERIFY(l[19].toLongLong() == std::numeric_limits::min()); } +void StreamTest::test_unpack_string() +{ + QString str = QStringLiteral("msgpack rocks"); + QByteArray packed = MsgPack::pack(str); + QString str2; + + { + MsgPackStream stream(packed); + stream >> str2; + QVERIFY(str == str2); + } + { + str = QString(QByteArray(32, 'm')); + packed = MsgPack::pack(str); + MsgPackStream stream(packed); + stream >> str2; + QVERIFY(str == str2); + } + { + str = QString::fromUtf8(QByteArray(256, 's')); + packed = MsgPack::pack(str); + MsgPackStream stream(packed); + stream >> str2; + QVERIFY(str == str2); + } + { + str = QString(QByteArray(65536, 'g')); + packed = MsgPack::pack(str); + MsgPackStream stream(packed); + stream >> str2; + QVERIFY(str == str2); + } +} + +void StreamTest::test_pack_string() +{ + QByteArray packed; + MsgPackStream stream(&packed, QIODevice::WriteOnly); + QStringList strs; + stream << "abc"; + strs << "abc"; + QString s; + for (int i = 0; i < 8; ++i) + s += "xy"; + stream << s; + strs << s; + s = QString(); + for (int i = 0; i < 64; ++i) + s += "msgp"; + stream << s; + strs << s; + s = QString(); + for (int i = 0; i < 4096; ++i) + s += "messagepack test"; + stream << s; + strs << s; + stream << ""; + + QStringList l = MsgPack::unpack(packed).toStringList(); + QVERIFY(l[0] == strs[0]); + QVERIFY(l[1] == strs[1]); + QVERIFY(l[2] == strs[2]); + QVERIFY(l[3] == strs[3]); + QVERIFY(l[4].isEmpty()); +} + QTEST_APPLESS_MAIN(StreamTest) From 2acfaf4cc546f1b7b0cd28560c266d8a0b8e8bdc Mon Sep 17 00:00:00 2001 From: Roman Date: Tue, 19 May 2015 23:02:13 +0300 Subject: [PATCH 14/22] Typo --- src/msgpack_common.h | 10 +++++----- src/stream.cpp | 15 ++++++++------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/msgpack_common.h b/src/msgpack_common.h index 17f713b..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 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/stream.cpp b/src/stream.cpp index 3c59216..468d226 100644 --- a/src/stream.cpp +++ b/src/stream.cpp @@ -121,7 +121,7 @@ MsgPackStream &MsgPackStream::operator>>(quint16 &u16) setStatus(ReadPastEnd); return *this; } - if (!unpack_upto_quint16(u16, &p { + if (!unpack_upto_quint16(u16, &p)) setStatus(ReadCorruptData); return *this; } @@ -134,7 +134,7 @@ MsgPackStream &MsgPackStream::operator>>(quint32 &u32) setStatus(ReadPastEnd); return *this; } - if (!unpack_upto_quint32(u32, &p { + if (!unpack_upto_quint32(u32, &p)) setStatus(ReadCorruptData); return *this; } @@ -147,7 +147,7 @@ MsgPackStream &MsgPackStream::operator>>(quint64 &u64) setStatus(ReadPastEnd); return *this; } - if (!unpack_upto_quint64(u64, &p { + if (!unpack_upto_quint64(u64, &p)) setStatus(ReadCorruptData); return *this; } @@ -160,7 +160,8 @@ MsgPackStream &MsgPackStream::operator>>(qint8 &i8) setStatus(ReadPastEnd); return *this; } - if (!unpack_upto_qint8(i8, &p)) setStatus(ReadCorruptData); + if (!unpack_upto_qint8(i8, &p)) + setStatus(ReadCorruptData); return *this; } @@ -172,7 +173,7 @@ MsgPackStream &MsgPackStream::operator>>(qint16 &i16) setStatus(ReadPastEnd); return *this; } - if (!unpack_upto_qint16(i16, &p){ + if (!unpack_upto_qint16(i16, &p)) setStatus(ReadCorruptData); return *this; } @@ -185,7 +186,7 @@ MsgPackStream &MsgPackStream::operator>>(qint32 &i32) setStatus(ReadPastEnd); return *this; } - if (!unpack_upto_qint32(i32, &p){ + if (!unpack_upto_qint32(i32, &p)) setStatus(ReadCorruptData); return *this; } @@ -198,7 +199,7 @@ MsgPackStream &MsgPackStream::operator>>(qint64 &i64) setStatus(ReadPastEnd); return *this; } - if (!unpack_upto_qint64(i64, &p){ + if (!unpack_upto_qint64(i64, &p)) setStatus(ReadCorruptData); return *this; } From 1277a0c204a7afb5363dea51ebaaa0cf2a70c8b0 Mon Sep 17 00:00:00 2001 From: Isaikin Roman Date: Sat, 23 May 2015 20:00:40 +0300 Subject: [PATCH 15/22] MsgPackStream: float, double --- src/private/pack_p.cpp | 20 +++++++++ src/private/pack_p.h | 1 + src/stream.cpp | 96 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+) diff --git a/src/private/pack_p.cpp b/src/private/pack_p.cpp index 7fa5166..757327c 100644 --- a/src/private/pack_p.cpp +++ b/src/private/pack_p.cpp @@ -37,6 +37,8 @@ quint8 *MsgPackPrivate::pack(const QVariant &v, quint8 *p, bool wr, QVector &user_data); diff --git a/src/stream.cpp b/src/stream.cpp index 468d226..42baf83 100644 --- a/src/stream.cpp +++ b/src/stream.cpp @@ -204,6 +204,52 @@ MsgPackStream &MsgPackStream::operator>>(qint64 &i64) return *this; } +MsgPackStream &MsgPackStream::operator>>(float &f) +{ + CHECK_STREAM_PRECOND(*this); + quint8 *fp = (quint8 *)&f; + quint8 p[5]; + if (dev->read((char *)&p, 1) != 1) { + setStatus(ReadPastEnd); + return *this; + } + if (p[0] != MsgPack::FirstByte::FLOAT32) { + setStatus(ReadCorruptData); + return *this; + } +#ifdef __LITTLE_ENDIAN__ + for (int i = 0; i < 4; ++i) + *(fp + 3 - i) = *(p + i + 1); +#else + for (int i = 0; i < 4; ++i) + *(fp + i) = *(p + i + 1); +#endif + return *this; +} + +MsgPackStream &MsgPackStream::operator>>(double &d) +{ + CHECK_STREAM_PRECOND(*this); + quint8 *fp = (quint8 *)&f; + quint8 p[9]; + if (dev->read((char *)&p, 1) != 1) { + setStatus(ReadPastEnd); + return *this; + } + if (p[0] != MsgPack::FirstByte::FLOAT64) { + setStatus(ReadCorruptData); + return *this; + } +#ifdef __LITTLE_ENDIAN__ + for (int i = 0; i < 8; ++i) + *(fp + 7 - i) = *(p + i + 1); +#else + for (int i = 0; i < 8; ++i) + *(fp + i) = *(p + i + 1); +#endif + return *this; +} + MsgPackStream &MsgPackStream::operator>>(QString &str) { CHECK_STREAM_PRECOND(*this); @@ -239,6 +285,21 @@ MsgPackStream &MsgPackStream::operator>>(QString &str) delete[] data; } +MsgPackStream &MsgPackStream::operator>>(QByteArray &array) +{ + +} + +MsgPackStream &MsgPackStream::operator>>(QVariantList &list) +{ + +} + +MsgPackStream &MsgPackStream::operator>>(QVariantMap &map) +{ + +} + MsgPackStream &MsgPackStream::operator<<(bool b) { CHECK_STREAM_WRITE_PRECOND(*this); @@ -289,6 +350,26 @@ MsgPackStream &MsgPackStream::operator<<(qint64 i64) return *this; } +MsgPackStream &MsgPackStream::operator<<(float f) +{ + CHECK_STREAM_WRITE_PRECOND(*this); + quint8 p[5]; + quint8 sz = MsgPackPrivate::pack_float(f, p, true) - p; + if (dev->write((char *)p, sz) != sz) + setStatus(WriteFailed); + return *this; +} + +MsgPackStream &MsgPackStream::operator<<(double d) +{ + CHECK_STREAM_WRITE_PRECOND(*this); + quint8 p[9]; + quint8 sz = MsgPackPrivate::pack_float(d, p, true) - p; + if (dev->write((char *)p, sz) != sz) + setStatus(WriteFailed); + return *this; +} + MsgPackStream &MsgPackStream::operator<<(QString str) { CHECK_STREAM_WRITE_PRECOND(*this); @@ -316,6 +397,21 @@ MsgPackStream &MsgPackStream::operator<<(const char *str) return *this; } +MsgPackStream &MsgPackStream::operator<<(QByteArray array) +{ + +} + +MsgPackStream &MsgPackStream::operator<<(QVariantList list) +{ + +} + +MsgPackStream &MsgPackStream::operator<<(QVariantMap map) +{ + +} + bool MsgPackStream::unpack_upto_quint8(quint8 &u8, quint8 *p) { if (*p <= MsgPack::FirstByte::POSITIVE_FIXINT) { From 7d5d72e8141987b2a991a721cd45c8814c150f48 Mon Sep 17 00:00:00 2001 From: Roman Date: Sun, 24 May 2015 22:31:35 +0300 Subject: [PATCH 16/22] Some bugs fixed float support added float, double, QByteArray, QList to MsgPackStream added float, double, QByteArrat tests for MsgPackStream added --- .gitignore | 1 + src/private/pack_p.cpp | 16 ++++-- src/private/pack_p.h | 1 + src/stream.cpp | 82 ++++++++++++++++++--------- src/stream.h | 29 ++++++++-- tests/mixed/mixed_test.cpp | 74 ++++++++++++++++++++++++ tests/pack/pack_test.cpp | 2 +- tests/stream/stream_test.cpp | 106 ++++++++++++++++++++++++++++++++++- 8 files changed, 272 insertions(+), 39 deletions(-) diff --git a/.gitignore b/.gitignore index ab6317a..c5ec2ea 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ build lib Makefile *.autosave +bin/ diff --git a/src/private/pack_p.cpp b/src/private/pack_p.cpp index 757327c..268fc06 100644 --- a/src/private/pack_p.cpp +++ b/src/private/pack_p.cpp @@ -216,7 +216,7 @@ quint8 *MsgPackPrivate::pack_float(float f, quint8 *p, bool wr) if (wr) *p = 0xca; p++; if (wr) { - quint8 *d = (quint8 *)&i; + quint8 *d = (quint8 *)&f; #ifdef __LITTLE_ENDIAN__ for (int i = 0; i < 4; ++i) *(p + 3 - i) = *(d + i); @@ -225,10 +225,9 @@ quint8 *MsgPackPrivate::pack_float(float f, quint8 *p, bool wr) *(p + i) = *(d + i); #endif } - return p + 8; + return p + 4; } - quint8 *MsgPackPrivate::pack_double(double i, quint8 *p, bool wr) { if (wr) *p = 0xcb; @@ -246,9 +245,8 @@ quint8 *MsgPackPrivate::pack_double(double i, quint8 *p, bool wr) return p + 8; } -quint8 *MsgPackPrivate::pack_bin(const QByteArray &arr, quint8 *p, bool wr) +quint8 *MsgPackPrivate::pack_bin_header(quint32 len, quint8 *p, bool wr) { - int len = arr.length(); if (len <= std::numeric_limits::max()) { if (wr) *p = compatibilityMode ? 0xd9 : 0xc4; p++; @@ -265,9 +263,15 @@ quint8 *MsgPackPrivate::pack_bin(const QByteArray &arr, quint8 *p, bool wr) if (wr) _msgpack_store32(p, len); p += 4; } + return p; +} + +quint8 *MsgPackPrivate::pack_bin(const QByteArray &arr, quint8 *p, bool wr) +{ + quint32 len = arr.length(); + p = pack_bin_header(len, p, wr); if (wr) memcpy(p, arr.data(), len); p += len; - return p; } diff --git a/src/private/pack_p.h b/src/private/pack_p.h index e8a55bf..db29911 100644 --- a/src/private/pack_p.h +++ b/src/private/pack_p.h @@ -40,6 +40,7 @@ quint8 * pack_string_raw(const char *str, quint32 len, quint8 *p, bool wr); quint8 * pack_string(const QString &str, quint8 *p, bool wr); quint8 * pack_float(float f, quint8 *p, bool wr); quint8 * pack_double(double i, quint8 *p, bool wr); +quint8 * pack_bin_header(quint32 len, quint8 *p, bool wr); quint8 * pack_bin(const QByteArray &arr, 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); diff --git a/src/stream.cpp b/src/stream.cpp index 42baf83..81a683d 100644 --- a/src/stream.cpp +++ b/src/stream.cpp @@ -209,7 +209,7 @@ MsgPackStream &MsgPackStream::operator>>(float &f) CHECK_STREAM_PRECOND(*this); quint8 *fp = (quint8 *)&f; quint8 p[5]; - if (dev->read((char *)&p, 1) != 1) { + if (dev->read((char *)p, 1) != 1) { setStatus(ReadPastEnd); return *this; } @@ -217,6 +217,10 @@ MsgPackStream &MsgPackStream::operator>>(float &f) setStatus(ReadCorruptData); return *this; } + if (dev->read((char *)p + 1, 4) != 4) { + setStatus(ReadPastEnd); + return *this; + } #ifdef __LITTLE_ENDIAN__ for (int i = 0; i < 4; ++i) *(fp + 3 - i) = *(p + i + 1); @@ -230,9 +234,9 @@ MsgPackStream &MsgPackStream::operator>>(float &f) MsgPackStream &MsgPackStream::operator>>(double &d) { CHECK_STREAM_PRECOND(*this); - quint8 *fp = (quint8 *)&f; + quint8 *fp = (quint8 *)&d; quint8 p[9]; - if (dev->read((char *)&p, 1) != 1) { + if (dev->read((char *)p, 1) != 1) { setStatus(ReadPastEnd); return *this; } @@ -240,6 +244,10 @@ MsgPackStream &MsgPackStream::operator>>(double &d) setStatus(ReadCorruptData); return *this; } + if (dev->read((char *)p + 1, 8) != 8) { + setStatus(ReadPastEnd); + return *this; + } #ifdef __LITTLE_ENDIAN__ for (int i = 0; i < 8; ++i) *(fp + 7 - i) = *(p + i + 1); @@ -287,17 +295,39 @@ MsgPackStream &MsgPackStream::operator>>(QString &str) MsgPackStream &MsgPackStream::operator>>(QByteArray &array) { - -} - -MsgPackStream &MsgPackStream::operator>>(QVariantList &list) -{ - -} - -MsgPackStream &MsgPackStream::operator>>(QVariantMap &map) -{ - + CHECK_STREAM_PRECOND(*this); + quint8 p[5]; + if (dev->read((char *)p, 1) != 1) { + setStatus(ReadPastEnd); + return *this; + } + quint32 len; + if (p[0] == MsgPack::FirstByte::BIN8) { + if (dev->read((char *)p + 1, 1) != 1) { + setStatus(ReadPastEnd); + return *this; + } + len = p[1]; + } else if (p[0] == MsgPack::FirstByte::BIN16) { + if (dev->read((char *)p + 1, 2) != 2) { + setStatus(ReadPastEnd); + return *this; + } + len = _msgpack_load16(quint16, &p[1]); + } else if (p[0] == MsgPack::FirstByte::BIN32) { + if (dev->read((char *)p + 1, 4) != 4) { + setStatus(ReadPastEnd); + return *this; + } + len = _msgpack_load32(quint32, &p[1]); + } else { + setStatus(ReadCorruptData); + return *this; + } + array.resize(len); + if (dev->read(array.data(), len) != len) + setStatus(ReadPastEnd); + return *this; } MsgPackStream &MsgPackStream::operator<<(bool b) @@ -364,7 +394,7 @@ MsgPackStream &MsgPackStream::operator<<(double d) { CHECK_STREAM_WRITE_PRECOND(*this); quint8 p[9]; - quint8 sz = MsgPackPrivate::pack_float(d, p, true) - p; + quint8 sz = MsgPackPrivate::pack_double(d, p, true) - p; if (dev->write((char *)p, sz) != sz) setStatus(WriteFailed); return *this; @@ -399,17 +429,17 @@ MsgPackStream &MsgPackStream::operator<<(const char *str) MsgPackStream &MsgPackStream::operator<<(QByteArray array) { - -} - -MsgPackStream &MsgPackStream::operator<<(QVariantList list) -{ - -} - -MsgPackStream &MsgPackStream::operator<<(QVariantMap map) -{ - + CHECK_STREAM_WRITE_PRECOND(*this); + quint8 p[5]; + quint32 len = array.length(); + quint8 header_len = MsgPackPrivate::pack_bin_header(len, p, true) - p; + if (dev->write((char *)p, header_len) != header_len) { + setStatus(WriteFailed); + return *this; + } + if (dev->write(array.data(), len) != len) + setStatus(WriteFailed); + return *this; } bool MsgPackStream::unpack_upto_quint8(quint8 &u8, quint8 *p) diff --git a/src/stream.h b/src/stream.h index 545973d..d84f874 100644 --- a/src/stream.h +++ b/src/stream.h @@ -33,8 +33,6 @@ public: MsgPackStream &operator>>(double &d); MsgPackStream &operator>>(QString &str); MsgPackStream &operator>>(QByteArray &array); - MsgPackStream &operator>>(QVariantList &list); - MsgPackStream &operator>>(QVariantMap &map); MsgPackStream &operator<<(bool b); MsgPackStream &operator<<(quint32 u32); @@ -46,8 +44,6 @@ public: MsgPackStream &operator<<(QString str); MsgPackStream &operator<<(const char *str); MsgPackStream &operator<<(QByteArray array); - MsgPackStream &operator<<(QVariantList list); - MsgPackStream &operator<<(QVariantMap map); private: QIODevice *dev; @@ -64,4 +60,29 @@ private: bool unpack_upto_qint64(qint64 &i64, quint8 *p); }; +template +MsgPackStream& operator<<(MsgPackStream& s, const QList &list) +{ + s << (quint32)list.size(); + for (int i = 0; i < list.size(); ++i) + s << list[i]; + return s; +} + +template +MsgPackStream& operator>>(MsgPackStream& s, QList &list) +{ + list.clear(); + quint32 size; + s >> size; + for (quint32 i = 0; i < size; ++i) { + T t; + s >> t; + list.append(t); + if (s.atEnd()) + break; + } + return s; +} + #endif // STREAM_H diff --git a/tests/mixed/mixed_test.cpp b/tests/mixed/mixed_test.cpp index 2f9ea1b..0f17b8d 100644 --- a/tests/mixed/mixed_test.cpp +++ b/tests/mixed/mixed_test.cpp @@ -8,11 +8,85 @@ class MixedTest : public QObject Q_OBJECT private Q_SLOTS: + void test_float(); + void test_double(); void test_map(); void test_ext(); void test_mixed(); }; +void MixedTest::test_float() +{ + float f; + QByteArray packed; + + packed = MsgPack::pack(0.0f); + f = MsgPack::unpack(packed).toFloat(); + QVERIFY(f == 0.0f); + QVERIFY(packed.size() == 5); + + packed = MsgPack::pack(-0.0f); + f = MsgPack::unpack(packed).toFloat(); + QVERIFY(f == -0.0f); + QVERIFY(packed.size() == 5); + + packed = MsgPack::pack(1.0f); + f = MsgPack::unpack(packed).toFloat(); + QVERIFY(f == 1.0f); + QVERIFY(packed.size() == 5); + + packed = MsgPack::pack(-1.0f); + f = MsgPack::unpack(packed).toFloat(); + QVERIFY(f == -1.0f); + QVERIFY(packed.size() == 5); + + packed = MsgPack::pack(32767.0f); + f = MsgPack::unpack(packed).toFloat(); + QVERIFY(f == 32767.0f); + QVERIFY(packed.size() == 5); + + packed = MsgPack::pack(-32767.0f); + f = MsgPack::unpack(packed).toFloat(); + QVERIFY(f == -32767.0f); + QVERIFY(packed.size() == 5); +} + +void MixedTest::test_double() +{ + double d; + QByteArray packed; + + packed = MsgPack::pack(0.0); + d = MsgPack::unpack(packed).toDouble(); + QVERIFY(d == 0.0); + QVERIFY(packed.size() == 9); + + packed = MsgPack::pack(-0.0); + d = MsgPack::unpack(packed).toDouble(); + QVERIFY(d == -0.0); + QVERIFY(packed.size() == 9); + + packed = MsgPack::pack(1.0); + d = MsgPack::unpack(packed).toDouble(); + QVERIFY(d == 1.0); + QVERIFY(packed.size() == 9); + + packed = MsgPack::pack(-1.0); + d = MsgPack::unpack(packed).toDouble(); + QVERIFY(d == -1.0); + QVERIFY(packed.size() == 9); + + packed = MsgPack::pack(32767.0); + d = MsgPack::unpack(packed).toDouble(); + QVERIFY(d == 32767.0); + QVERIFY(packed.size() == 9); + + packed = MsgPack::pack(-32767.0); + d = MsgPack::unpack(packed).toDouble(); + QVERIFY(d == -32767.0); + QVERIFY(packed.size() == 9); +} + void MixedTest::test_map() { QVariantMap map; diff --git a/tests/pack/pack_test.cpp b/tests/pack/pack_test.cpp index 8d01fc2..2bd6aea 100644 --- a/tests/pack/pack_test.cpp +++ b/tests/pack/pack_test.cpp @@ -271,7 +271,7 @@ void PackTest::test_bin() QVERIFY(p[2] == 0x00); QVERIFY(memcmp(p + 3, ba.data(), ba.size()) == 0); - ba = QByteArray(65536, 'r'); + ba = QByteArray(65536, 'x'); arr = MsgPack::pack(ba); QVERIFY(arr.size() == ba.size() + 5); p = (quint8 *)arr.data(); diff --git a/tests/stream/stream_test.cpp b/tests/stream/stream_test.cpp index 29662b3..f055a95 100644 --- a/tests/stream/stream_test.cpp +++ b/tests/stream/stream_test.cpp @@ -14,7 +14,9 @@ private Q_SLOTS: void test_pack_integers(); void test_unpack_string(); void test_pack_string(); - + void test_float(); + void test_double(); + void test_bin(); }; void StreamTest::test_unpack_integers() @@ -203,7 +205,107 @@ void StreamTest::test_pack_string() QVERIFY(l[4].isEmpty()); } +void StreamTest::test_float() +{ + QByteArray packed; + { + MsgPackStream stream(&packed, QIODevice::WriteOnly); + stream << -0.0f << 0.0f << -1.0f << 1.0f << -32767.0f << 32767.0f; + QVERIFY(packed.size() == 6 * 5); + QVERIFY(stream.status() == MsgPackStream::Ok); + } + + MsgPackStream stream(packed); + float f; + + stream >> f; + QVERIFY(f == -0.0f); + QVERIFY(stream.status() == MsgPackStream::Ok); + + stream >> f; + QVERIFY(f == 0.0f); + QVERIFY(stream.status() == MsgPackStream::Ok); + + stream >> f; + QVERIFY(f == -1.0f); + QVERIFY(stream.status() == MsgPackStream::Ok); + + stream >> f; + QVERIFY(f == 1.0f); + QVERIFY(stream.status() == MsgPackStream::Ok); + + stream >> f; + QVERIFY(f == -32767.0f); + QVERIFY(stream.status() == MsgPackStream::Ok); + + stream >> f; + QVERIFY(f == 32767.0f); + QVERIFY(stream.status() == MsgPackStream::Ok); +} + +void StreamTest::test_double() +{ + QByteArray packed; + { + MsgPackStream stream(&packed, QIODevice::WriteOnly); + stream << -0.0 << 0.0 << -1.0 << 1.0 << -32767.0 << 32767.0; + QVERIFY(packed.size() == 6 * 9); + QVERIFY(stream.status() == MsgPackStream::Ok); + } + + MsgPackStream stream(packed); + double d; + + stream >> d; + QVERIFY(d == -0.0); + QVERIFY(stream.status() == MsgPackStream::Ok); + + stream >> d; + QVERIFY(d == 0.0); + QVERIFY(stream.status() == MsgPackStream::Ok); + + stream >> d; + QVERIFY(d == -1.0); + QVERIFY(stream.status() == MsgPackStream::Ok); + + stream >> d; + QVERIFY(d == 1.0); + QVERIFY(stream.status() == MsgPackStream::Ok); + + stream >> d; + QVERIFY(d == -32767.0); + QVERIFY(stream.status() == MsgPackStream::Ok); + + stream >> d; + QVERIFY(d == 32767.0); + QVERIFY(stream.status() == MsgPackStream::Ok); +} + +void StreamTest::test_bin() +{ + QByteArray ba1("msgpack"), ba2(256, 'r'), ba3(65536, 'x'); + QByteArray packed; + { + MsgPackStream stream(&packed, QIODevice::WriteOnly); + stream << ba1 << ba2 << ba3; + } + QVERIFY(packed.size() == 7+2 + 256+3 + 65536+5); + + MsgPackStream stream(packed); + QByteArray ba; + + stream >> ba; + QVERIFY(ba == ba1); + QVERIFY(stream.status() == MsgPackStream::Ok); + + stream >> ba; + QVERIFY(ba == ba2); + QVERIFY(stream.status() == MsgPackStream::Ok); + + stream >> ba; + QVERIFY(ba == ba3); + QVERIFY(stream.status() == MsgPackStream::Ok); +} QTEST_APPLESS_MAIN(StreamTest) - #include "stream_test.moc" From 9e61498ca2daa06e2fec11390e927f785542ed0a Mon Sep 17 00:00:00 2001 From: Isaikin Roman Date: Fri, 29 May 2015 20:15:26 +0300 Subject: [PATCH 17/22] MsgPackStream: writeBytes() added --- .gitignore | 3 ++- src/stream.cpp | 8 ++++++++ src/stream.h | 20 +++++++++++++++++++- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index c5ec2ea..3e5bad7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ *.pro.user* build lib -Makefile +Makefile* *.autosave bin/ +*.o diff --git a/src/stream.cpp b/src/stream.cpp index 81a683d..a4a68a6 100644 --- a/src/stream.cpp +++ b/src/stream.cpp @@ -442,6 +442,14 @@ MsgPackStream &MsgPackStream::operator<<(QByteArray array) return *this; } +bool MsgPackStream::writeBytes(const char *data, uint len) +{ + CHECK_STREAM_WRITE_PRECOND(*this); + if (dev->write(data, len) != len) + setStatus(WriteFailed); + return *this; +} + bool MsgPackStream::unpack_upto_quint8(quint8 &u8, quint8 *p) { if (*p <= MsgPack::FirstByte::POSITIVE_FIXINT) { diff --git a/src/stream.h b/src/stream.h index d84f874..0b733d2 100644 --- a/src/stream.h +++ b/src/stream.h @@ -1,6 +1,7 @@ #ifndef STREAM_H #define STREAM_H #include +#include class MsgPackStream { @@ -44,6 +45,8 @@ public: MsgPackStream &operator<<(QString str); MsgPackStream &operator<<(const char *str); MsgPackStream &operator<<(QByteArray array); + bool writeBytes(const char *data, uint len); + private: QIODevice *dev; @@ -63,7 +66,22 @@ private: template MsgPackStream& operator<<(MsgPackStream& s, const QList &list) { - s << (quint32)list.size(); + quint32 len = list.size(); + quint8 p[5]; + if (len <= 15) { + p[0] = 0x90 | len; + s.writeBytes(p, 1); + } else if (len <= std::numeric_limits::max()) { + p[0] = 0xdc; + _msgpack_store16(p + 1, len); + s.writeBytes(p, 3); + } else { + p[0] = 0xdd; + _msgpack_store32(p + 1, len); + s.writeBytes(p, 5); + } + if (s.status() != MsgPackStream::Ok) + return *this; for (int i = 0; i < list.size(); ++i) s << list[i]; return s; From 318aa870cde934b48155b2ca0f68425cd2379047 Mon Sep 17 00:00:00 2001 From: Isaikin Roman Date: Wed, 10 Jun 2015 17:42:06 +0300 Subject: [PATCH 18/22] sysdep.h moved to endianhelper.h for MsgPackStream MsgPackStream integers fixed (unpack_upto_* removed, bad idea) MsgPackStream::test_array added --- src/CMakeLists.txt | 2 +- src/{private/sysdep.h => endianhelper.h} | 0 src/msgpack.cpp | 1 - src/msgpack_common.h | 4 +- src/msgpack_common.h.in | 4 +- src/private/pack_p.cpp | 2 +- src/private/qt_types_p.cpp | 2 +- src/private/unpack_p.cpp | 2 +- src/stream.cpp | 297 ++++++++--------------- src/stream.h | 46 ++-- tests/stream/stream_test.cpp | 60 +++++ 11 files changed, 199 insertions(+), 221 deletions(-) rename src/{private/sysdep.h => endianhelper.h} (100%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ed4735d..3d656d3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,5 @@ set(qmsgpack_srcs msgpack.cpp msgpack_common.cpp stream.cpp private/pack_p.cpp private/unpack_p.cpp private/qt_types_p.cpp) -set(qmsgpack_headers msgpack.h stream.h msgpack_common.h msgpack_export.h) +set(qmsgpack_headers msgpack.h stream.h msgpack_common.h msgpack_export.h endianhelper.h) add_library(qmsgpack SHARED ${qmsgpack_srcs} ${qmsgpack_headers}) diff --git a/src/private/sysdep.h b/src/endianhelper.h similarity index 100% rename from src/private/sysdep.h rename to src/endianhelper.h diff --git a/src/msgpack.cpp b/src/msgpack.cpp index d9fe7a8..57aefd1 100644 --- a/src/msgpack.cpp +++ b/src/msgpack.cpp @@ -3,7 +3,6 @@ #include "private/unpack_p.h" #include "private/pack_p.h" #include "private/qt_types_p.h" -#include "private/sysdep.h" #include QVariant MsgPack::unpack(const QByteArray &data) diff --git a/src/msgpack_common.h b/src/msgpack_common.h index e8cf602..9f399b2 100644 --- a/src/msgpack_common.h +++ b/src/msgpack_common.h @@ -62,8 +62,8 @@ const quint8 FIXEX16 = 0xd8; const quint8 STR8 = 0xd9; const quint8 STR16 = 0xda; const quint8 STR32 = 0xdb; -const quint8 ARRAY8 = 0xdc; -const quint8 ARRAY16 = 0xdd; +const quint8 ARRAY16 = 0xdc; +const quint8 ARRAY32 = 0xdd; const quint8 MAP16 = 0xde; const quint8 MAP32 = 0xdf; const quint8 NEGATIVE_FIXINT = 0xe0; diff --git a/src/msgpack_common.h.in b/src/msgpack_common.h.in index 3d43993..d39965a 100644 --- a/src/msgpack_common.h.in +++ b/src/msgpack_common.h.in @@ -62,8 +62,8 @@ const quint8 FIXEX16 = 0xd8; const quint8 STR8 = 0xd9; const quint8 STR16 = 0xda; const quint8 STR32 = 0xdb; -const quint8 ARRAY8 = 0xdc; -const quint8 ARRAY16 = 0xdd; +const quint8 ARRAY16 = 0xdc; +const quint8 ARRAY32 = 0xdd; const quint8 MAP16 = 0xde; const quint8 MAP32 = 0xdf; const quint8 NEGATIVE_FIXINT = 0xe0; diff --git a/src/private/pack_p.cpp b/src/private/pack_p.cpp index 268fc06..f7abe02 100644 --- a/src/private/pack_p.cpp +++ b/src/private/pack_p.cpp @@ -1,5 +1,5 @@ #include "pack_p.h" -#include "private/sysdep.h" +#include "../endianhelper.h" #include #include diff --git a/src/private/qt_types_p.cpp b/src/private/qt_types_p.cpp index 5630d12..1f1a068 100644 --- a/src/private/qt_types_p.cpp +++ b/src/private/qt_types_p.cpp @@ -2,7 +2,7 @@ #include "pack_p.h" #include "unpack_p.h" #include "stream.h" -#include "sysdep.h" +#include "../endianhelper.h" #include diff --git a/src/private/unpack_p.cpp b/src/private/unpack_p.cpp index 5901e9b..cefdb99 100644 --- a/src/private/unpack_p.cpp +++ b/src/private/unpack_p.cpp @@ -1,5 +1,5 @@ #include "unpack_p.h" -#include "sysdep.h" +#include "../endianhelper.h" #include #include diff --git a/src/stream.cpp b/src/stream.cpp index a4a68a6..932498f 100644 --- a/src/stream.cpp +++ b/src/stream.cpp @@ -1,9 +1,6 @@ #include "stream.h" #include -#include "private/sysdep.h" #include "private/pack_p.h" -#include "msgpack_common.h" -#include #include #undef CHECK_STREAM_PRECOND @@ -103,12 +100,10 @@ MsgPackStream &MsgPackStream::operator>>(bool &b) MsgPackStream &MsgPackStream::operator >>(quint8 &u8) { CHECK_STREAM_PRECOND(*this); - quint8 p; - if (dev->read((char *)&p, 1) != 1) { - setStatus(ReadPastEnd); - return *this; - } - if (!unpack_upto_quint8(u8, &p)) + quint64 u64; + if (unpack_ulonglong(u64) && u64 <= std::numeric_limits::max()) + u8 = u64; + else setStatus(ReadCorruptData); return *this; } @@ -116,12 +111,10 @@ MsgPackStream &MsgPackStream::operator >>(quint8 &u8) MsgPackStream &MsgPackStream::operator>>(quint16 &u16) { CHECK_STREAM_PRECOND(*this); - quint8 p; - if (dev->read((char *)&p, 1) != 1) { - setStatus(ReadPastEnd); - return *this; - } - if (!unpack_upto_quint16(u16, &p)) + quint64 u64; + if (unpack_ulonglong(u64) && u64 <= std::numeric_limits::max()) + u16 = u64; + else setStatus(ReadCorruptData); return *this; } @@ -129,12 +122,10 @@ MsgPackStream &MsgPackStream::operator>>(quint16 &u16) MsgPackStream &MsgPackStream::operator>>(quint32 &u32) { CHECK_STREAM_PRECOND(*this); - quint8 p; - if (dev->read((char *)&p, 1) != 1) { - setStatus(ReadPastEnd); - return *this; - } - if (!unpack_upto_quint32(u32, &p)) + quint64 u64; + if (unpack_ulonglong(u64) && u64 <= std::numeric_limits::max()) + u32 = u64; + else setStatus(ReadCorruptData); return *this; } @@ -142,25 +133,20 @@ MsgPackStream &MsgPackStream::operator>>(quint32 &u32) MsgPackStream &MsgPackStream::operator>>(quint64 &u64) { CHECK_STREAM_PRECOND(*this); - quint8 p; - if (dev->read((char *)&p, 1) != 1) { - setStatus(ReadPastEnd); - return *this; - } - if (!unpack_upto_quint64(u64, &p)) - setStatus(ReadCorruptData); + unpack_ulonglong(u64); return *this; } MsgPackStream &MsgPackStream::operator>>(qint8 &i8) { CHECK_STREAM_PRECOND(*this); - quint8 p; - if (dev->read((char *)&p, 1) != 1) { - setStatus(ReadPastEnd); + qint64 i64; + if (!unpack_longlong(i64)) return *this; - } - if (!unpack_upto_qint8(i8, &p)) + if (i64 >= std::numeric_limits::min() && + i64 <= std::numeric_limits::max()) + i8 = i64; + else setStatus(ReadCorruptData); return *this; } @@ -168,12 +154,13 @@ MsgPackStream &MsgPackStream::operator>>(qint8 &i8) MsgPackStream &MsgPackStream::operator>>(qint16 &i16) { CHECK_STREAM_PRECOND(*this); - quint8 p; - if (dev->read((char *)&p, 1) != 1) { - setStatus(ReadPastEnd); +qint64 i64; + if (!unpack_longlong(i64)) return *this; - } - if (!unpack_upto_qint16(i16, &p)) + if (i64 >= std::numeric_limits::min() && + i64 <= std::numeric_limits::max()) + i16 = i64; + else setStatus(ReadCorruptData); return *this; } @@ -181,12 +168,13 @@ MsgPackStream &MsgPackStream::operator>>(qint16 &i16) MsgPackStream &MsgPackStream::operator>>(qint32 &i32) { CHECK_STREAM_PRECOND(*this); - quint8 p; - if (dev->read((char *)&p, 1) != 1) { - setStatus(ReadPastEnd); + qint64 i64; + if (!unpack_longlong(i64)) return *this; - } - if (!unpack_upto_qint32(i32, &p)) + if (i64 >= std::numeric_limits::min() && + i64 <= std::numeric_limits::max()) + i32 = i64; + else setStatus(ReadCorruptData); return *this; } @@ -194,13 +182,7 @@ MsgPackStream &MsgPackStream::operator>>(qint32 &i32) MsgPackStream &MsgPackStream::operator>>(qint64 &i64) { CHECK_STREAM_PRECOND(*this); - quint8 p; - if (dev->read((char *)&p, 1) != 1) { - setStatus(ReadPastEnd); - return *this; - } - if (!unpack_upto_qint64(i64, &p)) - setStatus(ReadCorruptData); + unpack_longlong(i64); return *this; } @@ -330,6 +312,12 @@ MsgPackStream &MsgPackStream::operator>>(QByteArray &array) return *this; } +bool MsgPackStream::readBytes(char *data, uint len) +{ + CHECK_STREAM_PRECOND(false); + return dev->read(data, len) == len; +} + MsgPackStream &MsgPackStream::operator<<(bool b) { CHECK_STREAM_WRITE_PRECOND(*this); @@ -444,169 +432,94 @@ MsgPackStream &MsgPackStream::operator<<(QByteArray array) bool MsgPackStream::writeBytes(const char *data, uint len) { - CHECK_STREAM_WRITE_PRECOND(*this); + CHECK_STREAM_WRITE_PRECOND(false); if (dev->write(data, len) != len) setStatus(WriteFailed); - return *this; + return true; } -bool MsgPackStream::unpack_upto_quint8(quint8 &u8, quint8 *p) +bool MsgPackStream::unpack_longlong(qint64 &i64) { - if (*p <= MsgPack::FirstByte::POSITIVE_FIXINT) { - u8 = *p; - } else if (*p == MsgPack::FirstByte::UINT8) { - if (dev->read((char* )&u8, 1) != 1) - return false; - } else { + quint8 p[9]; + if (dev->read((char *)p, 1) != 1) { + setStatus(ReadPastEnd); 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) - return false; - u16 = _msgpack_load16(quint16, d); - } else { - quint8 u8; - bool ok = unpack_upto_quint8(u8, p); - u16 = u8; - return ok; - } - return true; -} - -bool MsgPackStream::unpack_upto_quint32(quint32 &u32, quint8 *p) -{ - if (*p == MsgPack::FirstByte::UINT32) { - quint8 d[4]; - if (dev->read((char *)d, 4) != 4) - return false; - u32 = _msgpack_load32(quint32, d); + if (p[0] <= 127) {// positive fixint 0x00 - 0x7f + i64 = p[0]; return true; - } else { - quint16 u16; - bool ok = unpack_upto_quint16(u16, p); - u32 = u16; - return ok; - } - return true; -} - -bool MsgPackStream::unpack_upto_quint64(quint64 &u64, quint8 *p) -{ - if (*p == MsgPack::FirstByte::UINT64) { - quint8 d[8]; - if (dev->read((char *)d, 8) != 8) { - return false; - } - u64 = _msgpack_load64(quint64, d); + } else if (*p >= 0xe0) { // negative fixint 0xe0 - 0xff + i64 = (qint8)p[0]; 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) { + static int typeLengths[] = {1, 2, 4, 8, 1, 2, 4, 8}; + int typeLength = typeLengths[p[0] - MsgPack::FirstByte::UINT8]; + if (dev->read((char *)p + 1, typeLength) != typeLength) { + setStatus(ReadPastEnd); + return false; + } + if (p[0] == MsgPack::FirstByte::UINT8) { + i64 = p[1]; + } else if (p[0] == MsgPack::FirstByte::INT8) { + i64 = (qint8)p[1]; + } else if (p[0] == MsgPack::FirstByte::UINT16) { + i64 = _msgpack_load16(quint16, p + 1); + } else if (p[0] == MsgPack::FirstByte::INT16) { + i64 = _msgpack_load16(qint16, p + 1); + } else if (p[0] == MsgPack::FirstByte::UINT32) { + i64 = _msgpack_load32(quint32, p + 1); + } else if (p[0] == MsgPack::FirstByte::INT32) { + i64 = _msgpack_load32(qint32, p + 1); + } else if (p[0] == MsgPack::FirstByte::UINT64) { + quint64 u64; + u64 = _msgpack_load64(quint64, p + 1); + if (u64 > std::numeric_limits::max()) { + setStatus(ReadCorruptData); return false; } - } else { - quint8 u8; - bool ok = unpack_upto_quint8(u8, p); - if (u8 > std::numeric_limits::max()) - return false; - else - i8 = u8; - return ok; + i64 = u64; + } else if (p[0] == MsgPack::FirstByte::INT64) { + i64 = _msgpack_load64(qint64, p + 1); } return true; } -bool MsgPackStream::unpack_upto_qint16(qint16 &i16, quint8 *p) +bool MsgPackStream::unpack_ulonglong(quint64 &u64) { - if (*p == MsgPack::FirstByte::INT16) { - quint8 d[2]; - if (dev->read((char *)d, 2) != 2) { - return false; - } - i16 = _msgpack_load16(qint16, d); - } 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()) - return false; - else - i16 = u16; - return ok; - } + quint8 p[9]; + if (dev->read((char *)p, 1) != 1) { + setStatus(ReadPastEnd); + return false; } - return true; -} -bool MsgPackStream::unpack_upto_qint32(qint32 &i32, quint8 *p) -{ - if(*p == MsgPack::FirstByte::INT32) { - quint8 d[4]; - if (dev->read((char *)d, 4) != 4) { - return false; - } - i32 = _msgpack_load32(qint32, d); - } 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()) - return false; - else - i32 = u32; - return ok; - } - } - return true; -} - -bool MsgPackStream::unpack_upto_qint64(qint64 &i64, quint8 *p) -{ - if(*p == MsgPack::FirstByte::INT64) { - quint8 d[8]; - if (dev->read((char *)d, 8) != 8) - return false; - i64 = _msgpack_load64(qint64, d); + if (p[0] <= 127) {// positive fixint 0x00 - 0x7f + u64 = p[0]; 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()) - return false; - else - i64 = u64; - return ok; - } + } else if (*p >= 0xe0) { // negative fixint 0xe0 - 0xff + return false; } - return true; + + static int typeLengths[] = {1, 2, 4, 8, 1, 2, 4, 8}; + int typeLength = typeLengths[p[0] - MsgPack::FirstByte::UINT8]; + if (dev->read((char *)p + 1, typeLength) != typeLength) { + setStatus(ReadPastEnd); + return false; + } + if (p[0] == MsgPack::FirstByte::UINT8) { + u64 = p[1]; + return true; + } else if (p[0] == MsgPack::FirstByte::UINT16) { + u64 = _msgpack_load16(quint64, p + 1); + return true; + } else if (p[0] == MsgPack::FirstByte::UINT32) { + u64 = _msgpack_load32(quint64, p + 1); + return true; + } else if (p[0] == MsgPack::FirstByte::UINT64) { + u64 = _msgpack_load64(quint64, p + 1); + return true; + } + setStatus(ReadCorruptData); + return false; } diff --git a/src/stream.h b/src/stream.h index 0b733d2..38a19b9 100644 --- a/src/stream.h +++ b/src/stream.h @@ -1,7 +1,9 @@ #ifndef STREAM_H #define STREAM_H #include -#include +#include +#include "msgpack_common.h" +#include "endianhelper.h" class MsgPackStream { @@ -34,6 +36,7 @@ public: MsgPackStream &operator>>(double &d); MsgPackStream &operator>>(QString &str); MsgPackStream &operator>>(QByteArray &array); + bool readBytes(char *data, uint len); MsgPackStream &operator<<(bool b); MsgPackStream &operator<<(quint32 u32); @@ -47,20 +50,13 @@ public: MsgPackStream &operator<<(QByteArray array); bool writeBytes(const char *data, uint len); - private: QIODevice *dev; bool owndev; Status q_status; - 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); + bool unpack_longlong(qint64 &i64); + bool unpack_ulonglong(quint64 &u64); }; template @@ -69,19 +65,19 @@ MsgPackStream& operator<<(MsgPackStream& s, const QList &list) quint32 len = list.size(); quint8 p[5]; if (len <= 15) { - p[0] = 0x90 | len; - s.writeBytes(p, 1); + p[0] = MsgPack::FirstByte::FIXARRAY | len; + s.writeBytes((const char *)p, 1); } else if (len <= std::numeric_limits::max()) { - p[0] = 0xdc; + p[0] = MsgPack::FirstByte::ARRAY16; _msgpack_store16(p + 1, len); - s.writeBytes(p, 3); + s.writeBytes((const char *)p, 3); } else { - p[0] = 0xdd; + p[0] = MsgPack::FirstByte::ARRAY32; _msgpack_store32(p + 1, len); - s.writeBytes(p, 5); + s.writeBytes((const char *)p, 5); } if (s.status() != MsgPackStream::Ok) - return *this; + return s; for (int i = 0; i < list.size(); ++i) s << list[i]; return s; @@ -91,9 +87,19 @@ template MsgPackStream& operator>>(MsgPackStream& s, QList &list) { list.clear(); - quint32 size; - s >> size; - for (quint32 i = 0; i < size; ++i) { + quint8 p[5]; + quint32 len; + s.readBytes((char *)p, 1); + if (p[0] >= 0x90 && p[0] <= 0x9f) { + len = p[0] & 0xf; + } else if (p[0] == MsgPack::FirstByte::ARRAY16) { + s.readBytes((char *)p + 1, 2); + len = _msgpack_load16(quint16, p + 1); + } else if (p[0] == MsgPack::FirstByte::ARRAY32) { + s.readBytes((char *)p + 1, 4); + len = _msgpack_load32(quint32, p + 1); + } + for (quint32 i = 0; i < len; ++i) { T t; s >> t; list.append(t); diff --git a/tests/stream/stream_test.cpp b/tests/stream/stream_test.cpp index f055a95..eccf804 100644 --- a/tests/stream/stream_test.cpp +++ b/tests/stream/stream_test.cpp @@ -17,6 +17,7 @@ private Q_SLOTS: void test_float(); void test_double(); void test_bin(); + void test_array(); }; void StreamTest::test_unpack_integers() @@ -307,5 +308,64 @@ void StreamTest::test_bin() QVERIFY(stream.status() == MsgPackStream::Ok); } +void StreamTest::test_array() +{ +{ + QList list; + list << 0 << 127 << -1 << -31 << 128 << 255 << -33 << -128 << 256; + list << 65535 << -129 << -32768 << 65536; + list << -32769 << (qint32)-2147483648; + list << (qint64)-2147483649; + list << std::numeric_limits::min(); + QByteArray packed; + { + MsgPackStream stream(&packed, QIODevice::WriteOnly); + stream << list; + QVERIFY(stream.status() == MsgPackStream::Ok); + } + + QVariantList list2 = MsgPack::unpack(packed).toList(); + QVERIFY(list.size() == list2.size()); + for (int i = 0; i < list.size(); ++i) + QVERIFY(list[i] == list2[i]); + + packed = MsgPack::pack(list2); + MsgPackStream stream(packed); + QList list3; + stream >> list3; + QVERIFY(stream.status() == MsgPackStream::Ok); + QVERIFY(list2.size() == list3.size()); + for (int i = 0; i < list2.size(); ++i) + QVERIFY(list2[i] == list3[i]); +} +{ + QList list; + list << 6; + list << std::numeric_limits::min(); + list << std::numeric_limits::max(); + list << -4; + QByteArray packed; + { + MsgPackStream stream(&packed, QIODevice::WriteOnly); + stream << list; + QVERIFY(stream.status() == MsgPackStream::Ok); + } + + QVariantList list2 = MsgPack::unpack(packed).toList(); + QVERIFY(list.size() == list2.size()); + for (int i = 0; i < list.size(); ++i) + QVERIFY(list[i] == list2[i]); + + packed = MsgPack::pack(list2); + MsgPackStream stream(packed); + QList list3; + stream >> list3; + QVERIFY(stream.status() == MsgPackStream::Ok); + QVERIFY(list2.size() == list3.size()); + for (int i = 0; i < list2.size(); ++i) + QVERIFY(list2[i] == list3[i]); +} +} + QTEST_APPLESS_MAIN(StreamTest) #include "stream_test.moc" From ce6ddab5e476de77ba531d12fca7a3234945365c Mon Sep 17 00:00:00 2001 From: Roman Date: Mon, 29 Jun 2015 14:32:35 +0300 Subject: [PATCH 19/22] CMake BUILD_TESTS variable added TRUE and FALSE renamed to MTRUE and MFALSE stream.h[cpp] renamed to msgpackstream.h[cpp] QMap and QHash added to MsgPackStream + test --- .travis.yml | 2 +- CMakeLists.txt | 6 +- src/CMakeLists.txt | 6 +- src/CMakeLists.txt~ | 34 +++++++ src/msgpack_common.h | 4 +- src/msgpack_common.h.in | 4 +- src/{stream.cpp => msgpackstream.cpp} | 42 ++++++-- src/{stream.h => msgpackstream.h} | 133 ++++++++++++++++++++++++++ src/private/qt_types_p.cpp | 6 +- tests/pack/pack_test.cpp | 2 +- tests/stream/stream_test.cpp | 48 +++++++++- 11 files changed, 260 insertions(+), 27 deletions(-) create mode 100644 src/CMakeLists.txt~ rename src/{stream.cpp => msgpackstream.cpp} (93%) rename src/{stream.h => msgpackstream.h} (51%) diff --git a/.travis.yml b/.travis.yml index b37d3ee..0706c70 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,6 +16,6 @@ before_install: script: - mkdir build - cd build - - cmake .. + - if [ -z ${QT4_BUILD+x} ]; then cmake -DBUILD_TESTS=TRUE -DQT4_BUILD=FALSE ..; else cmake -DBUILD_TESTS=TRUE -DQT4_BUILD=TRUE ..; fi - make - make test diff --git a/CMakeLists.txt b/CMakeLists.txt index 6f09424..5791159 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,14 +80,14 @@ set(MSGPACK_QT_LIB_VERSION_STRING "${QMSGPACK_MAJOR}.${QMSGPACK_MINOR}.${QMSGPAC set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") add_subdirectory(src) -#if (MSGPACK_BUILD_TESTS) +if (BUILD_TESTS) enable_testing() add_subdirectory(tests) -#endif () +endif () install(EXPORT qmsgpack-export DESTINATION ${CMAKECONFIG_INSTALL_DIR} FILE MsgPackQtTargets.cmake) file(RELATIVE_PATH relInstallDir ${CMAKE_INSTALL_PREFIX}/$CMAKECONFIG_INSTALL_DIR} ${CMAKE_INSTALL_PREFIX}) add_custom_target(uninstall - "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") \ No newline at end of file + "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3d656d3..6c76121 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,5 @@ -set(qmsgpack_srcs msgpack.cpp msgpack_common.cpp stream.cpp private/pack_p.cpp private/unpack_p.cpp private/qt_types_p.cpp) -set(qmsgpack_headers msgpack.h stream.h msgpack_common.h msgpack_export.h endianhelper.h) +set(qmsgpack_srcs msgpack.cpp msgpack_common.cpp msgpackstream.cpp private/pack_p.cpp private/unpack_p.cpp private/qt_types_p.cpp) +set(qmsgpack_headers msgpack.h msgpackstream.h msgpack_common.h msgpack_export.h endianhelper.h) add_library(qmsgpack SHARED ${qmsgpack_srcs} ${qmsgpack_headers}) @@ -31,4 +31,4 @@ install(TARGETS qmsgpack EXPORT qmsgpack-export LIBRARY DESTINATION ${LIB_INSTALL_DIR} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin ARCHIVE DESTINATION ${LIB_INSTALL_DIR} - PUBLIC_HEADER DESTINATION ${INCLUDE_INSTALL_DIR}/qmsgpack) \ No newline at end of file + PUBLIC_HEADER DESTINATION ${INCLUDE_INSTALL_DIR}/qmsgpack) diff --git a/src/CMakeLists.txt~ b/src/CMakeLists.txt~ new file mode 100644 index 0000000..3d656d3 --- /dev/null +++ b/src/CMakeLists.txt~ @@ -0,0 +1,34 @@ +set(qmsgpack_srcs msgpack.cpp msgpack_common.cpp stream.cpp private/pack_p.cpp private/unpack_p.cpp private/qt_types_p.cpp) +set(qmsgpack_headers msgpack.h stream.h msgpack_common.h msgpack_export.h endianhelper.h) + +add_library(qmsgpack SHARED ${qmsgpack_srcs} ${qmsgpack_headers}) + +if (Qt5Core_FOUND) + target_link_libraries(qmsgpack Qt5::Core) +else () + target_link_libraries(qmsgpack ${QT_LIBRARIES}) +endif () + +if (Qt5Gui_FOUND) + target_link_libraries(qmsgpack Qt5::Gui) +endif () + +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/msgpack_common.h.in" + "${CMAKE_CURRENT_SOURCE_DIR}/msgpack_common.h" + IMMEDIATE @ONLY) + +if (NOT android) + set_target_properties(qmsgpack PROPERTIES + VERSION ${QMSGPACK_MAJOR}.${QMSGPACK_MINOR}.${QMSGPACK_VERSION} + SOVERSION ${QMSGPACK_MAJOR}) +endif () +set_target_properties(qmsgpack PROPERTIES + DEFINE_SYMBOL MSGPACK_MAKE_LIB + PUBLIC_HEADER "${qmsgpack_headers}") + +install(TARGETS qmsgpack EXPORT qmsgpack-export + LIBRARY DESTINATION ${LIB_INSTALL_DIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin + ARCHIVE DESTINATION ${LIB_INSTALL_DIR} + PUBLIC_HEADER DESTINATION ${INCLUDE_INSTALL_DIR}/qmsgpack) \ No newline at end of file diff --git a/src/msgpack_common.h b/src/msgpack_common.h index 9f399b2..68a6479 100644 --- a/src/msgpack_common.h +++ b/src/msgpack_common.h @@ -36,8 +36,8 @@ const quint8 FIXARRAY = 0x90; const quint8 FIXSTR = 0xa0; const quint8 NIL = 0xc0; const quint8 NEVER_USED = 0xc1; -const quint8 FALSE = 0xc2; -const quint8 TRUE = 0xc3; +const quint8 MFALSE = 0xc2; +const quint8 MTRUE = 0xc3; const quint8 BIN8 = 0xc4; const quint8 BIN16 = 0xc5; const quint8 BIN32 = 0xc6; diff --git a/src/msgpack_common.h.in b/src/msgpack_common.h.in index d39965a..aaf6d82 100644 --- a/src/msgpack_common.h.in +++ b/src/msgpack_common.h.in @@ -36,8 +36,8 @@ const quint8 FIXARRAY = 0x90; const quint8 FIXSTR = 0xa0; const quint8 NIL = 0xc0; const quint8 NEVER_USED = 0xc1; -const quint8 FALSE = 0xc2; -const quint8 TRUE = 0xc3; +const quint8 MFALSE = 0xc2; +const quint8 MTRUE = 0xc3; const quint8 BIN8 = 0xc4; const quint8 BIN16 = 0xc5; const quint8 BIN32 = 0xc6; diff --git a/src/stream.cpp b/src/msgpackstream.cpp similarity index 93% rename from src/stream.cpp rename to src/msgpackstream.cpp index 932498f..cd71cff 100644 --- a/src/stream.cpp +++ b/src/msgpackstream.cpp @@ -1,6 +1,6 @@ -#include "stream.h" -#include +#include "msgpackstream.h" #include "private/pack_p.h" +#include #include #undef CHECK_STREAM_PRECOND @@ -27,7 +27,7 @@ MsgPackStream::MsgPackStream() : { } MsgPackStream::MsgPackStream(QIODevice *d) : - dev(d), owndev(false) + dev(d), owndev(false), q_status(Ok) { } MsgPackStream::MsgPackStream(QByteArray *a, QIODevice::OpenMode mode) : @@ -89,10 +89,10 @@ MsgPackStream &MsgPackStream::operator>>(bool &b) b = false; setStatus(ReadPastEnd); } else { - if (p[0] != MsgPack::FirstByte::TRUE || - p[0] != MsgPack::FirstByte::FALSE) + if (p[0] != MsgPack::FirstByte::MTRUE || + p[0] != MsgPack::FirstByte::MFALSE) setStatus(ReadCorruptData); - b = (p[0] == MsgPack::FirstByte::TRUE); + b = (p[0] == MsgPack::FirstByte::MTRUE); } return *this; } @@ -273,6 +273,7 @@ MsgPackStream &MsgPackStream::operator>>(QString &str) } str = QString::fromUtf8((const char*) data, len); delete[] data; + return *this; } MsgPackStream &MsgPackStream::operator>>(QByteArray &array) @@ -318,11 +319,23 @@ bool MsgPackStream::readBytes(char *data, uint len) return dev->read(data, len) == len; } +bool MsgPackStream::readNil() +{ + CHECK_STREAM_PRECOND(false); + quint8 b; + if (dev->read((char *)&b, 1) != 1 || + b != MsgPack::FirstByte::NIL) { + setStatus(ReadCorruptData); + return false; + } + return true; +} + MsgPackStream &MsgPackStream::operator<<(bool b) { CHECK_STREAM_WRITE_PRECOND(*this); quint8 m = b == true ? - MsgPack::FirstByte::TRUE : MsgPack::FirstByte::FALSE; + MsgPack::FirstByte::MTRUE : MsgPack::FirstByte::MFALSE; if (dev->write((char *)&m, 1) != 1) setStatus(WriteFailed); return *this; @@ -433,8 +446,21 @@ MsgPackStream &MsgPackStream::operator<<(QByteArray array) bool MsgPackStream::writeBytes(const char *data, uint len) { CHECK_STREAM_WRITE_PRECOND(false); - if (dev->write(data, len) != len) + if (dev->write(data, len) != len) { setStatus(WriteFailed); + return false; + } + return true; +} + +bool MsgPackStream::writeNil() +{ + CHECK_STREAM_WRITE_PRECOND(false); + quint8 b = MsgPack::FirstByte::NIL; + if (dev->write((char *)&b, 1) != 1) { + setStatus(WriteFailed); + return false; + } return true; } diff --git a/src/stream.h b/src/msgpackstream.h similarity index 51% rename from src/stream.h rename to src/msgpackstream.h index 38a19b9..50ccb68 100644 --- a/src/stream.h +++ b/src/msgpackstream.h @@ -37,6 +37,7 @@ public: MsgPackStream &operator>>(QString &str); MsgPackStream &operator>>(QByteArray &array); bool readBytes(char *data, uint len); + bool readNil(); MsgPackStream &operator<<(bool b); MsgPackStream &operator<<(quint32 u32); @@ -49,6 +50,7 @@ public: MsgPackStream &operator<<(const char *str); MsgPackStream &operator<<(QByteArray array); bool writeBytes(const char *data, uint len); + bool writeNil(); private: QIODevice *dev; @@ -76,10 +78,12 @@ MsgPackStream& operator<<(MsgPackStream& s, const QList &list) _msgpack_store32(p + 1, len); s.writeBytes((const char *)p, 5); } + if (s.status() != MsgPackStream::Ok) return s; for (int i = 0; i < list.size(); ++i) s << list[i]; + return s; } @@ -87,6 +91,7 @@ template MsgPackStream& operator>>(MsgPackStream& s, QList &list) { list.clear(); + quint8 p[5]; quint32 len; s.readBytes((char *)p, 1); @@ -99,6 +104,7 @@ MsgPackStream& operator>>(MsgPackStream& s, QList &list) s.readBytes((char *)p + 1, 4); len = _msgpack_load32(quint32, p + 1); } + for (quint32 i = 0; i < len; ++i) { T t; s >> t; @@ -106,6 +112,133 @@ MsgPackStream& operator>>(MsgPackStream& s, QList &list) if (s.atEnd()) break; } + + return s; +} + +template +MsgPackStream& operator<<(MsgPackStream &s, const QHash &hash) +{ + quint32 len = 0; + QHashIterator it(hash); + while (it.hasNext()) { + it.next(); + len++; + } + + quint8 p[5]; + if (len <= 15) { + p[0] = MsgPack::FirstByte::FIXMAP | len; + s.writeBytes((const char *)p, 1); + } else if (len <= std::numeric_limits::max()) { + p[0] = MsgPack::FirstByte::MAP16; + _msgpack_store16(p + 1, len); + s.writeBytes((const char *)p, 3); + } else { + p[0] = MsgPack::FirstByte::MAP32; + _msgpack_store32(p + 1, len); + s.writeBytes((const char *)p, 5); + } + + it.toFront(); + while (it.hasNext()) { + it.next(); + s << it.key() << it.value(); + } + + return s; +} + +template +MsgPackStream& operator>>(MsgPackStream& s, QHash &hash) +{ + hash.clear(); + + quint8 p[5]; + quint32 len; + s.readBytes((char *)p, 1); + if (p[0] >= 0x80 && p[0] <= 0x8f) { + len = p[0] & 0xf; + } else if (p[0] == MsgPack::FirstByte::MAP16) { + s.readBytes((char *)p + 1, 2); + len = _msgpack_load16(quint16, p + 1); + } else if (p[0] == MsgPack::FirstByte::MAP32) { + s.readBytes((char *)p + 1, 4); + len = _msgpack_load32(quint32, p + 1); + } + + for (quint32 i = 0; i < len; ++i) { + Key key; + T t; + s >> key >> t; + hash.insert(key, t); + if (s.atEnd()) + break; + } + + return s; +} + +template +MsgPackStream& operator<<(MsgPackStream &s, const QMap &map) +{ + quint32 len = 0; + QMapIterator it(map); + while (it.hasNext()) { + it.next(); + len++; + } + + quint8 p[5]; + if (len <= 15) { + p[0] = MsgPack::FirstByte::FIXMAP | len; + s.writeBytes((const char *)p, 1); + } else if (len <= std::numeric_limits::max()) { + p[0] = MsgPack::FirstByte::MAP16; + _msgpack_store16(p + 1, len); + s.writeBytes((const char *)p, 3); + } else { + p[0] = MsgPack::FirstByte::MAP32; + _msgpack_store32(p + 1, len); + s.writeBytes((const char *)p, 5); + } + + it.toFront(); + while (it.hasNext()) { + it.next(); + s << it.key() << it.value(); + } + + return s; +} + +template +MsgPackStream& operator>>(MsgPackStream& s, QMap &map) +{ + map.clear(); + + quint8 p[5]; + quint32 len; + s.readBytes((char *)p, 1); + if (p[0] >= 0x80 && p[0] <= 0x8f) { + len = p[0] & 0xf; + } else if (p[0] == MsgPack::FirstByte::MAP16) { + s.readBytes((char *)p + 1, 2); + len = _msgpack_load16(quint16, p + 1); + } else if (p[0] == MsgPack::FirstByte::MAP32) { + s.readBytes((char *)p + 1, 4); + len = _msgpack_load32(quint32, p + 1); + } + + for (quint32 i = 0; i < len; ++i) { + Key key; + T t; + s >> key >> t; + map.insert(key, t); + if (s.atEnd()) + break; + } + return s; } diff --git a/src/private/qt_types_p.cpp b/src/private/qt_types_p.cpp index 1f1a068..9ab73fe 100644 --- a/src/private/qt_types_p.cpp +++ b/src/private/qt_types_p.cpp @@ -1,9 +1,8 @@ #include "qt_types_p.h" #include "pack_p.h" #include "unpack_p.h" -#include "stream.h" -#include "../endianhelper.h" - +#include "msgpackstream.h" +#include "endianhelper.h" #include #ifdef QT_GUI_LIB @@ -182,7 +181,6 @@ QVariant MsgPackPrivate::unpack_qpoint(const QByteArray &data) MsgPackStream stream(data); qint32 x, y; stream >> x >> y; - qDebug() << "unpack qpoint stream" << (stream.status() == MsgPackStream::Ok); return QPoint(x, y); } diff --git a/tests/pack/pack_test.cpp b/tests/pack/pack_test.cpp index 2bd6aea..235dc63 100644 --- a/tests/pack/pack_test.cpp +++ b/tests/pack/pack_test.cpp @@ -216,7 +216,7 @@ void PackTest::test_float() void PackTest::test_str() { - QString str = QStringLiteral("msgpack rocks"); + QString str = QString("msgpack rocks"); QByteArray arr = MsgPack::pack(str); QVERIFY(arr.size() == 14); quint8 *p = (quint8 *)arr.data(); diff --git a/tests/stream/stream_test.cpp b/tests/stream/stream_test.cpp index eccf804..61eac91 100644 --- a/tests/stream/stream_test.cpp +++ b/tests/stream/stream_test.cpp @@ -1,7 +1,6 @@ #include #include -#include -#include +#include #include #include @@ -18,6 +17,7 @@ private Q_SLOTS: void test_double(); void test_bin(); void test_array(); + void test_map(); }; void StreamTest::test_unpack_integers() @@ -142,7 +142,7 @@ void StreamTest::test_pack_integers() void StreamTest::test_unpack_string() { - QString str = QStringLiteral("msgpack rocks"); + QString str = QString("msgpack rocks"); QByteArray packed = MsgPack::pack(str); QString str2; @@ -367,5 +367,47 @@ void StreamTest::test_array() } } +void StreamTest::test_map() +{ + QMap map, map2; + QByteArray ba; + + map.insert("m0", 0); + { + MsgPackStream stream(&ba, QIODevice::WriteOnly); + stream << map; + MsgPackStream stream2(ba); + stream2 >> map2; + } + QVERIFY(ba.length() == 5); + quint8 *p = (quint8 *)ba.data(); + QVERIFY(p[0] == 0x80 | 1); + QVERIFY(map == map2); + + for (int i = 1; i < 16; ++i) + map.insert(QString("m%1").QString::arg(i), i); + { + MsgPackStream stream(&ba, QIODevice::WriteOnly); + stream << map; + MsgPackStream stream2(ba); + stream2 >> map2; + } + p = (quint8 *)ba.data(); + QVERIFY(p[0] == 0xde); + QVERIFY(map == map2); + + for (int i = 16; i < 65536; ++i) + map.insert(QString("m%1").QString::arg(i), i); + { + MsgPackStream stream(&ba, QIODevice::WriteOnly); + stream << map; + MsgPackStream stream2(ba); + stream2 >> map2; + } + p = (quint8 *)ba.data(); + QVERIFY(p[0] == 0xdf); + QVERIFY(map == map2); +} + QTEST_APPLESS_MAIN(StreamTest) #include "stream_test.moc" From 564e57a0cb3e031cfb28587303d73da0b8d93cd2 Mon Sep 17 00:00:00 2001 From: Roman Date: Mon, 29 Jun 2015 14:58:59 +0300 Subject: [PATCH 20/22] Update .travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 0706c70..8683a39 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,4 +18,5 @@ script: - cd build - if [ -z ${QT4_BUILD+x} ]; then cmake -DBUILD_TESTS=TRUE -DQT4_BUILD=FALSE ..; else cmake -DBUILD_TESTS=TRUE -DQT4_BUILD=TRUE ..; fi - make + - export CTEST_OUTPUT_ON_FAILURE=1 - make test From 63c15f9eadf3f507389092846c7173feb678956d Mon Sep 17 00:00:00 2001 From: Roman Date: Mon, 29 Jun 2015 19:52:59 +0300 Subject: [PATCH 21/22] Qt4 user type fixes QDate, QTime, QDateTime, QPoint, QSize, QRect isNull() checks --- src/private/pack_p.cpp | 26 ++++++++++---------- src/private/qt_types_p.cpp | 35 +++++++++++++++++++++++---- tests/qttypes/qttypes_test.cpp | 44 ++++++++++++++++++++++++---------- 3 files changed, 74 insertions(+), 31 deletions(-) diff --git a/src/private/pack_p.cpp b/src/private/pack_p.cpp index f7abe02..4a84c87 100644 --- a/src/private/pack_p.cpp +++ b/src/private/pack_p.cpp @@ -43,17 +43,8 @@ quint8 *MsgPackPrivate::pack(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(); + QMetaType::Type t; + if (v.type() == QVariant::UserType) + t = (QMetaType::Type)v.userType(); + else + t = (QMetaType::Type)v.type(); + QReadLocker locker(&packers_lock); + bool has_packer = user_packers.contains(t); + if (!has_packer) { + qWarning() << "MsgPack::pack can't pack type:" << t; + return p; + } packer_t pt = user_packers[t]; locker.unlock(); diff --git a/src/private/qt_types_p.cpp b/src/private/qt_types_p.cpp index 9ab73fe..56246b5 100644 --- a/src/private/qt_types_p.cpp +++ b/src/private/qt_types_p.cpp @@ -69,7 +69,7 @@ QVariant MsgPackPrivate::unpack_qcolor(const QByteArray &data) // Date and Time void MsgPackPrivate::pack_qtime_raw(const QTime &time, quint8 *p) { - quint8 hm, ms; + quint8 hm = 0, ms = 0; hm = (quint8)time.hour() << 4; hm |= (quint8)time.minute() >> 2; ms = ((quint8)time.minute() << 6) & 0xc0; // 11000000 @@ -98,6 +98,8 @@ QTime MsgPackPrivate::unpack_qtime_raw(quint8 *p, bool with_ms) QByteArray MsgPackPrivate::pack_qtime(const QVariant &variant) { QTime time = variant.toTime(); + if (time.isNull()) + return QByteArray("\xc0", 1); quint8 size = time.msec() == 0 ? 2 : 4; QByteArray data; data.resize(size); @@ -107,6 +109,8 @@ QByteArray MsgPackPrivate::pack_qtime(const QVariant &variant) QVariant MsgPackPrivate::unpack_qtime(const QByteArray &data) { + if (data.size() == 1) + return QTime(); return unpack_qtime_raw((quint8 *)data.data(), data.size() == 4); } @@ -134,6 +138,9 @@ QDate MsgPackPrivate::unpack_qdate_raw(quint8 *p) QByteArray MsgPackPrivate::pack_qdate(const QVariant &variant) { + QDate date = variant.toDate(); + if (date.isNull()) + return QByteArray("\xc0", 1); QByteArray data; data.resize(3); pack_qdate_raw(variant.toDate(), (quint8 *)data.data()); @@ -142,12 +149,16 @@ QByteArray MsgPackPrivate::pack_qdate(const QVariant &variant) QVariant MsgPackPrivate::unpack_qdate(const QByteArray &data) { + if (data.size() == 1) + return QDate(); return unpack_qdate_raw((quint8 *)data.data()); } QByteArray MsgPackPrivate::pack_qdatetime(const QVariant &variant) { QDateTime dt = variant.toDateTime(); + if (dt.isNull()) + return QByteArray("\xc0", 1); quint8 time_size = dt.time().msec() == 0 ? 2 : 4; QByteArray data; data.resize(3 + time_size); @@ -160,6 +171,8 @@ QByteArray MsgPackPrivate::pack_qdatetime(const QVariant &variant) QVariant MsgPackPrivate::unpack_qdatetime(const QByteArray &data) { + if (data.size() == 1) + return QDateTime(); quint8 *p = (quint8 *)data.data(); QDate d = unpack_qdate_raw(p); QTime t = unpack_qtime_raw(p + 3, data.size() == 7); @@ -169,15 +182,19 @@ QVariant MsgPackPrivate::unpack_qdatetime(const QByteArray &data) // Points and Vectors QByteArray MsgPackPrivate::pack_qpoint(const QVariant &variant) { + QPoint point = variant.toPoint(); + if (point.isNull()) + return QByteArray("\xc0", 1); QByteArray packed; MsgPackStream stream(&packed, QIODevice::WriteOnly); - QPoint pt = variant.toPoint(); - stream << pt.x() << pt.y(); + stream << point.x() << point.y(); return packed; } QVariant MsgPackPrivate::unpack_qpoint(const QByteArray &data) { + if (data.size() == 1) + return QPoint(); MsgPackStream stream(data); qint32 x, y; stream >> x >> y; @@ -186,15 +203,19 @@ QVariant MsgPackPrivate::unpack_qpoint(const QByteArray &data) QByteArray MsgPackPrivate::pack_qsize(const QVariant &variant) { + QSize size = variant.toSize(); + if (size.isNull()) + return QByteArray("\xc0", 1); QByteArray packed; MsgPackStream stream(&packed, QIODevice::WriteOnly); - QSize sz = variant.toSize(); - stream << sz.width() << sz.height(); + stream << size.width() << size.height(); return packed; } QVariant MsgPackPrivate::unpack_qsize(const QByteArray &data) { + if (data.size() == 1) + return QSize(); MsgPackStream stream(data); qint32 width, height; stream >> width >> height; @@ -204,6 +225,8 @@ QVariant MsgPackPrivate::unpack_qsize(const QByteArray &data) QByteArray MsgPackPrivate::pack_qrect(const QVariant &variant) { QRect rect = variant.toRect(); + if (rect.isNull()) + return QByteArray("\xc0", 1); QPoint pt1 = rect.topLeft(); QPoint pt2 = rect.bottomRight(); QByteArray packed; @@ -214,6 +237,8 @@ QByteArray MsgPackPrivate::pack_qrect(const QVariant &variant) QVariant MsgPackPrivate::unpack_qrect(const QByteArray &data) { + if (data.size() == 1) + return QRect(); MsgPackStream stream(data); qint32 x, y; stream >> x >> y; diff --git a/tests/qttypes/qttypes_test.cpp b/tests/qttypes/qttypes_test.cpp index 9f4d31f..2d3bff2 100644 --- a/tests/qttypes/qttypes_test.cpp +++ b/tests/qttypes/qttypes_test.cpp @@ -19,11 +19,11 @@ private Q_SLOTS: void QtTypesTest::test_qtime() { MsgPack::registerType(QMetaType::QTime, 0x77); - QTime t(0, 0, 0, 0); + QTime t; QByteArray packed = MsgPack::pack(t); QTime t2 = MsgPack::unpack(packed).toTime(); QVERIFY(t == t2); - QVERIFY(packed.size() == 4); + QVERIFY(packed.size() == 3); // user, type, 0xc0 t = QTime(12, 01, 01, 0); packed = MsgPack::pack(t); @@ -47,11 +47,11 @@ void QtTypesTest::test_qtime() void QtTypesTest::test_qdate() { MsgPack::registerType(QMetaType::QDate, 0x78); - QDate d; + QDate d = QDate(); QByteArray packed = MsgPack::pack(d); QDate d2 = MsgPack::unpack(packed).toDate(); QVERIFY(d == d2); - QVERIFY(packed.size() == 6); + QVERIFY(packed.size() == 3); // user, type, 0xc0 d = QDate(1234, 12, 1); packed = MsgPack::pack(d); @@ -67,18 +67,23 @@ void QtTypesTest::test_qdate() void QtTypesTest::test_qpoint() { MsgPack::registerType(QMetaType::QPoint, 0x79); - QPoint pt(1, 2); - QByteArray packed = MsgPack::pack(pt); + + QPoint pt; + QByteArray packed = MsgPack::pack(pt); + QVERIFY(packed.size() == 3); + QPoint pt2 = MsgPack::unpack(packed).toPoint(); + QVERIFY(pt == pt2); + + pt = QPoint(1, 2); + packed = MsgPack::pack(pt); QVERIFY(packed.size() == 4); - QPoint pt2 = MsgPack::unpack(packed).toPoint(); + pt2 = MsgPack::unpack(packed).toPoint(); QVERIFY(pt == pt2); pt = QPoint(1234, 5678); packed = MsgPack::pack(pt); QVERIFY(packed.size() == 9); pt2 = MsgPack::unpack(packed).toPoint(); - qDebug() << pt << pt2; - qDebug() << packed.toHex() << packed.size(); QVERIFY(pt == pt2); pt = QPoint(std::numeric_limits::max(), std::numeric_limits::max()); @@ -91,12 +96,19 @@ void QtTypesTest::test_qpoint() void QtTypesTest::test_qsize() { MsgPack::registerType(QMetaType::QSize, 80); - QSize sz(1, 2); + + QSize sz; QByteArray packed = MsgPack::pack(sz); - QVERIFY(packed.size() == 4); +// QVERIFY(packed.size() == 3); QSize sz2 = MsgPack::unpack(packed).toSize(); QVERIFY(sz == sz2); + sz = QSize(1, 2); + packed = MsgPack::pack(sz); + QVERIFY(packed.size() == 4); + sz2 = MsgPack::unpack(packed).toSize(); + QVERIFY(sz == sz2); + sz = QSize(1234, 5678); packed = MsgPack::pack(sz); QVERIFY(packed.size() == 9); @@ -107,12 +119,18 @@ void QtTypesTest::test_qsize() void QtTypesTest::test_qrect() { MsgPack::registerType(QMetaType::QRect, 81); - QRect r(1, 2, 3, 4); + QRect r; QByteArray packed = MsgPack::pack(r); - QVERIFY(packed.size() == 6); + QVERIFY(packed.size() == 3); QRect r2 = MsgPack::unpack(packed).toRect(); QVERIFY(r == r2); + r = QRect(1, 2, 3, 4); + packed = MsgPack::pack(r); + QVERIFY(packed.size() == 6); + r2 = MsgPack::unpack(packed).toRect(); + QVERIFY(r == r2); + qint32 max = std::numeric_limits::max(); r = QRect(0, 0, max, max); packed = MsgPack::pack(r); From dfdeb25b0928907d9f4fe71cc98ad8c7ebc9e3ee Mon Sep 17 00:00:00 2001 From: Roman Date: Mon, 29 Jun 2015 19:58:14 +0300 Subject: [PATCH 22/22] Travis Qt5 build fix --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8683a39..ac76a5c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,7 @@ before_install: script: - mkdir build - cd build - - if [ -z ${QT4_BUILD+x} ]; then cmake -DBUILD_TESTS=TRUE -DQT4_BUILD=FALSE ..; else cmake -DBUILD_TESTS=TRUE -DQT4_BUILD=TRUE ..; fi + - if [ "$QT4_BUILD" == "OFF" ]; then cmake -DBUILD_TESTS=TRUE -DQT4_BUILD=FALSE ..; else cmake -DBUILD_TESTS=TRUE -DQT4_BUILD=TRUE ..; fi - make - export CTEST_OUTPUT_ON_FAILURE=1 - make test