mirror of
https://github.com/romixlab/qmsgpack.git
synced 2025-08-01 03:14:27 +02:00
6
.gitignore
vendored
6
.gitignore
vendored
@@ -1,5 +1,7 @@
|
||||
*.pro.user
|
||||
*.pro.user*
|
||||
build
|
||||
lib
|
||||
Makefile
|
||||
Makefile*
|
||||
*.autosave
|
||||
bin/
|
||||
*.o
|
||||
|
@@ -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
|
||||
|
@@ -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,14 +80,14 @@ set(MSGPACK_QT_LIB_VERSION_STRING "${QMSGPACK_MAJOR}.${QMSGPACK_MINOR}.${QMSGPAC
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
|
||||
|
||||
add_subdirectory(src)
|
||||
#if (MSGPACK_BUILD_TESTS)
|
||||
if (BUILD_TESTS)
|
||||
enable_testing()
|
||||
add_subdirectory(tests)
|
||||
#endif ()
|
||||
endif ()
|
||||
|
||||
install(EXPORT qmsgpack-export DESTINATION ${CMAKECONFIG_INSTALL_DIR} FILE MsgPackQtTargets.cmake)
|
||||
|
||||
file(RELATIVE_PATH relInstallDir ${CMAKE_INSTALL_PREFIX}/$CMAKECONFIG_INSTALL_DIR} ${CMAKE_INSTALL_PREFIX})
|
||||
|
||||
add_custom_target(uninstall
|
||||
"${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
|
||||
"${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
|
||||
|
@@ -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"
|
||||
@@ -27,4 +31,4 @@ install(TARGETS qmsgpack EXPORT qmsgpack-export
|
||||
LIBRARY DESTINATION ${LIB_INSTALL_DIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin
|
||||
ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
|
||||
PUBLIC_HEADER DESTINATION ${INCLUDE_INSTALL_DIR}/qmsgpack)
|
||||
PUBLIC_HEADER DESTINATION ${INCLUDE_INSTALL_DIR}/qmsgpack)
|
||||
|
34
src/CMakeLists.txt~
Normal file
34
src/CMakeLists.txt~
Normal 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)
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
551
src/msgpackstream.cpp
Normal 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
245
src/msgpackstream.h
Normal 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
|
@@ -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);
|
||||
else
|
||||
qWarning() << "MsgPack::pack can't pack type:" << t;
|
||||
}
|
||||
p = pack_map(v.toMap(), p, wr, user_data);
|
||||
else
|
||||
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;
|
||||
}
|
||||
|
||||
|
@@ -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
251
src/private/qt_types_p.cpp
Normal 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
59
src/private/qt_types_p.h
Normal 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
|
@@ -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;
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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})
|
||||
|
@@ -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) {
|
||||
data.resize(ct.size());
|
||||
quint8 *p = (quint8 *)data.data();
|
||||
for (int i = 0; i < ct.size(); ++i)
|
||||
p[i] = 7;
|
||||
}
|
||||
|
||||
return ct.size();
|
||||
QByteArray data;
|
||||
data.resize(ct.size());
|
||||
quint8 *p = (quint8 *)data.data();
|
||||
for (int i = 0; i < ct.size(); ++i)
|
||||
p[i] = 7;
|
||||
return data;
|
||||
}
|
||||
|
||||
QVariant unpack_custom_type(const QByteArray &data)
|
||||
@@ -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());
|
||||
|
@@ -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();
|
||||
|
24
tests/qttypes/CMakeLists.txt
Normal file
24
tests/qttypes/CMakeLists.txt
Normal 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()
|
144
tests/qttypes/qttypes_test.cpp
Normal file
144
tests/qttypes/qttypes_test.cpp
Normal 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"
|
24
tests/stream/CMakeLists.txt
Normal file
24
tests/stream/CMakeLists.txt
Normal 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()
|
413
tests/stream/stream_test.cpp
Normal file
413
tests/stream/stream_test.cpp
Normal 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"
|
Reference in New Issue
Block a user