/* QAD - Qt ADvanced Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #ifndef CHUNKSTREAM_H #define CHUNKSTREAM_H #include "qad_utils_export.h" #include #include #include #include #include class QAD_UTILS_EXPORT ChunkStream { public: enum Version { Version_1 /*! First, old version */, Version_2 /*! Second, more optimized version */ = 2, }; ChunkStream(const QByteArray & data): version_(Version_2) { setSource(data); } ChunkStream(QDataStream & str): version_(Version_2) { setSource(str); } ChunkStream(QByteArray * data = 0, Version v = Version_2): version_(v) { setSource(data); } ChunkStream(Version v): version_(v) { setSource(0); } ~ChunkStream(); template struct Chunk { Chunk(int i, const T & d): id(i), data(d) {} int id; T data; }; template struct ChunkConst { ChunkConst(int i, const T & d): id(i), data(d) {} int id; const T & data; }; template static ChunkConst chunk(int id, const T & data) { return ChunkConst(id, data); } template ChunkStream & add(int id, const T & data) { *this << ChunkConst(id, data); return *this; } void setSource(const QByteArray & data); void setSource(QDataStream & str); void setSource(QByteArray * data); QDataStream & dataStream() { return stream_; } QByteArray data() const { return tmp_data; } bool atEnd() const { return stream_.atEnd(); } Version version() const { return (Version)version_; } int read(); void readAll(); int getID() { return last_id; } template void get(T & v) const { v = getData(); } template typename std::enable_if::value, T>::type getData() const { QDataStream s(last_data); s.setVersion(QDataStream::Qt_4_8); T ret; s >> ret; return ret; } template typename std::enable_if::value, T>::type getData() const { QDataStream s(last_data); s.setVersion(QDataStream::Qt_4_8); typename std::underlying_type::type ret; s >> ret; return (T)ret; } template typename std::enable_if::value, T>::type getData(int id) const { T ret{}; QByteArray ba = data_map.value(id); if (!ba.isEmpty()) { QDataStream s(ba); s.setVersion(QDataStream::Qt_4_8); s >> ret; } return ret; } template typename std::enable_if::value, T>::type getData(int id) const { T ret{}; QByteArray ba = data_map.value(id); if (!ba.isEmpty()) { QDataStream s(ba); s.setVersion(QDataStream::Qt_4_8); typename std::underlying_type::type iv; s >> iv; ret = (T)iv; } return ret; } template typename std::enable_if::value, const ChunkStream &>::type get(int id, T & v) const { QByteArray ba = data_map.value(id); if (!ba.isEmpty()) { QDataStream s(ba); s.setVersion(QDataStream::Qt_4_8); s >> v; } return *this; } template typename std::enable_if::value, const ChunkStream &>::type get(int id, T & v) const { QByteArray ba = data_map.value(id); if (!ba.isEmpty()) { QDataStream s(ba); s.setVersion(QDataStream::Qt_4_8); typename std::underlying_type::type iv; s >> iv; v = (T)iv; } return *this; } private: void _init(); static uint readVInt(QDataStream & s); static void writeVInt(QDataStream & s, uint val); int last_id; uchar version_; QByteArray *data_, last_data, tmp_data; QBuffer buffer; QDataStream stream_; QMap data_map; template friend ChunkStream & operator<<(ChunkStream & s, const ChunkStream::Chunk & c); template friend ChunkStream & operator<<(ChunkStream & s, const ChunkStream::ChunkConst & c); }; template typename std::enable_if::value, void>::type __writeChunkData(QByteArray & ba, const ChunkStream::Chunk & c) { QDataStream bas(&ba, QIODevice::WriteOnly); bas.setVersion(QDataStream::Qt_4_8); bas << c.data; } template typename std::enable_if::value, void>::type __writeChunkData(QByteArray & ba, const ChunkStream::Chunk & c) { QDataStream bas(&ba, QIODevice::WriteOnly); bas.setVersion(QDataStream::Qt_4_8); typename std::underlying_type::type iv = c.data; bas << iv; } template typename std::enable_if::value, void>::type __writeChunkConstData(QByteArray & ba, const ChunkStream::ChunkConst & c) { QDataStream bas(&ba, QIODevice::WriteOnly); bas.setVersion(QDataStream::Qt_4_8); bas << c.data; } template typename std::enable_if::value, void>::type __writeChunkConstData(QByteArray & ba, const ChunkStream::ChunkConst & c) { QDataStream bas(&ba, QIODevice::WriteOnly); bas.setVersion(QDataStream::Qt_4_8); typename std::underlying_type::type iv = c.data; bas << iv; } template ChunkStream & operator<<(ChunkStream & s, const ChunkStream::Chunk & c) { QByteArray ba; __writeChunkData(ba, c); switch (s.version_) { case ChunkStream::Version_1: s.stream_ << c.id << ba; break; case ChunkStream::Version_2: if (s.data_->isEmpty()) s.stream_ << uchar(uchar(s.version_) | 0x80); ChunkStream::writeVInt(s.stream_, c.id); ChunkStream::writeVInt(s.stream_, ba.size()); s.stream_.writeRawData(ba.data(), ba.size()); break; default: break; } return s; } template ChunkStream & operator<<(ChunkStream & s, const ChunkStream::ChunkConst & c) { QByteArray ba; __writeChunkConstData(ba, c); switch (s.version_) { case ChunkStream::Version_1: s.stream_ << c.id << ba; break; case ChunkStream::Version_2: if (s.data_->isEmpty()) s.stream_ << uchar(uchar(s.version_) | 0x80); ChunkStream::writeVInt(s.stream_, c.id); ChunkStream::writeVInt(s.stream_, ba.size()); s.stream_.writeRawData(ba.data(), ba.size()); break; default: break; } return s; } #endif // CHUNKSTREAM_H