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
60namespace google {
61namespace protobuf {
62namespace io {
63
64namespace {
65
66static const int kMaxVarintBytes = 10;
67static const int kMaxVarint32Bytes = 5;
68
69
70inline 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
83CodedInputStream::~CodedInputStream() {
84 if (input_ != NULL) {
85 BackUpInputToCurrentPosition();
86 }
87}
88
89// Static.
90int CodedInputStream::default_recursion_limit_ = 100;
91
92
93void 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
106inline 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
119CodedInputStream::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
138void 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
149std::pair<CodedInputStream::Limit, int>
150CodedInputStream::IncrementRecursionDepthAndPushLimit(int byte_limit) {
151 return std::make_pair(x: PushLimit(byte_limit), y&: --recursion_budget_);
152}
153
154CodedInputStream::Limit CodedInputStream::ReadLengthAndPushLimit() {
155 uint32_t length;
156 return PushLimit(byte_limit: ReadVarint32(value: &length) ? length : 0);
157}
158
159bool 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
167bool CodedInputStream::CheckEntireMessageConsumedAndPopLimit(Limit limit) {
168 bool result = ConsumedEntireMessage();
169 PopLimit(limit);
170 return result;
171}
172
173int 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
180void 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
188int CodedInputStream::BytesUntilTotalBytesLimit() const {
189 if (total_bytes_limit_ == INT_MAX) return -1;
190 return total_bytes_limit_ - CurrentPosition();
191}
192
193void 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
203bool 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
234bool 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
242bool 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
259bool 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
278bool 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
312bool 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
329bool 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
346namespace {
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.
351template <size_t N>
352const 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.
366PROTOBUF_ALWAYS_INLINE
367::std::pair<bool, const uint8_t*> ReadVarint32FromArray(uint32_t first_byte,
368 const uint8_t* buffer,
369 uint32_t* value);
370inline ::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
408done:
409 *value = result;
410 return std::make_pair(x: true, y&: ptr);
411}
412
413PROTOBUF_ALWAYS_INLINE::std::pair<bool, const uint8_t*> ReadVarint64FromArray(
414 const uint8_t* buffer, uint64_t* value);
415inline ::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
450bool 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
458int64_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
480int 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
488int 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
506uint32_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
532uint32_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
569bool 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
598std::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
617bool 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
670void EpsCopyOutputStream::EnableAliasing(bool enabled) {
671 aliasing_enabled_ = enabled && stream_->AllowsAliasing();
672}
673
674int64_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)
683int 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
705uint8_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
715uint8_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
722bool 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
745bool 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
767uint8_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
788uint8_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
826uint8_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
838uint8_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
852uint8_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
865uint8_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
888uint8_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
913uint8_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
922uint8_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
930std::atomic<bool> CodedOutputStream::default_serialization_deterministic_{
931 false};
932
933CodedOutputStream::~CodedOutputStream() { Trim(); }
934
935
936uint8_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
943uint8_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