1 | // Protocol Buffers - Google's data interchange format |
2 | // Copyright 2008 Google Inc. All rights reserved. |
3 | // https://developers.google.com/protocol-buffers/ |
4 | // |
5 | // Redistribution and use in source and binary forms, with or without |
6 | // modification, are permitted provided that the following conditions are |
7 | // met: |
8 | // |
9 | // * Redistributions of source code must retain the above copyright |
10 | // notice, this list of conditions and the following disclaimer. |
11 | // * Redistributions in binary form must reproduce the above |
12 | // copyright notice, this list of conditions and the following disclaimer |
13 | // in the documentation and/or other materials provided with the |
14 | // distribution. |
15 | // * Neither the name of Google Inc. nor the names of its |
16 | // contributors may be used to endorse or promote products derived from |
17 | // this software without specific prior written permission. |
18 | // |
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
30 | |
31 | // Author: kenton@google.com (Kenton Varda) |
32 | // Based on original Protocol Buffers design by |
33 | // Sanjay Ghemawat, Jeff Dean, and others. |
34 | // |
35 | // This implementation is heavily optimized to make reads and writes |
36 | // of small values (especially varints) as fast as possible. In |
37 | // particular, we optimize for the common case that a read or a write |
38 | // will not cross the end of the buffer, since we can avoid a lot |
39 | // of branching in this case. |
40 | |
41 | #include <google/protobuf/io/coded_stream.h> |
42 | |
43 | #include <limits.h> |
44 | |
45 | #include <algorithm> |
46 | #include <cstring> |
47 | #include <utility> |
48 | |
49 | #include <google/protobuf/stubs/logging.h> |
50 | #include <google/protobuf/stubs/common.h> |
51 | #include <google/protobuf/arena.h> |
52 | #include <google/protobuf/io/zero_copy_stream.h> |
53 | #include <google/protobuf/io/zero_copy_stream_impl_lite.h> |
54 | #include <google/protobuf/stubs/stl_util.h> |
55 | |
56 | |
57 | // Must be included last. |
58 | #include <google/protobuf/port_def.inc> |
59 | |
60 | namespace google { |
61 | namespace protobuf { |
62 | namespace io { |
63 | |
64 | namespace { |
65 | |
66 | static const int kMaxVarintBytes = 10; |
67 | static const int kMaxVarint32Bytes = 5; |
68 | |
69 | |
70 | inline bool NextNonEmpty(ZeroCopyInputStream* input, const void** data, |
71 | int* size) { |
72 | bool success; |
73 | do { |
74 | success = input->Next(data, size); |
75 | } while (success && *size == 0); |
76 | return success; |
77 | } |
78 | |
79 | } // namespace |
80 | |
81 | // CodedInputStream ================================================== |
82 | |
83 | CodedInputStream::~CodedInputStream() { |
84 | if (input_ != NULL) { |
85 | BackUpInputToCurrentPosition(); |
86 | } |
87 | } |
88 | |
89 | // Static. |
90 | int CodedInputStream::default_recursion_limit_ = 100; |
91 | |
92 | |
93 | void CodedInputStream::BackUpInputToCurrentPosition() { |
94 | int backup_bytes = BufferSize() + buffer_size_after_limit_ + overflow_bytes_; |
95 | if (backup_bytes > 0) { |
96 | input_->BackUp(count: backup_bytes); |
97 | |
98 | // total_bytes_read_ doesn't include overflow_bytes_. |
99 | total_bytes_read_ -= BufferSize() + buffer_size_after_limit_; |
100 | buffer_end_ = buffer_; |
101 | buffer_size_after_limit_ = 0; |
102 | overflow_bytes_ = 0; |
103 | } |
104 | } |
105 | |
106 | inline void CodedInputStream::RecomputeBufferLimits() { |
107 | buffer_end_ += buffer_size_after_limit_; |
108 | int closest_limit = std::min(current_limit_, total_bytes_limit_); |
109 | if (closest_limit < total_bytes_read_) { |
110 | // The limit position is in the current buffer. We must adjust |
111 | // the buffer size accordingly. |
112 | buffer_size_after_limit_ = total_bytes_read_ - closest_limit; |
113 | buffer_end_ -= buffer_size_after_limit_; |
114 | } else { |
115 | buffer_size_after_limit_ = 0; |
116 | } |
117 | } |
118 | |
119 | CodedInputStream::Limit CodedInputStream::PushLimit(int byte_limit) { |
120 | // Current position relative to the beginning of the stream. |
121 | int current_position = CurrentPosition(); |
122 | |
123 | Limit old_limit = current_limit_; |
124 | |
125 | // security: byte_limit is possibly evil, so check for negative values |
126 | // and overflow. Also check that the new requested limit is before the |
127 | // previous limit; otherwise we continue to enforce the previous limit. |
128 | if (PROTOBUF_PREDICT_TRUE(byte_limit >= 0 && |
129 | byte_limit <= INT_MAX - current_position && |
130 | byte_limit < current_limit_ - current_position)) { |
131 | current_limit_ = current_position + byte_limit; |
132 | RecomputeBufferLimits(); |
133 | } |
134 | |
135 | return old_limit; |
136 | } |
137 | |
138 | void CodedInputStream::PopLimit(Limit limit) { |
139 | // The limit passed in is actually the *old* limit, which we returned from |
140 | // PushLimit(). |
141 | current_limit_ = limit; |
142 | RecomputeBufferLimits(); |
143 | |
144 | // We may no longer be at a legitimate message end. ReadTag() needs to be |
145 | // called again to find out. |
146 | legitimate_message_end_ = false; |
147 | } |
148 | |
149 | std::pair<CodedInputStream::Limit, int> |
150 | CodedInputStream::IncrementRecursionDepthAndPushLimit(int byte_limit) { |
151 | return std::make_pair(x: PushLimit(byte_limit), y&: --recursion_budget_); |
152 | } |
153 | |
154 | CodedInputStream::Limit CodedInputStream::ReadLengthAndPushLimit() { |
155 | uint32_t length; |
156 | return PushLimit(byte_limit: ReadVarint32(value: &length) ? length : 0); |
157 | } |
158 | |
159 | bool CodedInputStream::DecrementRecursionDepthAndPopLimit(Limit limit) { |
160 | bool result = ConsumedEntireMessage(); |
161 | PopLimit(limit); |
162 | GOOGLE_DCHECK_LT(recursion_budget_, recursion_limit_); |
163 | ++recursion_budget_; |
164 | return result; |
165 | } |
166 | |
167 | bool CodedInputStream::CheckEntireMessageConsumedAndPopLimit(Limit limit) { |
168 | bool result = ConsumedEntireMessage(); |
169 | PopLimit(limit); |
170 | return result; |
171 | } |
172 | |
173 | int CodedInputStream::BytesUntilLimit() const { |
174 | if (current_limit_ == INT_MAX) return -1; |
175 | int current_position = CurrentPosition(); |
176 | |
177 | return current_limit_ - current_position; |
178 | } |
179 | |
180 | void CodedInputStream::SetTotalBytesLimit(int total_bytes_limit) { |
181 | // Make sure the limit isn't already past, since this could confuse other |
182 | // code. |
183 | int current_position = CurrentPosition(); |
184 | total_bytes_limit_ = std::max(current_position, total_bytes_limit); |
185 | RecomputeBufferLimits(); |
186 | } |
187 | |
188 | int CodedInputStream::BytesUntilTotalBytesLimit() const { |
189 | if (total_bytes_limit_ == INT_MAX) return -1; |
190 | return total_bytes_limit_ - CurrentPosition(); |
191 | } |
192 | |
193 | void CodedInputStream::PrintTotalBytesLimitError() { |
194 | GOOGLE_LOG(ERROR) |
195 | << "A protocol message was rejected because it was too " |
196 | "big (more than " |
197 | << total_bytes_limit_ |
198 | << " bytes). To increase the limit (or to disable these " |
199 | "warnings), see CodedInputStream::SetTotalBytesLimit() " |
200 | "in third_party/protobuf/io/coded_stream.h." ; |
201 | } |
202 | |
203 | bool CodedInputStream::SkipFallback(int count, int original_buffer_size) { |
204 | if (buffer_size_after_limit_ > 0) { |
205 | // We hit a limit inside this buffer. Advance to the limit and fail. |
206 | Advance(amount: original_buffer_size); |
207 | return false; |
208 | } |
209 | |
210 | count -= original_buffer_size; |
211 | buffer_ = NULL; |
212 | buffer_end_ = buffer_; |
213 | |
214 | // Make sure this skip doesn't try to skip past the current limit. |
215 | int closest_limit = std::min(current_limit_, total_bytes_limit_); |
216 | int bytes_until_limit = closest_limit - total_bytes_read_; |
217 | if (bytes_until_limit < count) { |
218 | // We hit the limit. Skip up to it then fail. |
219 | if (bytes_until_limit > 0) { |
220 | total_bytes_read_ = closest_limit; |
221 | input_->Skip(count: bytes_until_limit); |
222 | } |
223 | return false; |
224 | } |
225 | |
226 | if (!input_->Skip(count)) { |
227 | total_bytes_read_ = input_->ByteCount(); |
228 | return false; |
229 | } |
230 | total_bytes_read_ += count; |
231 | return true; |
232 | } |
233 | |
234 | bool CodedInputStream::GetDirectBufferPointer(const void** data, int* size) { |
235 | if (BufferSize() == 0 && !Refresh()) return false; |
236 | |
237 | *data = buffer_; |
238 | *size = BufferSize(); |
239 | return true; |
240 | } |
241 | |
242 | bool CodedInputStream::ReadRaw(void* buffer, int size) { |
243 | int current_buffer_size; |
244 | while ((current_buffer_size = BufferSize()) < size) { |
245 | // Reading past end of buffer. Copy what we have, then refresh. |
246 | memcpy(dest: buffer, src: buffer_, n: current_buffer_size); |
247 | buffer = reinterpret_cast<uint8_t*>(buffer) + current_buffer_size; |
248 | size -= current_buffer_size; |
249 | Advance(amount: current_buffer_size); |
250 | if (!Refresh()) return false; |
251 | } |
252 | |
253 | memcpy(dest: buffer, src: buffer_, n: size); |
254 | Advance(amount: size); |
255 | |
256 | return true; |
257 | } |
258 | |
259 | bool CodedInputStream::ReadString(std::string* buffer, int size) { |
260 | if (size < 0) return false; // security: size is often user-supplied |
261 | |
262 | if (BufferSize() >= size) { |
263 | STLStringResizeUninitialized(s: buffer, new_size: size); |
264 | std::pair<char*, bool> z = as_string_data(s: buffer); |
265 | if (z.second) { |
266 | // Oddly enough, memcpy() requires its first two args to be non-NULL even |
267 | // if we copy 0 bytes. So, we have ensured that z.first is non-NULL here. |
268 | GOOGLE_DCHECK(z.first != NULL); |
269 | memcpy(dest: z.first, src: buffer_, n: size); |
270 | Advance(amount: size); |
271 | } |
272 | return true; |
273 | } |
274 | |
275 | return ReadStringFallback(buffer, size); |
276 | } |
277 | |
278 | bool CodedInputStream::ReadStringFallback(std::string* buffer, int size) { |
279 | if (!buffer->empty()) { |
280 | buffer->clear(); |
281 | } |
282 | |
283 | int closest_limit = std::min(current_limit_, total_bytes_limit_); |
284 | if (closest_limit != INT_MAX) { |
285 | int bytes_to_limit = closest_limit - CurrentPosition(); |
286 | if (bytes_to_limit > 0 && size > 0 && size <= bytes_to_limit) { |
287 | buffer->reserve(res_arg: size); |
288 | } |
289 | } |
290 | |
291 | int current_buffer_size; |
292 | while ((current_buffer_size = BufferSize()) < size) { |
293 | // Some STL implementations "helpfully" crash on buffer->append(NULL, 0). |
294 | if (current_buffer_size != 0) { |
295 | // Note: string1.append(string2) is O(string2.size()) (as opposed to |
296 | // O(string1.size() + string2.size()), which would be bad). |
297 | buffer->append(s: reinterpret_cast<const char*>(buffer_), |
298 | n: current_buffer_size); |
299 | } |
300 | size -= current_buffer_size; |
301 | Advance(amount: current_buffer_size); |
302 | if (!Refresh()) return false; |
303 | } |
304 | |
305 | buffer->append(s: reinterpret_cast<const char*>(buffer_), n: size); |
306 | Advance(amount: size); |
307 | |
308 | return true; |
309 | } |
310 | |
311 | |
312 | bool CodedInputStream::ReadLittleEndian32Fallback(uint32_t* value) { |
313 | uint8_t bytes[sizeof(*value)]; |
314 | |
315 | const uint8_t* ptr; |
316 | if (BufferSize() >= static_cast<int64_t>(sizeof(*value))) { |
317 | // Fast path: Enough bytes in the buffer to read directly. |
318 | ptr = buffer_; |
319 | Advance(amount: sizeof(*value)); |
320 | } else { |
321 | // Slow path: Had to read past the end of the buffer. |
322 | if (!ReadRaw(buffer: bytes, size: sizeof(*value))) return false; |
323 | ptr = bytes; |
324 | } |
325 | ReadLittleEndian32FromArray(buffer: ptr, value); |
326 | return true; |
327 | } |
328 | |
329 | bool CodedInputStream::ReadLittleEndian64Fallback(uint64_t* value) { |
330 | uint8_t bytes[sizeof(*value)]; |
331 | |
332 | const uint8_t* ptr; |
333 | if (BufferSize() >= static_cast<int64_t>(sizeof(*value))) { |
334 | // Fast path: Enough bytes in the buffer to read directly. |
335 | ptr = buffer_; |
336 | Advance(amount: sizeof(*value)); |
337 | } else { |
338 | // Slow path: Had to read past the end of the buffer. |
339 | if (!ReadRaw(buffer: bytes, size: sizeof(*value))) return false; |
340 | ptr = bytes; |
341 | } |
342 | ReadLittleEndian64FromArray(buffer: ptr, value); |
343 | return true; |
344 | } |
345 | |
346 | namespace { |
347 | |
348 | // Decodes varint64 with known size, N, and returns next pointer. Knowing N at |
349 | // compile time, compiler can generate optimal code. For example, instead of |
350 | // subtracting 0x80 at each iteration, it subtracts properly shifted mask once. |
351 | template <size_t N> |
352 | const uint8_t* DecodeVarint64KnownSize(const uint8_t* buffer, uint64_t* value) { |
353 | GOOGLE_DCHECK_GT(N, 0); |
354 | uint64_t result = static_cast<uint64_t>(buffer[N - 1]) << (7 * (N - 1)); |
355 | for (size_t i = 0, offset = 0; i < N - 1; i++, offset += 7) { |
356 | result += static_cast<uint64_t>(buffer[i] - 0x80) << offset; |
357 | } |
358 | *value = result; |
359 | return buffer + N; |
360 | } |
361 | |
362 | // Read a varint from the given buffer, write it to *value, and return a pair. |
363 | // The first part of the pair is true iff the read was successful. The second |
364 | // part is buffer + (number of bytes read). This function is always inlined, |
365 | // so returning a pair is costless. |
366 | PROTOBUF_ALWAYS_INLINE |
367 | ::std::pair<bool, const uint8_t*> ReadVarint32FromArray(uint32_t first_byte, |
368 | const uint8_t* buffer, |
369 | uint32_t* value); |
370 | inline ::std::pair<bool, const uint8_t*> ReadVarint32FromArray( |
371 | uint32_t first_byte, const uint8_t* buffer, uint32_t* value) { |
372 | // Fast path: We have enough bytes left in the buffer to guarantee that |
373 | // this read won't cross the end, so we can skip the checks. |
374 | GOOGLE_DCHECK_EQ(*buffer, first_byte); |
375 | GOOGLE_DCHECK_EQ(first_byte & 0x80, 0x80) << first_byte; |
376 | const uint8_t* ptr = buffer; |
377 | uint32_t b; |
378 | uint32_t result = first_byte - 0x80; |
379 | ++ptr; // We just processed the first byte. Move on to the second. |
380 | b = *(ptr++); |
381 | result += b << 7; |
382 | if (!(b & 0x80)) goto done; |
383 | result -= 0x80 << 7; |
384 | b = *(ptr++); |
385 | result += b << 14; |
386 | if (!(b & 0x80)) goto done; |
387 | result -= 0x80 << 14; |
388 | b = *(ptr++); |
389 | result += b << 21; |
390 | if (!(b & 0x80)) goto done; |
391 | result -= 0x80 << 21; |
392 | b = *(ptr++); |
393 | result += b << 28; |
394 | if (!(b & 0x80)) goto done; |
395 | // "result -= 0x80 << 28" is irrelevant. |
396 | |
397 | // If the input is larger than 32 bits, we still need to read it all |
398 | // and discard the high-order bits. |
399 | for (int i = 0; i < kMaxVarintBytes - kMaxVarint32Bytes; i++) { |
400 | b = *(ptr++); |
401 | if (!(b & 0x80)) goto done; |
402 | } |
403 | |
404 | // We have overrun the maximum size of a varint (10 bytes). Assume |
405 | // the data is corrupt. |
406 | return std::make_pair(x: false, y&: ptr); |
407 | |
408 | done: |
409 | *value = result; |
410 | return std::make_pair(x: true, y&: ptr); |
411 | } |
412 | |
413 | PROTOBUF_ALWAYS_INLINE::std::pair<bool, const uint8_t*> ReadVarint64FromArray( |
414 | const uint8_t* buffer, uint64_t* value); |
415 | inline ::std::pair<bool, const uint8_t*> ReadVarint64FromArray( |
416 | const uint8_t* buffer, uint64_t* value) { |
417 | // Assumes varint64 is at least 2 bytes. |
418 | GOOGLE_DCHECK_GE(buffer[0], 128); |
419 | |
420 | const uint8_t* next; |
421 | if (buffer[1] < 128) { |
422 | next = DecodeVarint64KnownSize<2>(buffer, value); |
423 | } else if (buffer[2] < 128) { |
424 | next = DecodeVarint64KnownSize<3>(buffer, value); |
425 | } else if (buffer[3] < 128) { |
426 | next = DecodeVarint64KnownSize<4>(buffer, value); |
427 | } else if (buffer[4] < 128) { |
428 | next = DecodeVarint64KnownSize<5>(buffer, value); |
429 | } else if (buffer[5] < 128) { |
430 | next = DecodeVarint64KnownSize<6>(buffer, value); |
431 | } else if (buffer[6] < 128) { |
432 | next = DecodeVarint64KnownSize<7>(buffer, value); |
433 | } else if (buffer[7] < 128) { |
434 | next = DecodeVarint64KnownSize<8>(buffer, value); |
435 | } else if (buffer[8] < 128) { |
436 | next = DecodeVarint64KnownSize<9>(buffer, value); |
437 | } else if (buffer[9] < 128) { |
438 | next = DecodeVarint64KnownSize<10>(buffer, value); |
439 | } else { |
440 | // We have overrun the maximum size of a varint (10 bytes). Assume |
441 | // the data is corrupt. |
442 | return std::make_pair(x: false, y: buffer + 11); |
443 | } |
444 | |
445 | return std::make_pair(x: true, y&: next); |
446 | } |
447 | |
448 | } // namespace |
449 | |
450 | bool CodedInputStream::ReadVarint32Slow(uint32_t* value) { |
451 | // Directly invoke ReadVarint64Fallback, since we already tried to optimize |
452 | // for one-byte varints. |
453 | std::pair<uint64_t, bool> p = ReadVarint64Fallback(); |
454 | *value = static_cast<uint32_t>(p.first); |
455 | return p.second; |
456 | } |
457 | |
458 | int64_t CodedInputStream::ReadVarint32Fallback(uint32_t first_byte_or_zero) { |
459 | if (BufferSize() >= kMaxVarintBytes || |
460 | // Optimization: We're also safe if the buffer is non-empty and it ends |
461 | // with a byte that would terminate a varint. |
462 | (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) { |
463 | GOOGLE_DCHECK_NE(first_byte_or_zero, 0) |
464 | << "Caller should provide us with *buffer_ when buffer is non-empty" ; |
465 | uint32_t temp; |
466 | ::std::pair<bool, const uint8_t*> p = |
467 | ReadVarint32FromArray(first_byte: first_byte_or_zero, buffer: buffer_, value: &temp); |
468 | if (!p.first) return -1; |
469 | buffer_ = p.second; |
470 | return temp; |
471 | } else { |
472 | // Really slow case: we will incur the cost of an extra function call here, |
473 | // but moving this out of line reduces the size of this function, which |
474 | // improves the common case. In micro benchmarks, this is worth about 10-15% |
475 | uint32_t temp; |
476 | return ReadVarint32Slow(value: &temp) ? static_cast<int64_t>(temp) : -1; |
477 | } |
478 | } |
479 | |
480 | int CodedInputStream::ReadVarintSizeAsIntSlow() { |
481 | // Directly invoke ReadVarint64Fallback, since we already tried to optimize |
482 | // for one-byte varints. |
483 | std::pair<uint64_t, bool> p = ReadVarint64Fallback(); |
484 | if (!p.second || p.first > static_cast<uint64_t>(INT_MAX)) return -1; |
485 | return p.first; |
486 | } |
487 | |
488 | int CodedInputStream::ReadVarintSizeAsIntFallback() { |
489 | if (BufferSize() >= kMaxVarintBytes || |
490 | // Optimization: We're also safe if the buffer is non-empty and it ends |
491 | // with a byte that would terminate a varint. |
492 | (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) { |
493 | uint64_t temp; |
494 | ::std::pair<bool, const uint8_t*> p = ReadVarint64FromArray(buffer: buffer_, value: &temp); |
495 | if (!p.first || temp > static_cast<uint64_t>(INT_MAX)) return -1; |
496 | buffer_ = p.second; |
497 | return temp; |
498 | } else { |
499 | // Really slow case: we will incur the cost of an extra function call here, |
500 | // but moving this out of line reduces the size of this function, which |
501 | // improves the common case. In micro benchmarks, this is worth about 10-15% |
502 | return ReadVarintSizeAsIntSlow(); |
503 | } |
504 | } |
505 | |
506 | uint32_t CodedInputStream::ReadTagSlow() { |
507 | if (buffer_ == buffer_end_) { |
508 | // Call refresh. |
509 | if (!Refresh()) { |
510 | // Refresh failed. Make sure that it failed due to EOF, not because |
511 | // we hit total_bytes_limit_, which, unlike normal limits, is not a |
512 | // valid place to end a message. |
513 | int current_position = total_bytes_read_ - buffer_size_after_limit_; |
514 | if (current_position >= total_bytes_limit_) { |
515 | // Hit total_bytes_limit_. But if we also hit the normal limit, |
516 | // we're still OK. |
517 | legitimate_message_end_ = current_limit_ == total_bytes_limit_; |
518 | } else { |
519 | legitimate_message_end_ = true; |
520 | } |
521 | return 0; |
522 | } |
523 | } |
524 | |
525 | // For the slow path, just do a 64-bit read. Try to optimize for one-byte tags |
526 | // again, since we have now refreshed the buffer. |
527 | uint64_t result = 0; |
528 | if (!ReadVarint64(value: &result)) return 0; |
529 | return static_cast<uint32_t>(result); |
530 | } |
531 | |
532 | uint32_t CodedInputStream::ReadTagFallback(uint32_t first_byte_or_zero) { |
533 | const int buf_size = BufferSize(); |
534 | if (buf_size >= kMaxVarintBytes || |
535 | // Optimization: We're also safe if the buffer is non-empty and it ends |
536 | // with a byte that would terminate a varint. |
537 | (buf_size > 0 && !(buffer_end_[-1] & 0x80))) { |
538 | GOOGLE_DCHECK_EQ(first_byte_or_zero, buffer_[0]); |
539 | if (first_byte_or_zero == 0) { |
540 | ++buffer_; |
541 | return 0; |
542 | } |
543 | uint32_t tag; |
544 | ::std::pair<bool, const uint8_t*> p = |
545 | ReadVarint32FromArray(first_byte: first_byte_or_zero, buffer: buffer_, value: &tag); |
546 | if (!p.first) { |
547 | return 0; |
548 | } |
549 | buffer_ = p.second; |
550 | return tag; |
551 | } else { |
552 | // We are commonly at a limit when attempting to read tags. Try to quickly |
553 | // detect this case without making another function call. |
554 | if ((buf_size == 0) && |
555 | ((buffer_size_after_limit_ > 0) || |
556 | (total_bytes_read_ == current_limit_)) && |
557 | // Make sure that the limit we hit is not total_bytes_limit_, since |
558 | // in that case we still need to call Refresh() so that it prints an |
559 | // error. |
560 | total_bytes_read_ - buffer_size_after_limit_ < total_bytes_limit_) { |
561 | // We hit a byte limit. |
562 | legitimate_message_end_ = true; |
563 | return 0; |
564 | } |
565 | return ReadTagSlow(); |
566 | } |
567 | } |
568 | |
569 | bool CodedInputStream::ReadVarint64Slow(uint64_t* value) { |
570 | // Slow path: This read might cross the end of the buffer, so we |
571 | // need to check and refresh the buffer if and when it does. |
572 | |
573 | uint64_t result = 0; |
574 | int count = 0; |
575 | uint32_t b; |
576 | |
577 | do { |
578 | if (count == kMaxVarintBytes) { |
579 | *value = 0; |
580 | return false; |
581 | } |
582 | while (buffer_ == buffer_end_) { |
583 | if (!Refresh()) { |
584 | *value = 0; |
585 | return false; |
586 | } |
587 | } |
588 | b = *buffer_; |
589 | result |= static_cast<uint64_t>(b & 0x7F) << (7 * count); |
590 | Advance(amount: 1); |
591 | ++count; |
592 | } while (b & 0x80); |
593 | |
594 | *value = result; |
595 | return true; |
596 | } |
597 | |
598 | std::pair<uint64_t, bool> CodedInputStream::ReadVarint64Fallback() { |
599 | if (BufferSize() >= kMaxVarintBytes || |
600 | // Optimization: We're also safe if the buffer is non-empty and it ends |
601 | // with a byte that would terminate a varint. |
602 | (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) { |
603 | uint64_t temp; |
604 | ::std::pair<bool, const uint8_t*> p = ReadVarint64FromArray(buffer: buffer_, value: &temp); |
605 | if (!p.first) { |
606 | return std::make_pair(x: 0, y: false); |
607 | } |
608 | buffer_ = p.second; |
609 | return std::make_pair(x&: temp, y: true); |
610 | } else { |
611 | uint64_t temp; |
612 | bool success = ReadVarint64Slow(value: &temp); |
613 | return std::make_pair(x&: temp, y&: success); |
614 | } |
615 | } |
616 | |
617 | bool CodedInputStream::Refresh() { |
618 | GOOGLE_DCHECK_EQ(0, BufferSize()); |
619 | |
620 | if (buffer_size_after_limit_ > 0 || overflow_bytes_ > 0 || |
621 | total_bytes_read_ == current_limit_) { |
622 | // We've hit a limit. Stop. |
623 | int current_position = total_bytes_read_ - buffer_size_after_limit_; |
624 | |
625 | if (current_position >= total_bytes_limit_ && |
626 | total_bytes_limit_ != current_limit_) { |
627 | // Hit total_bytes_limit_. |
628 | PrintTotalBytesLimitError(); |
629 | } |
630 | |
631 | return false; |
632 | } |
633 | |
634 | const void* void_buffer; |
635 | int buffer_size; |
636 | if (NextNonEmpty(input: input_, data: &void_buffer, size: &buffer_size)) { |
637 | buffer_ = reinterpret_cast<const uint8_t*>(void_buffer); |
638 | buffer_end_ = buffer_ + buffer_size; |
639 | GOOGLE_CHECK_GE(buffer_size, 0); |
640 | |
641 | if (total_bytes_read_ <= INT_MAX - buffer_size) { |
642 | total_bytes_read_ += buffer_size; |
643 | } else { |
644 | // Overflow. Reset buffer_end_ to not include the bytes beyond INT_MAX. |
645 | // We can't get that far anyway, because total_bytes_limit_ is guaranteed |
646 | // to be less than it. We need to keep track of the number of bytes |
647 | // we discarded, though, so that we can call input_->BackUp() to back |
648 | // up over them on destruction. |
649 | |
650 | // The following line is equivalent to: |
651 | // overflow_bytes_ = total_bytes_read_ + buffer_size - INT_MAX; |
652 | // except that it avoids overflows. Signed integer overflow has |
653 | // undefined results according to the C standard. |
654 | overflow_bytes_ = total_bytes_read_ - (INT_MAX - buffer_size); |
655 | buffer_end_ -= overflow_bytes_; |
656 | total_bytes_read_ = INT_MAX; |
657 | } |
658 | |
659 | RecomputeBufferLimits(); |
660 | return true; |
661 | } else { |
662 | buffer_ = NULL; |
663 | buffer_end_ = NULL; |
664 | return false; |
665 | } |
666 | } |
667 | |
668 | // CodedOutputStream ================================================= |
669 | |
670 | void EpsCopyOutputStream::EnableAliasing(bool enabled) { |
671 | aliasing_enabled_ = enabled && stream_->AllowsAliasing(); |
672 | } |
673 | |
674 | int64_t EpsCopyOutputStream::ByteCount(uint8_t* ptr) const { |
675 | // Calculate the current offset relative to the end of the stream buffer. |
676 | int delta = (end_ - ptr) + (buffer_end_ ? 0 : kSlopBytes); |
677 | return stream_->ByteCount() - delta; |
678 | } |
679 | |
680 | // Flushes what's written out to the underlying ZeroCopyOutputStream buffers. |
681 | // Returns the size remaining in the buffer and sets buffer_end_ to the start |
682 | // of the remaining buffer, ie. [buffer_end_, buffer_end_ + return value) |
683 | int EpsCopyOutputStream::Flush(uint8_t* ptr) { |
684 | while (buffer_end_ && ptr > end_) { |
685 | int overrun = ptr - end_; |
686 | GOOGLE_DCHECK(!had_error_); |
687 | GOOGLE_DCHECK(overrun <= kSlopBytes); // NOLINT |
688 | ptr = Next() + overrun; |
689 | if (had_error_) return 0; |
690 | } |
691 | int s; |
692 | if (buffer_end_) { |
693 | std::memcpy(dest: buffer_end_, src: buffer_, n: ptr - buffer_); |
694 | buffer_end_ += ptr - buffer_; |
695 | s = end_ - ptr; |
696 | } else { |
697 | // The stream is writing directly in the ZeroCopyOutputStream buffer. |
698 | s = end_ + kSlopBytes - ptr; |
699 | buffer_end_ = ptr; |
700 | } |
701 | GOOGLE_DCHECK(s >= 0); // NOLINT |
702 | return s; |
703 | } |
704 | |
705 | uint8_t* EpsCopyOutputStream::Trim(uint8_t* ptr) { |
706 | if (had_error_) return ptr; |
707 | int s = Flush(ptr); |
708 | stream_->BackUp(count: s); |
709 | // Reset to initial state (expecting new buffer) |
710 | buffer_end_ = end_ = buffer_; |
711 | return buffer_; |
712 | } |
713 | |
714 | |
715 | uint8_t* EpsCopyOutputStream::FlushAndResetBuffer(uint8_t* ptr) { |
716 | if (had_error_) return buffer_; |
717 | int s = Flush(ptr); |
718 | if (had_error_) return buffer_; |
719 | return SetInitialBuffer(data: buffer_end_, size: s); |
720 | } |
721 | |
722 | bool EpsCopyOutputStream::Skip(int count, uint8_t** pp) { |
723 | if (count < 0) return false; |
724 | if (had_error_) { |
725 | *pp = buffer_; |
726 | return false; |
727 | } |
728 | int size = Flush(ptr: *pp); |
729 | if (had_error_) { |
730 | *pp = buffer_; |
731 | return false; |
732 | } |
733 | void* data = buffer_end_; |
734 | while (count > size) { |
735 | count -= size; |
736 | if (!stream_->Next(data: &data, size: &size)) { |
737 | *pp = Error(); |
738 | return false; |
739 | } |
740 | } |
741 | *pp = SetInitialBuffer(data: static_cast<uint8_t*>(data) + count, size: size - count); |
742 | return true; |
743 | } |
744 | |
745 | bool EpsCopyOutputStream::GetDirectBufferPointer(void** data, int* size, |
746 | uint8_t** pp) { |
747 | if (had_error_) { |
748 | *pp = buffer_; |
749 | return false; |
750 | } |
751 | *size = Flush(ptr: *pp); |
752 | if (had_error_) { |
753 | *pp = buffer_; |
754 | return false; |
755 | } |
756 | *data = buffer_end_; |
757 | while (*size == 0) { |
758 | if (!stream_->Next(data, size)) { |
759 | *pp = Error(); |
760 | return false; |
761 | } |
762 | } |
763 | *pp = SetInitialBuffer(data: *data, size: *size); |
764 | return true; |
765 | } |
766 | |
767 | uint8_t* EpsCopyOutputStream::GetDirectBufferForNBytesAndAdvance(int size, |
768 | uint8_t** pp) { |
769 | if (had_error_) { |
770 | *pp = buffer_; |
771 | return nullptr; |
772 | } |
773 | int s = Flush(ptr: *pp); |
774 | if (had_error_) { |
775 | *pp = buffer_; |
776 | return nullptr; |
777 | } |
778 | if (s >= size) { |
779 | auto res = buffer_end_; |
780 | *pp = SetInitialBuffer(data: buffer_end_ + size, size: s - size); |
781 | return res; |
782 | } else { |
783 | *pp = SetInitialBuffer(data: buffer_end_, size: s); |
784 | return nullptr; |
785 | } |
786 | } |
787 | |
788 | uint8_t* EpsCopyOutputStream::Next() { |
789 | GOOGLE_DCHECK(!had_error_); // NOLINT |
790 | if (PROTOBUF_PREDICT_FALSE(stream_ == nullptr)) return Error(); |
791 | if (buffer_end_) { |
792 | // We're in the patch buffer and need to fill up the previous buffer. |
793 | std::memcpy(dest: buffer_end_, src: buffer_, n: end_ - buffer_); |
794 | uint8_t* ptr; |
795 | int size; |
796 | do { |
797 | void* data; |
798 | if (PROTOBUF_PREDICT_FALSE(!stream_->Next(&data, &size))) { |
799 | // Stream has an error, we use the patch buffer to continue to be |
800 | // able to write. |
801 | return Error(); |
802 | } |
803 | ptr = static_cast<uint8_t*>(data); |
804 | } while (size == 0); |
805 | if (PROTOBUF_PREDICT_TRUE(size > kSlopBytes)) { |
806 | std::memcpy(dest: ptr, src: end_, n: kSlopBytes); |
807 | end_ = ptr + size - kSlopBytes; |
808 | buffer_end_ = nullptr; |
809 | return ptr; |
810 | } else { |
811 | GOOGLE_DCHECK(size > 0); // NOLINT |
812 | // Buffer to small |
813 | std::memmove(dest: buffer_, src: end_, n: kSlopBytes); |
814 | buffer_end_ = ptr; |
815 | end_ = buffer_ + size; |
816 | return buffer_; |
817 | } |
818 | } else { |
819 | std::memcpy(dest: buffer_, src: end_, n: kSlopBytes); |
820 | buffer_end_ = end_; |
821 | end_ = buffer_ + kSlopBytes; |
822 | return buffer_; |
823 | } |
824 | } |
825 | |
826 | uint8_t* EpsCopyOutputStream::EnsureSpaceFallback(uint8_t* ptr) { |
827 | do { |
828 | if (PROTOBUF_PREDICT_FALSE(had_error_)) return buffer_; |
829 | int overrun = ptr - end_; |
830 | GOOGLE_DCHECK(overrun >= 0); // NOLINT |
831 | GOOGLE_DCHECK(overrun <= kSlopBytes); // NOLINT |
832 | ptr = Next() + overrun; |
833 | } while (ptr >= end_); |
834 | GOOGLE_DCHECK(ptr < end_); // NOLINT |
835 | return ptr; |
836 | } |
837 | |
838 | uint8_t* EpsCopyOutputStream::WriteRawFallback(const void* data, int size, |
839 | uint8_t* ptr) { |
840 | int s = GetSize(ptr); |
841 | while (s < size) { |
842 | std::memcpy(dest: ptr, src: data, n: s); |
843 | size -= s; |
844 | data = static_cast<const uint8_t*>(data) + s; |
845 | ptr = EnsureSpaceFallback(ptr: ptr + s); |
846 | s = GetSize(ptr); |
847 | } |
848 | std::memcpy(dest: ptr, src: data, n: size); |
849 | return ptr + size; |
850 | } |
851 | |
852 | uint8_t* EpsCopyOutputStream::WriteAliasedRaw(const void* data, int size, |
853 | uint8_t* ptr) { |
854 | if (size < GetSize(ptr) |
855 | ) { |
856 | return WriteRaw(data, size, ptr); |
857 | } else { |
858 | ptr = Trim(ptr); |
859 | if (stream_->WriteAliasedRaw(data, size)) return ptr; |
860 | return Error(); |
861 | } |
862 | } |
863 | |
864 | #ifndef PROTOBUF_LITTLE_ENDIAN |
865 | uint8_t* EpsCopyOutputStream::WriteRawLittleEndian32(const void* data, int size, |
866 | uint8_t* ptr) { |
867 | auto p = static_cast<const uint8_t*>(data); |
868 | auto end = p + size; |
869 | while (end - p >= kSlopBytes) { |
870 | ptr = EnsureSpace(ptr); |
871 | uint32_t buffer[4]; |
872 | static_assert(sizeof(buffer) == kSlopBytes, "Buffer must be kSlopBytes" ); |
873 | std::memcpy(buffer, p, kSlopBytes); |
874 | p += kSlopBytes; |
875 | for (auto x : buffer) |
876 | ptr = CodedOutputStream::WriteLittleEndian32ToArray(x, ptr); |
877 | } |
878 | while (p < end) { |
879 | ptr = EnsureSpace(ptr); |
880 | uint32_t buffer; |
881 | std::memcpy(&buffer, p, 4); |
882 | p += 4; |
883 | ptr = CodedOutputStream::WriteLittleEndian32ToArray(buffer, ptr); |
884 | } |
885 | return ptr; |
886 | } |
887 | |
888 | uint8_t* EpsCopyOutputStream::WriteRawLittleEndian64(const void* data, int size, |
889 | uint8_t* ptr) { |
890 | auto p = static_cast<const uint8_t*>(data); |
891 | auto end = p + size; |
892 | while (end - p >= kSlopBytes) { |
893 | ptr = EnsureSpace(ptr); |
894 | uint64_t buffer[2]; |
895 | static_assert(sizeof(buffer) == kSlopBytes, "Buffer must be kSlopBytes" ); |
896 | std::memcpy(buffer, p, kSlopBytes); |
897 | p += kSlopBytes; |
898 | for (auto x : buffer) |
899 | ptr = CodedOutputStream::WriteLittleEndian64ToArray(x, ptr); |
900 | } |
901 | while (p < end) { |
902 | ptr = EnsureSpace(ptr); |
903 | uint64_t buffer; |
904 | std::memcpy(&buffer, p, 8); |
905 | p += 8; |
906 | ptr = CodedOutputStream::WriteLittleEndian64ToArray(buffer, ptr); |
907 | } |
908 | return ptr; |
909 | } |
910 | #endif |
911 | |
912 | |
913 | uint8_t* EpsCopyOutputStream::WriteStringMaybeAliasedOutline(uint32_t num, |
914 | const std::string& s, |
915 | uint8_t* ptr) { |
916 | ptr = EnsureSpace(ptr); |
917 | uint32_t size = s.size(); |
918 | ptr = WriteLengthDelim(num, size, ptr); |
919 | return WriteRawMaybeAliased(data: s.data(), size, ptr); |
920 | } |
921 | |
922 | uint8_t* EpsCopyOutputStream::WriteStringOutline(uint32_t num, const std::string& s, |
923 | uint8_t* ptr) { |
924 | ptr = EnsureSpace(ptr); |
925 | uint32_t size = s.size(); |
926 | ptr = WriteLengthDelim(num, size, ptr); |
927 | return WriteRaw(data: s.data(), size, ptr); |
928 | } |
929 | |
930 | std::atomic<bool> CodedOutputStream::default_serialization_deterministic_{ |
931 | false}; |
932 | |
933 | CodedOutputStream::~CodedOutputStream() { Trim(); } |
934 | |
935 | |
936 | uint8_t* CodedOutputStream::WriteStringWithSizeToArray(const std::string& str, |
937 | uint8_t* target) { |
938 | GOOGLE_DCHECK_LE(str.size(), std::numeric_limits<uint32_t>::max()); |
939 | target = WriteVarint32ToArray(value: str.size(), target); |
940 | return WriteStringToArray(str, target); |
941 | } |
942 | |
943 | uint8_t* CodedOutputStream::WriteVarint32ToArrayOutOfLineHelper(uint32_t value, |
944 | uint8_t* target) { |
945 | GOOGLE_DCHECK_GE(value, 0x80); |
946 | target[0] |= static_cast<uint8_t>(0x80); |
947 | value >>= 7; |
948 | target[1] = static_cast<uint8_t>(value); |
949 | if (value < 0x80) { |
950 | return target + 2; |
951 | } |
952 | target += 2; |
953 | do { |
954 | // Turn on continuation bit in the byte we just wrote. |
955 | target[-1] |= static_cast<uint8_t>(0x80); |
956 | value >>= 7; |
957 | *target = static_cast<uint8_t>(value); |
958 | ++target; |
959 | } while (value >= 0x80); |
960 | return target; |
961 | } |
962 | |
963 | } // namespace io |
964 | } // namespace protobuf |
965 | } // namespace google |
966 | |
967 | #include <google/protobuf/port_undef.inc> |
968 | |