diff --git a/CMakeLists.txt b/CMakeLists.txt index 698d3583..90b5faec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,8 +2,8 @@ cmake_minimum_required(VERSION 3.0) cmake_policy(SET CMP0017 NEW) # need include() with .cmake project(pip) set(pip_MAJOR 2) -set(pip_MINOR 26) -set(pip_REVISION 1) +set(pip_MINOR 27) +set(pip_REVISION 0) set(pip_SUFFIX ) set(pip_COMPANY SHS) set(pip_DOMAIN org.SHS) diff --git a/libs/main/core/pichunkstream.cpp b/libs/main/core/pichunkstream.cpp index b5525aa3..c5a69664 100644 --- a/libs/main/core/pichunkstream.cpp +++ b/libs/main/core/pichunkstream.cpp @@ -72,6 +72,16 @@ void PIChunkStream::setSource(PIByteArray * data) { } +PIByteArray PIChunkStream::data() const { + if (first_byte_taken) { + PIByteArray ret(*data_); + ret.prepend((uchar)(0x80 | version_)); + return ret; + } + return *data_; +} + + int PIChunkStream::read() { switch (version_) { case Version_1: @@ -108,16 +118,40 @@ int PIChunkStream::peekVInt(Version version_, PIByteArray * data_, int pos, PIBy } +void PIChunkStream::replaceChunk(int id, const PIByteArray & v) { + if (!data_map.contains(id)) return; + auto & pos(data_map[id]); + PIByteArray nsba; + writeVInt(nsba, v.size()); + int size_mod = (v.size_s() + nsba.size_s()) - (pos.length + pos.size_bytes); + pos.length = v.size_s(); + if (size_mod != 0) { + auto it = data_map.makeIterator(); + while (it.next()) + if (it.valueRef().start > pos.start) + it.valueRef().start += size_mod; + if (size_mod > 0) + data_->insert(pos.start, PIByteArray(size_mod)); + else + data_->remove(pos.start, -size_mod); + } + memcpy(data_->data(pos.start - pos.size_bytes), nsba.data(), nsba.size()); + pos.start += nsba.size_s() - pos.size_bytes; + memcpy(data_->data(pos.start), v.data(), pos.length); +} + + void PIChunkStream::readAll() { data_map.clear(); if (!data_) return; - int pos = 0, sz = data_->size_s(); + int pos = 0, sz = data_->size_s(), hsz = 0; uint csz = 0, cid = 0; PIByteArray hdr; while (pos < sz) { pos += peekVInt((Version)version_, data_, pos, hdr, cid); - pos += peekVInt((Version)version_, data_, pos, hdr, csz); - data_map[cid] = PIPair(pos, csz); + hsz = peekVInt((Version)version_, data_, pos, hdr, csz); + pos += hsz; + data_map[cid] = CacheEntry(pos, csz, hsz); pos += csz; } } @@ -140,6 +174,7 @@ bool PIChunkStream::extract(PIByteArray & data, bool read_all) { void PIChunkStream::_init() { + first_byte_taken = false; last_id = -1; last_data.clear(); if (!data_->isEmpty()) { @@ -147,7 +182,7 @@ void PIChunkStream::_init() { if ((v & 0x80) == 0x80) { v &= 0x7f; switch (v) { - case 2: version_ = (uchar)Version_2; data_->pop_front(); break; + case 2: version_ = (uchar)Version_2; data_->pop_front(); first_byte_taken = true; break; default: version_ = Version_1; break; } } else diff --git a/libs/main/core/pichunkstream.h b/libs/main/core/pichunkstream.h index 256c620d..16f96824 100644 --- a/libs/main/core/pichunkstream.h +++ b/libs/main/core/pichunkstream.h @@ -76,7 +76,7 @@ public: void setSource(PIByteArray * data); //! Returns internal buffer with written data - PIByteArray data() const {return tmp_data;} + PIByteArray data() const; //! Returns if there is end of stream bool atEnd() const {return data_->size_s() <= 1;} @@ -105,25 +105,43 @@ public: //! Place value of chunk with id \"id\" into \"v\". You should call \a readAll() before using this function! template const PIChunkStream & get(int id, T & v) const { - PIPair pos = data_map.value(id); - if (pos.first < 0 || pos.second == 0) return *this; - PIByteArray ba(data_->data(pos.first), pos.second); + CacheEntry pos = data_map.value(id); + if (pos.start < 0 || pos.length == 0) return *this; + PIByteArray ba(data_->data(pos.start), pos.length); if (!ba.isEmpty()) ba >> v; return *this; } + //! Replace value of chunk with ID \"id\" to \"v\". You should call \a readAll() before using this function! + template + PIChunkStream & set(int id, const T & v) { + PIByteArray ba; + ba << v; + replaceChunk(id, ba); + return *this; + } + private: void _init(); + + struct CacheEntry { + CacheEntry(int s = 0, int l = 0, int b = 0): start(s), length(l), size_bytes(b) {} + int start; + int length; + int size_bytes; + }; static uint readVInt(PIByteArray & s, uchar * bytes = 0); static void writeVInt(PIByteArray & s, uint val); static int peekVInt(Version version_, PIByteArray * data_, int pos, PIByteArray & hdr, uint & ret); + void replaceChunk(int id, const PIByteArray & v); int last_id; uchar version_; - PIByteArray * data_, last_data, tmp_data; - PIMap> data_map; + mutable PIByteArray * data_, last_data, tmp_data; + PIMap data_map; + bool first_byte_taken; template friend PIChunkStream & operator <<(PIChunkStream & s, const PIChunkStream::Chunk & c); template friend PIChunkStream & operator <<(PIChunkStream & s, const PIChunkStream::ChunkConst & c); diff --git a/main.cpp b/main.cpp index a26a37b3..16ac8613 100644 --- a/main.cpp +++ b/main.cpp @@ -1,11 +1,39 @@ #include "pip.h" -PIPeer p0("p0"), p1("p1"); +//PIPeer p0("p0"), p1("p1"); int main() { - - PIMap sends, recs; + PIByteArray ba, bd, ext; + bd.resize(4096); + for (int i = 0; i < bd.size_s(); ++i) bd[i] = rand() % 256; + uint hash = bd.hash(); + piCout << hash; + { + PIChunkStream cs; + cs.add(1, PIString("string")).add(3, 123456).add(2, PIString("!!-second-!!")); + ba = cs.data(); + } + //piCout << ba.toHex(); + { + PIChunkStream cs(ba); + cs.readAll(); + PIString s1, s2; int i = 0; + cs.get(1, s1).get(3, i).get(2, s2); + piCout << s1 << s2 << i; + cs.set(3, PIString("WHATSAP!")); + cs.set(1, bd); + ba = cs.data(); + } + //piCout << ba.toHex(); + { + PIChunkStream cs(ba); + cs.readAll(); + PIString s1, s2, s3; + cs.get(1, ext).get(2, s2).get(3, s3); + piCout << ext.hash() << s2 << s3; + } + /*PIMap sends, recs; PISet errors, missed; CONNECTL(&p0, dataReceivedEvent, ([&](const PIString & from, const PIByteArray & data){ @@ -38,7 +66,7 @@ int main() { for (int i = 0; i < count; ++i) if (!recs.contains(i)) missed << i; piCout << "errors" << errors; - piCout << "missed" << missed; + piCout << "missed" << missed;*/ /*PIDataTransfer tr0, tr1;