| // 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); |
| } |