blob: 32c6af6bde549c961487744fae5d802ab01b8494 [file] [edit]
// 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 "proto.h"
#include <inttypes.h>
#include <stdint.h>
#include <string.h>
#include "proto_wire.h"
#include "output_stream.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.
static uint32_t MakeTag(int number, WireType wire_type) {
// Protobuf tags are (field_number << 3) | wire_type.
// Using uint32_t for the return type prevents truncation for field numbers
// greater than 31 (which would overflow the 8-bit return value).
// Note: field numbers 16-31 also overflow the 7 bits available in the
// first byte of a varint-encoded tag, but would still fit in a uint8_t
// before being passed to the varint encoder. uint32_t is safer and standard.
return (static_cast<uint32_t>(number) << kTagTypeBits) |
static_cast<uint32_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;
};
void WriteVarint32NoTag(OutputStream* 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);
}
static void WriteVarint32WithType(OutputStream* output, int number,
uint32_t value, WireType type) {
WriteVarint32NoTag(output, MakeTag(number, type));
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(OutputStream* output, int number, uint32_t value) {
WriteVarint32WithType(output, number, value, WIRETYPE_VARINT);
}
void WriteVarint32SignExtended(OutputStream* 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(OutputStream* output, int number, uint64_t value) {
WriteVarint32NoTag(output, MakeTag(number, WIRETYPE_VARINT));
uint8_t buf[StaticVarintSize<UINT64_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 WriteFixed32NoTag(OutputStream* output, uint32_t value) {
output->Write(reinterpret_cast<const char*>(&value), sizeof(value));
}
void WriteFixed32(OutputStream* output, int number, uint32_t value) {
WriteVarint32NoTag(output, MakeTag(number, WIRETYPE_FIXED32));
WriteFixed32NoTag(output, value);
}
void WriteFixed64NoTag(OutputStream* output, uint64_t value) {
output->Write(reinterpret_cast<const char*>(&value), sizeof(value));
}
void WriteFixed64(OutputStream* output, int number, uint64_t value) {
WriteVarint32NoTag(output, MakeTag(number, WIRETYPE_FIXED64));
WriteFixed64NoTag(output, value);
}
void WriteFloat(OutputStream* output, int number, float value) {
uint32_t raw;
memcpy(&raw, &value, sizeof(value));
WriteFixed32(output, number, raw);
}
void WriteFloatNoTag(OutputStream* output, float value) {
uint32_t raw;
memcpy(&raw, &value, sizeof(value));
WriteFixed32NoTag(output, raw);
}
void WriteDouble(OutputStream* output, int number, double value) {
uint64_t raw;
memcpy(&raw, &value, sizeof(value));
WriteFixed64(output, number, raw);
}
void WriteDoubleNoTag(OutputStream* output, double value) {
uint64_t raw;
memcpy(&raw, &value, sizeof(value));
WriteFixed64NoTag(output, raw);
}
void WriteString(OutputStream* output, int number, const std::string& value) {
WriteLengthDelimited(output, number, value.size());
output->Write(value.data(), value.size());
}
void WriteLengthDelimited(OutputStream* output, int number, size_t size) {
WriteVarint32WithType(output, number, size, WIRETYPE_LENGTH_DELIMITED);
}