blob: c29e62115fb80a062b9baba9d19dae10340c2938 [file] [log] [blame]
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#define __STDC_LIMIT_MACROS
#include <inttypes.h>
#include <stdint.h>
#include <string.h>
#include "proto.h"
// This file and proto.h implement a minimal write-only protobuf runtime to be
// used with headers generated by misc/generate_proto_header.py.
// From https://github.com/google/protobuf/blob/3.0.x/src/google/protobuf/wire_format_lite.h
enum WireType {
WIRETYPE_VARINT = 0,
WIRETYPE_FIXED64 = 1,
WIRETYPE_LENGTH_DELIMITED = 2,
WIRETYPE_START_GROUP = 3,
WIRETYPE_END_GROUP = 4,
WIRETYPE_FIXED32 = 5,
};
static uint8_t MakeTag(int number, WireType wire_type) {
const size_t FIELD_NUMBER_SHIFT = 3;
return (number << FIELD_NUMBER_SHIFT) | static_cast<uint8_t>(wire_type);
}
// Based on https://github.com/google/protobuf/blob/3.0.x/src/google/protobuf/io/coded_stream.h
// Compile-time equivalent of VarintSize64().
template <uint64_t Value>
struct StaticVarintSize {
static const int value =
(Value < (1ULL << 7))
? 1
: (Value < (1ULL << 14))
? 2
: (Value < (1ULL << 21))
? 3
: (Value < (1ULL << 28))
? 4
: (Value < (1ULL << 35))
? 5
: (Value < (1ULL << 42))
? 6
: (Value < (1ULL << 49))
? 7
: (Value < (1ULL << 56))
? 8
: (Value < (1ULL << 63))
? 9
: 10;
};
static void WriteVarint32WithType(std::ostream* output, int number,
uint32_t value, WireType type) {
uint8_t buf[StaticVarintSize<UINT32_MAX>::value + 1];
uint8_t *target = buf;
*target++ = MakeTag(number, type);
while (value >= 0x80) {
*target = static_cast<uint8_t>(value | 0x80);
value >>= 7;
++target;
}
*target++ = static_cast<uint8_t>(value);
output->write(reinterpret_cast<char*>(buf), target - buf);
}
void WriteVarint32NoTag(std::ostream* output, uint32_t value) {
uint8_t buf[StaticVarintSize<UINT32_MAX>::value];
uint8_t *target = buf;
while (value >= 0x80) {
*target = static_cast<uint8_t>(value | 0x80);
value >>= 7;
++target;
}
*target++ = static_cast<uint8_t>(value);
output->write(reinterpret_cast<char*>(buf), target - buf);
}
void WriteVarint32(std::ostream* output, int number, uint32_t value) {
WriteVarint32WithType(output, number, value, WIRETYPE_VARINT);
}
void WriteVarint32SignExtended(std::ostream* output, int number,
int32_t value) {
if (value < 0) {
WriteVarint64(output, number, static_cast<uint64_t>(value));
} else {
WriteVarint32(output, number, static_cast<uint32_t>(value));
}
}
void WriteVarint64(std::ostream* output, int number, uint64_t value) {
uint8_t buf[StaticVarintSize<UINT64_MAX>::value + 1];
uint8_t *target = buf;
*target++ = MakeTag(number, WIRETYPE_VARINT);
while (value >= 0x80) {
*target = static_cast<uint8_t>(value | 0x80);
value >>= 7;
++target;
}
*target++ = static_cast<uint8_t>(value);
output->write(reinterpret_cast<char*>(buf), target - buf);
}
void WriteFixed32(std::ostream* output, int number, uint32_t value) {
uint8_t buf[sizeof(value) + 1];
uint8_t *target = buf;
*target++ = MakeTag(number, WIRETYPE_FIXED32);
memcpy(target, &value, sizeof(value));
output->write(reinterpret_cast<char*>(buf), sizeof(buf));
}
void WriteFixed64(std::ostream* output, int number, uint64_t value) {
uint8_t buf[sizeof(value) + 1];
uint8_t *target = buf;
*target++ = MakeTag(number, WIRETYPE_FIXED64);
memcpy(target, &value, sizeof(value));
output->write(reinterpret_cast<char*>(buf), sizeof(buf));
}
void WriteString(std::ostream* output, int number, const std::string& value) {
WriteLengthDelimited(output, number, value.size());
output->write(value.data(), value.size());
}
void WriteLengthDelimited(std::ostream* output, int number, size_t size) {
WriteVarint32WithType(output, number, size, WIRETYPE_LENGTH_DELIMITED);
}