From 4debaaaf8544b640746516ae8d4926810ebf839a Mon Sep 17 00:00:00 2001 From: mfreiholz Date: Fri, 1 Apr 2016 09:52:59 +0200 Subject: [PATCH] Serialization - Adds prototype impls for InMemoryWriter and InMemoryReader. - Use major- and minor-version idiom --- .../include/ads/Serialization.h | 67 +++++- AdvancedDockingSystem/src/Serialization.cpp | 215 ++++++++++++++++-- 2 files changed, 251 insertions(+), 31 deletions(-) diff --git a/AdvancedDockingSystem/include/ads/Serialization.h b/AdvancedDockingSystem/include/ads/Serialization.h index bcd0fae..10d93c3 100644 --- a/AdvancedDockingSystem/include/ads/Serialization.h +++ b/AdvancedDockingSystem/include/ads/Serialization.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "ads/API.h" @@ -13,26 +14,32 @@ ADS_NAMESPACE_SER_BEGIN class Header { public: + static qint32 MAGIC; + static qint32 MAJOR_VERSION; + static qint32 MINOR_VERSION; + Header(); qint32 magic; - qint32 version; + qint32 majorVersion; + qint32 minorVersion; }; QDataStream& operator<<(QDataStream& out, const Header& data); QDataStream& operator>>(QDataStream& in, Header& data); -class OffsetHeader +class OffsetsHeader { public: - OffsetHeader(); - qint64 length; - QList entries; + OffsetsHeader(); + + qint64 entriesCount; + QList entries; }; -QDataStream& operator<<(QDataStream& out, const OffsetHeader& data); -QDataStream& operator>>(QDataStream& in, OffsetHeader& data); +QDataStream& operator<<(QDataStream& out, const OffsetsHeader& data); +QDataStream& operator>>(QDataStream& in, OffsetsHeader& data); -class OffsetHeaderEntry +class OffsetsHeaderEntry { public: enum Type @@ -42,13 +49,13 @@ public: SectionIndex = 0x00000003 }; - OffsetHeaderEntry(); + OffsetsHeaderEntry(); qint32 type; qint64 offset; - qint64 length; + qint64 contentSize; }; -QDataStream& operator<<(QDataStream& out, const OffsetHeaderEntry& data); -QDataStream& operator>>(QDataStream& in, OffsetHeaderEntry& data); +QDataStream& operator<<(QDataStream& out, const OffsetsHeaderEntry& data); +QDataStream& operator>>(QDataStream& in, OffsetsHeaderEntry& data); class Section @@ -111,6 +118,42 @@ public: qint32 sectionsCount; QList
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 #endif diff --git a/AdvancedDockingSystem/src/Serialization.cpp b/AdvancedDockingSystem/src/Serialization.cpp index f51e96d..49d2d1e 100644 --- a/AdvancedDockingSystem/src/Serialization.cpp +++ b/AdvancedDockingSystem/src/Serialization.cpp @@ -1,5 +1,7 @@ #include "ads/Serialization.h" +#include + ADS_NAMESPACE_SER_BEGIN /* @@ -11,7 +13,8 @@ ADS_NAMESPACE_SER_BEGIN # Data Format Header quint32 Magic - quint32 Version + quint32 Major Version + quint32 Minor Version # 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() : - magic(0), version(0) + magic(0), majorVersion(0), minorVersion(0) { } QDataStream& operator<<(QDataStream& out, const Header& data) { out << data.magic; - out << data.version; + out << data.majorVersion; + out << data.minorVersion; return out; } QDataStream& operator>>(QDataStream& in, Header& data) { in >> data.magic; - in >> data.version; + in >> data.majorVersion; + in >> data.minorVersion; return in; } /////////////////////////////////////////////////////////////////////////////// -OffsetHeader::OffsetHeader() : - length(0) +OffsetsHeader::OffsetsHeader() : + entriesCount(0) { } -QDataStream& operator<<(QDataStream& out, const OffsetHeader& data) +QDataStream& operator<<(QDataStream& out, const OffsetsHeader& data) { - out << data.length; - for (int i = 0; i < data.length; ++i) + out << data.entriesCount; + for (int i = 0; i < data.entriesCount; ++i) { out << data.entries.at(i); } return out; } -QDataStream& operator>>(QDataStream& in, OffsetHeader& data) +QDataStream& operator>>(QDataStream& in, OffsetsHeader& data) { - in >> data.length; - for (int i = 0; i < data.length; ++i) + in >> data.entriesCount; + for (int i = 0; i < data.entriesCount; ++i) { - OffsetHeaderEntry entry; + OffsetsHeaderEntry entry; in >> entry; data.entries.append(entry); } @@ -108,24 +117,24 @@ QDataStream& operator>>(QDataStream& in, OffsetHeader& data) /////////////////////////////////////////////////////////////////////////////// -OffsetHeaderEntry::OffsetHeaderEntry() : - type(Unknown), offset(0), length(0) +OffsetsHeaderEntry::OffsetsHeaderEntry() : + 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.offset; - out << data.length; + out << data.contentSize; return out; } -QDataStream& operator>>(QDataStream& in, OffsetHeaderEntry& data) +QDataStream& operator>>(QDataStream& in, OffsetsHeaderEntry& data) { in >> data.type; in >> data.offset; - in >> data.length; + in >> data.contentSize; 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