mumble-voip_mumble/src/PacketDataStream.h

414 lines
10 KiB
C++

// Copyright 2009-2023 The Mumble Developers. All rights reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file at the root of the
// Mumble source tree or at <https://www.mumble.info/LICENSE>.
#ifndef MUMBLE_PACKETDATASTREAM_H_
#define MUMBLE_PACKETDATASTREAM_H_
#include <QByteArray>
#include <QPair>
#include <QString>
#include <cstring>
/*
* GCC doesn't yet do inter-object-file inlining, so unfortunately, this all has to be defined here.
*/
class PacketDataStream {
private:
Q_DISABLE_COPY(PacketDataStream)
private:
unsigned char *data;
quint32 maxsize;
quint32 offset;
quint32 overshoot;
bool ok;
public:
quint32 size() const { return offset; }
quint32 capacity() const { return maxsize; }
bool isValid() const { return ok; }
quint32 left() const { return maxsize - offset; }
quint32 undersize() const { return overshoot; }
void append(const quint64 v) {
#ifndef QT_NO_DEBUG
Q_ASSERT(v <= 0xff);
#endif
if (offset < maxsize)
data[offset++] = static_cast< unsigned char >(v);
else {
ok = false;
overshoot++;
}
};
void append(const char *d, quint32 len) {
if (left() >= len) {
memcpy(&data[offset], d, len);
offset += len;
} else {
unsigned int l = left();
memset(&data[offset], 0, l);
offset += l;
overshoot += len - l;
ok = false;
}
}
void skip(quint32 len) {
if (left() >= len)
offset += len;
else
ok = false;
}
quint64 next() {
if (offset < maxsize)
return data[offset++];
else {
ok = false;
return 0;
}
};
quint8 next8() {
if (offset < maxsize)
return data[offset++];
else {
ok = false;
return 0;
}
}
void rewind() { offset = 0; }
void truncate() { maxsize = offset; }
const unsigned char *dataPtr() const { return reinterpret_cast< const unsigned char * >(&data[offset]); }
unsigned char *dataPtr() { return reinterpret_cast< unsigned char * >(&data[offset]); }
const char *charPtr() const { return reinterpret_cast< const char * >(&data[offset]); }
QByteArray dataBlock(quint32 len) {
if (len <= left()) {
QByteArray a(charPtr(), static_cast< int >(len));
offset += len;
return a;
} else {
ok = false;
return QByteArray();
}
}
protected:
void setup(unsigned char *d, unsigned int msize) {
data = d;
offset = 0;
overshoot = 0;
maxsize = msize;
ok = true;
}
public:
PacketDataStream(const unsigned char *d, unsigned int msize) { setup(const_cast< unsigned char * >(d), msize); };
PacketDataStream(const char *d, unsigned int msize) {
setup(const_cast< unsigned char * >(reinterpret_cast< const unsigned char * >(d)), msize);
};
PacketDataStream(char *d, unsigned int msize) { setup(reinterpret_cast< unsigned char * >(d), msize); };
PacketDataStream(unsigned char *d, unsigned int msize) { setup(d, msize); };
PacketDataStream(const QByteArray &qba) {
setup(const_cast< unsigned char * >(reinterpret_cast< const unsigned char * >(qba.constData())),
static_cast< unsigned int >(qba.size()));
}
PacketDataStream(QByteArray &qba) {
unsigned char *ptr = reinterpret_cast< unsigned char * >(qba.data());
setup(ptr, static_cast< unsigned int >(qba.capacity()));
}
PacketDataStream &operator<<(const quint64 value) {
quint64 i = value;
if ((i & 0x8000000000000000LL) && (~i < 0x100000000LL)) {
// Signed number.
i = ~i;
if (i <= 0x3) {
// Special case for -1 to -4. The most significant bits of the first byte must be (in binary) 111111
// followed by the 2 bits representing the absolute value of the encoded number. Shortcase for -1 to -4
append(0xFC | i);
return *this;
} else {
// Add flag byte, whose most significant bits are (in binary) 111110 that indicates
// that what follows is the varint encoding of the absolute value of i, but that the
// value itself is supposed to be negative.
append(0xF8);
}
}
if (i < 0x80) {
// Encode as 7-bit, positive number -> most significant bit of first byte must be zero
append(i);
} else if (i < 0x4000) {
// Encode as 14-bit, positive number -> most significant bits of first byte must be (in binary) 10
append((i >> 8) | 0x80);
append(i & 0xFF);
} else if (i < 0x200000) {
// Encode as 21-bit, positive number -> most significant bits of first byte must be (in binary) 110
append((i >> 16) | 0xC0);
append((i >> 8) & 0xFF);
append(i & 0xFF);
} else if (i < 0x10000000) {
// Encode as 28-bit, positive number -> most significant bits of first byte must be (in binary) 1110
append((i >> 24) | 0xE0);
append((i >> 16) & 0xFF);
append((i >> 8) & 0xFF);
append(i & 0xFF);
} else if (i < 0x100000000LL) {
// Encode as 32-bit, positive number -> most significant bits of first byte must be (in binary) 111100
// Remaining bits in first byte remain unused
append(0xF0);
append((i >> 24) & 0xFF);
append((i >> 16) & 0xFF);
append((i >> 8) & 0xFF);
append(i & 0xFF);
} else {
// Encode as 64-bit, positive number -> most significant bits of first byte must be (in binary) 111101
// Remaining bits in first byte remain unused
append(0xF4);
append((i >> 56) & 0xFF);
append((i >> 48) & 0xFF);
append((i >> 40) & 0xFF);
append((i >> 32) & 0xFF);
append((i >> 24) & 0xFF);
append((i >> 16) & 0xFF);
append((i >> 8) & 0xFF);
append(i & 0xFF);
}
return *this;
}
PacketDataStream &operator>>(quint64 &i) {
quint64 v = next();
if ((v & 0x80) == 0x00) {
i = (v & 0x7F);
} else if ((v & 0xC0) == 0x80) {
i = (v & 0x3F) << 8 | next();
} else if ((v & 0xF0) == 0xF0) {
switch (v & 0xFC) {
case 0xF0:
i = next() << 24 | next() << 16 | next() << 8 | next();
break;
case 0xF4:
i = next() << 56 | next() << 48 | next() << 40 | next() << 32 | next() << 24 | next() << 16
| next() << 8 | next();
break;
case 0xF8:
*this >> i;
i = ~i;
break;
case 0xFC:
i = v & 0x03;
i = ~i;
break;
default:
ok = false;
i = 0;
break;
}
} else if ((v & 0xF0) == 0xE0) {
i = (v & 0x0F) << 24 | next() << 16 | next() << 8 | next();
} else if ((v & 0xE0) == 0xC0) {
i = (v & 0x1F) << 16 | next() << 8 | next();
}
return *this;
}
PacketDataStream &operator<<(const QByteArray &a) {
*this << a.size();
append(a.constData(), static_cast< unsigned int >(a.size()));
return *this;
}
PacketDataStream &operator>>(QByteArray &a) {
quint32 len;
*this >> len;
if (len > left()) {
len = left();
ok = false;
}
a = QByteArray(reinterpret_cast< const char * >(&data[offset]), static_cast< int >(len));
offset += len;
return *this;
}
PacketDataStream &operator<<(const QString &s) { return *this << s.toUtf8(); }
// Using the data directly instead of through qbuff avoids a copy.
PacketDataStream &operator>>(QString &s) {
quint32 len;
*this >> len;
if (len > left()) {
len = left();
ok = false;
}
s = QString::fromUtf8(reinterpret_cast< const char * >(&data[offset]), static_cast< int >(len));
offset += len;
return *this;
}
PacketDataStream &operator<<(const bool b) {
quint32 v = b ? 1 : 0;
return *this << v;
}
PacketDataStream &operator>>(bool &b) {
quint32 v;
*this >> v;
b = v ? true : false;
return *this;
}
#define INTMAPOPERATOR(type) \
PacketDataStream &operator<<(const type v) { return *this << static_cast< quint64 >(v); } \
PacketDataStream &operator>>(type &v) { \
quint64 vv; \
*this >> vv; \
v = static_cast< type >(vv); \
return *this; \
}
INTMAPOPERATOR(int);
INTMAPOPERATOR(unsigned int);
INTMAPOPERATOR(short);
INTMAPOPERATOR(unsigned short);
INTMAPOPERATOR(char);
INTMAPOPERATOR(unsigned char);
union double64u {
quint64 ui;
double d;
};
PacketDataStream &operator<<(const double v) {
double64u u;
u.d = v;
return *this << u.ui;
}
PacketDataStream &operator>>(double &v) {
double64u u;
*this >> u.ui;
v = u.d;
return *this;
}
union float32u {
quint8 ui[4];
float f;
};
PacketDataStream &operator<<(const float v) {
float32u u;
u.f = v;
append(u.ui[0]);
append(u.ui[1]);
append(u.ui[2]);
append(u.ui[3]);
return *this;
}
PacketDataStream &operator>>(float &v) {
float32u u;
if (left() < 4) {
ok = false;
v = 0;
}
u.ui[0] = next8();
u.ui[1] = next8();
u.ui[2] = next8();
u.ui[3] = next8();
v = u.f;
return *this;
}
template< typename T > PacketDataStream &operator<<(const QList< T > &l) {
*this << l.size();
for (int i = 0; i < l.size(); i++)
*this << l.at(i);
return *this;
}
template< typename T > PacketDataStream &operator>>(QList< T > &l) {
l.clear();
quint32 len;
*this >> len;
if (len > left()) {
len = left();
ok = false;
}
for (quint32 i = 0; i < len; i++) {
if (left() == 0) {
ok = false;
break;
}
T t;
*this >> t;
l.append(t);
}
return *this;
}
template< typename T > PacketDataStream &operator<<(const QSet< T > &s) {
*this << s.size();
for (typename QSet< T >::const_iterator i = s.constBegin(); i != s.constEnd(); ++i)
*this << *i;
return *this;
}
template< typename T > PacketDataStream &operator>>(QSet< T > &s) {
s.clear();
quint32 len;
*this >> len;
if (len > left()) {
len = left();
ok = false;
}
for (quint32 i = 0; i < len; i++) {
if (left() == 0) {
ok = false;
break;
}
T t;
*this >> t;
s.insert(t);
}
return *this;
}
template< typename T, typename U > PacketDataStream &operator<<(const QPair< T, U > &p) {
return *this << p.first << p.second;
}
template< typename T, typename U > PacketDataStream &operator>>(QPair< T, U > &p) {
return *this >> p.first >> p.second;
}
};
#endif