PIChunkStream::set() new feature

This commit is contained in:
2021-07-16 01:05:48 +03:00
parent 040eb3b279
commit c87e48c0a5
4 changed files with 97 additions and 16 deletions

View File

@@ -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<int, int>(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

View File

@@ -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 <typename T>
const PIChunkStream & get(int id, T & v) const {
PIPair<int, int> 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 <typename T>
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<int, PIPair<int, int>> data_map;
mutable PIByteArray * data_, last_data, tmp_data;
PIMap<int, CacheEntry> data_map;
bool first_byte_taken;
template <typename T> friend PIChunkStream & operator <<(PIChunkStream & s, const PIChunkStream::Chunk<T> & c);
template <typename T> friend PIChunkStream & operator <<(PIChunkStream & s, const PIChunkStream::ChunkConst<T> & c);