From 7d360917f538064cd247e81f1d5c32bbe276eafe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D0=B5=D0=BB=D0=B8=D0=BF=D0=B5=D0=BD=D0=BA=D0=BE=20?= =?UTF-8?q?=D0=98=D0=B2=D0=B0=D0=BD?= Date: Mon, 28 Oct 2019 09:10:38 +0000 Subject: [PATCH] git-svn-id: svn://db.shs.com.ru/libs@622 a8b55f48-bf90-11e4-a774-851b48703e85 --- qad/utils/chunkstream.cpp | 75 +++++++++++++++++++++++++++++++++++++++ qad/utils/chunkstream.h | 45 ++++++++++++++++++++--- 2 files changed, 115 insertions(+), 5 deletions(-) diff --git a/qad/utils/chunkstream.cpp b/qad/utils/chunkstream.cpp index 8c30120..e5e3e8c 100644 --- a/qad/utils/chunkstream.cpp +++ b/qad/utils/chunkstream.cpp @@ -23,6 +23,32 @@ void ChunkStream::setSource(QDataStream & str) { } +int ChunkStream::read() { + switch (version_) { + case Version_1: + stream_ >> last_id >> last_data; + break; + case Version_2: + last_id = readVInt(stream_); + last_data.resize(readVInt(stream_)); + //piCout << last_id << last_data.size(); + stream_.readRawData(last_data.data(), last_data.size()); + break; + default: break; + } + return last_id; +} + + +void ChunkStream::readAll() { + data_map.clear(); + while (!atEnd()) { + read(); + data_map[last_id] = last_data; + } +} + + ChunkStream::~ChunkStream() { } @@ -35,4 +61,53 @@ void ChunkStream::_init() { buffer.setBuffer(data_); buffer.open(QIODevice::ReadWrite); stream_.setDevice(&buffer); + if (!data_->isEmpty()) { + uchar v = data_->at(0); + if ((v & 0x80) == 0x80) { + v &= 0x7f; + switch (v) { + case 2: version_ = (uchar)Version_2; stream_.skipRawData(1); break; + default: break; + } + } else + version_ = Version_1; + } +} + + +uint ChunkStream::readVInt(QDataStream & s) { + if (s.atEnd()) return 0; + uchar bytes[4]; s >> bytes[0]; + uchar abc = 0; + for (abc = 0; abc < 3; ++abc) { + uchar mask = (0x80 >> abc); + if ((bytes[0] & mask) == mask) { + //if (s.isEmpty()) return 0; + bytes[0] &= (mask - 1); + s >> bytes[abc + 1]; + } else break; + } + uint ret = 0; + for (int i = 0; i <= abc; ++i) { + ret += (bytes[i] << (8 * ((int)abc - i))); + } + return ret; +} + + +void ChunkStream::writeVInt(QDataStream & s, uint val) { + if (val > 0xfffffff) return; + if (val <= 0x7f) { + s << uchar(val); + return; + } + if (val <= 0x3fff) { + s << uchar((val >> 8) | 0x80) << uchar(val & 0xff); + return; + } + if (val <= 0x1fffff) { + s << uchar((val >> 16) | 0xc0) << uchar((val >> 8) & 0xff) << uchar(val & 0xff); + return; + } + s << uchar((val >> 24) | 0xe0) << uchar((val >> 16) & 0xff) << uchar((val >> 8) & 0xff) << uchar(val & 0xff); } diff --git a/qad/utils/chunkstream.h b/qad/utils/chunkstream.h index e873395..575bcbe 100644 --- a/qad/utils/chunkstream.h +++ b/qad/utils/chunkstream.h @@ -4,14 +4,20 @@ #include #include #include +#include class ChunkStream { public: - ChunkStream(const QByteArray & data) {setSource(data);} - ChunkStream(QDataStream & str) {setSource(str);} - ChunkStream(QByteArray * data = 0) {setSource(data);} + 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 @@ -30,21 +36,38 @@ public: QDataStream & dataStream() {return stream_;} QByteArray data() const {return tmp_data;} bool atEnd() const {return stream_.atEnd();} + Version version() const {return (Version)version_;} - int read() {stream_ >> last_id >> last_data; return last_id;} + int read(); + void readAll(); int getID() {return last_id;} template T getData() const {T ret; QDataStream s(last_data); s.setVersion(QDataStream::Qt_4_8); s >> ret; return ret;} template void get(T & v) const {v = getData();} + template + const ChunkStream & 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; + } 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 @@ -53,7 +76,19 @@ ChunkStream & operator <<(ChunkStream & s, const ChunkStream::Chunk & c) { QDataStream bas(&ba, QIODevice::WriteOnly); bas.setVersion(QDataStream::Qt_4_8); bas << c.data; - s.dataStream() << c.id << ba; + 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; }