diff --git a/src/msgpackcommon.h b/src/msgpackcommon.h index 5205c19..3c728ca 100644 --- a/src/msgpackcommon.h +++ b/src/msgpackcommon.h @@ -37,41 +37,51 @@ MSGPACK_EXPORT QString version(); */ 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 FIXMAP = 0x80; +const quint8 FIXMAP_MASK = 0xf; +const quint8 FIXMAP_LAST = 0x8f; + +const quint8 FIXARRAY = 0x90; +const quint8 FIXARRAY_MASK = 0xf; +const quint8 FIXARRAY_LAST = 0x9f; + +const quint8 FIXSTR = 0xa0; +const quint8 FIXSTR_MASK = 0x1f; +const quint8 FIXSTR_LAST = 0xbf; + +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; } } diff --git a/src/msgpackstream.cpp b/src/msgpackstream.cpp index 05374dd..b930134 100644 --- a/src/msgpackstream.cpp +++ b/src/msgpackstream.cpp @@ -26,15 +26,15 @@ return retVal; MsgPackStream::MsgPackStream() : - dev(0), owndev(false), q_status(Ok), flushWrites(false) + dev(0), owndev(false), q_status(Ok), flushWrites(false), blocking(false), m_rawMode(false) { } MsgPackStream::MsgPackStream(QIODevice *d) : - dev(d), owndev(false), q_status(Ok), flushWrites(false) + dev(d), owndev(false), q_status(Ok), flushWrites(false), blocking(false), m_rawMode(false) { } MsgPackStream::MsgPackStream(QByteArray *a, QIODevice::OpenMode mode) : - owndev(true), q_status(Ok), flushWrites(false) + owndev(true), q_status(Ok), flushWrites(false), blocking(false), m_rawMode(false) { QBuffer *buf = new QBuffer(a); buf->open(mode); @@ -42,7 +42,7 @@ MsgPackStream::MsgPackStream(QByteArray *a, QIODevice::OpenMode mode) : } MsgPackStream::MsgPackStream(const QByteArray &a) : - owndev(true), q_status(Ok), flushWrites(false) + owndev(true), q_status(Ok), flushWrites(false), blocking(false), m_rawMode(false) { QBuffer *buf = new QBuffer(); buf->setData(a); @@ -336,20 +336,25 @@ bool MsgPackStream::readBytes(char *data, qint64 len) CHECK_STREAM_PRECOND(false); qint64 readed = 0; qint64 thisRead = 0; - while (readed < len) - { - thisRead = dev->read(data, (len - readed)); - if (thisRead < 0) - break; - /* Advance the read pointer */ - data += thisRead; - readed += thisRead; - /* Data might not be available for a bit, so wait before reading again. */ - if (readed < len) { - dev->waitForReadyRead(-1); + if (blocking) { + while (readed < len) + { + thisRead = dev->read(data, (len - readed)); + if (thisRead < 0) + break; + /* Advance the read pointer */ + data += thisRead; + readed += thisRead; + /* Data might not be available for a bit, so wait before reading again. */ + if (readed < len) { + dev->waitForReadyRead(-1); + } } + } else { + thisRead = dev->read(data, len); } - if (thisRead < 0) { + + if (thisRead < 0 || thisRead < len) { /* FIXME: There are actual errors that can happen here. */ setStatus(ReadPastEnd); return false; @@ -357,7 +362,7 @@ bool MsgPackStream::readBytes(char *data, qint64 len) return true; } -bool MsgPackStream::readExtHeader(quint32 &len) +bool MsgPackStream::readExtHeader(quint32 &len, qint8 &type) { CHECK_STREAM_PRECOND(false); quint8 d[6]; @@ -369,6 +374,7 @@ bool MsgPackStream::readExtHeader(quint32 &len) d[0] <= MsgPack::FirstByte::FIXEX16) { len = 1; len <<= d[0] - MsgPack::FirstByte::FIXEXT1; + type = d[1]; return true; } @@ -381,10 +387,13 @@ bool MsgPackStream::readExtHeader(quint32 &len) if (d[0] == MsgPack::FirstByte::EXT8) { len = d[1]; + type = d[2]; } else if (d[0] == MsgPack::FirstByte::EXT16) { len = _msgpack_load16(quint32, &d[1]); + type = d[3]; } else if (d[0] == MsgPack::FirstByte::EXT32) { len = _msgpack_load32(quint32, &d[1]); + type = d[5]; } else { setStatus(ReadCorruptData); return false; @@ -392,6 +401,38 @@ bool MsgPackStream::readExtHeader(quint32 &len) return true; } +bool MsgPackStream::readArrayHeader(quint32 &len) +{ + CHECK_STREAM_PRECOND(false); + quint8 d[5]; + if (!readBytes((char*)d, 1)) { + setStatus(ReadPastEnd); + return false; + } + + if (d[0] >= MsgPack::FirstByte::FIXARRAY && d[0] <= MsgPack::FirstByte::FIXARRAY_LAST) { + len = d[0] & MsgPack::FirstByte::FIXARRAY_MASK; + return true; + } + if (d[0] == MsgPack::FirstByte::ARRAY16 || d[0] == MsgPack::FirstByte::ARRAY32) { + quint8 lengthSectionSize = 2; + lengthSectionSize <<= d[0] - MsgPack::FirstByte::ARRAY16; // 2 or 4 + if (!readBytes((char *)d + 1, lengthSectionSize)) { + setStatus(ReadPastEnd); + return false; + } + if (d[0] == MsgPack::FirstByte::ARRAY16) { + len = _msgpack_load16(quint16, d + 1); + } else { + len = _msgpack_load32(quint32, d + 1); + } + return true; + } + + setStatus(ReadCorruptData); + return false; +} + MsgPackStream &MsgPackStream::operator<<(bool b) { CHECK_STREAM_WRITE_PRECOND(*this); @@ -572,6 +613,118 @@ bool MsgPackStream::writeExtHeader(quint32 len, qint8 msgpackType) return true; } +void MsgPackStream::setBlocking(bool enabled) +{ + blocking = enabled; +} + +void MsgPackStream::setRawMode(bool enabled) +{ + m_rawMode = enabled; +} + +PeekResult MsgPackStream::peek() const +{ + if (!dev) + return PeekResult(); + quint8 buf[6]; + if (dev->peek((char *)buf, 1) != 1) + return PeekResult(); + PeekResult p; + if (buf[0] >= MsgPack::FirstByte::FIXEXT1 && buf[0] <= MsgPack::FirstByte::FIXEX16 ) { + if (dev->peek((char *)buf, 2) != 2) + return PeekResult(); + p.status = PeekResult::PeekOk; + p.msgpackType = MsgPack::FirstByte::FIXEXT1; + p.userType = buf[1]; + return p; + } + if (buf[0] >= MsgPack::FirstByte::EXT8 && buf[0] <= MsgPack::FirstByte::EXT32) { + quint8 lengthSectionSize = 1; + lengthSectionSize <<= buf[0] - MsgPack::FirstByte::EXT8; // 1 or 2 or 4 + if (dev->peek((char*)buf, lengthSectionSize + 2) != lengthSectionSize + 2) + return PeekResult(); + p.status = PeekResult::PeekOk; + p.msgpackType = MsgPack::FirstByte::FIXEXT1; + p.userType = buf[lengthSectionSize + 1]; + return p; + } + if (buf[0] >= MsgPack::FirstByte::FIXARRAY && buf[0] <= MsgPack::FirstByte::FIXARRAY_LAST) { + p.status = PeekResult::PeekOk; + p.msgpackType = buf[0] & ~MsgPack::FirstByte::FIXARRAY_MASK; + p.length = buf[0] & MsgPack::FirstByte::FIXARRAY_MASK; + return p; + } + if (buf[0] == MsgPack::FirstByte::ARRAY16 || buf[0] == MsgPack::FirstByte::ARRAY32) { + quint8 lengthSectionSize = 2; + lengthSectionSize <<= buf[0] - MsgPack::FirstByte::ARRAY16; // 2 or 4 + if (dev->peek((char*)buf, lengthSectionSize + 1) != lengthSectionSize + 1) + return PeekResult(); + p.status = PeekResult::PeekOk; + p.msgpackType = buf[0]; + if (buf[0] == MsgPack::FirstByte::ARRAY16) { + p.length = _msgpack_load16(quint16, buf + 1); + } else { + p.length = _msgpack_load32(quint32, buf + 1); + } + return p; + } + return PeekResult(); +} + +// PeekResult p; +// p.status = PeekResult::Status::PeekOk; // all values is covered below +// if ( buf[0] >= MsgPack::FirstByte::FIXMAP && buf[0] <= MsgPack::FirstByte::FIXMAP_LAST) { +// p.msgpackType = buf[0] & ~MsgPack::FirstByte::FIXMAP_MASK; +// p.length = buf[0] & MsgPack::FirstByte::FIXMAP_MASK; +// return p; +// } + +// if (buf[0] >= MsgPack::FirstByte::FIXSTR && buf[0] <= MsgPack::FirstByte::FIXSTR_LAST) { +// p.msgpackType = buf[0] & ~MsgPack::FirstByte::FIXSTR_MASK; +// p.length = buf[0] & MsgPack::FirstByte::FIXSTR_MASK; +// return p; +// } +// if (buf[0] == MsgPack::FirstByte::BIN8 || buf[0] == MsgPack::FirstByte::STR8) { + +// } +// if ( buf[0] == MsgPack::FirstByte::NIL || +// buf[0] == MsgPack::FirstByte::NEVER_USED || +// buf[0] == MsgPack::FirstByte::MFALSE || +// buf[0] == MsgPack::FirstByte::MTRUE || +// buf[0] <= MsgPack::FirstByte::POSITIVE_FIXINT || +// buf[0] >= MsgPack::FirstByte::NEGATIVE_FIXINT ) { +// p.msgpackType = buf[0]; +// return p; +// } +// if ( buf[0] == MsgPack::FirstByte::UINT8 || +// buf[0] == MsgPack::FirstByte::INT8 ) { +// p.msgpackType = buf[0]; +// p.length = 1; +// return p; +// } +// if ( buf[0] == MsgPack::FirstByte::UINT16 || +// buf[0] == MsgPack::FirstByte::INT16 ) { +// p.msgpackType = buf[0]; +// p.length = 2; +// return p; +// } +// if ( buf[0] == MsgPack::FirstByte::UINT32 || +// buf[0] == MsgPack::FirstByte::INT32 || +// MsgPack::FirstByte::FLOAT32 ) { +// p.msgpackType = buf[0]; +// p.length = 4; +// return p; +// } +// if ( buf[0] == MsgPack::FirstByte::UINT64 || +// buf[0] == MsgPack::FirstByte::INT64 || +// MsgPack::FirstByte::FLOAT64 ) { +// p.msgpackType = buf[0]; +// p.length = 8; +// return p; +// } +//} + bool MsgPackStream::unpack_longlong(qint64 &i64) { quint8 p[9]; diff --git a/src/msgpackstream.h b/src/msgpackstream.h index cfe81d9..f256218 100644 --- a/src/msgpackstream.h +++ b/src/msgpackstream.h @@ -9,6 +9,21 @@ #include +class PeekResult { +public: + PeekResult() : status(PeekFailed), msgpackType(0), userType(0), length(0) {} + + quint8 msgpackType; + quint8 userType; + quint32 length; + + enum Status { + PeekOk, + PeekFailed + }; + Status status; +}; + class MSGPACK_EXPORT MsgPackStream { public: @@ -43,7 +58,8 @@ public: MsgPackStream &operator>>(QString &str); MsgPackStream &operator>>(QByteArray &array); bool readBytes(char *data, qint64 len); - bool readExtHeader(quint32 &len); + bool readExtHeader(quint32 &len, qint8 &type); + bool readArrayHeader(quint32 &len); MsgPackStream &operator<<(bool b); MsgPackStream &operator<<(quint32 u32); @@ -58,11 +74,17 @@ public: bool writeBytes(const char *data, qint64 len); bool writeExtHeader(quint32 len, qint8 msgpackType); + PeekResult peek() const; + void setBlocking(bool enabled); + void setRawMode(bool enabled); + private: QIODevice *dev; bool owndev; Status q_status; bool flushWrites; + bool blocking; + bool m_rawMode; bool unpack_longlong(qint64 &i64); bool unpack_ulonglong(quint64 &u64); diff --git a/src/stream/time.cpp b/src/stream/time.cpp index cc24baa..8c88c90 100644 --- a/src/stream/time.cpp +++ b/src/stream/time.cpp @@ -74,7 +74,8 @@ MsgPackStream &operator<<(MsgPackStream &s, const QTime &t) MsgPackStream& operator>>(MsgPackStream& s, QTime &t) { quint32 len; - s.readExtHeader(len); + qint8 type; + s.readExtHeader(len, type); if (len != 1 && len != 2 && len != 4) { s.setStatus(MsgPackStream::ReadCorruptData); t = QTime(); @@ -109,7 +110,8 @@ MsgPackStream &operator<<(MsgPackStream &s, const QDate &date) MsgPackStream& operator>>(MsgPackStream& s, QDate &date) { quint32 len; - s.readExtHeader(len); + qint8 type; + s.readExtHeader(len, type); if (len != 1 && len != 3) { s.setStatus(MsgPackStream::ReadCorruptData); date = QDate(); @@ -150,7 +152,8 @@ MsgPackStream &operator<<(MsgPackStream& s, const QDateTime &dt) MsgPackStream& operator>>(MsgPackStream& s, QDateTime &dt) { quint32 len; - s.readExtHeader(len); + qint8 type; + s.readExtHeader(len, type); if (len != 1 && len != 5 && len != 7) { s.setStatus(MsgPackStream::ReadCorruptData); dt = QDateTime();