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