Files

152 lines
4.7 KiB
C++
Raw Permalink Normal View History

2023-07-08 21:36:39 +02:00
/*
* 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();
}