Files
Qt-Advanced-Docking-System/AdvancedDockingSystem/src/Serialization.cpp

424 lines
10 KiB
C++

#include "ads/Serialization.h"
#include <QDebug>
ADS_NAMESPACE_SER_BEGIN
/*
\namespace ads::serialization
Serialization of ContainerWidget
--------------------------------
# Data Format Header
quint32 Magic
quint32 Major Version
quint32 Minor Version
# Offsets of available contents
qint32 Number of offset headers
LOOP
qint32 Type (e.g. Hierachy, SectionIndex)
qint64 Offset
qint64 Length
# Type: Hierachy
# Used to recreate the GUI geometry and state.
int Number of floating widgets
LOOP Floating widgets
QString Unique name of content
QByteArray Geometry of floating widget
bool Visibility
int Number of layout items (Valid values: 0, 1)
IF 0
int Number of hidden contents
LOOP Contents
QString Unique name of content
ELSEIF 1
... todo ...
ENDIF
# Type: SectionIndex
# Can be used for quick lookups on details for SectionWidgets.
# It includes sizes and its contents.
qint32 Number of section-widgets
LOOP
qint32 Width
qint32 Height
qint32 Current active tab index
qint32 Number of contents
LOOP
QString Unique name of content
bool Visibility
qint32 Preferred tab index
*/
///////////////////////////////////////////////////////////////////////////////
qint32 HeaderEntity::MAGIC = 0x00001337;
qint32 HeaderEntity::MAJOR_VERSION = 2;
qint32 HeaderEntity::MINOR_VERSION = 0;
HeaderEntity::HeaderEntity() :
magic(0), majorVersion(0), minorVersion(0)
{
}
QDataStream& operator<<(QDataStream& out, const HeaderEntity& data)
{
out << data.magic;
out << data.majorVersion;
out << data.minorVersion;
return out;
}
QDataStream& operator>>(QDataStream& in, HeaderEntity& data)
{
in >> data.magic;
in >> data.majorVersion;
in >> data.minorVersion;
return in;
}
///////////////////////////////////////////////////////////////////////////////
OffsetsHeaderEntity::OffsetsHeaderEntity() :
entriesCount(0)
{
}
QDataStream& operator<<(QDataStream& out, const OffsetsHeaderEntity& data)
{
out << data.entriesCount;
for (int i = 0; i < data.entriesCount; ++i)
{
out << data.entries.at(i);
}
return out;
}
QDataStream& operator>>(QDataStream& in, OffsetsHeaderEntity& data)
{
in >> data.entriesCount;
for (int i = 0; i < data.entriesCount; ++i)
{
OffsetsHeaderEntryEntity entry;
in >> entry;
data.entries.append(entry);
}
return in;
}
///////////////////////////////////////////////////////////////////////////////
OffsetsHeaderEntryEntity::OffsetsHeaderEntryEntity() :
type(ET_Unknown), offset(0), contentSize(0)
{
}
QDataStream& operator<<(QDataStream& out, const OffsetsHeaderEntryEntity& data)
{
out << data.type;
out << data.offset;
out << data.contentSize;
return out;
}
QDataStream& operator>>(QDataStream& in, OffsetsHeaderEntryEntity& data)
{
in >> data.type;
in >> data.offset;
in >> data.contentSize;
return in;
}
///////////////////////////////////////////////////////////////////////////////
SectionEntity::SectionEntity() :
width(0), height(0), currentIndex(0), sectionContentsCount(0)
{
}
QDataStream& operator<<(QDataStream& out, const SectionEntity& data)
{
out << data.width;
out << data.height;
out << data.currentIndex;
out << data.sectionContentsCount;
for (int i = 0; i < data.sectionContentsCount; ++i)
{
out << data.sectionContents.at(i);
}
return out;
}
QDataStream& operator>>(QDataStream& in, SectionEntity& data)
{
in >> data.width;
in >> data.height;
in >> data.currentIndex;
in >> data.sectionContentsCount;
for (int i = 0; i < data.sectionContentsCount; ++i)
{
SectionContentEntity sc;
in >> sc;
data.sectionContents.append(sc);
}
return in;
}
///////////////////////////////////////////////////////////////////////////////
SectionContentEntity::SectionContentEntity() :
visible(false), preferredIndex(0)
{
}
QDataStream& operator<<(QDataStream& out, const SectionContentEntity& data)
{
out << data.uniqueName;
out << data.visible;
out << data.preferredIndex;
return out;
}
QDataStream& operator>>(QDataStream& in, SectionContentEntity& data)
{
in >> data.uniqueName;
in >> data.visible;
in >> data.preferredIndex;
return in;
}
///////////////////////////////////////////////////////////////////////////////
FloatingContentEntity::FloatingContentEntity() :
xpos(0), ypos(0), width(0), height(0), visible(false)
{
}
QDataStream& operator<<(QDataStream& out, const FloatingContentEntity& data)
{
out << data.uniqueName;
out << data.xpos;
out << data.ypos;
out << data.width;
out << data.height;
out << data.visible;
return out;
}
QDataStream& operator>>(QDataStream& in, FloatingContentEntity& data)
{
in >> data.uniqueName;
in >> data.xpos;
in >> data.ypos;
in >> data.width;
in >> data.height;
in >> data.visible;
return in;
}
///////////////////////////////////////////////////////////////////////////////
HierarchyData::HierarchyData()
{
}
QDataStream& operator<<(QDataStream& out, const HierarchyData& data)
{
out << data.data;
return out;
}
QDataStream& operator>>(QDataStream& in, HierarchyData& data)
{
in >> data.data;
return in;
}
///////////////////////////////////////////////////////////////////////////////
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)
{
SectionEntity s;
in >> s;
data.sections.append(s);
}
return in;
}
///////////////////////////////////////////////////////////////////////////////
InMemoryWriter::InMemoryWriter()
{
_contentBuffer.open(QIODevice::ReadWrite);
}
bool InMemoryWriter::write(qint32 entryType, const QByteArray& data)
{
OffsetsHeaderEntryEntity entry;
entry.type = entryType;
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)
{
OffsetsHeaderEntryEntity entry;
entry.type = ET_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;
QDataStream out(&data, QIODevice::ReadWrite);
out.setVersion(QDataStream::Qt_4_5);
// Basic format header.
HeaderEntity header;
header.magic = HeaderEntity::MAGIC;
header.majorVersion = HeaderEntity::MAJOR_VERSION;
header.minorVersion = HeaderEntity::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 = out.device()->pos();
OffsetsHeaderEntity 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 = out.device()->pos();
for (int i = 0; i < offsetsHeader.entriesCount; ++i)
{
offsetsHeader.entries[i].offset += allHeaderSize; // Absolute offset!
}
// Seek back and write again with absolute offsets.
// TODO Thats not nice, but it works...
out.device()->seek(posOffsetHeaders);
out << offsetsHeader;
// Write contents.
out.writeRawData(_contentBuffer.data().constData(), _contentBuffer.size());
return data;
}
///////////////////////////////////////////////////////////////////////////////
InMemoryReader::InMemoryReader(const QByteArray& data) :
_data(data)
{
}
bool InMemoryReader::initReadHeader()
{
QDataStream in(_data);
in.setVersion(QDataStream::Qt_4_5);
// Basic format header.
HeaderEntity header;
in >> header;
if (header.magic != HeaderEntity::MAGIC)
{
qWarning() << QString("invalid format (magic=%1)").arg(header.magic);
return false;
}
if (header.majorVersion > HeaderEntity::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(qint32 entryType, QByteArray& data)
{
// Find offset for "type".
int index = -1;
for (int i = 0; i < _offsetsHeader.entriesCount; ++i)
{
if (_offsetsHeader.entries.at(i).type == entryType)
{
index = i;
break;
}
}
if (index < 0)
return false;
else if (_offsetsHeader.entries.at(index).offset == 0)
return false;
const OffsetsHeaderEntryEntity& entry = _offsetsHeader.entries.at(index);
QDataStream in(_data);
in.setVersion(QDataStream::Qt_4_5);
in.device()->seek(entry.offset);
char* buff = new char[entry.contentSize];
in.readRawData(buff, entry.contentSize);
data.append(buff, entry.contentSize);
delete[] buff;
return true;
}
///////////////////////////////////////////////////////////////////////////////
ADS_NAMESPACE_SER_END