Merge pull request #13 from romixlab/qt_types

Qt types, MsgPackStream
This commit is contained in:
Roman
2015-06-29 20:35:45 +03:00
26 changed files with 2109 additions and 90 deletions

6
.gitignore vendored
View File

@@ -1,5 +1,7 @@
*.pro.user
*.pro.user*
build
lib
Makefile
Makefile*
*.autosave
bin/
*.o

View File

@@ -16,6 +16,7 @@ before_install:
script:
- mkdir build
- cd build
- cmake ..
- 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

View File

@@ -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 ()
@@ -63,10 +80,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

@@ -1,5 +1,5 @@
set(qmsgpack_srcs msgpack.cpp msgpack_common.cpp private/pack_p.cpp private/unpack_p.cpp)
set(qmsgpack_headers msgpack.h msgpack_common.h msgpack_export.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})
@@ -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"

34
src/CMakeLists.txt~ Normal file
View File

@@ -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)

View File

@@ -6,7 +6,7 @@
QT += core
QT -= gui
QT += gui
TARGET = qmsgpack
CONFIG -= app_bundle
@@ -26,7 +26,9 @@ 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 \
stream.cpp
HEADERS += \
msgpack.h \
@@ -34,4 +36,6 @@ HEADERS += \
private/unpack_p.h \
private/sysdep.h \
msgpack_common.h \
msgpack_export.h
msgpack_export.h \
private/qt_types_p.h \
stream.h

View File

@@ -2,6 +2,8 @@
#include "msgpack_common.h"
#include "private/unpack_p.h"
#include "private/pack_p.h"
#include "private/qt_types_p.h"
#include <QVector>
QVariant MsgPack::unpack(const QByteArray &data)
{
@@ -14,13 +16,14 @@ QVariant MsgPack::unpack(const QByteArray &data)
QByteArray MsgPack::pack(const QVariant &variant)
{
quint8 *p = 0;
quint8 *end = MsgPackPrivate::pack(variant, p, false);
QVector<QByteArray> 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;
}
@@ -35,6 +38,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;

View File

@@ -5,7 +5,7 @@
#include "msgpack_export.h"
#include <QByteArray>
#include <QMetaType>
#include <QVariantList>
namespace MsgPack
{
@@ -15,7 +15,22 @@ 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);
}
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

View File

@@ -2,6 +2,7 @@
#define COMMON_H
#include <QVariant>
#include <QtGlobal>
#define MSGPACK_MAJOR 0
#define MSGPACK_MINOR 1
@@ -9,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);
/**
@@ -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 = 0x7f;
const quint8 FIXMAP = 0x80;
const quint8 FIXARRAY = 0x90;
const quint8 FIXSTR = 0xa0;
const quint8 NIL = 0xc0;
const quint8 NEVER_USED = 0xc1;
const quint8 MFALSE = 0xc2;
const quint8 MTRUE = 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 ARRAY16 = 0xdc;
const quint8 ARRAY32 = 0xdd;
const quint8 MAP16 = 0xde;
const quint8 MAP32 = 0xdf;
const quint8 NEGATIVE_FIXINT = 0xe0;
}
}
#endif // COMMON_H

View File

@@ -2,6 +2,7 @@
#define COMMON_H
#include <QVariant>
#include <QtGlobal>
#define MSGPACK_MAJOR @QMSGPACK_MAJOR@
#define MSGPACK_MINOR @QMSGPACK_MINOR@
@@ -9,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);
/**
@@ -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 = 0x7f;
const quint8 FIXMAP = 0x80;
const quint8 FIXARRAY = 0x90;
const quint8 FIXSTR = 0xa0;
const quint8 NIL = 0xc0;
const quint8 NEVER_USED = 0xc1;
const quint8 MFALSE = 0xc2;
const quint8 MTRUE = 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 ARRAY16 = 0xdc;
const quint8 ARRAY32 = 0xdd;
const quint8 MAP16 = 0xde;
const quint8 MAP32 = 0xdf;
const quint8 NEGATIVE_FIXINT = 0xe0;
}
}
#endif // COMMON_H

551
src/msgpackstream.cpp Normal file
View File

@@ -0,0 +1,551 @@
#include "msgpackstream.h"
#include "private/pack_p.h"
#include <QBuffer>
#include <QDebug>
#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), owndev(false), q_status(Ok)
{ }
MsgPackStream::MsgPackStream(QIODevice *d) :
dev(d), owndev(false), q_status(Ok)
{ }
MsgPackStream::MsgPackStream(QByteArray *a, QIODevice::OpenMode mode) :
owndev(true), q_status(Ok)
{
QBuffer *buf = new QBuffer(a);
buf->open(mode);
dev = buf;
}
MsgPackStream::MsgPackStream(const QByteArray &a) :
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;
}
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>>(bool &b)
{
CHECK_STREAM_PRECOND(*this)
quint8 p[1];
if (!dev->getChar((char *)p)) {
b = false;
setStatus(ReadPastEnd);
} else {
if (p[0] != MsgPack::FirstByte::MTRUE ||
p[0] != MsgPack::FirstByte::MFALSE)
setStatus(ReadCorruptData);
b = (p[0] == MsgPack::FirstByte::MTRUE);
}
return *this;
}
MsgPackStream &MsgPackStream::operator >>(quint8 &u8)
{
CHECK_STREAM_PRECOND(*this);
quint64 u64;
if (unpack_ulonglong(u64) && u64 <= std::numeric_limits<quint8>::max())
u8 = u64;
else
setStatus(ReadCorruptData);
return *this;
}
MsgPackStream &MsgPackStream::operator>>(quint16 &u16)
{
CHECK_STREAM_PRECOND(*this);
quint64 u64;
if (unpack_ulonglong(u64) && u64 <= std::numeric_limits<quint16>::max())
u16 = u64;
else
setStatus(ReadCorruptData);
return *this;
}
MsgPackStream &MsgPackStream::operator>>(quint32 &u32)
{
CHECK_STREAM_PRECOND(*this);
quint64 u64;
if (unpack_ulonglong(u64) && u64 <= std::numeric_limits<quint32>::max())
u32 = u64;
else
setStatus(ReadCorruptData);
return *this;
}
MsgPackStream &MsgPackStream::operator>>(quint64 &u64)
{
CHECK_STREAM_PRECOND(*this);
unpack_ulonglong(u64);
return *this;
}
MsgPackStream &MsgPackStream::operator>>(qint8 &i8)
{
CHECK_STREAM_PRECOND(*this);
qint64 i64;
if (!unpack_longlong(i64))
return *this;
if (i64 >= std::numeric_limits<qint8>::min() &&
i64 <= std::numeric_limits<qint8>::max())
i8 = i64;
else
setStatus(ReadCorruptData);
return *this;
}
MsgPackStream &MsgPackStream::operator>>(qint16 &i16)
{
CHECK_STREAM_PRECOND(*this);
qint64 i64;
if (!unpack_longlong(i64))
return *this;
if (i64 >= std::numeric_limits<qint16>::min() &&
i64 <= std::numeric_limits<qint16>::max())
i16 = i64;
else
setStatus(ReadCorruptData);
return *this;
}
MsgPackStream &MsgPackStream::operator>>(qint32 &i32)
{
CHECK_STREAM_PRECOND(*this);
qint64 i64;
if (!unpack_longlong(i64))
return *this;
if (i64 >= std::numeric_limits<qint32>::min() &&
i64 <= std::numeric_limits<qint32>::max())
i32 = i64;
else
setStatus(ReadCorruptData);
return *this;
}
MsgPackStream &MsgPackStream::operator>>(qint64 &i64)
{
CHECK_STREAM_PRECOND(*this);
unpack_longlong(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;
}
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);
#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 *)&d;
quint8 p[9];
if (dev->read((char *)p, 1) != 1) {
setStatus(ReadPastEnd);
return *this;
}
if (p[0] != MsgPack::FirstByte::FLOAT64) {
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);
#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);
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;
}
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;
return *this;
}
MsgPackStream &MsgPackStream::operator>>(QByteArray &array)
{
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;
}
bool MsgPackStream::readBytes(char *data, uint len)
{
CHECK_STREAM_PRECOND(false);
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::MTRUE : MsgPack::FirstByte::MFALSE;
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<<(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;
}
MsgPackStream &MsgPackStream::operator<<(qint32 i32)
{
CHECK_STREAM_WRITE_PRECOND(*this);
quint8 p[5];
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;
}
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_double(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);
quint8 *p = (quint8 *)0;
quint32 sz = MsgPackPrivate::pack_string(str, p, false) - p;
quint8 *data = new quint8[sz];
MsgPackPrivate::pack_string(str, data, true);
if (dev->write((char *)data, sz) != sz)
setStatus(WriteFailed);
delete[] data;
return *this;
}
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;
}
MsgPackStream &MsgPackStream::operator<<(QByteArray array)
{
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::writeBytes(const char *data, uint len)
{
CHECK_STREAM_WRITE_PRECOND(false);
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;
}
bool MsgPackStream::unpack_longlong(qint64 &i64)
{
quint8 p[9];
if (dev->read((char *)p, 1) != 1) {
setStatus(ReadPastEnd);
return false;
}
if (p[0] <= 127) {// positive fixint 0x00 - 0x7f
i64 = p[0];
return true;
} else if (*p >= 0xe0) { // negative fixint 0xe0 - 0xff
i64 = (qint8)p[0];
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) {
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<qint64>::max()) {
setStatus(ReadCorruptData);
return false;
}
i64 = u64;
} else if (p[0] == MsgPack::FirstByte::INT64) {
i64 = _msgpack_load64(qint64, p + 1);
}
return true;
}
bool MsgPackStream::unpack_ulonglong(quint64 &u64)
{
quint8 p[9];
if (dev->read((char *)p, 1) != 1) {
setStatus(ReadPastEnd);
return false;
}
if (p[0] <= 127) {// positive fixint 0x00 - 0x7f
u64 = p[0];
return true;
} else if (*p >= 0xe0) { // negative fixint 0xe0 - 0xff
return false;
}
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;
}

245
src/msgpackstream.h Normal file
View File

@@ -0,0 +1,245 @@
#ifndef STREAM_H
#define STREAM_H
#include <QIODevice>
#include <limits>
#include "msgpack_common.h"
#include "endianhelper.h"
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;
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);
bool readBytes(char *data, uint len);
bool readNil();
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<<(const char *str);
MsgPackStream &operator<<(QByteArray array);
bool writeBytes(const char *data, uint len);
bool writeNil();
private:
QIODevice *dev;
bool owndev;
Status q_status;
bool unpack_longlong(qint64 &i64);
bool unpack_ulonglong(quint64 &u64);
};
template <typename T>
MsgPackStream& operator<<(MsgPackStream& s, const QList<T> &list)
{
quint32 len = list.size();
quint8 p[5];
if (len <= 15) {
p[0] = MsgPack::FirstByte::FIXARRAY | len;
s.writeBytes((const char *)p, 1);
} else if (len <= std::numeric_limits<quint16>::max()) {
p[0] = MsgPack::FirstByte::ARRAY16;
_msgpack_store16(p + 1, len);
s.writeBytes((const char *)p, 3);
} else {
p[0] = MsgPack::FirstByte::ARRAY32;
_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;
}
template <typename T>
MsgPackStream& operator>>(MsgPackStream& s, QList<T> &list)
{
list.clear();
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);
if (s.atEnd())
break;
}
return s;
}
template <class Key, class T>
MsgPackStream& operator<<(MsgPackStream &s, const QHash<Key, T> &hash)
{
quint32 len = 0;
QHashIterator<Key, T> 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<quint16>::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 <class Key, class T>
MsgPackStream& operator>>(MsgPackStream& s, QHash<Key, T> &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 <class Key, class T>
MsgPackStream& operator<<(MsgPackStream &s, const QMap<Key, T> &map)
{
quint32 len = 0;
QMapIterator<Key, T> 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<quint16>::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 <class Key, class T>
MsgPackStream& operator>>(MsgPackStream& s, QMap<Key, T> &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;
}
#endif // STREAM_H

View File

@@ -1,5 +1,5 @@
#include "pack_p.h"
#include "private/sysdep.h"
#include "../endianhelper.h"
#include <QByteArray>
#include <QDebug>
@@ -9,10 +9,14 @@
#include <limits>
#include <QReadLocker>
#include <QWriteLocker>
QHash<QMetaType::Type, MsgPackPrivate::packer_t> 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<QByteArray> &user_data)
{
QMetaType::Type t = (QMetaType::Type)v.type();
if (t == QMetaType::Int)
@@ -24,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)
@@ -33,16 +37,14 @@ quint8 *MsgPackPrivate::pack(const QVariant &v, quint8 *p, bool wr)
p = pack_ulonglong(v.toULongLong(), p, wr);
else if (t == QMetaType::Double)
p = pack_double(v.toDouble(), p, wr);
else if (t == QMetaType::Float)
p = pack_float(v.toFloat(), p, wr);
else if (t == QMetaType::QByteArray)
p = pack_bin(v.toByteArray(), p, wr);
else if (t == QMetaType::QVariantMap)
p = pack_map(v.toMap(), p, wr);
else {
if (user_packers.contains(t))
p = pack_user(v, p, wr);
p = pack_map(v.toMap(), p, wr, user_data);
else
qWarning() << "MsgPack::pack can't pack type:" << t;
}
p = pack_user(v, p, wr, user_data);
return p;
}
@@ -148,12 +150,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<QByteArray> &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;
}
@@ -166,9 +168,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++;
@@ -189,11 +190,35 @@ 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_float(float f, quint8 *p, bool wr)
{
if (wr) *p = 0xca;
p++;
if (wr) {
quint8 *d = (quint8 *)&f;
#ifdef __LITTLE_ENDIAN__
for (int i = 0; i < 4; ++i)
*(p + 3 - i) = *(d + i);
#else
for (int i = 0; i < 4; ++i)
*(p + i) = *(d + i);
#endif
}
return p + 4;
}
quint8 *MsgPackPrivate::pack_double(double i, quint8 *p, bool wr)
{
if (wr) *p = 0xcb;
@@ -211,9 +236,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<quint8>::max()) {
if (wr) *p = compatibilityMode ? 0xd9 : 0xc4;
p++;
@@ -230,14 +254,20 @@ 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;
}
quint8 *MsgPackPrivate::pack_map(const QVariantMap &map, quint8 *p, bool wr)
quint8 *MsgPackPrivate::pack_map(const QVariantMap &map, quint8 *p, bool wr, QVector<QByteArray> &user_data)
{
QMapIterator<QString, QVariant> it(map);
int len = 0;
@@ -263,23 +293,23 @@ 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;
}
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;
}
QWriteLocker locker(&packers_lock);
if (user_packers.contains(q_type)) {
qWarning() << "MsgPack::packer for qtype" << q_type << "already exist";
return false;
}
packer_t p;
p.packer = packer;
p.type = msgpack_type;
@@ -287,13 +317,34 @@ 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<QByteArray> &user_data)
{
QMetaType::Type t = (QMetaType::Type)v.type() == QMetaType::User ?
(QMetaType::Type)v.userType() : (QMetaType::Type)v.type();
QByteArray data;
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];
quint32 len = pt.packer(v, data, wr);
locker.unlock();
QByteArray data;
if (wr) {
data = user_data.front();
user_data.pop_front();
} else {
data = pt.packer(v);
user_data.push_back(data);
}
quint32 len = data.size();
if (len == 1) {
if (wr) *p = 0xd4;
p++;
@@ -331,4 +382,3 @@ quint8 *MsgPackPrivate::pack_user(const QVariant &v, quint8 *p, bool wr)
memcpy(p, data.data(), len);
return p += len;
}

View File

@@ -5,6 +5,7 @@
#include <QHash>
#include <QMetaType>
#include <QReadWriteLock>
class QByteArray;
class QString;
@@ -19,9 +20,10 @@ typedef struct {
} packer_t;
bool register_packer(QMetaType::Type q_type, qint8 msgpack_type, MsgPack::pack_user_f packer);
extern QHash<QMetaType::Type, packer_t> 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<QByteArray> &user_data);
quint8 * pack_int(qint32 i, quint8 *p, bool wr);
quint8 * pack_uint(quint32 i, quint8 *p, bool wr);
@@ -31,14 +33,17 @@ 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<QByteArray> &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_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);
quint8 * pack_user(const QVariant &v, quint8 *p, bool wr);
quint8 * pack_map(const QVariantMap &map, quint8 *p, bool wr, QVector<QByteArray> &user_data);
quint8 * pack_user(const QVariant &v, quint8 *p, bool wr, QVector<QByteArray> &user_data);
}
#endif // PACK_P_H

251
src/private/qt_types_p.cpp Normal file
View File

@@ -0,0 +1,251 @@
#include "qt_types_p.h"
#include "pack_p.h"
#include "unpack_p.h"
#include "msgpackstream.h"
#include "endianhelper.h"
#include <QDebug>
#ifdef QT_GUI_LIB
#include <QColor>
#endif
#define NO_QTGUI_WARNING "Library built without QtGui, hence some types are not available"
#include <QTime>
#include <QRect>
bool MsgPackPrivate::register_qtype(QMetaType::Type q_type, quint8 msgpack_type)
{
if (q_type == QMetaType::QColor) {
#ifdef QT_GUI_LIB
MsgPackPrivate::register_packer(q_type, msgpack_type, pack_qcolor);
MsgPackPrivate::register_unpacker(msgpack_type, unpack_qcolor);
#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);
} 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;
}
#ifdef QT_GUI_LIB
QByteArray MsgPackPrivate::pack_qcolor(const QVariant &variant)
{
QByteArray data;
data.resize(4);
QColor color = variant.value<QColor>();
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)
{
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)
{
quint8 hm = 0, ms = 0;
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);
}
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);
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.isNull())
return QByteArray("\xc0", 1);
QByteArray data;
data.resize(3);
pack_qdate_raw(variant.toDate(), (quint8 *)data.data());
return data;
}
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);
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)
{
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);
return QDateTime(d, t);
}
// 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);
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;
return QPoint(x, y);
}
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);
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;
return QSize(width, height);
}
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;
MsgPackStream stream(&packed, QIODevice::WriteOnly);
stream << pt1.x() << pt1.y() << pt2.x() << pt2.y();
return packed;
}
QVariant MsgPackPrivate::unpack_qrect(const QByteArray &data)
{
if (data.size() == 1)
return QRect();
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;
}

59
src/private/qt_types_p.h Normal file
View File

@@ -0,0 +1,59 @@
#ifndef QT_TYPES_P_H
#define QT_TYPES_P_H
#include <QVariant>
#include <QByteArray>
namespace MsgPackPrivate
{
bool register_qtype(QMetaType::Type q_type, quint8 msgpack_type);
#ifdef QT_GUI_LIB
QByteArray pack_qcolor(const QVariant &variant);
QVariant unpack_qcolor(const QByteArray &data);
#endif //QT_GUI_LIB
// Date and Time
/**
* @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);
QByteArray pack_qtime(const QVariant &variant);
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);
QByteArray pack_qdate(const QVariant &variant);
QVariant unpack_qdate(const QByteArray &data);
QByteArray pack_qdatetime(const QVariant &variant);
QVariant unpack_qdatetime(const QByteArray &data);
// Points and Vectors
QByteArray pack_qpoint(const QVariant &variant);
QVariant unpack_qpoint(const QByteArray &data);
QByteArray pack_qsize(const QVariant &variant);
QVariant unpack_qsize(const QByteArray &data);
QByteArray pack_qrect(const QVariant &variant);
QVariant unpack_qrect(const QByteArray &data);
} // MsgPackPrivate
#endif // QT_TYPES_P_H

View File

@@ -1,10 +1,13 @@
#include "unpack_p.h"
#include "sysdep.h"
#include "../endianhelper.h"
#include <QByteArray>
#include <QDebug>
#include <QMap>
#include <QReadLocker>
#include <QWriteLocker>
MsgPackPrivate::type_parser_f MsgPackPrivate::unpackers[32] = {
unpack_nil,
unpack_never_used,
@@ -21,6 +24,7 @@ MsgPackPrivate::type_parser_f MsgPackPrivate::unpackers[32] = {
};
QHash<qint8, MsgPack::unpack_user_f> MsgPackPrivate::user_unpackers;
QReadWriteLock MsgPackPrivate::unpackers_lock;
QVariant MsgPackPrivate::unpack(quint8 *p, quint8 *end)
{
@@ -143,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;
}
@@ -179,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;
@@ -314,6 +318,7 @@ quint8 * MsgPackPrivate::unpack_map32(QVariant &v, quint8 *p)
quint8 *MsgPackPrivate::unpack_ext(QVariant &v, quint8 *p, qint8 type, quint32 len)
{
QReadLocker locker(&unpackers_lock);
if (!user_unpackers.contains(type)) {
qWarning() << "MsgPack::unpack() unpacker for type" << type << "doesn't exist";
return p + len;
@@ -382,14 +387,15 @@ 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;
}
QWriteLocker locker(&unpackers_lock);
if (user_unpackers.contains(msgpack_type)) {
qWarning() << "MsgPack::unpacker for type" << msgpack_type << "already exists";
return false;
}
user_unpackers.insert(msgpack_type, unpacker);
return true;
}

View File

@@ -5,6 +5,7 @@
#include <QHash>
#include <QVariant>
#include <QReadWriteLock>
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<qint8, MsgPack::unpack_user_f> user_unpackers;
extern QReadWriteLock unpackers_lock;
// goes from p to end unpacking types with unpack_type function below
QVariant unpack(quint8 *p, quint8 *end);

View File

@@ -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 stream)
foreach(subdir ${TEST_SUBDIRS})
add_subdirectory(${subdir})

View File

@@ -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;
@@ -66,17 +140,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<CustomType>();
if (write) {
QByteArray data;
data.resize(ct.size());
quint8 *p = (quint8 *)data.data();
for (int i = 0; i < ct.size(); ++i)
p[i] = 7;
}
return ct.size();
return data;
}
QVariant unpack_custom_type(const QByteArray &data)
@@ -90,9 +162,11 @@ void MixedTest::test_ext()
QVariant custom;
custom.setValue(ct);
MsgPack::registerPacker((QMetaType::Type)qMetaTypeId<CustomType>(),
bool packer_registered = MsgPack::registerPacker((QMetaType::Type)qMetaTypeId<CustomType>(),
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());

View File

@@ -216,14 +216,14 @@ void PackTest::test_float()
void PackTest::test_str()
{
QString str = QString::fromUtf8("msgpack rocks");
QString str = QString("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();
@@ -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();

View File

@@ -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()

View File

@@ -0,0 +1,144 @@
#include <QString>
#include <QtTest>
#include <QDebug>
#include <msgpack.h>
#include <limits>
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;
QByteArray packed = MsgPack::pack(t);
QTime t2 = MsgPack::unpack(packed).toTime();
QVERIFY(t == t2);
QVERIFY(packed.size() == 3); // user, type, 0xc0
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 = QDate();
QByteArray packed = MsgPack::pack(d);
QDate d2 = MsgPack::unpack(packed).toDate();
QVERIFY(d == d2);
QVERIFY(packed.size() == 3); // user, type, 0xc0
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;
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);
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<qint32>::max(), std::numeric_limits<qint32>::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;
QByteArray packed = MsgPack::pack(sz);
// 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);
sz2 = MsgPack::unpack(packed).toSize();
QVERIFY(sz == sz2);
}
void QtTypesTest::test_qrect()
{
MsgPack::registerType(QMetaType::QRect, 81);
QRect r;
QByteArray packed = MsgPack::pack(r);
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<qint32>::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"

View File

@@ -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()

View File

@@ -0,0 +1,413 @@
#include <QString>
#include <QtTest>
#include <msgpackstream.h>
#include <msgpack.h>
#include <limits>
class StreamTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
void test_unpack_integers();
void test_pack_integers();
void test_unpack_string();
void test_pack_string();
void test_float();
void test_double();
void test_bin();
void test_array();
void test_map();
};
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<quint64>::max());
stream >> i64;
QVERIFY(stream.status() == MsgPackStream::Ok);
QVERIFY(i64 == -2147483649);
stream >> i64;
QVERIFY(stream.status() == MsgPackStream::Ok);
QVERIFY(i64 == std::numeric_limits<qint64>::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<quint64>::max();
QVERIFY(stream.status() == MsgPackStream::Ok);
stream << (qint64)-2147483649;
QVERIFY(stream.status() == MsgPackStream::Ok);
stream << std::numeric_limits<qint64>::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<quint64>::max());
QVERIFY(l[18].toLongLong() == -2147483649);
QVERIFY(l[19].toLongLong() == std::numeric_limits<qint64>::min());
}
void StreamTest::test_unpack_string()
{
QString str = QString("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());
}
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);
}
void StreamTest::test_array()
{
{
QList<qint64> 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<qint64>::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<qint64> 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<quint64> list;
list << 6;
list << std::numeric_limits<quint64>::min();
list << std::numeric_limits<quint64>::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<quint64> 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]);
}
}
void StreamTest::test_map()
{
QMap<QString, int> 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"