/* * This file is part of the Flowee project * Copyright (C) 2016,2018-2019 Tom Zander * * 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 . */ #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 &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(); }