mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-25 09:18:54 -05:00
745 lines
17 KiB
C++
745 lines
17 KiB
C++
///////////////////////////////////////////////////////////////////////////////////////
|
|
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
|
|
// written by Christian Daniel //
|
|
// Copyright (C) 2014 John Greb <hexameron@spam.no> //
|
|
// //
|
|
// This program is free software; you can redistribute it and/or modify //
|
|
// it under the terms of the GNU General Public License as published by //
|
|
// the Free Software Foundation as version 3 of the License, or //
|
|
// (at your option) any later version. //
|
|
// //
|
|
// This program is distributed in the hope that it will be useful, //
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
|
// GNU General Public License V3 for more details. //
|
|
// //
|
|
// You should have received a copy of the GNU General Public License //
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
#include <stdint.h>
|
|
#include "util/simpleserializer.h"
|
|
|
|
#if __WORDSIZE == 64
|
|
#define PRINTF_FORMAT_S32 "%d"
|
|
#define PRINTF_FORMAT_U32 "%u"
|
|
#define PRINTF_FORMAT_S64 "%d"
|
|
#define PRINTF_FORMAT_U64 "%u"
|
|
#else
|
|
#define PRINTF_FORMAT_S32 "%d"
|
|
#define PRINTF_FORMAT_U32 "%u"
|
|
#define PRINTF_FORMAT_S64 "%lld"
|
|
#define PRINTF_FORMAT_U64 "%llu"
|
|
#endif
|
|
|
|
template <bool> struct Assert { };
|
|
typedef Assert<(bool(sizeof(float) == 4))> float_must_be_32_bits[bool(sizeof(float) == 4) ? 1 : -1];
|
|
typedef Assert<(bool(sizeof(double) == 8))> double_must_be_64_bits[bool(sizeof(double) == 8) ? 1 : -1];
|
|
|
|
SimpleSerializer::SimpleSerializer(uint version) :
|
|
m_data(),
|
|
m_finalized(false)
|
|
{
|
|
m_data.reserve(100);
|
|
|
|
// write version information
|
|
int length;
|
|
if(version >= (1 << 24))
|
|
length = 4;
|
|
else if(version >= (1 << 16))
|
|
length = 3;
|
|
else if(version >= (1 << 8))
|
|
length = 2;
|
|
else if(version > 0)
|
|
length = 1;
|
|
else length = 0;
|
|
if(!writeTag(TVersion, 0, length))
|
|
return;
|
|
length--;
|
|
for(int i = length; i >= 0; i--)
|
|
m_data.push_back((char)((version >> (i * 8)) & 0xff));
|
|
}
|
|
|
|
void SimpleSerializer::writeS32(quint32 id, qint32 value)
|
|
{
|
|
int length;
|
|
|
|
if(id == 0) {
|
|
qCritical("SimpleSerializer: ID 0 is not allowed");
|
|
return;
|
|
}
|
|
|
|
if((value < -(1 << 23)) || (value >= (1 << 23)))
|
|
length = 4;
|
|
else if((value < -(1 << 15)) || (value >= (1 << 15)))
|
|
length = 3;
|
|
else if((value < -(1 << 7)) || (value >= (1 << 7)))
|
|
length = 2;
|
|
else if(value != 0)
|
|
length = 1;
|
|
else length = 0;
|
|
|
|
if(!writeTag(TSigned32, id, length))
|
|
return;
|
|
|
|
length--;
|
|
for(int i = length; i >= 0; i--)
|
|
m_data.push_back((char)((value >> (i * 8)) & 0xff));
|
|
}
|
|
|
|
void SimpleSerializer::writeU32(quint32 id, quint32 value)
|
|
{
|
|
int length;
|
|
|
|
if(id == 0) {
|
|
qCritical("SimpleSerializer: ID 0 is not allowed");
|
|
return;
|
|
}
|
|
|
|
if(value >= (1 << 24))
|
|
length = 4;
|
|
else if(value >= (1 << 16))
|
|
length = 3;
|
|
else if(value >= (1 << 8))
|
|
length = 2;
|
|
else if(value > 0)
|
|
length = 1;
|
|
else length = 0;
|
|
|
|
if(!writeTag(TUnsigned32, id, length))
|
|
return;
|
|
|
|
length--;
|
|
for(int i = length; i >= 0; i--)
|
|
m_data.push_back((char)((value >> (i * 8)) & 0xff));
|
|
}
|
|
|
|
void SimpleSerializer::writeS64(quint32 id, qint64 value)
|
|
{
|
|
int length;
|
|
|
|
if(id == 0) {
|
|
qCritical("SimpleSerializer: ID 0 is not allowed");
|
|
return;
|
|
}
|
|
|
|
if((value < -(1ll << 55)) || (value >= (1ll << 55)))
|
|
length = 8;
|
|
else if((value < -(1ll << 47)) || (value >= (1ll << 47)))
|
|
length = 7;
|
|
else if((value < -(1ll << 39)) || (value >= (1ll << 39)))
|
|
length = 6;
|
|
else if((value < -(1ll << 31)) || (value >= (1ll << 31)))
|
|
length = 5;
|
|
else if((value < -(1ll << 23)) || (value >= (1ll << 23)))
|
|
length = 4;
|
|
else if((value < -(1ll << 15)) || (value >= (1ll << 15)))
|
|
length = 3;
|
|
else if((value < -(1ll << 7)) || (value >= (1ll << 7)))
|
|
length = 2;
|
|
else if(value != 0)
|
|
length = 1;
|
|
else length = 0;
|
|
|
|
if(!writeTag(TSigned64, id, length))
|
|
return;
|
|
|
|
length--;
|
|
for(int i = length; i >= 0; i--)
|
|
m_data.push_back((char)((value >> (i * 8)) & 0xff));
|
|
}
|
|
|
|
void SimpleSerializer::writeU64(quint32 id, quint64 value)
|
|
{
|
|
int length;
|
|
|
|
if(id == 0) {
|
|
qCritical("SimpleSerializer: ID 0 is not allowed");
|
|
return;
|
|
}
|
|
|
|
if(value >= (1ll << 56))
|
|
length = 8;
|
|
else if(value >= (1ll << 48))
|
|
length = 7;
|
|
else if(value >= (1ll << 40))
|
|
length = 6;
|
|
else if(value >= (1ll << 32))
|
|
length = 5;
|
|
else if(value >= (1ll << 24))
|
|
length = 4;
|
|
else if(value >= (1ll << 16))
|
|
length = 3;
|
|
else if(value >= (1ll << 8))
|
|
length = 2;
|
|
else if(value > 0)
|
|
length = 1;
|
|
else length = 0;
|
|
|
|
if(!writeTag(TUnsigned64, id, length))
|
|
return;
|
|
|
|
length--;
|
|
for(int i = length; i >= 0; i--)
|
|
m_data.push_back((char)((value >> (i * 8)) & 0xff));
|
|
}
|
|
|
|
union floatasint {
|
|
quint32 u;
|
|
float f;
|
|
};
|
|
|
|
void SimpleSerializer::writeFloat(quint32 id, float value)
|
|
{
|
|
union floatasint tmp;
|
|
if(id == 0) {
|
|
qCritical("SimpleSerializer: ID 0 is not allowed");
|
|
return;
|
|
}
|
|
|
|
if(!writeTag(TFloat, id, 4))
|
|
return;
|
|
|
|
tmp.f = value;
|
|
m_data.push_back((char)((tmp.u >> 24) & 0xff));
|
|
m_data.push_back((char)((tmp.u >> 16) & 0xff));
|
|
m_data.push_back((char)((tmp.u >> 8) & 0xff));
|
|
m_data.push_back((char)(tmp.u & 0xff));
|
|
}
|
|
|
|
union doubleasint {
|
|
quint64 u;
|
|
double d;
|
|
};
|
|
|
|
void SimpleSerializer::writeDouble(quint32 id, double value)
|
|
{
|
|
union doubleasint tmp;
|
|
if(id == 0) {
|
|
qCritical("SimpleSerializer: ID 0 is not allowed");
|
|
return;
|
|
}
|
|
|
|
if(!writeTag(TDouble, id, 8))
|
|
return;
|
|
|
|
tmp.d = value;
|
|
m_data.push_back((char)((tmp.u >> 56) & 0xff));
|
|
m_data.push_back((char)((tmp.u >> 48) & 0xff));
|
|
m_data.push_back((char)((tmp.u >> 40) & 0xff));
|
|
m_data.push_back((char)((tmp.u >> 32) & 0xff));
|
|
m_data.push_back((char)((tmp.u >> 24) & 0xff));
|
|
m_data.push_back((char)((tmp.u >> 16) & 0xff));
|
|
m_data.push_back((char)((tmp.u >> 8) & 0xff));
|
|
m_data.push_back((char)(tmp.u & 0xff));
|
|
}
|
|
|
|
void SimpleSerializer::writeBool(quint32 id, bool value)
|
|
{
|
|
if(id == 0) {
|
|
qCritical("SimpleSerializer: ID 0 is not allowed");
|
|
return;
|
|
}
|
|
|
|
if(!writeTag(TBool, id, 1))
|
|
return;
|
|
if(value)
|
|
m_data.push_back((char)0x01);
|
|
else m_data.push_back((char)0x00);
|
|
}
|
|
|
|
void SimpleSerializer::writeString(quint32 id, const QString& value)
|
|
{
|
|
if(id == 0) {
|
|
qCritical("SimpleSerializer: ID 0 is not allowed");
|
|
return;
|
|
}
|
|
|
|
QByteArray utf8 = value.toUtf8();
|
|
if(!writeTag(TString, id, utf8.size()))
|
|
return;
|
|
m_data.append(utf8);
|
|
}
|
|
|
|
void SimpleSerializer::writeBlob(quint32 id, const QByteArray& value)
|
|
{
|
|
if(id == 0) {
|
|
qCritical("SimpleSerializer: ID 0 is not allowed");
|
|
return;
|
|
}
|
|
|
|
if(!writeTag(TBlob, id, value.size()))
|
|
return;
|
|
m_data.append(value);
|
|
}
|
|
|
|
const QByteArray& SimpleSerializer::final()
|
|
{
|
|
m_finalized = true;
|
|
return m_data;
|
|
}
|
|
|
|
bool SimpleSerializer::writeTag(Type type, quint32 id, quint32 length)
|
|
{
|
|
if(m_finalized) {
|
|
qCritical("SimpleSerializer: config has already been finalized (id %u)", id);
|
|
return false;
|
|
}
|
|
|
|
int idLen;
|
|
int lengthLen;
|
|
|
|
if(id < (1 << 8))
|
|
idLen = 0;
|
|
else if(id < (1 << 16))
|
|
idLen = 1;
|
|
else if(id < (1 << 24))
|
|
idLen = 2;
|
|
else idLen = 3;
|
|
|
|
if(length < (1 << 8))
|
|
lengthLen = 0;
|
|
else if(length < (1 << 16))
|
|
lengthLen = 1;
|
|
else if(length < (1 << 24))
|
|
lengthLen = 2;
|
|
else lengthLen = 3;
|
|
|
|
m_data.push_back((char)((type << 4) | (idLen << 2) | lengthLen));
|
|
for(int i = idLen; i >= 0; i--)
|
|
m_data.push_back((char)((id >> (i * 8)) & 0xff));
|
|
for(int i = lengthLen; i >= 0; i--)
|
|
m_data.push_back((char)((length >> (i * 8)) & 0xff));
|
|
return true;
|
|
}
|
|
|
|
SimpleDeserializer::SimpleDeserializer(const QByteArray& data) :
|
|
m_data(data)
|
|
{
|
|
m_valid = parseAll();
|
|
|
|
// read version information
|
|
uint readOfs;
|
|
Elements::const_iterator it = m_elements.constFind(0);
|
|
if(it == m_elements.constEnd())
|
|
goto setInvalid;
|
|
if(it->type != TVersion)
|
|
goto setInvalid;
|
|
if(it->length > 4)
|
|
goto setInvalid;
|
|
|
|
readOfs = it->ofs;
|
|
m_version = 0;
|
|
for(uint i = 0; i < it->length; i++)
|
|
m_version = (m_version << 8) | readByte(&readOfs);
|
|
return;
|
|
|
|
setInvalid:
|
|
m_valid = false;
|
|
}
|
|
|
|
bool SimpleDeserializer::readS32(quint32 id, qint32* result, qint32 def) const
|
|
{
|
|
uint readOfs;
|
|
qint32 tmp;
|
|
Elements::const_iterator it = m_elements.constFind(id);
|
|
if(it == m_elements.constEnd())
|
|
goto returnDefault;
|
|
if(it->type != TSigned32)
|
|
goto returnDefault;
|
|
if(it->length > 4)
|
|
goto returnDefault;
|
|
|
|
readOfs = it->ofs;
|
|
tmp = 0;
|
|
for(uint i = 0; i < it->length; i++) {
|
|
quint8 byte = readByte(&readOfs);
|
|
if((i == 0) && (byte & 0x80))
|
|
tmp = -1;
|
|
tmp = (tmp << 8) | byte;
|
|
}
|
|
*result = tmp;
|
|
return true;
|
|
|
|
returnDefault:
|
|
*result = def;
|
|
return false;
|
|
}
|
|
|
|
bool SimpleDeserializer::readU32(quint32 id, quint32* result, quint32 def) const
|
|
{
|
|
uint readOfs;
|
|
quint32 tmp;
|
|
Elements::const_iterator it = m_elements.constFind(id);
|
|
if(it == m_elements.constEnd())
|
|
goto returnDefault;
|
|
if(it->type != TUnsigned32)
|
|
goto returnDefault;
|
|
if(it->length > 4)
|
|
goto returnDefault;
|
|
|
|
readOfs = it->ofs;
|
|
tmp = 0;
|
|
for(uint i = 0; i < it->length; i++)
|
|
tmp = (tmp << 8) | readByte(&readOfs);
|
|
*result = tmp;
|
|
return true;
|
|
|
|
returnDefault:
|
|
*result = def;
|
|
return false;
|
|
}
|
|
|
|
bool SimpleDeserializer::readS64(quint32 id, qint64* result, qint64 def) const
|
|
{
|
|
uint readOfs;
|
|
qint64 tmp;
|
|
Elements::const_iterator it = m_elements.constFind(id);
|
|
if(it == m_elements.constEnd())
|
|
goto returnDefault;
|
|
if(it->type != TSigned64)
|
|
goto returnDefault;
|
|
if(it->length > 8)
|
|
goto returnDefault;
|
|
|
|
readOfs = it->ofs;
|
|
tmp = 0;
|
|
for(uint i = 0; i < it->length; i++) {
|
|
quint8 byte = readByte(&readOfs);
|
|
if((i == 0) && (byte & 0x80))
|
|
tmp = -1;
|
|
tmp = (tmp << 8) | byte;
|
|
}
|
|
*result = tmp;
|
|
return true;
|
|
|
|
returnDefault:
|
|
*result = def;
|
|
return false;
|
|
}
|
|
|
|
bool SimpleDeserializer::readU64(quint32 id, quint64* result, quint64 def) const
|
|
{
|
|
uint readOfs;
|
|
quint64 tmp;
|
|
Elements::const_iterator it = m_elements.constFind(id);
|
|
if(it == m_elements.constEnd())
|
|
goto returnDefault;
|
|
if(it->type != TUnsigned64)
|
|
goto returnDefault;
|
|
if(it->length > 8)
|
|
goto returnDefault;
|
|
|
|
readOfs = it->ofs;
|
|
tmp = 0;
|
|
for(uint i = 0; i < it->length; i++)
|
|
tmp = (tmp << 8) | readByte(&readOfs);
|
|
*result = tmp;
|
|
return true;
|
|
|
|
returnDefault:
|
|
*result = def;
|
|
return false;
|
|
}
|
|
|
|
bool SimpleDeserializer::readFloat(quint32 id, float* result, float def) const
|
|
{
|
|
uint readOfs;
|
|
union floatasint tmp;
|
|
Elements::const_iterator it = m_elements.constFind(id);
|
|
if(it == m_elements.constEnd())
|
|
goto returnDefault;
|
|
if(it->type != TFloat)
|
|
goto returnDefault;
|
|
if(it->length != 4)
|
|
goto returnDefault;
|
|
|
|
readOfs = it->ofs;
|
|
tmp.u = 0;
|
|
for(int i = 0; i < 4; i++)
|
|
tmp.u = (tmp.u << 8) | readByte(&readOfs);
|
|
*result = tmp.f;
|
|
return true;
|
|
|
|
returnDefault:
|
|
*result = def;
|
|
return false;
|
|
}
|
|
|
|
bool SimpleDeserializer::readDouble(quint32 id, double* result, double def) const
|
|
{
|
|
uint readOfs;
|
|
union doubleasint tmp;
|
|
Elements::const_iterator it = m_elements.constFind(id);
|
|
if(it == m_elements.constEnd())
|
|
goto returnDefault;
|
|
if(it->type != TDouble)
|
|
goto returnDefault;
|
|
if(it->length != 8)
|
|
goto returnDefault;
|
|
|
|
readOfs = it->ofs;
|
|
tmp.u = 0;
|
|
for(int i = 0; i < 8; i++)
|
|
tmp.u = (tmp.u << 8) | readByte(&readOfs);
|
|
*result = tmp.d;
|
|
return true;
|
|
|
|
returnDefault:
|
|
*result = def;
|
|
return false;
|
|
}
|
|
|
|
union real4asint {
|
|
quint32 u;
|
|
Real r;
|
|
};
|
|
|
|
union real8asint {
|
|
quint64 u;
|
|
Real r;
|
|
};
|
|
|
|
bool SimpleDeserializer::readReal(quint32 id, Real* result, Real def) const
|
|
{
|
|
if(sizeof(Real) == 4) {
|
|
uint readOfs;
|
|
union real4asint tmp;
|
|
Elements::const_iterator it = m_elements.constFind(id);
|
|
if(it == m_elements.constEnd())
|
|
goto returnDefault32;
|
|
if(it->type != TFloat)
|
|
goto returnDefault32;
|
|
if(it->length != 4)
|
|
goto returnDefault32;
|
|
|
|
readOfs = it->ofs;
|
|
tmp.u = 0;
|
|
for(int i = 0; i < 4; i++)
|
|
tmp.u = (tmp.u << 8) | readByte(&readOfs);
|
|
*result = tmp.r;
|
|
return true;
|
|
|
|
returnDefault32:
|
|
*result = def;
|
|
return false;
|
|
} else {
|
|
uint readOfs;
|
|
union real8asint tmp;
|
|
Elements::const_iterator it = m_elements.constFind(id);
|
|
if(it == m_elements.constEnd())
|
|
goto returnDefault64;
|
|
if(it->type != TDouble)
|
|
goto returnDefault64;
|
|
if(it->length != 8)
|
|
goto returnDefault64;
|
|
|
|
readOfs = it->ofs;
|
|
tmp.u = 0;
|
|
for(int i = 0; i < 8; i++)
|
|
tmp.u = (tmp.u << 8) | readByte(&readOfs);
|
|
*result = tmp.r;
|
|
return true;
|
|
|
|
returnDefault64:
|
|
*result = def;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool SimpleDeserializer::readBool(quint32 id, bool* result, bool def) const
|
|
{
|
|
uint readOfs;
|
|
quint8 tmp;
|
|
Elements::const_iterator it = m_elements.constFind(id);
|
|
if(it == m_elements.constEnd())
|
|
goto returnDefault;
|
|
if(it->type != TBool)
|
|
goto returnDefault;
|
|
if(it->length != 1)
|
|
goto returnDefault;
|
|
|
|
readOfs = it->ofs;
|
|
tmp = readByte(&readOfs);
|
|
if(tmp == 0x00)
|
|
*result = false;
|
|
else *result = true;
|
|
return true;
|
|
|
|
returnDefault:
|
|
*result = def;
|
|
return false;
|
|
}
|
|
|
|
bool SimpleDeserializer::readString(quint32 id, QString* result, const QString& def) const
|
|
{
|
|
Elements::const_iterator it = m_elements.constFind(id);
|
|
if(it == m_elements.constEnd())
|
|
goto returnDefault;
|
|
if(it->type != TString)
|
|
goto returnDefault;
|
|
|
|
*result = QString::fromUtf8(m_data.data() + it->ofs, it->length);
|
|
return true;
|
|
|
|
returnDefault:
|
|
*result = def;
|
|
return false;
|
|
}
|
|
|
|
bool SimpleDeserializer::readBlob(quint32 id, QByteArray* result, const QByteArray& def) const
|
|
{
|
|
Elements::const_iterator it = m_elements.constFind(id);
|
|
if(it == m_elements.constEnd())
|
|
goto returnDefault;
|
|
if(it->type != TBlob)
|
|
goto returnDefault;
|
|
|
|
*result = QByteArray(m_data.data() + it->ofs, it->length);
|
|
return true;
|
|
|
|
returnDefault:
|
|
*result = def;
|
|
return false;
|
|
}
|
|
|
|
void SimpleDeserializer::dump() const
|
|
{
|
|
if(!m_valid) {
|
|
qDebug("SimpleDeserializer dump: data invalid");
|
|
return;
|
|
} else {
|
|
qDebug("SimpleDeserializer dump: version %u", m_version);
|
|
}
|
|
|
|
for(Elements::const_iterator it = m_elements.constBegin(); it != m_elements.constEnd(); ++it) {
|
|
switch(it->type) {
|
|
case TSigned32: {
|
|
qint32 tmp;
|
|
readS32(it.key(), &tmp);
|
|
qDebug("id %d, S32, len %d: " PRINTF_FORMAT_S32, it.key(), it->length, tmp);
|
|
break;
|
|
}
|
|
case TUnsigned32: {
|
|
quint32 tmp;
|
|
readU32(it.key(), &tmp);
|
|
qDebug("id %d, U32, len %d: " PRINTF_FORMAT_U32, it.key(), it->length, tmp);
|
|
break;
|
|
}
|
|
case TSigned64: {
|
|
qint64 tmp;
|
|
readS64(it.key(), &tmp);
|
|
// qDebug("id %d, S64, len %d: " PRINTF_FORMAT_S64, it.key(), it->length, (int)tmp);
|
|
break;
|
|
}
|
|
case TUnsigned64: {
|
|
quint64 tmp;
|
|
readU64(it.key(), &tmp);
|
|
// qDebug("id %d, U64, len %d: " PRINTF_FORMAT_U64, it.key(), it->length, (uint)tmp);
|
|
break;
|
|
}
|
|
case TFloat: {
|
|
float tmp;
|
|
readFloat(it.key(), &tmp);
|
|
qDebug("id %d, FLOAT, len %d: %f", it.key(), it->length, tmp);
|
|
break;
|
|
}
|
|
case TDouble: {
|
|
double tmp;
|
|
readDouble(it.key(), &tmp);
|
|
qDebug("id %d, DOUBLE, len %d: %f", it.key(), it->length, tmp);
|
|
break;
|
|
}
|
|
case TBool: {
|
|
bool tmp;
|
|
readBool(it.key(), &tmp);
|
|
qDebug("id %d, BOOL, len %d: %s", it.key(), it->length, tmp ? "true" : "false");
|
|
break;
|
|
}
|
|
case TString: {
|
|
QString tmp;
|
|
readString(it.key(), &tmp);
|
|
qDebug("id %d, STRING, len %d: \"%s\"", it.key(), it->length, qPrintable(tmp));
|
|
break;
|
|
}
|
|
case TBlob: {
|
|
QByteArray tmp;
|
|
readBlob(it.key(), &tmp);
|
|
qDebug("id %d, BLOB, len %d", it.key(), it->length);
|
|
break;
|
|
}
|
|
case TVersion: {
|
|
qDebug("id %d, VERSION, len %d", it.key(), it->length);
|
|
break;
|
|
}
|
|
default: {
|
|
qDebug("id %d, UNKNOWN TYPE 0x%02x, len %d", it.key(), it->type, it->length);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool SimpleDeserializer::parseAll()
|
|
{
|
|
uint readOfs = 0;
|
|
Type type;
|
|
quint32 id;
|
|
quint32 length;
|
|
|
|
/*
|
|
QString hex;
|
|
for(int i = 0; i < m_data.size(); i++)
|
|
hex.append(QString("%1 ").arg((quint8)m_data[i], 2, 16, QChar('0')));
|
|
qDebug("%s", qPrintable(hex));
|
|
qDebug("==");
|
|
*/
|
|
|
|
while(readOfs < (uint)m_data.size()) {
|
|
if(!readTag(&readOfs, m_data.size(), &type, &id, &length))
|
|
return false;
|
|
|
|
//qDebug("-- id %d, TYPE 0x%02x, len %d", id, type, length);
|
|
|
|
if(m_elements.contains(id)) {
|
|
qDebug("SimpleDeserializer: same ID found twice (id %u)", id);
|
|
return false;
|
|
}
|
|
|
|
m_elements.insert(id, Element(type, readOfs, length));
|
|
|
|
readOfs += length;
|
|
|
|
if(readOfs == (uint)m_data.size())
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool SimpleDeserializer::readTag(uint* readOfs, uint readEnd, Type* type, quint32* id, quint32* length) const
|
|
{
|
|
quint8 tag = readByte(readOfs);
|
|
|
|
*type = (Type)(tag >> 4);
|
|
int idLen = ((tag >> 2) & 0x03) + 1;
|
|
int lengthLen = (tag & 0x03) + 1;
|
|
|
|
// make sure we have enough header bytes left
|
|
if(((*readOfs) + idLen + lengthLen) > readEnd)
|
|
return false;
|
|
|
|
quint32 tmp = 0;
|
|
for(int i = 0; i < idLen; i++)
|
|
tmp = (tmp << 8) | readByte(readOfs);
|
|
*id = tmp;
|
|
tmp = 0;
|
|
for(int i = 0; i < lengthLen; i++)
|
|
tmp = (tmp << 8) | readByte(readOfs);
|
|
*length = tmp;
|
|
|
|
// check if payload fits the buffer
|
|
if(((*readOfs) + (*length)) > readEnd)
|
|
return false;
|
|
else return true;
|
|
}
|
|
|