Add peek(), readArrayHeader(), add length return to readExtHeader().

This commit is contained in:
Roman Isaikin
2019-07-11 14:35:24 +03:00
parent 7e1ca5b414
commit 1560252d1a
4 changed files with 244 additions and 56 deletions

View File

@ -37,41 +37,51 @@ MSGPACK_EXPORT QString version();
*/ */
namespace FirstByte { namespace FirstByte {
const quint8 POSITIVE_FIXINT = 0x7f; const quint8 POSITIVE_FIXINT = 0x7f;
const quint8 FIXMAP = 0x80;
const quint8 FIXARRAY = 0x90; const quint8 FIXMAP = 0x80;
const quint8 FIXSTR = 0xa0; const quint8 FIXMAP_MASK = 0xf;
const quint8 NIL = 0xc0; const quint8 FIXMAP_LAST = 0x8f;
const quint8 NEVER_USED = 0xc1;
const quint8 MFALSE = 0xc2; const quint8 FIXARRAY = 0x90;
const quint8 MTRUE = 0xc3; const quint8 FIXARRAY_MASK = 0xf;
const quint8 BIN8 = 0xc4; const quint8 FIXARRAY_LAST = 0x9f;
const quint8 BIN16 = 0xc5;
const quint8 BIN32 = 0xc6; const quint8 FIXSTR = 0xa0;
const quint8 EXT8 = 0xc7; const quint8 FIXSTR_MASK = 0x1f;
const quint8 EXT16 = 0xc8; const quint8 FIXSTR_LAST = 0xbf;
const quint8 EXT32 = 0xc9;
const quint8 FLOAT32 = 0xca; const quint8 NIL = 0xc0;
const quint8 FLOAT64 = 0xcb; const quint8 NEVER_USED = 0xc1;
const quint8 UINT8 = 0xcc; const quint8 MFALSE = 0xc2;
const quint8 UINT16 = 0xcd; const quint8 MTRUE = 0xc3;
const quint8 UINT32 = 0xce; const quint8 BIN8 = 0xc4;
const quint8 UINT64 = 0xcf; const quint8 BIN16 = 0xc5;
const quint8 INT8 = 0xd0; const quint8 BIN32 = 0xc6;
const quint8 INT16 = 0xd1; const quint8 EXT8 = 0xc7;
const quint8 INT32 = 0xd2; const quint8 EXT16 = 0xc8;
const quint8 INT64 = 0xd3; const quint8 EXT32 = 0xc9;
const quint8 FIXEXT1 = 0xd4; const quint8 FLOAT32 = 0xca;
const quint8 FIXEXT2 = 0xd5; const quint8 FLOAT64 = 0xcb;
const quint8 FIXEXT4 = 0xd6; const quint8 UINT8 = 0xcc;
const quint8 FIXEXT8 = 0xd7; const quint8 UINT16 = 0xcd;
const quint8 FIXEX16 = 0xd8; const quint8 UINT32 = 0xce;
const quint8 STR8 = 0xd9; const quint8 UINT64 = 0xcf;
const quint8 STR16 = 0xda; const quint8 INT8 = 0xd0;
const quint8 STR32 = 0xdb; const quint8 INT16 = 0xd1;
const quint8 ARRAY16 = 0xdc; const quint8 INT32 = 0xd2;
const quint8 ARRAY32 = 0xdd; const quint8 INT64 = 0xd3;
const quint8 MAP16 = 0xde; const quint8 FIXEXT1 = 0xd4;
const quint8 MAP32 = 0xdf; 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; const quint8 NEGATIVE_FIXINT = 0xe0;
} }
} }

View File

@ -26,15 +26,15 @@
return retVal; return retVal;
MsgPackStream::MsgPackStream() : 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) : 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) : 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); QBuffer *buf = new QBuffer(a);
buf->open(mode); buf->open(mode);
@ -42,7 +42,7 @@ MsgPackStream::MsgPackStream(QByteArray *a, QIODevice::OpenMode mode) :
} }
MsgPackStream::MsgPackStream(const QByteArray &a) : 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(); QBuffer *buf = new QBuffer();
buf->setData(a); buf->setData(a);
@ -336,20 +336,25 @@ bool MsgPackStream::readBytes(char *data, qint64 len)
CHECK_STREAM_PRECOND(false); CHECK_STREAM_PRECOND(false);
qint64 readed = 0; qint64 readed = 0;
qint64 thisRead = 0; qint64 thisRead = 0;
while (readed < len) if (blocking) {
{ while (readed < len)
thisRead = dev->read(data, (len - readed)); {
if (thisRead < 0) thisRead = dev->read(data, (len - readed));
break; if (thisRead < 0)
/* Advance the read pointer */ break;
data += thisRead; /* Advance the read pointer */
readed += thisRead; data += thisRead;
/* Data might not be available for a bit, so wait before reading again. */ readed += thisRead;
if (readed < len) { /* Data might not be available for a bit, so wait before reading again. */
dev->waitForReadyRead(-1); 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. */ /* FIXME: There are actual errors that can happen here. */
setStatus(ReadPastEnd); setStatus(ReadPastEnd);
return false; return false;
@ -357,7 +362,7 @@ bool MsgPackStream::readBytes(char *data, qint64 len)
return true; return true;
} }
bool MsgPackStream::readExtHeader(quint32 &len) bool MsgPackStream::readExtHeader(quint32 &len, qint8 &type)
{ {
CHECK_STREAM_PRECOND(false); CHECK_STREAM_PRECOND(false);
quint8 d[6]; quint8 d[6];
@ -369,6 +374,7 @@ bool MsgPackStream::readExtHeader(quint32 &len)
d[0] <= MsgPack::FirstByte::FIXEX16) { d[0] <= MsgPack::FirstByte::FIXEX16) {
len = 1; len = 1;
len <<= d[0] - MsgPack::FirstByte::FIXEXT1; len <<= d[0] - MsgPack::FirstByte::FIXEXT1;
type = d[1];
return true; return true;
} }
@ -381,10 +387,13 @@ bool MsgPackStream::readExtHeader(quint32 &len)
if (d[0] == MsgPack::FirstByte::EXT8) { if (d[0] == MsgPack::FirstByte::EXT8) {
len = d[1]; len = d[1];
type = d[2];
} else if (d[0] == MsgPack::FirstByte::EXT16) { } else if (d[0] == MsgPack::FirstByte::EXT16) {
len = _msgpack_load16(quint32, &d[1]); len = _msgpack_load16(quint32, &d[1]);
type = d[3];
} else if (d[0] == MsgPack::FirstByte::EXT32) { } else if (d[0] == MsgPack::FirstByte::EXT32) {
len = _msgpack_load32(quint32, &d[1]); len = _msgpack_load32(quint32, &d[1]);
type = d[5];
} else { } else {
setStatus(ReadCorruptData); setStatus(ReadCorruptData);
return false; return false;
@ -392,6 +401,38 @@ bool MsgPackStream::readExtHeader(quint32 &len)
return true; 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) MsgPackStream &MsgPackStream::operator<<(bool b)
{ {
CHECK_STREAM_WRITE_PRECOND(*this); CHECK_STREAM_WRITE_PRECOND(*this);
@ -572,6 +613,118 @@ bool MsgPackStream::writeExtHeader(quint32 len, qint8 msgpackType)
return true; 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) bool MsgPackStream::unpack_longlong(qint64 &i64)
{ {
quint8 p[9]; quint8 p[9];

View File

@ -9,6 +9,21 @@
#include <QIODevice> #include <QIODevice>
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 class MSGPACK_EXPORT MsgPackStream
{ {
public: public:
@ -43,7 +58,8 @@ public:
MsgPackStream &operator>>(QString &str); MsgPackStream &operator>>(QString &str);
MsgPackStream &operator>>(QByteArray &array); MsgPackStream &operator>>(QByteArray &array);
bool readBytes(char *data, qint64 len); 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<<(bool b);
MsgPackStream &operator<<(quint32 u32); MsgPackStream &operator<<(quint32 u32);
@ -58,11 +74,17 @@ public:
bool writeBytes(const char *data, qint64 len); bool writeBytes(const char *data, qint64 len);
bool writeExtHeader(quint32 len, qint8 msgpackType); bool writeExtHeader(quint32 len, qint8 msgpackType);
PeekResult peek() const;
void setBlocking(bool enabled);
void setRawMode(bool enabled);
private: private:
QIODevice *dev; QIODevice *dev;
bool owndev; bool owndev;
Status q_status; Status q_status;
bool flushWrites; bool flushWrites;
bool blocking;
bool m_rawMode;
bool unpack_longlong(qint64 &i64); bool unpack_longlong(qint64 &i64);
bool unpack_ulonglong(quint64 &u64); bool unpack_ulonglong(quint64 &u64);

View File

@ -74,7 +74,8 @@ MsgPackStream &operator<<(MsgPackStream &s, const QTime &t)
MsgPackStream& operator>>(MsgPackStream& s, QTime &t) MsgPackStream& operator>>(MsgPackStream& s, QTime &t)
{ {
quint32 len; quint32 len;
s.readExtHeader(len); qint8 type;
s.readExtHeader(len, type);
if (len != 1 && len != 2 && len != 4) { if (len != 1 && len != 2 && len != 4) {
s.setStatus(MsgPackStream::ReadCorruptData); s.setStatus(MsgPackStream::ReadCorruptData);
t = QTime(); t = QTime();
@ -109,7 +110,8 @@ MsgPackStream &operator<<(MsgPackStream &s, const QDate &date)
MsgPackStream& operator>>(MsgPackStream& s, QDate &date) MsgPackStream& operator>>(MsgPackStream& s, QDate &date)
{ {
quint32 len; quint32 len;
s.readExtHeader(len); qint8 type;
s.readExtHeader(len, type);
if (len != 1 && len != 3) { if (len != 1 && len != 3) {
s.setStatus(MsgPackStream::ReadCorruptData); s.setStatus(MsgPackStream::ReadCorruptData);
date = QDate(); date = QDate();
@ -150,7 +152,8 @@ MsgPackStream &operator<<(MsgPackStream& s, const QDateTime &dt)
MsgPackStream& operator>>(MsgPackStream& s, QDateTime &dt) MsgPackStream& operator>>(MsgPackStream& s, QDateTime &dt)
{ {
quint32 len; quint32 len;
s.readExtHeader(len); qint8 type;
s.readExtHeader(len, type);
if (len != 1 && len != 5 && len != 7) { if (len != 1 && len != 5 && len != 7) {
s.setStatus(MsgPackStream::ReadCorruptData); s.setStatus(MsgPackStream::ReadCorruptData);
dt = QDateTime(); dt = QDateTime();