Serialization

- Adds prototype impls for InMemoryWriter and InMemoryReader.
- Use major- and minor-version idiom
This commit is contained in:
mfreiholz 2016-04-01 09:52:59 +02:00
parent 6c587ff8c4
commit 4debaaaf85
2 changed files with 251 additions and 31 deletions

View File

@ -5,6 +5,7 @@
#include <QList> #include <QList>
#include <QString> #include <QString>
#include <QDataStream> #include <QDataStream>
#include <QBuffer>
#include "ads/API.h" #include "ads/API.h"
@ -13,26 +14,32 @@ ADS_NAMESPACE_SER_BEGIN
class Header class Header
{ {
public: public:
static qint32 MAGIC;
static qint32 MAJOR_VERSION;
static qint32 MINOR_VERSION;
Header(); Header();
qint32 magic; qint32 magic;
qint32 version; qint32 majorVersion;
qint32 minorVersion;
}; };
QDataStream& operator<<(QDataStream& out, const Header& data); QDataStream& operator<<(QDataStream& out, const Header& data);
QDataStream& operator>>(QDataStream& in, Header& data); QDataStream& operator>>(QDataStream& in, Header& data);
class OffsetHeader class OffsetsHeader
{ {
public: public:
OffsetHeader(); OffsetsHeader();
qint64 length;
QList<class OffsetHeaderEntry> entries; qint64 entriesCount;
QList<class OffsetsHeaderEntry> entries;
}; };
QDataStream& operator<<(QDataStream& out, const OffsetHeader& data); QDataStream& operator<<(QDataStream& out, const OffsetsHeader& data);
QDataStream& operator>>(QDataStream& in, OffsetHeader& data); QDataStream& operator>>(QDataStream& in, OffsetsHeader& data);
class OffsetHeaderEntry class OffsetsHeaderEntry
{ {
public: public:
enum Type enum Type
@ -42,13 +49,13 @@ public:
SectionIndex = 0x00000003 SectionIndex = 0x00000003
}; };
OffsetHeaderEntry(); OffsetsHeaderEntry();
qint32 type; qint32 type;
qint64 offset; qint64 offset;
qint64 length; qint64 contentSize;
}; };
QDataStream& operator<<(QDataStream& out, const OffsetHeaderEntry& data); QDataStream& operator<<(QDataStream& out, const OffsetsHeaderEntry& data);
QDataStream& operator>>(QDataStream& in, OffsetHeaderEntry& data); QDataStream& operator>>(QDataStream& in, OffsetsHeaderEntry& data);
class Section class Section
@ -111,6 +118,42 @@ public:
qint32 sectionsCount; qint32 sectionsCount;
QList<Section> sections; QList<Section> sections;
}; };
QDataStream& operator<<(QDataStream& out, const SectionIndexData& data);
QDataStream& operator>>(QDataStream& in, SectionIndexData& data);
/*!
* \brief The InMemoryWriter class writes into a QByteArray.
*/
class InMemoryWriter
{
public:
InMemoryWriter();
bool write(OffsetsHeaderEntry::Type type, const QByteArray& data);
bool write(const SectionIndexData& data);
QByteArray toByteArray() const;
private:
QBuffer _contentBuffer;
OffsetsHeader _offsetsHeader;
};
/*!
* \brief The InMemoryReader class
*/
class InMemoryReader
{
public:
InMemoryReader(const QByteArray& data);
bool initReadHeader();
bool read(OffsetsHeaderEntry::Type type, QByteArray &data) const;
private:
QByteArray _data;
QBuffer _buff;
OffsetsHeader _offsetsHeader;
};
ADS_NAMESPACE_SER_END ADS_NAMESPACE_SER_END
#endif #endif

View File

@ -1,5 +1,7 @@
#include "ads/Serialization.h" #include "ads/Serialization.h"
#include <QDebug>
ADS_NAMESPACE_SER_BEGIN ADS_NAMESPACE_SER_BEGIN
/* /*
@ -11,7 +13,8 @@ ADS_NAMESPACE_SER_BEGIN
# Data Format Header # Data Format Header
quint32 Magic quint32 Magic
quint32 Version quint32 Major Version
quint32 Minor Version
# Offsets of available contents # Offsets of available contents
@ -58,48 +61,54 @@ ADS_NAMESPACE_SER_BEGIN
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
qint32 Header::MAGIC = 0x00001337;
qint32 Header::MAJOR_VERSION = 2;
qint32 Header::MINOR_VERSION = 0;
Header::Header() : Header::Header() :
magic(0), version(0) magic(0), majorVersion(0), minorVersion(0)
{ {
} }
QDataStream& operator<<(QDataStream& out, const Header& data) QDataStream& operator<<(QDataStream& out, const Header& data)
{ {
out << data.magic; out << data.magic;
out << data.version; out << data.majorVersion;
out << data.minorVersion;
return out; return out;
} }
QDataStream& operator>>(QDataStream& in, Header& data) QDataStream& operator>>(QDataStream& in, Header& data)
{ {
in >> data.magic; in >> data.magic;
in >> data.version; in >> data.majorVersion;
in >> data.minorVersion;
return in; return in;
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
OffsetHeader::OffsetHeader() : OffsetsHeader::OffsetsHeader() :
length(0) entriesCount(0)
{ {
} }
QDataStream& operator<<(QDataStream& out, const OffsetHeader& data) QDataStream& operator<<(QDataStream& out, const OffsetsHeader& data)
{ {
out << data.length; out << data.entriesCount;
for (int i = 0; i < data.length; ++i) for (int i = 0; i < data.entriesCount; ++i)
{ {
out << data.entries.at(i); out << data.entries.at(i);
} }
return out; return out;
} }
QDataStream& operator>>(QDataStream& in, OffsetHeader& data) QDataStream& operator>>(QDataStream& in, OffsetsHeader& data)
{ {
in >> data.length; in >> data.entriesCount;
for (int i = 0; i < data.length; ++i) for (int i = 0; i < data.entriesCount; ++i)
{ {
OffsetHeaderEntry entry; OffsetsHeaderEntry entry;
in >> entry; in >> entry;
data.entries.append(entry); data.entries.append(entry);
} }
@ -108,24 +117,24 @@ QDataStream& operator>>(QDataStream& in, OffsetHeader& data)
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
OffsetHeaderEntry::OffsetHeaderEntry() : OffsetsHeaderEntry::OffsetsHeaderEntry() :
type(Unknown), offset(0), length(0) type(Unknown), offset(0), contentSize(0)
{ {
} }
QDataStream& operator<<(QDataStream& out, const OffsetHeaderEntry& data) QDataStream& operator<<(QDataStream& out, const OffsetsHeaderEntry& data)
{ {
out << data.type; out << data.type;
out << data.offset; out << data.offset;
out << data.length; out << data.contentSize;
return out; return out;
} }
QDataStream& operator>>(QDataStream& in, OffsetHeaderEntry& data) QDataStream& operator>>(QDataStream& in, OffsetsHeaderEntry& data)
{ {
in >> data.type; in >> data.type;
in >> data.offset; in >> data.offset;
in >> data.length; in >> data.contentSize;
return in; return in;
} }
@ -236,4 +245,172 @@ QDataStream& operator>>(QDataStream& in, HierarchyData& data)
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
SectionIndexData::SectionIndexData() :
sectionsCount(0)
{
}
QDataStream& operator<<(QDataStream& out, const SectionIndexData& data)
{
out << data.sectionsCount;
for (int i = 0; i < data.sectionsCount; ++i)
{
out << data.sections.at(i);
}
return out;
}
QDataStream& operator>>(QDataStream& in, SectionIndexData& data)
{
in >> data.sectionsCount;
for (int i = 0; i < data.sectionsCount; ++i)
{
Section s;
in >> s;
data.sections.append(s);
}
return in;
}
///////////////////////////////////////////////////////////////////////////////
InMemoryWriter::InMemoryWriter()
{
}
bool InMemoryWriter::write(OffsetsHeaderEntry::Type type, const QByteArray& data)
{
OffsetsHeaderEntry entry;
entry.type = type;
entry.offset = _contentBuffer.pos(); // Relative offset!
entry.contentSize = data.size();
_contentBuffer.write(data);
_offsetsHeader.entries.append(entry);
_offsetsHeader.entriesCount += 1;
return true;
}
bool InMemoryWriter::write(const SectionIndexData& data)
{
OffsetsHeaderEntry entry;
entry.type = OffsetsHeaderEntry::SectionIndex;
entry.offset = _contentBuffer.pos(); // Relative offset!
QDataStream out(&_contentBuffer);
out.setVersion(QDataStream::Qt_4_5);
out << data;
entry.contentSize = _contentBuffer.size() - entry.offset;
_offsetsHeader.entries.append(entry);
_offsetsHeader.entriesCount += 1;
return true;
}
QByteArray InMemoryWriter::toByteArray() const
{
QByteArray data;
QBuffer buff(&data);
QDataStream out(&buff);
out.setVersion(QDataStream::Qt_4_5);
// Basic format header.
Header header;
header.magic = Header::MAGIC;
header.majorVersion = Header::MAJOR_VERSION;
header.minorVersion = Header::MINOR_VERSION;
out << header;
// Offsets-Header
// - Save begin pos
// - Write OffsetsHeader
// - Convert relative- to absolute-offsets
// - Seek back to begin-pos and write OffsetsHeader again.
// Use a copy of OffsetsHeader to keep the _offsetsHeader relative.
const qint64 posOffsetHeaders = buff.pos();
OffsetsHeader offsetsHeader = _offsetsHeader;
out << offsetsHeader;
// Now we know the size of the entire header.
// We can update the relative- to absolute-offsets now.
const qint64 allHeaderSize = buff.pos();
for (int i = 0; i < offsetsHeader.entriesCount; ++i)
{
offsetsHeader.entries[i].offset += allHeaderSize;
}
// Seek back and write again with absolute offsets.
// TODO Thats not nice, but it works...
buff.seek(posOffsetHeaders);
out << offsetsHeader;
// Write contents.
buff.write(_contentBuffer.data());
return data;
}
///////////////////////////////////////////////////////////////////////////////
InMemoryReader::InMemoryReader(const QByteArray& data) :
_data(data), _buff(&_data)
{
}
bool InMemoryReader::initReadHeader()
{
QDataStream in(&_buff);
in.setVersion(QDataStream::Qt_4_5);
// Basic format header.
Header header;
in >> header;
if (header.magic != Header::MAGIC)
{
qWarning() << QString("invalid format (magic=%1)").arg(header.magic);
return false;
}
if (header.majorVersion > Header::MAJOR_VERSION)
{
qWarning() << QString("format is too new (major=%1; minor=%2)")
.arg(header.majorVersion).arg(header.minorVersion);
return false;
}
// OffsetsHeader.
in >> _offsetsHeader;
return !in.atEnd();
}
bool InMemoryReader::read(OffsetsHeaderEntry::Type type, QByteArray& data) const
{
// Find offset for "type".
int index = -1;
for (int i = 0; i < _offsetsHeader.entriesCount; ++i)
{
if (_offsetsHeader.entries.at(index).type == type)
{
index = i;
break;
}
}
if (index < 0)
return false;
else if (_offsetsHeader.entries.at(index).offset == 0)
return false;
const OffsetsHeaderEntry& entry = _offsetsHeader.entries.at(index);
_buff.seek(entry.offset);
data.append(_buff.read(entry.contentSize));
return true;
}
///////////////////////////////////////////////////////////////////////////////
ADS_NAMESPACE_SER_END ADS_NAMESPACE_SER_END