Qt types stream operators, documentation updated, custom types support improved, bug fixes and new tests.

This commit is contained in:
Isaikin Roman
2015-09-12 16:48:21 +03:00
parent 4da435044d
commit 5761f66683
25 changed files with 1244 additions and 102 deletions

View File

@ -39,8 +39,8 @@ else ()
set(PC_Requires "QtCore")
endif ()
option (QTGUI_TYPES "Build with support for QtGui types")
if (QTGUI_TYPES)
option (WITH_GUI_TYPES "Build with support for QtGui types")
if (WITH_GUI_TYPES)
if (QT4_BUILD)
find_package(Qt4 QTGUI)
else ()
@ -48,12 +48,17 @@ if (QTGUI_TYPES)
endif ()
endif ()
if (Qt5Gui_FOUND)
message("Qt5Gui found")
include_directories(${Qt5Gui_INCLUDE_DIRS})
add_definitions(${Qt5Gui_DEFINITIONS})
option (WITH_LOCATION_TYPES "Build with support for QtLocation types")
if (WITH_LOCATION_TYPES)
find_package(Qt5Location QUIET)
endif ()
if (Qt5Location_FOUND)
message("Qt5Location found")
include_directories(${Qt5Location_INCLUDE_DIRS})
add_definitions(${Qt5Location_DEFINITIONS})
else ()
message("Qt5Gui not found")
message("Qt5Location not found")
endif ()
if (NOT WIN32)
@ -80,10 +85,10 @@ 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)

View File

@ -73,6 +73,22 @@ Unpacking is handled by ``MsgPack::unpack()`` function:
If packed data contains only one msgpack type (fixstr of fixmap for example), unpack will return it as ``QVariant(QString())`` and ``QVariant(QMap())`` respectively.
But if there are several values packed, ``QVariant(QList())`` will be returned (consider this 5 bool values packed without msgpack's list: [0xc3, 0xc3, 0xc3, 0xc3, 0xc3])
More types
==========
There are built in packers and unpackers (basic and stream ones) for following types:
``QPoint, QSize, QRect, QTime, QDate, QDateTime, QColor, QGeoCoordinate``.
But since there is no such types in msgpack spec, ext type is used.
Example:
.. code-block:: cpp
MsgPack::registerType(QMetaType::QPoint, 37); // 37 is msgpack user type id
QByteArray ba = MsgPack::pack(QPoint(12, 34));
qDebug() << MsgPack::unpack(ba).toPoint();
Note, that QColor and QGeoCoordinate is enabled by default only in qmake project.
Thread safety
=============

141
doc/custom.rst Normal file
View File

@ -0,0 +1,141 @@
Custom types
------------
.. contents::
:depth: 4
Custom QVariant
===============
You can provide two functions for packing QVariant with custom type inside to QByteArray and vise versa.
For example here is how QColor packer and unpacker looks like:
.. code-block:: cpp
QByteArray pack_qcolor(const QVariant &variant)
{
QColor color = variant.value<QColor>();
if (!color.isValid())
return QByteArray(1, 0);
QByteArray data;
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 data;
}
QVariant unpack_qcolor(const QByteArray &data)
{
if (data.length() == 1)
return QColor();
quint8 *p = (quint8 *)data.data();
return QColor(p[0], p[1], p[2], p[3]);
}
And that's it!
Now register this two functions:
.. code-block:: cpp
MsgPack::registerPacker(QMetaType::QColor, 3, pack_qcolor); // 3 is msgpack ext type id
MsgPack::registerUnpacker(3, unpack_qcolor);
After that ``MsgPack::pack(QColor(127, 127, 127))`` will start to work!
Custom stream
=============
You can provide stream operators for any other type you might want to work with. But there are some pitfalls to consider if you want to unpack something with other MsgPack implementations.
Example:
.. code-block:: cpp
class SomeType
{
public:
double x() const { return m_x; }
void setX(double x) { m_x = x;}
double y() const { return m_y; }
void setY(double y) { m_y = y;}
double z() const { return m_z; }
void setZ(double z) { m_z = z;}
private:
double m_x, m_y, m_z;
};
MsgPackStream &operator<<(MsgPackStream &s, const SomeType &t)
{
s.writeExtHeader(27, <msgpack user type id>); // size of packed double is 9 * 3 = 27
s << t.x() << t.y() << t.z();
return s;
}
MsgPackStream &operator>>(MsgPackStream &s, SomeType &t)
{
quint32 len;
s.readExtHeader(len);
if (len != 27) {
s.setStatus(MsgPackStream::ReadCorruptData);
return s;
}
double x, y, z;
s >> x >> y >> z;
t.setX(x);
t.setY(y);
t.setZ(z);
return s;
}
In this case size of data is known id advance, if this is not the case, then you can use QByteArray. Here is how QPoint operators are implemented:
.. code-block:: cpp
MsgPackStream &operator<<(MsgPackStream &s, const QPoint &point)
{
// we need to know user type id, that was registered with MsgPack::registerType
qint8 msgpackType = MsgPack::msgpackType(QMetaType::QPoint);
if (msgpackType == -1) {
s.setStatus(MsgPackStream::WriteFailed);
return s;
}
QByteArray ba;
MsgPackStream out(&ba, QIODevice::WriteOnly); // stream inside stream ;)
if (point.isNull()) { // save some bytes if point is invalid
quint8 p[1] = {0};
out.writeBytes((const char *)p, 1);
} else {
out << point.x() << point.y();
}
s.writeExtHeader(ba.length(), msgpackType); // only now write msgpack ext field
s.writeBytes(ba.data(), ba.length()); // and variable length data
return s;
}
MsgPackStream &operator>>(MsgPackStream &s, QPoint &point)
{
quint32 len;
s.readExtHeader(len); // read msgpack ext field
if (len == 1) { // handle invalid QPoint
point = QPoint();
return s;
}
QByteArray ba;
ba.resize(len);
s.readBytes(ba.data(), len); // read len bytes to byte array
MsgPackStream in(ba);
int x, y;
in >> x >> y;
point = QPoint(x, y);
return s;
}
.. tip::
Of course you can just stream out everything without any ext header and user type id's, like this: ``s << point.x() << point.y();`` but in that case you will not be able to unpack anything useful with MsgPack::unpack() or in other MsgPack implementations.

View File

@ -6,6 +6,8 @@ qmsgpack - MessagePack serializer implementation for Qt
install.rst
basics.rst
stream.rst
custom.rst
Contents:

View File

@ -5,7 +5,7 @@ Installation
:depth: 4
qmsgpack is a pure Qt library (Qt4 and Qt5 supported), so you can build it for almost any platform Qt supports.
Also there are several build options:
There are two build methods:
- CMake
- qmake
@ -48,6 +48,14 @@ There are several useful cmake options available:
Change build type to debug mode (default is `Release`), could be very useful if something goes wrong
.. cmdoption:: -DWITH_GUI_TYPES=True
Build with support for QtGui types (QColor)
.. cmdoption:: -DWITH_LOCATION_TYPES=True
Build with support for QtLocation types(QGeoCoordinate). Might not work, because CMake seems to be failing to find QtLocation, in this case you can try qmake instead.
Add options before ``..`` as follow:
.. code-block:: bash

68
doc/stream.rst Normal file
View File

@ -0,0 +1,68 @@
Streams
-------
.. contents::
:depth: 4
There are QDataStream analogue with almost identical API. Every basic type is supported as well as QList<T> and Qt types (QPoint, QSize, QRect, QTime, QDate, QDateTime, QColor, QGeoCoordinate). More types are on the way.
Packing
=======
You can use any QIODevice derived class or QByteArray.
.. code-block:: cpp
QByteArray ba;
MsgPackStream out(&ba, QIODevice::WriteOnly);
out << 1 << true << "Hello";
qDebug() << ba.toHex();
Of course you can unpack this byte array using ``MsgPack::unpack``:
.. code-block:: cpp
qDebug() << MsgPack::unpack(ba);
// output:
// QVariant(QVariantList, (QVariant(uint, 1), QVariant(bool, true), QVariant(QString, "Hello")))
QList of any type are also supported:
.. code-block:: cpp
QList<int> list;
list << 1 << 2 << 3;
QByteArray ba;
MsgPackStream out(&ba, QIODevice::WriteOnly);
out << list;
Unpacking
=========
To unpack QByteArray just pass it by value, or use QIODevice::ReadOnly for other devices:
.. code-block:: cpp
MsgPackStream in(ba);
QList<int> list2;
in >> list2;
qDebug() << list2; // (1, 2, 3)
More types
==========
Include ``<qmsgpack/stream/geometry.h`` (or location.h or time.h) for additional types.
And do not forget to register type, so that MsgPackStream will know which user type id to use.
.. code-block:: cpp
#include <qmsgpack/stream/geometry.h>
// ...
MsgPack::registerType(QMetaType::QPoint, 3);
QByteArray ba;
MsgPackStream out(&ba, QIODevice::WriteOnly);
out << QPoint(1, 2) << QPoint();
qDebug() << MsgPack::unpack(ba);
// output:
// QVariant(QVariantList, (QVariant(QPoint, QPoint(1,2)), QVariant(QPoint, QPoint(0,0))))

View File

@ -1,5 +1,6 @@
set(qmsgpack_srcs msgpack.cpp msgpackcommon.cpp msgpackstream.cpp private/pack_p.cpp private/unpack_p.cpp private/qt_types_p.cpp)
set(qmsgpack_srcs msgpack.cpp msgpackcommon.cpp msgpackstream.cpp private/pack_p.cpp private/unpack_p.cpp private/qt_types_p.cpp stream/time.cpp stream/geometry.cpp)
set(qmsgpack_headers msgpack.h msgpackstream.h msgpackcommon.h msgpack_export.h endianhelper.h)
set(qmsgpack_stream_headers stream/location.h stream/time.h stream/geometry.h)
add_library(qmsgpack SHARED ${qmsgpack_srcs} ${qmsgpack_headers})
@ -31,4 +32,7 @@ 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)
PUBLIC_HEADER DESTINATION ${INCLUDE_INSTALL_DIR}/qmsgpack)
install(FILES ${qmsgpack_stream_headers} DESTINATION ${INCLUDE_INSTALL_DIR}/qmsgpack/stream)

View File

@ -38,6 +38,11 @@ bool MsgPack::registerUnpacker(qint8 msgpackType, MsgPack::unpack_user_f unpacke
return MsgPackPrivate::register_unpacker(msgpackType, unpacker);
}
qint8 MsgPack::msgpackType(int qType)
{
return MsgPackPrivate::msgpack_type((QMetaType::Type)qType);
}
bool MsgPack::registerType(QMetaType::Type qType, quint8 msgpackType)
{
return MsgPackPrivate::register_qtype(qType, msgpackType);

View File

@ -14,6 +14,7 @@ namespace MsgPack
MSGPACK_EXPORT QByteArray pack(const QVariant &variant);
MSGPACK_EXPORT bool registerPacker(QMetaType::Type qType, qint8 msgpackType, pack_user_f packer);
MSGPACK_EXPORT qint8 msgpackType(int qType);
MSGPACK_EXPORT bool registerType(QMetaType::Type qType, quint8 msgpackType);

View File

@ -322,7 +322,47 @@ MsgPackStream &MsgPackStream::operator>>(QByteArray &array)
bool MsgPackStream::readBytes(char *data, uint len)
{
CHECK_STREAM_PRECOND(false);
return dev->read(data, len) == len;
uint readed = dev->read(data, len);
if (readed != len) {
setStatus(ReadPastEnd);
return false;
}
return true;
}
bool MsgPackStream::readExtHeader(quint32 &len)
{
CHECK_STREAM_PRECOND(false);
quint8 d[6];
if (dev->read((char*)d, 2) != 2) {
setStatus(ReadPastEnd);
return false;
}
if (d[0] >= MsgPack::FirstByte::FIXEXT1 &&
d[0] <= MsgPack::FirstByte::FIXEX16) {
len = 1;
len <<= d[0] - MsgPack::FirstByte::FIXEXT1;
return true;
}
quint8 toRead = 1;
toRead <<= d[0] - MsgPack::FirstByte::EXT8;
if (dev->read((char*)&d[2], toRead) != toRead) {
setStatus(ReadPastEnd);
return false;
}
if (d[0] == MsgPack::FirstByte::EXT8) {
len = d[1];
} else if (d[0] == MsgPack::FirstByte::EXT16) {
len = _msgpack_load16(quint32, &d[1]);
} else if (d[0] == MsgPack::FirstByte::EXT32) {
len = _msgpack_load32(quint32, &d[1]);
} else {
setStatus(ReadCorruptData);
return false;
}
return true;
}
MsgPackStream &MsgPackStream::operator<<(bool b)
@ -440,8 +480,49 @@ 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::writeExtHeader(quint32 len, qint8 msgpackType)
{
CHECK_STREAM_WRITE_PRECOND(false);
quint8 d[6];
d[1] = msgpackType;
quint8 sz = 2;
if (len == 1) {
d[0] = 0xd4;
} else if (len == 2) {
d[0] = 0xd5;
} else if (len == 4) {
d[0] = 0xd6;
} else if (len == 8) {
d[0] = 0xd7;
} else if (len == 16) {
d[0] = 0xd8;
} else if (len <= std::numeric_limits<quint8>::max()) {
d[0] = 0xc7;
d[1] = (quint8)len;
d[2] = msgpackType;
sz = 3;
} else if (len <= std::numeric_limits<quint16>::max()) {
d[0] = 0xc8;
_msgpack_store16(&d[1], len);
d[3] = msgpackType;
sz = 4;
} else {
d[0] = 0xc9;
_msgpack_store32(&d[1], len);
d[5] = msgpackType;
sz = 6;
}
if (dev->write((const char *)d, sz) != sz) {
setStatus(WriteFailed);
return false;
}
return true;
}

View File

@ -40,6 +40,7 @@ public:
MsgPackStream &operator>>(QString &str);
MsgPackStream &operator>>(QByteArray &array);
bool readBytes(char *data, uint len);
bool readExtHeader(quint32 &len);
MsgPackStream &operator<<(bool b);
MsgPackStream &operator<<(quint32 u32);
@ -52,6 +53,7 @@ public:
MsgPackStream &operator<<(const char *str);
MsgPackStream &operator<<(QByteArray array);
bool writeBytes(const char *data, uint len);
bool writeExtHeader(quint32 len, qint8 msgpackType);
private:
QIODevice *dev;

View File

@ -47,6 +47,8 @@ quint8 *MsgPackPrivate::pack(const QVariant &v, quint8 *p, bool wr, QVector<QByt
t = (QMetaType::Type)v.userType();
QReadLocker locker(&packers_lock);
bool has_packer = user_packers.contains(t);
if (has_packer)
has_packer &= user_packers[t].packer != 0;
locker.unlock();
if (has_packer)
p = pack_user(v, p, wr, user_data);
@ -309,10 +311,6 @@ quint8 *MsgPackPrivate::pack_map(const QVariantMap &map, quint8 *p, bool wr, QVe
bool MsgPackPrivate::register_packer(QMetaType::Type q_type, qint8 msgpack_type, MsgPack::pack_user_f packer)
{
if (packer == 0) {
qWarning() << "MsgPack::packer for qtype" << q_type << "is invalid";
return false;
}
QWriteLocker locker(&packers_lock);
if (user_packers.contains(q_type)) {
qWarning() << "MsgPack::packer for qtype" << q_type << "already exist";
@ -325,6 +323,14 @@ bool MsgPackPrivate::register_packer(QMetaType::Type q_type, qint8 msgpack_type,
return true;
}
qint8 MsgPackPrivate::msgpack_type(QMetaType::Type q_type)
{
QReadLocker locker(&packers_lock);
if (user_packers.contains(q_type))
return user_packers[q_type].type;
return -1;
}
quint8 *MsgPackPrivate::pack_user(const QVariant &v, quint8 *p, bool wr, QVector<QByteArray> &user_data)
{
QMetaType::Type t = (QMetaType::Type)v.type() == QMetaType::User ?

View File

@ -1,3 +1,4 @@
#ifndef PACK_P_H
#define PACK_P_H
@ -19,6 +20,7 @@ typedef struct {
qint8 type;
} packer_t;
bool register_packer(QMetaType::Type q_type, qint8 msgpack_type, MsgPack::pack_user_f packer);
qint8 msgpack_type(QMetaType::Type q_type);
extern QHash<QMetaType::Type, packer_t> user_packers;
extern QReadWriteLock packers_lock;
extern bool compatibilityMode;

View File

@ -3,13 +3,19 @@
#include "unpack_p.h"
#include "../msgpackstream.h"
#include "../endianhelper.h"
#include "../stream/time.h"
#include <QDebug>
#ifdef QT_GUI_LIB
#include <QColor>
#else
#define NO_QTGUI_WARNING "qmsgpack was built without QtGui, hence some types are not available"
#endif
#ifdef QT_LOCATION_LIB
#include <QGeoCoordinate>
#endif
#define NO_QTGUI_WARNING "Library built without QtGui, hence some types are not available"
#include <QTime>
#include <QRect>
@ -24,6 +30,13 @@ bool MsgPackPrivate::register_qtype(QMetaType::Type q_type, quint8 msgpack_type)
qWarning() << NO_QTGUI_WARNING;
return false;
#endif //QT_GUI_LIB
#ifdef QT_LOCATION_LIB
} else if ((int)q_type == qMetaTypeId<QGeoCoordinate>()) {
MsgPackPrivate::register_packer((QMetaType::Type)qMetaTypeId<QGeoCoordinate>(),
msgpack_type,
pack_qgeocoordinate);
MsgPackPrivate::register_unpacker(msgpack_type, unpack_qgeocoordinate);
#endif
} else if (q_type == QMetaType::QTime) {
MsgPackPrivate::register_packer(q_type, msgpack_type, pack_qtime);
MsgPackPrivate::register_unpacker(msgpack_type, unpack_qtime);
@ -49,9 +62,11 @@ bool MsgPackPrivate::register_qtype(QMetaType::Type q_type, quint8 msgpack_type)
#ifdef QT_GUI_LIB
QByteArray MsgPackPrivate::pack_qcolor(const QVariant &variant)
{
QColor color = variant.value<QColor>();
if (!color.isValid())
return QByteArray(1, 0);
QByteArray data;
data.resize(4);
QColor color = variant.value<QColor>();
quint8 *p = (quint8 *)data.data();
p[0] = color.red();
p[1] = color.green();
@ -62,93 +77,83 @@ QByteArray MsgPackPrivate::pack_qcolor(const QVariant &variant)
QVariant MsgPackPrivate::unpack_qcolor(const QByteArray &data)
{
if (data.length() == 1)
return QColor();
quint8 *p = (quint8 *)data.data();
return QColor(p[0], p[1], p[2], p[3]);
}
#endif // QT_GUI_LIB
// Date and Time
void MsgPackPrivate::pack_qtime_raw(const QTime &time, quint8 *p)
#ifdef QT_LOCATION_LIB
QByteArray MsgPackPrivate::pack_qgeocoordinate(const QVariant &variant)
{
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();
}
QGeoCoordinate c = variant.value<QGeoCoordinate>();
if (!c.isValid())
return QByteArray(1, 0);
QByteArray ba;
MsgPackStream out(&ba, QIODevice::WriteOnly);
out << c.latitude() << c.longitude();
return ba;
}
QTime MsgPackPrivate::unpack_qtime_raw(quint8 *p, bool with_ms)
QVariant MsgPackPrivate::unpack_qgeocoordinate(const QByteArray &data)
{
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);
if (data.length() == 1)
return QVariant::fromValue(QGeoCoordinate());
MsgPackStream in(data);
QGeoCoordinate c;
double x;
in >> x;
c.setLatitude(x);
in >> x;
c.setLongitude(x);
return QVariant::fromValue(c);
}
#endif // QT_LOCATION_LIB
QByteArray MsgPackPrivate::pack_qtime(const QVariant &variant)
{
QTime time = variant.toTime();
if (!time.isValid())
return QByteArray(1, 0);
quint8 size = time.msec() == 0 ? 2 : 4;
QByteArray data;
data.resize(size);
data.data()[0] = 0;
pack_qtime_raw(time, (quint8 *)data.data());
return data;
}
QVariant MsgPackPrivate::unpack_qtime(const QByteArray &data)
{
if (data.size() == 1)
return QTime();
return unpack_qtime_raw((quint8 *)data.data(), data.size() == 4);
}
void MsgPackPrivate::pack_qdate_raw(const QDate &date, quint8 *p)
{
quint16 year = date.year();
quint8 month = date.month();
quint8 day = date.day();
if (day > 15)
year |= 0x8000;
quint8 md = (month << 4) | (day & 0xf);
_msgpack_store16(p, year);
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);
}
QByteArray MsgPackPrivate::pack_qdate(const QVariant &variant)
{
QDate date = variant.toDate();
if (!date.isValid())
return QByteArray(1, 0);
QByteArray data;
data.resize(3);
pack_qdate_raw(variant.toDate(), (quint8 *)data.data());
pack_qdate_raw(date, (quint8 *)data.data());
return data;
}
QVariant MsgPackPrivate::unpack_qdate(const QByteArray &data)
{
if (data.length() == 1)
return QDate();
return unpack_qdate_raw((quint8 *)data.data());
}
QByteArray MsgPackPrivate::pack_qdatetime(const QVariant &variant)
{
QDateTime dt = variant.toDateTime();
if (!dt.isValid())
return QByteArray(1, 0);
quint8 time_size = dt.time().msec() == 0 ? 2 : 4;
QByteArray data;
data.resize(3 + time_size);
@ -161,6 +166,8 @@ QByteArray MsgPackPrivate::pack_qdatetime(const QVariant &variant)
QVariant MsgPackPrivate::unpack_qdatetime(const QByteArray &data)
{
if (data.length() == 1)
return QDateTime();
quint8 *p = (quint8 *)data.data();
QDate d = unpack_qdate_raw(p);
QTime t = unpack_qtime_raw(p + 3, data.size() == 7);
@ -170,33 +177,40 @@ QVariant MsgPackPrivate::unpack_qdatetime(const QByteArray &data)
// Points and Vectors
QByteArray MsgPackPrivate::pack_qpoint(const QVariant &variant)
{
QPoint pt = variant.toPoint();
if (pt.isNull())
return QByteArray(1, 0);
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)
{
if (data.length() == 1)
return QPoint();
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();
if (!sz.isValid())
return QByteArray(1, 0);
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)
{
if (data.length() == 1)
return QSize();
MsgPackStream stream(data);
qint32 width, height;
stream >> width >> height;
@ -206,6 +220,8 @@ QVariant MsgPackPrivate::unpack_qsize(const QByteArray &data)
QByteArray MsgPackPrivate::pack_qrect(const QVariant &variant)
{
QRect rect = variant.toRect();
if (!rect.isValid())
return QByteArray(1, 0);
QPoint pt1 = rect.topLeft();
QPoint pt2 = rect.bottomRight();
QByteArray packed;
@ -216,6 +232,8 @@ QByteArray MsgPackPrivate::pack_qrect(const QVariant &variant)
QVariant MsgPackPrivate::unpack_qrect(const QByteArray &data)
{
if (data.length() == 1)
return QRect();
MsgPackStream stream(data);
qint32 x, y;
stream >> x >> y;
@ -225,4 +243,3 @@ QVariant MsgPackPrivate::unpack_qrect(const QByteArray &data)
rect.setBottomRight(QPoint(x, y));
return rect;
}

View File

@ -13,6 +13,11 @@ QByteArray pack_qcolor(const QVariant &variant);
QVariant unpack_qcolor(const QByteArray &data);
#endif //QT_GUI_LIB
#ifdef QT_LOCATION_LIB
QByteArray pack_qgeocoordinate(const QVariant &variant);
QVariant unpack_qgeocoordinate(const QByteArray &data);
#endif
// Date and Time
/**
* @brief pack_qtime_raw internal: packs QTime to 4 or 2 bytes (with or without ms)
@ -20,14 +25,12 @@ QVariant unpack_qcolor(const QByteArray &data);
* @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);
QByteArray pack_qtime(const QVariant &variant);
QVariant unpack_qtime(const QByteArray &data);
@ -37,9 +40,7 @@ QVariant unpack_qtime(const QByteArray &data);
* @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);
QByteArray pack_qdate(const QVariant &variant);
QVariant unpack_qdate(const QByteArray &data);

View File

@ -1,5 +1,4 @@
QT += core
QT -= gui
QT += core gui location
TARGET = qmsgpack
CONFIG -= app_bundle
@ -20,7 +19,10 @@ SOURCES += msgpack.cpp \
private/pack_p.cpp \
private/unpack_p.cpp \
private/qt_types_p.cpp \
msgpackstream.cpp
msgpackstream.cpp \
stream/time.cpp \
stream/geometry.cpp \
stream/location.cpp
HEADERS += \
msgpack.h \
@ -30,7 +32,10 @@ HEADERS += \
msgpackcommon.h \
msgpack_export.h \
private/qt_types_p.h \
msgpackstream.h
msgpackstream.h \
stream/location.h \
stream/time.h \
stream/geometry.h
HEADERS_INSTALL = \
msgpack.h \
@ -40,7 +45,8 @@ HEADERS_INSTALL = \
msgpackstream.h \
STREAM_HEADERS_INSTALL = \
stream/location.h
stream/location.h \
stream/time.h
unix {
header_files.files = $$HEADERS_INSTALL

117
src/stream/geometry.cpp Normal file
View File

@ -0,0 +1,117 @@
#include "geometry.h"
#include "../msgpack.h"
#include "../msgpackstream.h"
MsgPackStream &operator<<(MsgPackStream &s, const QPoint &point)
{
qint8 msgpackType = MsgPack::msgpackType(QMetaType::QPoint);
if (msgpackType == -1) {
s.setStatus(MsgPackStream::WriteFailed);
return s;
}
QByteArray ba;
MsgPackStream out(&ba, QIODevice::WriteOnly);
if (point.isNull()) {
quint8 p[1] = {0};
out.writeBytes((const char *)p, 1);
} else {
out << point.x() << point.y();
}
s.writeExtHeader(ba.length(), msgpackType);
s.writeBytes(ba.data(), ba.length());
return s;
}
MsgPackStream &operator>>(MsgPackStream &s, QPoint &point)
{
quint32 len;
s.readExtHeader(len);
if (len == 1) {
point = QPoint();
return s;
}
QByteArray ba;
ba.resize(len);
s.readBytes(ba.data(), len);
MsgPackStream in(ba);
int x, y;
in >> x >> y;
point = QPoint(x, y);
return s;
}
MsgPackStream &operator<<(MsgPackStream &s, const QSize &sz)
{
qint8 msgpackType = MsgPack::msgpackType(QMetaType::QSize);
if (msgpackType == -1) {
s.setStatus(MsgPackStream::WriteFailed);
return s;
}
QByteArray ba;
MsgPackStream out(&ba, QIODevice::WriteOnly);
if (!sz.isValid()) {
quint8 p[1] = {0};
out.writeBytes((const char *)p, 1);
} else {
out << sz.width() << sz.height();
}
s.writeExtHeader(ba.length(), msgpackType);
s.writeBytes(ba.data(), ba.length());
return s;
}
MsgPackStream &operator>>(MsgPackStream &s, QSize &sz)
{
quint32 len;
s.readExtHeader(len);
if (len == 1) {
sz = QSize();
return s;
}
QByteArray ba;
ba.resize(len);
s.readBytes(ba.data(), len);
MsgPackStream in(ba);
int w, h;
in >> w >> h;
sz = QSize(w, h);
return s;
}
MsgPackStream &operator<<(MsgPackStream &s, const QRect &rect)
{
qint8 msgpackType = MsgPack::msgpackType(QMetaType::QRect);
if (msgpackType == -1) {
s.setStatus(MsgPackStream::WriteFailed);
return s;
}
QByteArray ba;
MsgPackStream out(&ba, QIODevice::WriteOnly);
if (!rect.isValid()) {
quint8 p[1] = {0};
out.writeBytes((const char *)p, 1);
} else {
out << rect.left() << rect.top() << rect.width() << rect.height();
}
s.writeExtHeader(ba.length(), msgpackType);
s.writeBytes(ba.data(), ba.length());
return s;
}
MsgPackStream &operator>>(MsgPackStream &s, QRect &rect)
{
quint32 len;
s.readExtHeader(len);
if (len == 1) {
rect = QRect();
return s;
}
QByteArray ba;
ba.resize(len);
s.readBytes(ba.data(), len);
MsgPackStream in(ba);
int l, t, w, h;
in >> l >> t >> w >> h;
rect = QRect(l, t, w, h);
return s;
}

19
src/stream/geometry.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef GEOMETRY_H
#define GEOMETRY_H
#include "../msgpack_export.h"
#include "../msgpackstream.h"
#include <QRect>
MSGPACK_EXPORT MsgPackStream &operator<<(MsgPackStream& s, const QPoint &point);
MSGPACK_EXPORT MsgPackStream& operator>>(MsgPackStream& s, QPoint &point);
MSGPACK_EXPORT MsgPackStream &operator<<(MsgPackStream& s, const QSize &sz);
MSGPACK_EXPORT MsgPackStream& operator>>(MsgPackStream& s, QSize &sz);
MSGPACK_EXPORT MsgPackStream &operator<<(MsgPackStream& s, const QRect &rect);
MSGPACK_EXPORT MsgPackStream& operator>>(MsgPackStream& s, QRect &rect);
#endif // GEOMETRY_H

34
src/stream/location.cpp Normal file
View File

@ -0,0 +1,34 @@
#ifdef QT_LOCATION_LIB
#include "location.h"
#include "../msgpack.h"
MsgPackStream& operator>>(MsgPackStream& s, QGeoCoordinate &coordinate)
{
quint32 len;
s.readExtHeader(len);
if (len != 18) {
s.setStatus(MsgPackStream::ReadCorruptData);
return s;
}
double x;
s >> x;
coordinate.setLatitude(x);
s >> x;
coordinate.setLongitude(x);
return s;
}
MsgPackStream &operator<<(MsgPackStream& s, const QGeoCoordinate &coordinate)
{
qint8 msgpackType = MsgPack::msgpackType((QMetaType::Type)qMetaTypeId<QGeoCoordinate>());
if (msgpackType == -1) {
s.setStatus(MsgPackStream::WriteFailed);
return s;
}
s.writeExtHeader(18, msgpackType);
s << coordinate.latitude() << coordinate.longitude();
return s;
}
#endif

View File

@ -1,24 +1,15 @@
#ifndef QMSGPACK_STREAM_LOCATION_H
#define QMSGPACK_STREAM_LOCATION_H
#ifdef QT_LOCATION_LIB
#include "../msgpack_export.h"
#include "../msgpackstream.h"
#include <QGeoCoordinate>
MsgPackStream& operator>>(MsgPackStream& s, QGeoCoordinate &coordinate)
{
double x;
s >> x;
coordinate.setLatitude(x);
s >> x;
coordinate.setLongitude(x);
return s;
}
MSGPACK_EXPORT MsgPackStream& operator>>(MsgPackStream& s, QGeoCoordinate &coordinate);
MSGPACK_EXPORT MsgPackStream &operator<<(MsgPackStream& s, const QGeoCoordinate &coordinate);
MsgPackStream &operator<<(MsgPackStream& s, const QGeoCoordinate &coordinate)
{
s << coordinate.latitude() << coordinate.longitude();
return s;
}
#endif // QMSGPACK_STREAM_LOCATION_H
#endif // QT_LOCATION_LIB
#endif // QMSGPACK_STREAM_LOCATION_H

166
src/stream/time.cpp Normal file
View File

@ -0,0 +1,166 @@
#include "time.h"
#include "../msgpack.h"
void MsgPackPrivate::pack_qtime_raw(const QTime &time, quint8 *p)
{
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, bool with_ms)
{
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);
}
void MsgPackPrivate::pack_qdate_raw(const QDate &date, quint8 *p)
{
quint16 year = date.year();
quint8 month = date.month();
quint8 day = date.day();
if (day > 15)
year |= 0x8000;
quint8 md = (month << 4) | (day & 0xf);
_msgpack_store16(p, year);
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);
}
MsgPackStream &operator<<(MsgPackStream &s, const QTime &t)
{
qint8 msgpackType = MsgPack::msgpackType(QMetaType::QTime);
if (msgpackType == -1) {
s.setStatus(MsgPackStream::WriteFailed);
return s;
}
quint8 len = 1;
if (t.isValid())
len = t.msec() == 0 ? 2 : 4;
s.writeExtHeader(len, msgpackType);
quint8 p[4] = {0};
if (len != 1)
MsgPackPrivate::pack_qtime_raw(t, p);
s.writeBytes((const char *)p, len);
return s;
}
MsgPackStream& operator>>(MsgPackStream& s, QTime &t)
{
quint32 len;
s.readExtHeader(len);
if (len != 1 && len != 2 && len != 4) {
s.setStatus(MsgPackStream::ReadCorruptData);
t = QTime();
return s;
}
if (len == 1) {
t == QTime();
return s;
}
quint8 p[4];
s.readBytes((char *)p, len);
t = MsgPackPrivate::unpack_qtime_raw(p, len == 4);
return s;
}
MsgPackStream &operator<<(MsgPackStream &s, const QDate &date)
{
qint8 msgpackType = MsgPack::msgpackType(QMetaType::QDate);
if (msgpackType == -1) {
s.setStatus(MsgPackStream::WriteFailed);
return s;
}
quint8 len = date.isValid() ? 3 : 1;
s.writeExtHeader(len, msgpackType);
quint8 p[3] = {0};
if (len != 1)
MsgPackPrivate::pack_qdate_raw(date, p);
s.writeBytes((const char *)p, len);
return s;
}
MsgPackStream& operator>>(MsgPackStream& s, QDate &date)
{
quint32 len;
s.readExtHeader(len);
if (len != 1 && len != 3) {
s.setStatus(MsgPackStream::ReadCorruptData);
date = QDate();
return s;
}
if (len == 1) {
date = QDate();
return s;
}
quint8 p[3];
s.readBytes((char *)p, len);
date = MsgPackPrivate::unpack_qdate_raw(p);
return s;
}
MsgPackStream &operator<<(MsgPackStream& s, const QDateTime &dt)
{
qint8 msgpackType = MsgPack::msgpackType(QMetaType::QDateTime);
if (msgpackType == -1) {
s.setStatus(MsgPackStream::WriteFailed);
return s;
}
quint8 len = 1;
if (dt.isValid()) {
len = 3;
len += dt.time().msec() == 0 ? 2 : 4;
}
s.writeExtHeader(len, msgpackType);
quint8 p[7] = {0};
if (len != 1) {
MsgPackPrivate::pack_qdate_raw(dt.date(), p);
MsgPackPrivate::pack_qtime_raw(dt.time(), p + 3);
}
s.writeBytes((const char *)p, len);
return s;
}
MsgPackStream& operator>>(MsgPackStream& s, QDateTime &dt)
{
quint32 len;
s.readExtHeader(len);
if (len != 1 && len != 5 && len != 7) {
s.setStatus(MsgPackStream::ReadCorruptData);
dt = QDateTime();
return s;
}
if (len == 1) {
dt = QDateTime();
return s;
}
quint8 p[7];
s.readBytes((char *)p, len);
dt.setDate(MsgPackPrivate::unpack_qdate_raw(p));
dt.setTime(MsgPackPrivate::unpack_qtime_raw(p + 3, len == 7));
return s;
}

26
src/stream/time.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef TIME_H
#define TIME_H
#include "../msgpack_export.h"
#include "../msgpackstream.h"
#include <QDateTime>
MSGPACK_EXPORT MsgPackStream &operator<<(MsgPackStream& s, const QTime &time);
MSGPACK_EXPORT MsgPackStream& operator>>(MsgPackStream& s, QTime &time);
MSGPACK_EXPORT MsgPackStream &operator<<(MsgPackStream& s, const QDate &date);
MSGPACK_EXPORT MsgPackStream& operator>>(MsgPackStream& s, QDate &date);
MSGPACK_EXPORT MsgPackStream &operator<<(MsgPackStream& s, const QDateTime &dt);
MSGPACK_EXPORT MsgPackStream& operator>>(MsgPackStream& s, QDateTime &dt);
namespace MsgPackPrivate {
void pack_qtime_raw(const QTime &time, quint8 *p);
QTime unpack_qtime_raw(quint8 *p, bool with_ms);
void pack_qdate_raw(const QDate &date, quint8 *p);
QDate unpack_qdate_raw(quint8 *p);
}
#endif // TIME_H

View File

@ -8,7 +8,7 @@ if (Qt5Core_FOUND)
set(TEST_LIBRARIES ${Qt5Test_LIBRARIES})
endif ()
set(TEST_SUBDIRS pack unpack mixed stream)
set(TEST_SUBDIRS pack unpack mixed stream qttypes)
foreach(subdir ${TEST_SUBDIRS})
add_subdirectory(${subdir})

View File

@ -4,18 +4,63 @@
#include <msgpack.h>
#include <limits>
#ifdef QT_GUI_LIB
#include <QColor>
#endif
#ifdef QT_LOCATION_LIB
#include <QGeoCoordinate>
#endif
class QtTypesTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
#ifdef QT_GUI_LIB
void test_qcolor();
#endif
#ifdef QT_LOCATION_LIB
void test_qgeocoordinte();
#endif
void test_qtime();
void test_qdate();
void test_qdatetime();
void test_qpoint();
void test_qsize();
void test_qrect();
};
#ifdef QT_GUI_LIB
void QtTypesTest::test_qcolor()
{
MsgPack::registerType(QMetaType::QColor, 0x75);
QColor color;
QByteArray packed = MsgPack::pack(color);
QColor color2 = MsgPack::unpack(packed).value<QColor>();
QVERIFY(color == color2);
QVERIFY(packed.size() == 3);
color = QColor(100, 200, 255);
packed = MsgPack::pack(color);
color2 = MsgPack::unpack(packed).value<QColor>();
QVERIFY(color == color2);
QVERIFY(packed.size() == 6);
}
#endif
#ifdef QT_LOCATION_LIB
void QtTypesTest::test_qgeocoordinte()
{
MsgPack::registerType((QMetaType::Type)qMetaTypeId<QGeoCoordinate>(), 0x76);
QGeoCoordinate c;
QByteArray packed = MsgPack::pack(QVariant::fromValue(c));
QGeoCoordinate c2 = MsgPack::unpack(packed).value<QGeoCoordinate>();
QVERIFY(c == c2);
QVERIFY(packed.size() == 3);
}
#endif
void QtTypesTest::test_qtime()
{
MsgPack::registerType(QMetaType::QTime, 0x77);
@ -23,7 +68,7 @@ void QtTypesTest::test_qtime()
QByteArray packed = MsgPack::pack(t);
QTime t2 = MsgPack::unpack(packed).toTime();
QVERIFY(t == t2);
QVERIFY(packed.size() == 1);
QVERIFY(packed.size() == 3);
t = QTime(12, 01, 01, 0);
packed = MsgPack::pack(t);
@ -51,7 +96,7 @@ void QtTypesTest::test_qdate()
QByteArray packed = MsgPack::pack(d);
QDate d2 = MsgPack::unpack(packed).toDate();
QVERIFY(d == d2);
QVERIFY(packed.size() == 1);
QVERIFY(packed.size() == 3);
d = QDate(1234, 12, 1);
packed = MsgPack::pack(d);
@ -64,13 +109,35 @@ void QtTypesTest::test_qdate()
QVERIFY(d == d2);
}
void QtTypesTest::test_qdatetime()
{
MsgPack::registerType(QMetaType::QDateTime, 3);
QDateTime dt;
QByteArray packed = MsgPack::pack(dt);
QVERIFY(packed.size() == 3);
QDateTime dt2 = MsgPack::unpack(packed).toDateTime();
QVERIFY(dt == dt2);
dt = QDateTime(QDate(1234, 12, 1), QTime(12, 34, 56));
packed = MsgPack::pack(dt);
QVERIFY(packed.size() == 8);
dt2 = MsgPack::unpack(packed).toDateTime();
QVERIFY(dt == dt2);
dt = QDateTime(QDate(1234, 12, 1), QTime(12, 34, 56, 789));
packed = MsgPack::pack(dt);
QVERIFY(packed.size() == 10);
dt2 = MsgPack::unpack(packed).toDateTime();
QVERIFY(dt == dt2);
}
void QtTypesTest::test_qpoint()
{
MsgPack::registerType(QMetaType::QPoint, 0x79);
QPoint pt;
QByteArray packed = MsgPack::pack(pt);
QVERIFY(packed.size() == 1);
QVERIFY(packed.size() == 3);
QPoint pt2 = MsgPack::unpack(packed).toPoint();
QVERIFY(pt == pt2);
@ -99,7 +166,7 @@ void QtTypesTest::test_qsize()
QSize sz;
QByteArray packed = MsgPack::pack(sz);
// QVERIFY(packed.size() == 1);
QVERIFY(packed.size() == 3);
QSize sz2 = MsgPack::unpack(packed).toSize();
QVERIFY(sz == sz2);
@ -121,7 +188,7 @@ void QtTypesTest::test_qrect()
MsgPack::registerType(QMetaType::QRect, 81);
QRect r;
QByteArray packed = MsgPack::pack(r);
QVERIFY(packed.size() == 1);
QVERIFY(packed.size() == 3);
QRect r2 = MsgPack::unpack(packed).toRect();
QVERIFY(r == r2);

View File

@ -3,6 +3,8 @@
#include <QDebug>
#include <msgpackstream.h>
#include <msgpack.h>
#include <stream/time.h>
#include <stream/geometry.h>
#include <limits>
class StreamTest : public QObject
@ -18,6 +20,9 @@ private Q_SLOTS:
void test_double();
void test_bin();
void test_array();
void test_ext();
void test_time();
void test_geometry();
};
void StreamTest::test_unpack_integers()
@ -367,5 +372,357 @@ void StreamTest::test_array()
}
}
void StreamTest::test_ext()
{
{
QByteArray ba;
MsgPackStream out(&ba, QIODevice::WriteOnly);
out.writeExtHeader(1, 7);
QVERIFY(out.status() == MsgPackStream::Ok);
quint8 *p = (quint8 *)ba.data();
QVERIFY(ba.length() == 2);
QVERIFY(p[0] == 0xd4);
QVERIFY(p[1] == 7);
MsgPackStream in(ba);
quint32 len;
QVERIFY(in.readExtHeader(len));
QVERIFY(in.status() == MsgPackStream::Ok);
QVERIFY(len == 1);
QVERIFY(in.device()->pos() == 2);
}
{
QByteArray ba;
MsgPackStream out(&ba, QIODevice::WriteOnly);
out.writeExtHeader(17, 7);
QVERIFY(out.status() == MsgPackStream::Ok);
quint8 *p = (quint8 *)ba.data();
QVERIFY(ba.length() == 3);
QVERIFY(p[0] == 0xc7);
QVERIFY(p[2] == 7);
MsgPackStream in(ba);
quint32 len;
QVERIFY(in.readExtHeader(len));
QVERIFY(in.status() == MsgPackStream::Ok);
QVERIFY(len == 17);
QVERIFY(in.device()->pos() == 3);
}
{
QByteArray ba;
MsgPackStream out(&ba, QIODevice::WriteOnly);
out.writeExtHeader(256, 7);
QVERIFY(out.status() == MsgPackStream::Ok);
quint8 *p = (quint8 *)ba.data();
QVERIFY(ba.length() == 4);
QVERIFY(p[0] == 0xc8);
QVERIFY(p[3] == 7);
MsgPackStream in(ba);
quint32 len;
QVERIFY(in.readExtHeader(len));
QVERIFY(in.status() == MsgPackStream::Ok);
QVERIFY(len == 256);
QVERIFY(in.device()->pos() == 4);
}
{
QByteArray ba;
MsgPackStream out(&ba, QIODevice::WriteOnly);
out.writeExtHeader(65536, 7);
QVERIFY(out.status() == MsgPackStream::Ok);
quint8 *p = (quint8 *)ba.data();
QVERIFY(ba.length() == 6);
QVERIFY(p[0] == 0xc9);
QVERIFY(p[5] == 7);
MsgPackStream in(ba);
quint32 len;
QVERIFY(in.readExtHeader(len));
QVERIFY(in.status() == MsgPackStream::Ok);
QVERIFY(len == 65536);
QVERIFY(in.device()->pos() == 6);
}
}
void StreamTest::test_time()
{
MsgPack::registerType(QMetaType::QTime, 3);
MsgPack::registerType(QMetaType::QDate, 4);
MsgPack::registerType(QMetaType::QDateTime, 5);
{
QTime t;
QByteArray ba;
MsgPackStream out(&ba, QIODevice::WriteOnly);
out << t;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(ba.length() == 3);
MsgPackStream in(ba);
QTime t2;
in >> t2;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(t == t2);
}
{
QTime t = QTime(12, 01, 01, 0);
QByteArray ba;
MsgPackStream out(&ba, QIODevice::WriteOnly);
out << t;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(ba.length() == 4);
MsgPackStream in(ba);
QTime t2;
in >> t2;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(t == t2);
}
{
QTime t = QTime(12, 59, 59, 0);
QByteArray ba;
MsgPackStream out(&ba, QIODevice::WriteOnly);
out << t;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(ba.length() == 4);
MsgPackStream in(ba);
QTime t2;
in >> t2;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(t == t2);
}
{
QTime t = QTime(12, 34, 56, 789);
QByteArray ba;
MsgPackStream out(&ba, QIODevice::WriteOnly);
out << t;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(ba.length() == 6);
MsgPackStream in(ba);
QTime t2;
in >> t2;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(t == t2);
}
{
QDate d;
QByteArray ba;
MsgPackStream out(&ba, QIODevice::WriteOnly);
out << d;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(ba.length() == 3);
MsgPackStream in(ba);
QDate d2;
in >> d2;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(d == d2);
}
{
QDate d = QDate(1234, 12, 1);
QByteArray ba;
MsgPackStream out(&ba, QIODevice::WriteOnly);
out << d;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(ba.length() == 6);
MsgPackStream in(ba);
QDate d2;
in >> d2;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(d == d2);
}
{
QDate d = QDate(9999, 1, 31);
QByteArray ba;
MsgPackStream out(&ba, QIODevice::WriteOnly);
out << d;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(ba.length() == 6);
MsgPackStream in(ba);
QDate d2;
in >> d2;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(d == d2);
}
{
QDateTime dt;
QByteArray ba;
MsgPackStream out(&ba, QIODevice::WriteOnly);
out << dt;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(ba.length() == 3);
MsgPackStream in(ba);
QDateTime dt2;
in >> dt2;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(dt == dt2);
}
{
QDateTime dt(QDate(1234, 12, 1), QTime(12, 34, 56));
QByteArray ba;
MsgPackStream out(&ba, QIODevice::WriteOnly);
out << dt;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(ba.length() == 8);
MsgPackStream in(ba);
QDateTime dt2;
in >> dt2;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(dt == dt2);
}
{
QDateTime dt(QDate(1234, 12, 1), QTime(12, 34, 56, 789));
QByteArray ba;
MsgPackStream out(&ba, QIODevice::WriteOnly);
out << dt;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(ba.length() == 10);
MsgPackStream in(ba);
QDateTime dt2;
in >> dt2;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(dt == dt2);
}
}
void StreamTest::test_geometry()
{
MsgPack::registerType(QMetaType::QPoint, 6);
MsgPack::registerType(QMetaType::QSize, 7);
MsgPack::registerType(QMetaType::QRect, 8);
{
QPoint pt;
QByteArray ba;
MsgPackStream out(&ba, QIODevice::WriteOnly);
out << pt;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(ba.length() == 3);
MsgPackStream in(ba);
QPoint pt2;
in >> pt2;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(pt == pt2);
}
{
QPoint pt(1, 2);
QByteArray ba;
MsgPackStream out(&ba, QIODevice::WriteOnly);
out << pt;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(ba.length() == 4);
MsgPackStream in(ba);
QPoint pt2;
in >> pt2;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(pt == pt2);
}
{
QPoint pt(1234, 5678);
QByteArray ba;
MsgPackStream out(&ba, QIODevice::WriteOnly);
out << pt;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(ba.length() == 9);
MsgPackStream in(ba);
QPoint pt2;
in >> pt2;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(pt == pt2);
}
{
QSize sz;
QByteArray ba;
MsgPackStream out(&ba, QIODevice::WriteOnly);
out << sz;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(ba.length() == 3);
MsgPackStream in(ba);
QSize sz2;
in >> sz2;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(sz == sz2);
}
{
QSize sz(1, 2);
QByteArray ba;
MsgPackStream out(&ba, QIODevice::WriteOnly);
out << sz;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(ba.length() == 4);
MsgPackStream in(ba);
QSize sz2;
in >> sz2;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(sz == sz2);
}
{
QSize sz(1234, 5678);
QByteArray ba;
MsgPackStream out(&ba, QIODevice::WriteOnly);
out << sz;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(ba.length() == 9);
MsgPackStream in(ba);
QSize sz2;
in >> sz2;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(sz == sz2);
}
{
QRect rect;
QByteArray ba;
MsgPackStream out(&ba, QIODevice::WriteOnly);
out << rect;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(ba.length() == 3);
MsgPackStream in(ba);
QRect rect2;
in >> rect2;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(rect == rect2);
}
{
QRect rect(1, 2, 3, 4);
QByteArray ba;
MsgPackStream out(&ba, QIODevice::WriteOnly);
out << rect;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(ba.length() == 6);
MsgPackStream in(ba);
QRect rect2;
in >> rect2;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(rect == rect2);
}
{
QRect rect(0, 0, 65536, 65536);
QByteArray ba;
MsgPackStream out(&ba, QIODevice::WriteOnly);
out << rect;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(ba.length() == 15);
MsgPackStream in(ba);
QRect rect2;
in >> rect2;
QVERIFY(out.status() == MsgPackStream::Ok);
QVERIFY(rect == rect2);
}
}
QTEST_APPLESS_MAIN(StreamTest)
#include "stream_test.moc"