1 // Copyright 2020 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "absl/log/internal/proto.h"
16
17 #include <algorithm>
18 #include <cassert>
19 #include <cstddef>
20 #include <cstdint>
21 #include <cstring>
22
23 #include "absl/base/attributes.h"
24 #include "absl/base/config.h"
25 #include "absl/types/span.h"
26
27 namespace absl {
28 ABSL_NAMESPACE_BEGIN
29 namespace log_internal {
30 namespace {
EncodeRawVarint(uint64_t value,size_t size,absl::Span<char> * buf)31 void EncodeRawVarint(uint64_t value, size_t size, absl::Span<char> *buf) {
32 for (size_t s = 0; s < size; s++) {
33 (*buf)[s] = static_cast<char>((value & 0x7f) | (s + 1 == size ? 0 : 0x80));
34 value >>= 7;
35 }
36 buf->remove_prefix(size);
37 }
38 } // namespace
39
EncodeVarint(uint64_t tag,uint64_t value,absl::Span<char> * buf)40 bool EncodeVarint(uint64_t tag, uint64_t value, absl::Span<char> *buf) {
41 const uint64_t tag_type = MakeTagType(tag, WireType::kVarint);
42 const size_t tag_type_size = VarintSize(tag_type);
43 const size_t value_size = VarintSize(value);
44 if (tag_type_size + value_size > buf->size()) {
45 buf->remove_suffix(buf->size());
46 return false;
47 }
48 EncodeRawVarint(tag_type, tag_type_size, buf);
49 EncodeRawVarint(value, value_size, buf);
50 return true;
51 }
52
Encode64Bit(uint64_t tag,uint64_t value,absl::Span<char> * buf)53 bool Encode64Bit(uint64_t tag, uint64_t value, absl::Span<char> *buf) {
54 const uint64_t tag_type = MakeTagType(tag, WireType::k64Bit);
55 const size_t tag_type_size = VarintSize(tag_type);
56 if (tag_type_size + sizeof(value) > buf->size()) {
57 buf->remove_suffix(buf->size());
58 return false;
59 }
60 EncodeRawVarint(tag_type, tag_type_size, buf);
61 for (size_t s = 0; s < sizeof(value); s++) {
62 (*buf)[s] = static_cast<char>(value & 0xff);
63 value >>= 8;
64 }
65 buf->remove_prefix(sizeof(value));
66 return true;
67 }
68
Encode32Bit(uint64_t tag,uint32_t value,absl::Span<char> * buf)69 bool Encode32Bit(uint64_t tag, uint32_t value, absl::Span<char> *buf) {
70 const uint64_t tag_type = MakeTagType(tag, WireType::k32Bit);
71 const size_t tag_type_size = VarintSize(tag_type);
72 if (tag_type_size + sizeof(value) > buf->size()) {
73 buf->remove_suffix(buf->size());
74 return false;
75 }
76 EncodeRawVarint(tag_type, tag_type_size, buf);
77 for (size_t s = 0; s < sizeof(value); s++) {
78 (*buf)[s] = static_cast<char>(value & 0xff);
79 value >>= 8;
80 }
81 buf->remove_prefix(sizeof(value));
82 return true;
83 }
84
EncodeBytes(uint64_t tag,absl::Span<const char> value,absl::Span<char> * buf)85 bool EncodeBytes(uint64_t tag, absl::Span<const char> value,
86 absl::Span<char> *buf) {
87 const uint64_t tag_type = MakeTagType(tag, WireType::kLengthDelimited);
88 const size_t tag_type_size = VarintSize(tag_type);
89 uint64_t length = value.size();
90 const size_t length_size = VarintSize(length);
91 if (tag_type_size + length_size + value.size() > buf->size()) {
92 buf->remove_suffix(buf->size());
93 return false;
94 }
95 EncodeRawVarint(tag_type, tag_type_size, buf);
96 EncodeRawVarint(length, length_size, buf);
97 memcpy(buf->data(), value.data(), value.size());
98 buf->remove_prefix(value.size());
99 return true;
100 }
101
EncodeBytesTruncate(uint64_t tag,absl::Span<const char> value,absl::Span<char> * buf)102 bool EncodeBytesTruncate(uint64_t tag, absl::Span<const char> value,
103 absl::Span<char> *buf) {
104 const uint64_t tag_type = MakeTagType(tag, WireType::kLengthDelimited);
105 const size_t tag_type_size = VarintSize(tag_type);
106 uint64_t length = value.size();
107 const size_t length_size =
108 VarintSize(std::min<uint64_t>(length, buf->size()));
109 if (tag_type_size + length_size <= buf->size() &&
110 tag_type_size + length_size + value.size() > buf->size()) {
111 value.remove_suffix(tag_type_size + length_size + value.size() -
112 buf->size());
113 length = value.size();
114 }
115 if (tag_type_size + length_size + value.size() > buf->size()) {
116 buf->remove_suffix(buf->size());
117 return false;
118 }
119 EncodeRawVarint(tag_type, tag_type_size, buf);
120 EncodeRawVarint(length, length_size, buf);
121 memcpy(buf->data(), value.data(), value.size());
122 buf->remove_prefix(value.size());
123 return true;
124 }
125
EncodeMessageStart(uint64_t tag,uint64_t max_size,absl::Span<char> * buf)126 ABSL_MUST_USE_RESULT absl::Span<char> EncodeMessageStart(
127 uint64_t tag, uint64_t max_size, absl::Span<char> *buf) {
128 const uint64_t tag_type = MakeTagType(tag, WireType::kLengthDelimited);
129 const size_t tag_type_size = VarintSize(tag_type);
130 max_size = std::min<uint64_t>(max_size, buf->size());
131 const size_t length_size = VarintSize(max_size);
132 if (tag_type_size + length_size > buf->size()) {
133 buf->remove_suffix(buf->size());
134 return absl::Span<char>();
135 }
136 EncodeRawVarint(tag_type, tag_type_size, buf);
137 const absl::Span<char> ret = buf->subspan(0, length_size);
138 EncodeRawVarint(0, length_size, buf);
139 return ret;
140 }
141
EncodeMessageLength(absl::Span<char> msg,const absl::Span<char> * buf)142 void EncodeMessageLength(absl::Span<char> msg, const absl::Span<char> *buf) {
143 if (!msg.data()) return;
144 assert(buf->data() >= msg.data());
145 if (buf->data() < msg.data()) return;
146 EncodeRawVarint(
147 static_cast<uint64_t>(buf->data() - (msg.data() + msg.size())),
148 msg.size(), &msg);
149 }
150
151 namespace {
DecodeVarint(absl::Span<const char> * buf)152 uint64_t DecodeVarint(absl::Span<const char> *buf) {
153 uint64_t value = 0;
154 size_t s = 0;
155 while (s < buf->size()) {
156 value |= static_cast<uint64_t>(static_cast<unsigned char>((*buf)[s]) & 0x7f)
157 << 7 * s;
158 if (!((*buf)[s++] & 0x80)) break;
159 }
160 buf->remove_prefix(s);
161 return value;
162 }
163
Decode64Bit(absl::Span<const char> * buf)164 uint64_t Decode64Bit(absl::Span<const char> *buf) {
165 uint64_t value = 0;
166 size_t s = 0;
167 while (s < buf->size()) {
168 value |= static_cast<uint64_t>(static_cast<unsigned char>((*buf)[s]))
169 << 8 * s;
170 if (++s == sizeof(value)) break;
171 }
172 buf->remove_prefix(s);
173 return value;
174 }
175
Decode32Bit(absl::Span<const char> * buf)176 uint32_t Decode32Bit(absl::Span<const char> *buf) {
177 uint32_t value = 0;
178 size_t s = 0;
179 while (s < buf->size()) {
180 value |= static_cast<uint32_t>(static_cast<unsigned char>((*buf)[s]))
181 << 8 * s;
182 if (++s == sizeof(value)) break;
183 }
184 buf->remove_prefix(s);
185 return value;
186 }
187 } // namespace
188
DecodeFrom(absl::Span<const char> * data)189 bool ProtoField::DecodeFrom(absl::Span<const char> *data) {
190 if (data->empty()) return false;
191 const uint64_t tag_type = DecodeVarint(data);
192 tag_ = tag_type >> 3;
193 type_ = static_cast<WireType>(tag_type & 0x07);
194 switch (type_) {
195 case WireType::kVarint:
196 value_ = DecodeVarint(data);
197 break;
198 case WireType::k64Bit:
199 value_ = Decode64Bit(data);
200 break;
201 case WireType::kLengthDelimited: {
202 value_ = DecodeVarint(data);
203 data_ = data->subspan(
204 0, static_cast<size_t>(std::min<uint64_t>(value_, data->size())));
205 data->remove_prefix(data_.size());
206 break;
207 }
208 case WireType::k32Bit:
209 value_ = Decode32Bit(data);
210 break;
211 }
212 return true;
213 }
214
215 } // namespace log_internal
216 ABSL_NAMESPACE_END
217 } // namespace absl
218