diff --git a/.gitignore b/.gitignore index 33c5afb..ab6317a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -*.pro.user +*.pro.user* build lib Makefile diff --git a/src/msgpack_common.h b/src/msgpack_common.h index e8cf602..17f713b 100644 --- a/src/msgpack_common.h +++ b/src/msgpack_common.h @@ -10,14 +10,14 @@ namespace MsgPack { /** - * @brief pack user type to byte array data - * @arg variant user type, must be registered first - * @return array with user data only, all other fields will be added automatically + * pack some variant to byte array data + * when write == false only calculates and returns size + * when write == true writes bytes to data, and returns the same size + * return type size */ typedef QByteArray (*pack_user_f)(const QVariant &variant); /** - * @brief unpack user type to QVariant - * @arg data only user data, without size and messagepack type + * unpack user type to QVariant */ typedef QVariant (*unpack_user_f)(const QByteArray &data); /** diff --git a/src/msgpack_common.h.in b/src/msgpack_common.h.in index af55f1f..3d43993 100644 --- a/src/msgpack_common.h.in +++ b/src/msgpack_common.h.in @@ -10,14 +10,14 @@ namespace MsgPack { /** - * pack some variant to byte array data - * when write == false only calculates and returns size - * when write == true writes bytes to data, and returns the same size - * return type size + * @brief pack user type to byte array data + * @arg variant user type, must be registered first + * @return array with user data only, all other fields will be added automatically */ -typedef quint32 (*pack_user_f)(const QVariant &variant, QByteArray &data, bool write); +typedef QByteArray (*pack_user_f)(const QVariant &variant); /** - * unpack user type to QVariant + * @brief unpack user type to QVariant + * @arg data only user data, without size and messagepack type */ typedef QVariant (*unpack_user_f)(const QByteArray &data); /** diff --git a/src/private/pack_p.cpp b/src/private/pack_p.cpp index c94b989..7fa5166 100644 --- a/src/private/pack_p.cpp +++ b/src/private/pack_p.cpp @@ -175,9 +175,8 @@ quint8 *MsgPackPrivate::pack_stringlist(const QStringList &list, quint8 *p, bool return p; } -quint8 *MsgPackPrivate::pack_string(const QString &str, quint8 *p, bool wr) +quint8 *MsgPackPrivate::pack_string_raw(const char *str, quint32 len, quint8 *p, bool wr) { - int len = str.length(); if (len <= 31) { if (wr) *p = 0xa0 | len; p++; @@ -198,11 +197,18 @@ quint8 *MsgPackPrivate::pack_string(const QString &str, quint8 *p, bool wr) if (wr) _msgpack_store32(p, len); p += 4; } - if (wr) memcpy(p, str.toUtf8().data(), len); + if (wr) memcpy(p, str, len); return p + len; } +quint8 *MsgPackPrivate::pack_string(const QString &str, quint8 *p, bool wr) +{ + QByteArray str_data = str.toUtf8(); + quint32 str_len = str_data.length(); + return pack_string_raw(str_data.data(), str_len, p, wr); +} + quint8 *MsgPackPrivate::pack_double(double i, quint8 *p, bool wr) { if (wr) *p = 0xcb; diff --git a/src/private/pack_p.h b/src/private/pack_p.h index d3afda4..d16d81b 100644 --- a/src/private/pack_p.h +++ b/src/private/pack_p.h @@ -36,6 +36,7 @@ quint8 * pack_arraylen(quint32 len, quint8 *p, bool wr); quint8 * pack_array(const QVariantList &list, quint8 *p, bool wr, QVector &user_data); quint8 * pack_stringlist(const QStringList &list, quint8 *p, bool wr); +quint8 * pack_string_raw(const char *str, quint32 len, quint8 *p, bool wr); quint8 * pack_string(const QString &str, quint8 *p, bool wr); quint8 * pack_double(double i, quint8 *p, bool wr); quint8 * pack_bin(const QByteArray &arr, quint8 *p, bool wr); diff --git a/src/private/qt_types_p.cpp b/src/private/qt_types_p.cpp index 5975429..5630d12 100644 --- a/src/private/qt_types_p.cpp +++ b/src/private/qt_types_p.cpp @@ -1,6 +1,7 @@ #include "qt_types_p.h" #include "pack_p.h" #include "unpack_p.h" +#include "stream.h" #include "sysdep.h" #include @@ -169,90 +170,59 @@ QVariant MsgPackPrivate::unpack_qdatetime(const QByteArray &data) // Points and Vectors QByteArray MsgPackPrivate::pack_qpoint(const QVariant &variant) { - // QPoint pt = variant.toPoint(); - // quint8 size = pack_two_integers(pt.x(), pt.y(), 0, false); - // if (write) { - // data.resize(size); - // pack_two_integers(pt.x(), pt.y(), (quint8 *)data.data(), true); - // } - // return size; + QByteArray packed; + MsgPackStream stream(&packed, QIODevice::WriteOnly); + QPoint pt = variant.toPoint(); + stream << pt.x() << pt.y(); + return packed; } QVariant MsgPackPrivate::unpack_qpoint(const QByteArray &data) { - // quint8 *p = (quint8 *)data.data(); - // qint32 x; - // bool ok; - // p = MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); - // QPoint pt; - // pt.setX(x); - // MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); - // pt.setY(x); - // return pt; + MsgPackStream stream(data); + qint32 x, y; + stream >> x >> y; + qDebug() << "unpack qpoint stream" << (stream.status() == MsgPackStream::Ok); + return QPoint(x, y); } QByteArray MsgPackPrivate::pack_qsize(const QVariant &variant) { - // QSize sz = variant.toSize(); - // quint8 size = pack_two_integers(sz.width(), sz.height(), 0, false); - // if (write) { - // data.resize(size); - // pack_two_integers(sz.width(), sz.height(), (quint8 *)data.data(), true); - // } - // return size; + QByteArray packed; + MsgPackStream stream(&packed, QIODevice::WriteOnly); + QSize sz = variant.toSize(); + stream << sz.width() << sz.height(); + return packed; } QVariant MsgPackPrivate::unpack_qsize(const QByteArray &data) { - // quint8 *p = (quint8 *)data.data(); - // qint32 x; - // bool ok; - // p = MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); - // QSize sz; - // sz.setWidth(x); - // MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); - // sz.setHeight(x); - // return sz; + MsgPackStream stream(data); + qint32 width, height; + stream >> width >> height; + return QSize(width, height); } QByteArray MsgPackPrivate::pack_qrect(const QVariant &variant) { - // QRect rect = variant.toRect(); - // QPoint pt1 = rect.topLeft(); - // QPoint pt2 = rect.bottomRight(); - // quint8 size = pack_two_integers(pt1.x(), pt1.y(), 0, false); - // size += pack_two_integers(pt2.x(), pt2.y(), 0, false); - // if (write) { - // data.resize(size); - // quint8 *p = (quint8 *)data.data(); - // p += pack_two_integers(pt1.x(), pt1.y(), p, true); - // pack_two_integers(pt2.x(), pt2.y(), p, true); - // } - // return size; + QRect rect = variant.toRect(); + QPoint pt1 = rect.topLeft(); + QPoint pt2 = rect.bottomRight(); + QByteArray packed; + MsgPackStream stream(&packed, QIODevice::WriteOnly); + stream << pt1.x() << pt1.y() << pt2.x() << pt2.y(); + return packed; } QVariant MsgPackPrivate::unpack_qrect(const QByteArray &data) { - // quint8 *p = (quint8 *)data.data(); - // qint32 x; - // bool ok; - - // p = MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); - // QPoint pt; - // pt.setX(x); - // p = MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); - // pt.setY(x); - - // QRect rect; - // rect.setTopLeft(pt); - - // p = MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); - // pt.setX(x); - // p = MsgPack::Ext::unpack_upto_qint32(&x, p, &ok); - // pt.setY(x); - - // rect.setBottomRight(pt); - - // return rect; + MsgPackStream stream(data); + qint32 x, y; + stream >> x >> y; + QRect rect; + rect.setTopLeft(QPoint(x, y)); + stream >> x >> y; + rect.setBottomRight(QPoint(x, y)); + return rect; } diff --git a/src/stream.cpp b/src/stream.cpp index 71b6f72..3c59216 100644 --- a/src/stream.cpp +++ b/src/stream.cpp @@ -26,15 +26,15 @@ return retVal; MsgPackStream::MsgPackStream() : - dev(0), compatibility(false), owndev(false), q_status(Ok) + dev(0), owndev(false), q_status(Ok) { } MsgPackStream::MsgPackStream(QIODevice *d) : - dev(d), compatibility(false), owndev(false) + dev(d), owndev(false) { } MsgPackStream::MsgPackStream(QByteArray *a, QIODevice::OpenMode mode) : - compatibility(false), owndev(true), q_status(Ok) + owndev(true), q_status(Ok) { QBuffer *buf = new QBuffer(a); buf->open(mode); @@ -42,7 +42,7 @@ MsgPackStream::MsgPackStream(QByteArray *a, QIODevice::OpenMode mode) : } MsgPackStream::MsgPackStream(const QByteArray &a) : - compatibility(false), owndev(true), q_status(Ok) + owndev(true), q_status(Ok) { QBuffer *buf = new QBuffer(); buf->setData(a); @@ -69,11 +69,6 @@ bool MsgPackStream::atEnd() const return dev ? dev->atEnd() : true; } -void MsgPackStream::setCompatibility(bool isEnabled) -{ - compatibility = isEnabled; -} - MsgPackStream::Status MsgPackStream::status() const { return q_status; @@ -113,7 +108,8 @@ MsgPackStream &MsgPackStream::operator >>(quint8 &u8) setStatus(ReadPastEnd); return *this; } - unpack_upto_quint8(u8, &p); + if (!unpack_upto_quint8(u8, &p)) + setStatus(ReadCorruptData); return *this; } @@ -125,7 +121,8 @@ MsgPackStream &MsgPackStream::operator>>(quint16 &u16) setStatus(ReadPastEnd); return *this; } - unpack_upto_quint16(u16, &p); + if (!unpack_upto_quint16(u16, &p { + setStatus(ReadCorruptData); return *this; } @@ -137,7 +134,8 @@ MsgPackStream &MsgPackStream::operator>>(quint32 &u32) setStatus(ReadPastEnd); return *this; } - unpack_upto_quint32(u32, &p); + if (!unpack_upto_quint32(u32, &p { + setStatus(ReadCorruptData); return *this; } @@ -149,7 +147,8 @@ MsgPackStream &MsgPackStream::operator>>(quint64 &u64) setStatus(ReadPastEnd); return *this; } - unpack_upto_quint64(u64, &p); + if (!unpack_upto_quint64(u64, &p { + setStatus(ReadCorruptData); return *this; } @@ -161,7 +160,7 @@ MsgPackStream &MsgPackStream::operator>>(qint8 &i8) setStatus(ReadPastEnd); return *this; } - unpack_upto_qint8(i8, &p); + if (!unpack_upto_qint8(i8, &p)) setStatus(ReadCorruptData); return *this; } @@ -173,7 +172,8 @@ MsgPackStream &MsgPackStream::operator>>(qint16 &i16) setStatus(ReadPastEnd); return *this; } - unpack_upto_qint16(i16, &p); + if (!unpack_upto_qint16(i16, &p){ + setStatus(ReadCorruptData); return *this; } @@ -185,7 +185,8 @@ MsgPackStream &MsgPackStream::operator>>(qint32 &i32) setStatus(ReadPastEnd); return *this; } - unpack_upto_qint32(i32, &p); + if (!unpack_upto_qint32(i32, &p){ + setStatus(ReadCorruptData); return *this; } @@ -197,7 +198,8 @@ MsgPackStream &MsgPackStream::operator>>(qint64 &i64) setStatus(ReadPastEnd); return *this; } - unpack_upto_qint64(i64, &p); + if (!unpack_upto_qint64(i64, &p){ + setStatus(ReadCorruptData); return *this; } @@ -226,6 +228,14 @@ MsgPackStream &MsgPackStream::operator>>(QString &str) setStatus(ReadCorruptData); return *this; } + quint8 *data = new quint8[len]; + if (dev->read((char *)data, len) != len) { + setStatus(ReadPastEnd); + delete[] data; + return *this; + } + str = QString::fromUtf8((const char*) data, len); + delete[] data; } MsgPackStream &MsgPackStream::operator<<(bool b) @@ -284,8 +294,7 @@ MsgPackStream &MsgPackStream::operator<<(QString str) quint8 *p = (quint8 *)0; quint32 sz = MsgPackPrivate::pack_string(str, p, false) - p; quint8 *data = new quint8[sz]; - QVector user_data; - MsgPackPrivate::pack(str, data, true, user_data); + MsgPackPrivate::pack_string(str, data, true); if (dev->write((char *)data, sz) != sz) setStatus(WriteFailed); delete[] data; @@ -294,21 +303,26 @@ MsgPackStream &MsgPackStream::operator<<(QString str) MsgPackStream &MsgPackStream::operator<<(const char *str) { - + CHECK_STREAM_WRITE_PRECOND(*this); + quint8 *p = (quint8 *)0; + quint32 str_len = strlen(str); + quint32 sz = MsgPackPrivate::pack_string_raw(str, str_len, p, false) - p; + quint8 *data = new quint8[sz]; + MsgPackPrivate::pack_string_raw(str, str_len, data, true); + if (dev->write((char *)data, sz) != sz) + setStatus(WriteFailed); + delete[] data; + return *this; } - bool MsgPackStream::unpack_upto_quint8(quint8 &u8, quint8 *p) { if (*p <= MsgPack::FirstByte::POSITIVE_FIXINT) { u8 = *p; } else if (*p == MsgPack::FirstByte::UINT8) { - if (dev->read((char* )&u8, 1) != 1) { - setStatus(ReadPastEnd); + if (dev->read((char* )&u8, 1) != 1) return false; - } } else { - setStatus(ReadCorruptData); return false; } return true; @@ -318,10 +332,8 @@ bool MsgPackStream::unpack_upto_quint16(quint16 &u16, quint8 *p) { if (*p == MsgPack::FirstByte::UINT16) { quint8 d[2]; - if (dev->read((char *)d, 2) != 2) { - setStatus(ReadPastEnd); + if (dev->read((char *)d, 2) != 2) return false; - } u16 = _msgpack_load16(quint16, d); } else { quint8 u8; @@ -329,16 +341,15 @@ bool MsgPackStream::unpack_upto_quint16(quint16 &u16, quint8 *p) u16 = u8; return ok; } + return true; } bool MsgPackStream::unpack_upto_quint32(quint32 &u32, quint8 *p) { if (*p == MsgPack::FirstByte::UINT32) { quint8 d[4]; - if (dev->read((char *)d, 4) != 4) { - setStatus(ReadPastEnd); + if (dev->read((char *)d, 4) != 4) return false; - } u32 = _msgpack_load32(quint32, d); return true; } else { @@ -347,6 +358,7 @@ bool MsgPackStream::unpack_upto_quint32(quint32 &u32, quint8 *p) u32 = u16; return ok; } + return true; } bool MsgPackStream::unpack_upto_quint64(quint64 &u64, quint8 *p) @@ -354,7 +366,6 @@ bool MsgPackStream::unpack_upto_quint64(quint64 &u64, quint8 *p) if (*p == MsgPack::FirstByte::UINT64) { quint8 d[8]; if (dev->read((char *)d, 8) != 8) { - setStatus(ReadPastEnd); return false; } u64 = _msgpack_load64(quint64, d); @@ -373,14 +384,13 @@ bool MsgPackStream::unpack_upto_qint8(qint8 &i8, quint8 *p) i8 = *p; } else if (*p == MsgPack::FirstByte::INT8) { if (dev->read((char *)&i8, 1) != 1) { - setStatus(ReadPastEnd); return false; } } else { quint8 u8; bool ok = unpack_upto_quint8(u8, p); if (u8 > std::numeric_limits::max()) - setStatus(ReadCorruptData); + return false; else i8 = u8; return ok; @@ -393,11 +403,9 @@ bool MsgPackStream::unpack_upto_qint16(qint16 &i16, quint8 *p) if (*p == MsgPack::FirstByte::INT16) { quint8 d[2]; if (dev->read((char *)d, 2) != 2) { - setStatus(ReadPastEnd); return false; } - i16 = _msgpack_load16(qint16, d); - return true; + i16 = _msgpack_load16(qint16, d); } else { qint8 i8; bool ok = unpack_upto_qint8(i8, p); @@ -406,13 +414,14 @@ bool MsgPackStream::unpack_upto_qint16(qint16 &i16, quint8 *p) } else { quint16 u16; bool ok = unpack_upto_quint16(u16, p); - if (u16 <= std::numeric_limits::max()) - i16 = u16; + if (u16 > std::numeric_limits::max()) + return false; else - setStatus(ReadCorruptData); + i16 = u16; return ok; } } + return true; } bool MsgPackStream::unpack_upto_qint32(qint32 &i32, quint8 *p) @@ -420,11 +429,9 @@ bool MsgPackStream::unpack_upto_qint32(qint32 &i32, quint8 *p) if(*p == MsgPack::FirstByte::INT32) { quint8 d[4]; if (dev->read((char *)d, 4) != 4) { - setStatus(ReadPastEnd); return false; } i32 = _msgpack_load32(qint32, d); - return true; } else { qint16 i16; bool ok = unpack_upto_qint16(i16, p); @@ -433,23 +440,22 @@ bool MsgPackStream::unpack_upto_qint32(qint32 &i32, quint8 *p) } else { quint32 u32; bool ok = unpack_upto_quint32(u32, p); - if (u32 <= std::numeric_limits::max()) - i32 = u32; + if (u32 > std::numeric_limits::max()) + return false; else - setStatus(ReadCorruptData); + i32 = u32; return ok; } } + return true; } bool MsgPackStream::unpack_upto_qint64(qint64 &i64, quint8 *p) { if(*p == MsgPack::FirstByte::INT64) { quint8 d[8]; - if (dev->read((char *)d, 8) != 8) { - setStatus(ReadPastEnd); + if (dev->read((char *)d, 8) != 8) return false; - } i64 = _msgpack_load64(qint64, d); return true; } else { @@ -460,11 +466,12 @@ bool MsgPackStream::unpack_upto_qint64(qint64 &i64, quint8 *p) } else { quint64 u64; bool ok = unpack_upto_quint64(u64, p); - if (u64 <= std::numeric_limits::max()) - i64 = u64; + if (u64 > std::numeric_limits::max()) + return false; else - setStatus(ReadCorruptData); + i64 = u64; return ok; } } + return true; } diff --git a/src/stream.h b/src/stream.h index e4aa849..545973d 100644 --- a/src/stream.h +++ b/src/stream.h @@ -15,8 +15,6 @@ public: QIODevice *device() const; bool atEnd() const; - void setCompatibility(bool isEnabled); - enum Status {Ok, ReadPastEnd, ReadCorruptData, WriteFailed}; Status status() const; void resetStatus(); @@ -46,19 +44,16 @@ public: MsgPackStream &operator<<(float f); MsgPackStream &operator<<(double d); MsgPackStream &operator<<(QString str); - + MsgPackStream &operator<<(const char *str); MsgPackStream &operator<<(QByteArray array); MsgPackStream &operator<<(QVariantList list); MsgPackStream &operator<<(QVariantMap map); private: QIODevice *dev; - bool compatibility; bool owndev; Status q_status; - MsgPackStream &operator<<(const char *str); // use QStringLiteral instead - bool unpack_upto_quint8(quint8 &u8, quint8 *p); bool unpack_upto_quint16(quint16 &u16, quint8 *p); bool unpack_upto_quint32(quint32 &u32, quint8 *p); diff --git a/tests/pack/pack_test.cpp b/tests/pack/pack_test.cpp index 70b2963..8d01fc2 100644 --- a/tests/pack/pack_test.cpp +++ b/tests/pack/pack_test.cpp @@ -216,14 +216,14 @@ void PackTest::test_float() void PackTest::test_str() { - QString str = QString::fromUtf8("msgpack rocks"); + QString str = QStringLiteral("msgpack rocks"); QByteArray arr = MsgPack::pack(str); QVERIFY(arr.size() == 14); quint8 *p = (quint8 *)arr.data(); QVERIFY(p[0] == (0xa0 | str.length())); QVERIFY(memcmp(p + 1, str.toUtf8().data(), str.size()) == 0); - str = QString::fromUtf8(QByteArray(32, 'm')); + str = QString(QByteArray(32, 'm')); arr = MsgPack::pack(str); QVERIFY(arr.size() == 32 + 2); p = (quint8 *)arr.data(); @@ -231,7 +231,7 @@ void PackTest::test_str() QVERIFY(p[1] == 32); QVERIFY(memcmp(p + 2, str.toUtf8().data(), str.size()) == 0); - str = QString::fromUtf8(QByteArray(256, 's')); + str = QString(QByteArray(256, 's')); arr = MsgPack::pack(str); QVERIFY(arr.size() == 256 + 3); p = (quint8 *)arr.data(); @@ -240,7 +240,7 @@ void PackTest::test_str() QVERIFY(p[2] == 0x00); QVERIFY(memcmp(p + 3, str.toUtf8().data(), str.size()) == 0); - str = QString::fromUtf8(QByteArray(65536, 'g')); + str = QString(QByteArray(65536, 'g')); arr = MsgPack::pack(str); QVERIFY(arr.size() == 65536 + 5); p = (quint8 *)arr.data(); diff --git a/tests/qttypes/qttypes_test.cpp b/tests/qttypes/qttypes_test.cpp index ebcaa28..9f4d31f 100644 --- a/tests/qttypes/qttypes_test.cpp +++ b/tests/qttypes/qttypes_test.cpp @@ -77,6 +77,8 @@ void QtTypesTest::test_qpoint() packed = MsgPack::pack(pt); QVERIFY(packed.size() == 9); pt2 = MsgPack::unpack(packed).toPoint(); + qDebug() << pt << pt2; + qDebug() << packed.toHex() << packed.size(); QVERIFY(pt == pt2); pt = QPoint(std::numeric_limits::max(), std::numeric_limits::max()); diff --git a/tests/stream/stream_test.cpp b/tests/stream/stream_test.cpp index a389512..29662b3 100644 --- a/tests/stream/stream_test.cpp +++ b/tests/stream/stream_test.cpp @@ -12,6 +12,8 @@ class StreamTest : public QObject private Q_SLOTS: void test_unpack_integers(); void test_pack_integers(); + void test_unpack_string(); + void test_pack_string(); }; @@ -135,6 +137,72 @@ void StreamTest::test_pack_integers() QVERIFY(l[19].toLongLong() == std::numeric_limits::min()); } +void StreamTest::test_unpack_string() +{ + QString str = QStringLiteral("msgpack rocks"); + QByteArray packed = MsgPack::pack(str); + QString str2; + + { + MsgPackStream stream(packed); + stream >> str2; + QVERIFY(str == str2); + } + { + str = QString(QByteArray(32, 'm')); + packed = MsgPack::pack(str); + MsgPackStream stream(packed); + stream >> str2; + QVERIFY(str == str2); + } + { + str = QString::fromUtf8(QByteArray(256, 's')); + packed = MsgPack::pack(str); + MsgPackStream stream(packed); + stream >> str2; + QVERIFY(str == str2); + } + { + str = QString(QByteArray(65536, 'g')); + packed = MsgPack::pack(str); + MsgPackStream stream(packed); + stream >> str2; + QVERIFY(str == str2); + } +} + +void StreamTest::test_pack_string() +{ + QByteArray packed; + MsgPackStream stream(&packed, QIODevice::WriteOnly); + QStringList strs; + stream << "abc"; + strs << "abc"; + QString s; + for (int i = 0; i < 8; ++i) + s += "xy"; + stream << s; + strs << s; + s = QString(); + for (int i = 0; i < 64; ++i) + s += "msgp"; + stream << s; + strs << s; + s = QString(); + for (int i = 0; i < 4096; ++i) + s += "messagepack test"; + stream << s; + strs << s; + stream << ""; + + QStringList l = MsgPack::unpack(packed).toStringList(); + QVERIFY(l[0] == strs[0]); + QVERIFY(l[1] == strs[1]); + QVERIFY(l[2] == strs[2]); + QVERIFY(l[3] == strs[3]); + QVERIFY(l[4].isEmpty()); +} + QTEST_APPLESS_MAIN(StreamTest)