diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ed4735d..3d656d3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,5 @@ set(qmsgpack_srcs msgpack.cpp msgpack_common.cpp stream.cpp private/pack_p.cpp private/unpack_p.cpp private/qt_types_p.cpp) -set(qmsgpack_headers msgpack.h stream.h msgpack_common.h msgpack_export.h) +set(qmsgpack_headers msgpack.h stream.h msgpack_common.h msgpack_export.h endianhelper.h) add_library(qmsgpack SHARED ${qmsgpack_srcs} ${qmsgpack_headers}) diff --git a/src/private/sysdep.h b/src/endianhelper.h similarity index 100% rename from src/private/sysdep.h rename to src/endianhelper.h diff --git a/src/msgpack.cpp b/src/msgpack.cpp index d9fe7a8..57aefd1 100644 --- a/src/msgpack.cpp +++ b/src/msgpack.cpp @@ -3,7 +3,6 @@ #include "private/unpack_p.h" #include "private/pack_p.h" #include "private/qt_types_p.h" -#include "private/sysdep.h" #include QVariant MsgPack::unpack(const QByteArray &data) diff --git a/src/msgpack_common.h b/src/msgpack_common.h index e8cf602..9f399b2 100644 --- a/src/msgpack_common.h +++ b/src/msgpack_common.h @@ -62,8 +62,8 @@ const quint8 FIXEX16 = 0xd8; const quint8 STR8 = 0xd9; const quint8 STR16 = 0xda; const quint8 STR32 = 0xdb; -const quint8 ARRAY8 = 0xdc; -const quint8 ARRAY16 = 0xdd; +const quint8 ARRAY16 = 0xdc; +const quint8 ARRAY32 = 0xdd; const quint8 MAP16 = 0xde; const quint8 MAP32 = 0xdf; const quint8 NEGATIVE_FIXINT = 0xe0; diff --git a/src/msgpack_common.h.in b/src/msgpack_common.h.in index 3d43993..d39965a 100644 --- a/src/msgpack_common.h.in +++ b/src/msgpack_common.h.in @@ -62,8 +62,8 @@ const quint8 FIXEX16 = 0xd8; const quint8 STR8 = 0xd9; const quint8 STR16 = 0xda; const quint8 STR32 = 0xdb; -const quint8 ARRAY8 = 0xdc; -const quint8 ARRAY16 = 0xdd; +const quint8 ARRAY16 = 0xdc; +const quint8 ARRAY32 = 0xdd; const quint8 MAP16 = 0xde; const quint8 MAP32 = 0xdf; const quint8 NEGATIVE_FIXINT = 0xe0; diff --git a/src/private/pack_p.cpp b/src/private/pack_p.cpp index 268fc06..f7abe02 100644 --- a/src/private/pack_p.cpp +++ b/src/private/pack_p.cpp @@ -1,5 +1,5 @@ #include "pack_p.h" -#include "private/sysdep.h" +#include "../endianhelper.h" #include #include diff --git a/src/private/qt_types_p.cpp b/src/private/qt_types_p.cpp index 5630d12..1f1a068 100644 --- a/src/private/qt_types_p.cpp +++ b/src/private/qt_types_p.cpp @@ -2,7 +2,7 @@ #include "pack_p.h" #include "unpack_p.h" #include "stream.h" -#include "sysdep.h" +#include "../endianhelper.h" #include diff --git a/src/private/unpack_p.cpp b/src/private/unpack_p.cpp index 5901e9b..cefdb99 100644 --- a/src/private/unpack_p.cpp +++ b/src/private/unpack_p.cpp @@ -1,5 +1,5 @@ #include "unpack_p.h" -#include "sysdep.h" +#include "../endianhelper.h" #include #include diff --git a/src/stream.cpp b/src/stream.cpp index a4a68a6..932498f 100644 --- a/src/stream.cpp +++ b/src/stream.cpp @@ -1,9 +1,6 @@ #include "stream.h" #include -#include "private/sysdep.h" #include "private/pack_p.h" -#include "msgpack_common.h" -#include #include #undef CHECK_STREAM_PRECOND @@ -103,12 +100,10 @@ MsgPackStream &MsgPackStream::operator>>(bool &b) MsgPackStream &MsgPackStream::operator >>(quint8 &u8) { CHECK_STREAM_PRECOND(*this); - quint8 p; - if (dev->read((char *)&p, 1) != 1) { - setStatus(ReadPastEnd); - return *this; - } - if (!unpack_upto_quint8(u8, &p)) + quint64 u64; + if (unpack_ulonglong(u64) && u64 <= std::numeric_limits::max()) + u8 = u64; + else setStatus(ReadCorruptData); return *this; } @@ -116,12 +111,10 @@ MsgPackStream &MsgPackStream::operator >>(quint8 &u8) MsgPackStream &MsgPackStream::operator>>(quint16 &u16) { CHECK_STREAM_PRECOND(*this); - quint8 p; - if (dev->read((char *)&p, 1) != 1) { - setStatus(ReadPastEnd); - return *this; - } - if (!unpack_upto_quint16(u16, &p)) + quint64 u64; + if (unpack_ulonglong(u64) && u64 <= std::numeric_limits::max()) + u16 = u64; + else setStatus(ReadCorruptData); return *this; } @@ -129,12 +122,10 @@ MsgPackStream &MsgPackStream::operator>>(quint16 &u16) MsgPackStream &MsgPackStream::operator>>(quint32 &u32) { CHECK_STREAM_PRECOND(*this); - quint8 p; - if (dev->read((char *)&p, 1) != 1) { - setStatus(ReadPastEnd); - return *this; - } - if (!unpack_upto_quint32(u32, &p)) + quint64 u64; + if (unpack_ulonglong(u64) && u64 <= std::numeric_limits::max()) + u32 = u64; + else setStatus(ReadCorruptData); return *this; } @@ -142,25 +133,20 @@ MsgPackStream &MsgPackStream::operator>>(quint32 &u32) MsgPackStream &MsgPackStream::operator>>(quint64 &u64) { CHECK_STREAM_PRECOND(*this); - quint8 p; - if (dev->read((char *)&p, 1) != 1) { - setStatus(ReadPastEnd); - return *this; - } - if (!unpack_upto_quint64(u64, &p)) - setStatus(ReadCorruptData); + unpack_ulonglong(u64); return *this; } MsgPackStream &MsgPackStream::operator>>(qint8 &i8) { CHECK_STREAM_PRECOND(*this); - quint8 p; - if (dev->read((char *)&p, 1) != 1) { - setStatus(ReadPastEnd); + qint64 i64; + if (!unpack_longlong(i64)) return *this; - } - if (!unpack_upto_qint8(i8, &p)) + if (i64 >= std::numeric_limits::min() && + i64 <= std::numeric_limits::max()) + i8 = i64; + else setStatus(ReadCorruptData); return *this; } @@ -168,12 +154,13 @@ MsgPackStream &MsgPackStream::operator>>(qint8 &i8) MsgPackStream &MsgPackStream::operator>>(qint16 &i16) { CHECK_STREAM_PRECOND(*this); - quint8 p; - if (dev->read((char *)&p, 1) != 1) { - setStatus(ReadPastEnd); +qint64 i64; + if (!unpack_longlong(i64)) return *this; - } - if (!unpack_upto_qint16(i16, &p)) + if (i64 >= std::numeric_limits::min() && + i64 <= std::numeric_limits::max()) + i16 = i64; + else setStatus(ReadCorruptData); return *this; } @@ -181,12 +168,13 @@ MsgPackStream &MsgPackStream::operator>>(qint16 &i16) MsgPackStream &MsgPackStream::operator>>(qint32 &i32) { CHECK_STREAM_PRECOND(*this); - quint8 p; - if (dev->read((char *)&p, 1) != 1) { - setStatus(ReadPastEnd); + qint64 i64; + if (!unpack_longlong(i64)) return *this; - } - if (!unpack_upto_qint32(i32, &p)) + if (i64 >= std::numeric_limits::min() && + i64 <= std::numeric_limits::max()) + i32 = i64; + else setStatus(ReadCorruptData); return *this; } @@ -194,13 +182,7 @@ MsgPackStream &MsgPackStream::operator>>(qint32 &i32) MsgPackStream &MsgPackStream::operator>>(qint64 &i64) { CHECK_STREAM_PRECOND(*this); - quint8 p; - if (dev->read((char *)&p, 1) != 1) { - setStatus(ReadPastEnd); - return *this; - } - if (!unpack_upto_qint64(i64, &p)) - setStatus(ReadCorruptData); + unpack_longlong(i64); return *this; } @@ -330,6 +312,12 @@ MsgPackStream &MsgPackStream::operator>>(QByteArray &array) return *this; } +bool MsgPackStream::readBytes(char *data, uint len) +{ + CHECK_STREAM_PRECOND(false); + return dev->read(data, len) == len; +} + MsgPackStream &MsgPackStream::operator<<(bool b) { CHECK_STREAM_WRITE_PRECOND(*this); @@ -444,169 +432,94 @@ MsgPackStream &MsgPackStream::operator<<(QByteArray array) bool MsgPackStream::writeBytes(const char *data, uint len) { - CHECK_STREAM_WRITE_PRECOND(*this); + CHECK_STREAM_WRITE_PRECOND(false); if (dev->write(data, len) != len) setStatus(WriteFailed); - return *this; + return true; } -bool MsgPackStream::unpack_upto_quint8(quint8 &u8, quint8 *p) +bool MsgPackStream::unpack_longlong(qint64 &i64) { - if (*p <= MsgPack::FirstByte::POSITIVE_FIXINT) { - u8 = *p; - } else if (*p == MsgPack::FirstByte::UINT8) { - if (dev->read((char* )&u8, 1) != 1) - return false; - } else { + quint8 p[9]; + if (dev->read((char *)p, 1) != 1) { + setStatus(ReadPastEnd); return false; } - return true; -} -bool MsgPackStream::unpack_upto_quint16(quint16 &u16, quint8 *p) -{ - if (*p == MsgPack::FirstByte::UINT16) { - quint8 d[2]; - if (dev->read((char *)d, 2) != 2) - return false; - u16 = _msgpack_load16(quint16, d); - } else { - quint8 u8; - bool ok = unpack_upto_quint8(u8, p); - u16 = u8; - return ok; - } - return true; -} - -bool MsgPackStream::unpack_upto_quint32(quint32 &u32, quint8 *p) -{ - if (*p == MsgPack::FirstByte::UINT32) { - quint8 d[4]; - if (dev->read((char *)d, 4) != 4) - return false; - u32 = _msgpack_load32(quint32, d); + if (p[0] <= 127) {// positive fixint 0x00 - 0x7f + i64 = p[0]; return true; - } else { - quint16 u16; - bool ok = unpack_upto_quint16(u16, p); - u32 = u16; - return ok; - } - return true; -} - -bool MsgPackStream::unpack_upto_quint64(quint64 &u64, quint8 *p) -{ - if (*p == MsgPack::FirstByte::UINT64) { - quint8 d[8]; - if (dev->read((char *)d, 8) != 8) { - return false; - } - u64 = _msgpack_load64(quint64, d); + } else if (*p >= 0xe0) { // negative fixint 0xe0 - 0xff + i64 = (qint8)p[0]; return true; - } else { - quint32 u32; - bool ok = unpack_upto_quint32(u32, p); - u64 = u32; - return ok; } -} -bool MsgPackStream::unpack_upto_qint8(qint8 &i8, quint8 *p) -{ - if (*p >= MsgPack::FirstByte::NEGATIVE_FIXINT) { - i8 = *p; - } else if (*p == MsgPack::FirstByte::INT8) { - if (dev->read((char *)&i8, 1) != 1) { + static int typeLengths[] = {1, 2, 4, 8, 1, 2, 4, 8}; + int typeLength = typeLengths[p[0] - MsgPack::FirstByte::UINT8]; + if (dev->read((char *)p + 1, typeLength) != typeLength) { + setStatus(ReadPastEnd); + return false; + } + if (p[0] == MsgPack::FirstByte::UINT8) { + i64 = p[1]; + } else if (p[0] == MsgPack::FirstByte::INT8) { + i64 = (qint8)p[1]; + } else if (p[0] == MsgPack::FirstByte::UINT16) { + i64 = _msgpack_load16(quint16, p + 1); + } else if (p[0] == MsgPack::FirstByte::INT16) { + i64 = _msgpack_load16(qint16, p + 1); + } else if (p[0] == MsgPack::FirstByte::UINT32) { + i64 = _msgpack_load32(quint32, p + 1); + } else if (p[0] == MsgPack::FirstByte::INT32) { + i64 = _msgpack_load32(qint32, p + 1); + } else if (p[0] == MsgPack::FirstByte::UINT64) { + quint64 u64; + u64 = _msgpack_load64(quint64, p + 1); + if (u64 > std::numeric_limits::max()) { + setStatus(ReadCorruptData); return false; } - } else { - quint8 u8; - bool ok = unpack_upto_quint8(u8, p); - if (u8 > std::numeric_limits::max()) - return false; - else - i8 = u8; - return ok; + i64 = u64; + } else if (p[0] == MsgPack::FirstByte::INT64) { + i64 = _msgpack_load64(qint64, p + 1); } return true; } -bool MsgPackStream::unpack_upto_qint16(qint16 &i16, quint8 *p) +bool MsgPackStream::unpack_ulonglong(quint64 &u64) { - if (*p == MsgPack::FirstByte::INT16) { - quint8 d[2]; - if (dev->read((char *)d, 2) != 2) { - return false; - } - i16 = _msgpack_load16(qint16, d); - } else { - qint8 i8; - bool ok = unpack_upto_qint8(i8, p); - if (ok) { - i16 = i8; - } else { - quint16 u16; - bool ok = unpack_upto_quint16(u16, p); - if (u16 > std::numeric_limits::max()) - return false; - else - i16 = u16; - return ok; - } + quint8 p[9]; + if (dev->read((char *)p, 1) != 1) { + setStatus(ReadPastEnd); + return false; } - return true; -} -bool MsgPackStream::unpack_upto_qint32(qint32 &i32, quint8 *p) -{ - if(*p == MsgPack::FirstByte::INT32) { - quint8 d[4]; - if (dev->read((char *)d, 4) != 4) { - return false; - } - i32 = _msgpack_load32(qint32, d); - } else { - qint16 i16; - bool ok = unpack_upto_qint16(i16, p); - if (ok) { - i32 = i16; - } else { - quint32 u32; - bool ok = unpack_upto_quint32(u32, p); - if (u32 > std::numeric_limits::max()) - return false; - else - i32 = u32; - return ok; - } - } - return true; -} - -bool MsgPackStream::unpack_upto_qint64(qint64 &i64, quint8 *p) -{ - if(*p == MsgPack::FirstByte::INT64) { - quint8 d[8]; - if (dev->read((char *)d, 8) != 8) - return false; - i64 = _msgpack_load64(qint64, d); + if (p[0] <= 127) {// positive fixint 0x00 - 0x7f + u64 = p[0]; return true; - } else { - qint32 i32; - bool ok = unpack_upto_qint32(i32, p); - if (ok) { - i64 = i32; - } else { - quint64 u64; - bool ok = unpack_upto_quint64(u64, p); - if (u64 > std::numeric_limits::max()) - return false; - else - i64 = u64; - return ok; - } + } else if (*p >= 0xe0) { // negative fixint 0xe0 - 0xff + return false; } - return true; + + static int typeLengths[] = {1, 2, 4, 8, 1, 2, 4, 8}; + int typeLength = typeLengths[p[0] - MsgPack::FirstByte::UINT8]; + if (dev->read((char *)p + 1, typeLength) != typeLength) { + setStatus(ReadPastEnd); + return false; + } + if (p[0] == MsgPack::FirstByte::UINT8) { + u64 = p[1]; + return true; + } else if (p[0] == MsgPack::FirstByte::UINT16) { + u64 = _msgpack_load16(quint64, p + 1); + return true; + } else if (p[0] == MsgPack::FirstByte::UINT32) { + u64 = _msgpack_load32(quint64, p + 1); + return true; + } else if (p[0] == MsgPack::FirstByte::UINT64) { + u64 = _msgpack_load64(quint64, p + 1); + return true; + } + setStatus(ReadCorruptData); + return false; } diff --git a/src/stream.h b/src/stream.h index 0b733d2..38a19b9 100644 --- a/src/stream.h +++ b/src/stream.h @@ -1,7 +1,9 @@ #ifndef STREAM_H #define STREAM_H #include -#include +#include +#include "msgpack_common.h" +#include "endianhelper.h" class MsgPackStream { @@ -34,6 +36,7 @@ public: MsgPackStream &operator>>(double &d); MsgPackStream &operator>>(QString &str); MsgPackStream &operator>>(QByteArray &array); + bool readBytes(char *data, uint len); MsgPackStream &operator<<(bool b); MsgPackStream &operator<<(quint32 u32); @@ -47,20 +50,13 @@ public: MsgPackStream &operator<<(QByteArray array); bool writeBytes(const char *data, uint len); - private: QIODevice *dev; bool owndev; Status q_status; - bool unpack_upto_quint8(quint8 &u8, quint8 *p); - bool unpack_upto_quint16(quint16 &u16, quint8 *p); - bool unpack_upto_quint32(quint32 &u32, quint8 *p); - bool unpack_upto_quint64(quint64 &u64, quint8 *p); - bool unpack_upto_qint8(qint8 &i8, quint8 *p); - bool unpack_upto_qint16(qint16 &i16, quint8 *p); - bool unpack_upto_qint32(qint32 &i32, quint8 *p); - bool unpack_upto_qint64(qint64 &i64, quint8 *p); + bool unpack_longlong(qint64 &i64); + bool unpack_ulonglong(quint64 &u64); }; template @@ -69,19 +65,19 @@ MsgPackStream& operator<<(MsgPackStream& s, const QList &list) quint32 len = list.size(); quint8 p[5]; if (len <= 15) { - p[0] = 0x90 | len; - s.writeBytes(p, 1); + p[0] = MsgPack::FirstByte::FIXARRAY | len; + s.writeBytes((const char *)p, 1); } else if (len <= std::numeric_limits::max()) { - p[0] = 0xdc; + p[0] = MsgPack::FirstByte::ARRAY16; _msgpack_store16(p + 1, len); - s.writeBytes(p, 3); + s.writeBytes((const char *)p, 3); } else { - p[0] = 0xdd; + p[0] = MsgPack::FirstByte::ARRAY32; _msgpack_store32(p + 1, len); - s.writeBytes(p, 5); + s.writeBytes((const char *)p, 5); } if (s.status() != MsgPackStream::Ok) - return *this; + return s; for (int i = 0; i < list.size(); ++i) s << list[i]; return s; @@ -91,9 +87,19 @@ template MsgPackStream& operator>>(MsgPackStream& s, QList &list) { list.clear(); - quint32 size; - s >> size; - for (quint32 i = 0; i < size; ++i) { + quint8 p[5]; + quint32 len; + s.readBytes((char *)p, 1); + if (p[0] >= 0x90 && p[0] <= 0x9f) { + len = p[0] & 0xf; + } else if (p[0] == MsgPack::FirstByte::ARRAY16) { + s.readBytes((char *)p + 1, 2); + len = _msgpack_load16(quint16, p + 1); + } else if (p[0] == MsgPack::FirstByte::ARRAY32) { + s.readBytes((char *)p + 1, 4); + len = _msgpack_load32(quint32, p + 1); + } + for (quint32 i = 0; i < len; ++i) { T t; s >> t; list.append(t); diff --git a/tests/stream/stream_test.cpp b/tests/stream/stream_test.cpp index f055a95..eccf804 100644 --- a/tests/stream/stream_test.cpp +++ b/tests/stream/stream_test.cpp @@ -17,6 +17,7 @@ private Q_SLOTS: void test_float(); void test_double(); void test_bin(); + void test_array(); }; void StreamTest::test_unpack_integers() @@ -307,5 +308,64 @@ void StreamTest::test_bin() QVERIFY(stream.status() == MsgPackStream::Ok); } +void StreamTest::test_array() +{ +{ + QList list; + list << 0 << 127 << -1 << -31 << 128 << 255 << -33 << -128 << 256; + list << 65535 << -129 << -32768 << 65536; + list << -32769 << (qint32)-2147483648; + list << (qint64)-2147483649; + list << std::numeric_limits::min(); + QByteArray packed; + { + MsgPackStream stream(&packed, QIODevice::WriteOnly); + stream << list; + QVERIFY(stream.status() == MsgPackStream::Ok); + } + + QVariantList list2 = MsgPack::unpack(packed).toList(); + QVERIFY(list.size() == list2.size()); + for (int i = 0; i < list.size(); ++i) + QVERIFY(list[i] == list2[i]); + + packed = MsgPack::pack(list2); + MsgPackStream stream(packed); + QList list3; + stream >> list3; + QVERIFY(stream.status() == MsgPackStream::Ok); + QVERIFY(list2.size() == list3.size()); + for (int i = 0; i < list2.size(); ++i) + QVERIFY(list2[i] == list3[i]); +} +{ + QList list; + list << 6; + list << std::numeric_limits::min(); + list << std::numeric_limits::max(); + list << -4; + QByteArray packed; + { + MsgPackStream stream(&packed, QIODevice::WriteOnly); + stream << list; + QVERIFY(stream.status() == MsgPackStream::Ok); + } + + QVariantList list2 = MsgPack::unpack(packed).toList(); + QVERIFY(list.size() == list2.size()); + for (int i = 0; i < list.size(); ++i) + QVERIFY(list[i] == list2[i]); + + packed = MsgPack::pack(list2); + MsgPackStream stream(packed); + QList list3; + stream >> list3; + QVERIFY(stream.status() == MsgPackStream::Ok); + QVERIFY(list2.size() == list3.size()); + for (int i = 0; i < list2.size(); ++i) + QVERIFY(list2[i] == list3[i]); +} +} + QTEST_APPLESS_MAIN(StreamTest) #include "stream_test.moc"