152 lines
4.7 KiB
C++
152 lines
4.7 KiB
C++
|
|
/*
|
||
|
|
* This file is part of the Flowee project
|
||
|
|
* Copyright (C) 2016,2018-2019 Tom Zander <tom@flowee.org>
|
||
|
|
*
|
||
|
|
* This program is free software: you can redistribute it and/or modify
|
||
|
|
* it under the terms of the GNU 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 General Public License for more details.
|
||
|
|
*
|
||
|
|
* You should have received a copy of the GNU General Public License
|
||
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
|
*/
|
||
|
|
#include "ProtoBuilder.h"
|
||
|
|
#include "ProtoParser.h"
|
||
|
|
#include "BufferPool.h"
|
||
|
|
|
||
|
|
namespace {
|
||
|
|
int serializeProto(char *data, uint64_t value)
|
||
|
|
{
|
||
|
|
int pos = 0;
|
||
|
|
while (true) {
|
||
|
|
data[pos] = (value & 0x7F) | (value >= 0x80 ? 0x80 : 0x00);
|
||
|
|
if (value <= 0x7F)
|
||
|
|
break;
|
||
|
|
value = value >> 7;
|
||
|
|
pos++;
|
||
|
|
}
|
||
|
|
|
||
|
|
return pos + 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
int write(char *data, uint32_t tag, Streaming::ProtoParser::WireType type) {
|
||
|
|
assert(tag < 32);
|
||
|
|
uint8_t byte = tag;
|
||
|
|
byte = byte << 3;
|
||
|
|
byte += type;
|
||
|
|
data[0] = byte;
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
Streaming::ProtoBuilder::ProtoBuilder(Streaming::BufferPool &pool)
|
||
|
|
: m_buffer(&pool)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
void Streaming::ProtoBuilder::add(uint32_t tag, uint64_t value)
|
||
|
|
{
|
||
|
|
handleNestedBuilder();
|
||
|
|
int tagSize = write(m_buffer->data(), tag, Streaming::ProtoParser::VarInt);
|
||
|
|
m_buffer->markUsed(tagSize);
|
||
|
|
tagSize = ::serializeProto(m_buffer->data(), value);
|
||
|
|
m_buffer->markUsed(tagSize);
|
||
|
|
}
|
||
|
|
|
||
|
|
void Streaming::ProtoBuilder::add(uint32_t tag, const std::string &value)
|
||
|
|
{
|
||
|
|
handleNestedBuilder();
|
||
|
|
int tagSize = write(m_buffer->data(), tag, Streaming::ProtoParser::Data);
|
||
|
|
const unsigned int size = value.size();
|
||
|
|
tagSize += ::serializeProto(m_buffer->data() + tagSize, size);
|
||
|
|
m_buffer->markUsed(tagSize);
|
||
|
|
memcpy(m_buffer->data(), value.c_str(), value.size());
|
||
|
|
m_buffer->markUsed(value.size());
|
||
|
|
}
|
||
|
|
|
||
|
|
void Streaming::ProtoBuilder::add(uint32_t tag, const std::vector<char> &data)
|
||
|
|
{
|
||
|
|
addByteArray(tag, data.data(), data.size());
|
||
|
|
}
|
||
|
|
|
||
|
|
void Streaming::ProtoBuilder::addByteArray(uint32_t tag, const void *data, int bytes)
|
||
|
|
{
|
||
|
|
handleNestedBuilder();
|
||
|
|
int tagSize = write(m_buffer->data(), tag, Streaming::ProtoParser::Data);
|
||
|
|
tagSize += ::serializeProto(m_buffer->data() + tagSize, bytes);
|
||
|
|
m_buffer->markUsed(tagSize);
|
||
|
|
memcpy(m_buffer->data(), data, bytes);
|
||
|
|
m_buffer->markUsed(bytes);
|
||
|
|
}
|
||
|
|
|
||
|
|
void Streaming::ProtoBuilder::add(uint32_t tag, const Streaming::ConstBuffer &data)
|
||
|
|
{
|
||
|
|
handleNestedBuilder();
|
||
|
|
int tagSize = write(m_buffer->data(), tag, Streaming::ProtoParser::Data);
|
||
|
|
tagSize += ::serializeProto(m_buffer->data() + tagSize, data.size());
|
||
|
|
m_buffer->markUsed(tagSize);
|
||
|
|
memcpy(m_buffer->data(), data.begin(), data.size());
|
||
|
|
m_buffer->markUsed(data.size());
|
||
|
|
}
|
||
|
|
|
||
|
|
void Streaming::ProtoBuilder::add(uint32_t tag, bool value)
|
||
|
|
{
|
||
|
|
return add(tag, (int32_t) (value ? 1 : 0));
|
||
|
|
}
|
||
|
|
|
||
|
|
void Streaming::ProtoBuilder::add(uint32_t tag, int32_t value)
|
||
|
|
{
|
||
|
|
handleNestedBuilder();
|
||
|
|
int tagSize = write(m_buffer->data(), tag, Streaming::ProtoParser::VarInt);
|
||
|
|
m_buffer->markUsed(tagSize);
|
||
|
|
tagSize = ::serializeProto(m_buffer->data(), value);
|
||
|
|
m_buffer->markUsed(tagSize);
|
||
|
|
}
|
||
|
|
|
||
|
|
Streaming::ProtoBuilder *Streaming::ProtoBuilder::addNestedMessage(uint32_t tag)
|
||
|
|
{
|
||
|
|
handleNestedBuilder();
|
||
|
|
write(m_buffer->data(), tag, Streaming::ProtoParser::Data);
|
||
|
|
m_buffer->markUsed(1);
|
||
|
|
m_nestedBufferPool = new BufferPool();
|
||
|
|
m_nestedBuilder = new Streaming::ProtoBuilder(*m_nestedBufferPool);
|
||
|
|
return m_nestedBuilder;
|
||
|
|
}
|
||
|
|
|
||
|
|
void Streaming::ProtoBuilder::add(uint32_t tag, const unsigned char *data, unsigned int length)
|
||
|
|
{
|
||
|
|
handleNestedBuilder();
|
||
|
|
int tagSize = write(m_buffer->data(), tag, Streaming::ProtoParser::Data);
|
||
|
|
tagSize += ::serializeProto(m_buffer->data() + tagSize, length);
|
||
|
|
m_buffer->markUsed(tagSize);
|
||
|
|
memcpy(m_buffer->data(), data, length);
|
||
|
|
m_buffer->markUsed(length);
|
||
|
|
}
|
||
|
|
|
||
|
|
void Streaming::ProtoBuilder::handleNestedBuilder()
|
||
|
|
{
|
||
|
|
if (m_nestedBuilder == nullptr)
|
||
|
|
return;
|
||
|
|
|
||
|
|
delete m_nestedBuilder;
|
||
|
|
m_nestedBuilder = nullptr;
|
||
|
|
auto blob = m_nestedBufferPool->commit();
|
||
|
|
delete m_nestedBufferPool;
|
||
|
|
m_nestedBufferPool = nullptr;
|
||
|
|
auto tagSize = ::serializeProto(m_buffer->data(), blob.size());
|
||
|
|
m_buffer->markUsed(tagSize);
|
||
|
|
memcpy(m_buffer->data(), blob.begin(), blob.size());
|
||
|
|
m_buffer->markUsed(blob.size());
|
||
|
|
}
|
||
|
|
|
||
|
|
Streaming::ConstBuffer Streaming::ProtoBuilder::buffer()
|
||
|
|
{
|
||
|
|
handleNestedBuilder();
|
||
|
|
return m_buffer->commit();
|
||
|
|
}
|