blob: 0851ff0cb6547db7b22fb405a348d4a5850832c8 [file] [log] [blame]
Brian Silverman9c614bc2016-02-15 20:20:02 -05001// 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_inl.h>
42#include <algorithm>
43#include <utility>
44#include <limits.h>
45#include <google/protobuf/io/zero_copy_stream.h>
46#include <google/protobuf/arena.h>
47#include <google/protobuf/stubs/logging.h>
48#include <google/protobuf/stubs/common.h>
49#include <google/protobuf/stubs/stl_util.h>
50
51
52namespace google {
53namespace protobuf {
54namespace io {
55
56namespace {
57
58static const int kMaxVarintBytes = 10;
59static const int kMaxVarint32Bytes = 5;
60
61
62inline bool NextNonEmpty(ZeroCopyInputStream* input,
63 const void** data, int* size) {
64 bool success;
65 do {
66 success = input->Next(data, size);
67 } while (success && *size == 0);
68 return success;
69}
70
71} // namespace
72
73// CodedInputStream ==================================================
74
75CodedInputStream::~CodedInputStream() {
76 if (input_ != NULL) {
77 BackUpInputToCurrentPosition();
78 }
Brian Silverman9c614bc2016-02-15 20:20:02 -050079}
80
81// Static.
82int CodedInputStream::default_recursion_limit_ = 100;
83
84
85void CodedOutputStream::EnableAliasing(bool enabled) {
86 aliasing_enabled_ = enabled && output_->AllowsAliasing();
87}
88
89void CodedInputStream::BackUpInputToCurrentPosition() {
90 int backup_bytes = BufferSize() + buffer_size_after_limit_ + overflow_bytes_;
91 if (backup_bytes > 0) {
92 input_->BackUp(backup_bytes);
93
94 // total_bytes_read_ doesn't include overflow_bytes_.
95 total_bytes_read_ -= BufferSize() + buffer_size_after_limit_;
96 buffer_end_ = buffer_;
97 buffer_size_after_limit_ = 0;
98 overflow_bytes_ = 0;
99 }
100}
101
102inline void CodedInputStream::RecomputeBufferLimits() {
103 buffer_end_ += buffer_size_after_limit_;
Austin Schuh40c16522018-10-28 20:27:54 -0700104 int closest_limit = std::min(current_limit_, total_bytes_limit_);
Brian Silverman9c614bc2016-02-15 20:20:02 -0500105 if (closest_limit < total_bytes_read_) {
106 // The limit position is in the current buffer. We must adjust
107 // the buffer size accordingly.
108 buffer_size_after_limit_ = total_bytes_read_ - closest_limit;
109 buffer_end_ -= buffer_size_after_limit_;
110 } else {
111 buffer_size_after_limit_ = 0;
112 }
113}
114
115CodedInputStream::Limit CodedInputStream::PushLimit(int byte_limit) {
116 // Current position relative to the beginning of the stream.
117 int current_position = CurrentPosition();
118
119 Limit old_limit = current_limit_;
120
121 // security: byte_limit is possibly evil, so check for negative values
Austin Schuh40c16522018-10-28 20:27:54 -0700122 // and overflow. Also check that the new requested limit is before the
123 // previous limit; otherwise we continue to enforce the previous limit.
124 if (GOOGLE_PREDICT_TRUE(byte_limit >= 0 &&
125 byte_limit <= INT_MAX - current_position &&
126 byte_limit < current_limit_ - current_position)) {
Brian Silverman9c614bc2016-02-15 20:20:02 -0500127 current_limit_ = current_position + byte_limit;
Austin Schuh40c16522018-10-28 20:27:54 -0700128 RecomputeBufferLimits();
Brian Silverman9c614bc2016-02-15 20:20:02 -0500129 }
130
Brian Silverman9c614bc2016-02-15 20:20:02 -0500131 return old_limit;
132}
133
134void CodedInputStream::PopLimit(Limit limit) {
135 // The limit passed in is actually the *old* limit, which we returned from
136 // PushLimit().
137 current_limit_ = limit;
138 RecomputeBufferLimits();
139
140 // We may no longer be at a legitimate message end. ReadTag() needs to be
141 // called again to find out.
142 legitimate_message_end_ = false;
143}
144
145std::pair<CodedInputStream::Limit, int>
146CodedInputStream::IncrementRecursionDepthAndPushLimit(int byte_limit) {
147 return std::make_pair(PushLimit(byte_limit), --recursion_budget_);
148}
149
150CodedInputStream::Limit CodedInputStream::ReadLengthAndPushLimit() {
151 uint32 length;
152 return PushLimit(ReadVarint32(&length) ? length : 0);
153}
154
155bool CodedInputStream::DecrementRecursionDepthAndPopLimit(Limit limit) {
156 bool result = ConsumedEntireMessage();
157 PopLimit(limit);
158 GOOGLE_DCHECK_LT(recursion_budget_, recursion_limit_);
159 ++recursion_budget_;
160 return result;
161}
162
163bool CodedInputStream::CheckEntireMessageConsumedAndPopLimit(Limit limit) {
164 bool result = ConsumedEntireMessage();
165 PopLimit(limit);
166 return result;
167}
168
169int CodedInputStream::BytesUntilLimit() const {
170 if (current_limit_ == INT_MAX) return -1;
171 int current_position = CurrentPosition();
172
173 return current_limit_ - current_position;
174}
175
Austin Schuh40c16522018-10-28 20:27:54 -0700176void CodedInputStream::SetTotalBytesLimit(int total_bytes_limit) {
Brian Silverman9c614bc2016-02-15 20:20:02 -0500177 // Make sure the limit isn't already past, since this could confuse other
178 // code.
179 int current_position = CurrentPosition();
Austin Schuh40c16522018-10-28 20:27:54 -0700180 total_bytes_limit_ = std::max(current_position, total_bytes_limit);
Brian Silverman9c614bc2016-02-15 20:20:02 -0500181 RecomputeBufferLimits();
182}
183
184int CodedInputStream::BytesUntilTotalBytesLimit() const {
185 if (total_bytes_limit_ == INT_MAX) return -1;
186 return total_bytes_limit_ - CurrentPosition();
187}
188
189void CodedInputStream::PrintTotalBytesLimitError() {
190 GOOGLE_LOG(ERROR) << "A protocol message was rejected because it was too "
191 "big (more than " << total_bytes_limit_
192 << " bytes). To increase the limit (or to disable these "
193 "warnings), see CodedInputStream::SetTotalBytesLimit() "
194 "in google/protobuf/io/coded_stream.h.";
195}
196
Austin Schuh40c16522018-10-28 20:27:54 -0700197bool CodedInputStream::SkipFallback(int count, int original_buffer_size) {
Brian Silverman9c614bc2016-02-15 20:20:02 -0500198 if (buffer_size_after_limit_ > 0) {
199 // We hit a limit inside this buffer. Advance to the limit and fail.
200 Advance(original_buffer_size);
201 return false;
202 }
203
204 count -= original_buffer_size;
205 buffer_ = NULL;
206 buffer_end_ = buffer_;
207
208 // Make sure this skip doesn't try to skip past the current limit.
Austin Schuh40c16522018-10-28 20:27:54 -0700209 int closest_limit = std::min(current_limit_, total_bytes_limit_);
Brian Silverman9c614bc2016-02-15 20:20:02 -0500210 int bytes_until_limit = closest_limit - total_bytes_read_;
211 if (bytes_until_limit < count) {
212 // We hit the limit. Skip up to it then fail.
213 if (bytes_until_limit > 0) {
214 total_bytes_read_ = closest_limit;
215 input_->Skip(bytes_until_limit);
216 }
217 return false;
218 }
219
Austin Schuh40c16522018-10-28 20:27:54 -0700220 if (!input_->Skip(count)) {
221 total_bytes_read_ = input_->ByteCount();
222 return false;
223 }
Brian Silverman9c614bc2016-02-15 20:20:02 -0500224 total_bytes_read_ += count;
Austin Schuh40c16522018-10-28 20:27:54 -0700225 return true;
Brian Silverman9c614bc2016-02-15 20:20:02 -0500226}
227
228bool CodedInputStream::GetDirectBufferPointer(const void** data, int* size) {
229 if (BufferSize() == 0 && !Refresh()) return false;
230
231 *data = buffer_;
232 *size = BufferSize();
233 return true;
234}
235
236bool CodedInputStream::ReadRaw(void* buffer, int size) {
237 return InternalReadRawInline(buffer, size);
238}
239
240bool CodedInputStream::ReadString(string* buffer, int size) {
241 if (size < 0) return false; // security: size is often user-supplied
242 return InternalReadStringInline(buffer, size);
243}
244
245bool CodedInputStream::ReadStringFallback(string* buffer, int size) {
246 if (!buffer->empty()) {
247 buffer->clear();
248 }
249
Austin Schuh40c16522018-10-28 20:27:54 -0700250 int closest_limit = std::min(current_limit_, total_bytes_limit_);
Brian Silverman9c614bc2016-02-15 20:20:02 -0500251 if (closest_limit != INT_MAX) {
252 int bytes_to_limit = closest_limit - CurrentPosition();
253 if (bytes_to_limit > 0 && size > 0 && size <= bytes_to_limit) {
254 buffer->reserve(size);
255 }
256 }
257
258 int current_buffer_size;
259 while ((current_buffer_size = BufferSize()) < size) {
260 // Some STL implementations "helpfully" crash on buffer->append(NULL, 0).
261 if (current_buffer_size != 0) {
262 // Note: string1.append(string2) is O(string2.size()) (as opposed to
263 // O(string1.size() + string2.size()), which would be bad).
264 buffer->append(reinterpret_cast<const char*>(buffer_),
265 current_buffer_size);
266 }
267 size -= current_buffer_size;
268 Advance(current_buffer_size);
269 if (!Refresh()) return false;
270 }
271
272 buffer->append(reinterpret_cast<const char*>(buffer_), size);
273 Advance(size);
274
275 return true;
276}
277
278
279bool CodedInputStream::ReadLittleEndian32Fallback(uint32* value) {
280 uint8 bytes[sizeof(*value)];
281
282 const uint8* ptr;
283 if (BufferSize() >= sizeof(*value)) {
284 // Fast path: Enough bytes in the buffer to read directly.
285 ptr = buffer_;
286 Advance(sizeof(*value));
287 } else {
288 // Slow path: Had to read past the end of the buffer.
289 if (!ReadRaw(bytes, sizeof(*value))) return false;
290 ptr = bytes;
291 }
292 ReadLittleEndian32FromArray(ptr, value);
293 return true;
294}
295
296bool CodedInputStream::ReadLittleEndian64Fallback(uint64* value) {
297 uint8 bytes[sizeof(*value)];
298
299 const uint8* ptr;
300 if (BufferSize() >= sizeof(*value)) {
301 // Fast path: Enough bytes in the buffer to read directly.
302 ptr = buffer_;
303 Advance(sizeof(*value));
304 } else {
305 // Slow path: Had to read past the end of the buffer.
306 if (!ReadRaw(bytes, sizeof(*value))) return false;
307 ptr = bytes;
308 }
309 ReadLittleEndian64FromArray(ptr, value);
310 return true;
311}
312
313namespace {
314
315// Read a varint from the given buffer, write it to *value, and return a pair.
316// The first part of the pair is true iff the read was successful. The second
317// part is buffer + (number of bytes read). This function is always inlined,
318// so returning a pair is costless.
Austin Schuh40c16522018-10-28 20:27:54 -0700319GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
320::std::pair<bool, const uint8*> ReadVarint32FromArray(
Brian Silverman9c614bc2016-02-15 20:20:02 -0500321 uint32 first_byte, const uint8* buffer,
322 uint32* value);
323inline ::std::pair<bool, const uint8*> ReadVarint32FromArray(
324 uint32 first_byte, const uint8* buffer, uint32* value) {
325 // Fast path: We have enough bytes left in the buffer to guarantee that
326 // this read won't cross the end, so we can skip the checks.
327 GOOGLE_DCHECK_EQ(*buffer, first_byte);
328 GOOGLE_DCHECK_EQ(first_byte & 0x80, 0x80) << first_byte;
329 const uint8* ptr = buffer;
330 uint32 b;
331 uint32 result = first_byte - 0x80;
332 ++ptr; // We just processed the first byte. Move on to the second.
333 b = *(ptr++); result += b << 7; if (!(b & 0x80)) goto done;
334 result -= 0x80 << 7;
335 b = *(ptr++); result += b << 14; if (!(b & 0x80)) goto done;
336 result -= 0x80 << 14;
337 b = *(ptr++); result += b << 21; if (!(b & 0x80)) goto done;
338 result -= 0x80 << 21;
339 b = *(ptr++); result += b << 28; if (!(b & 0x80)) goto done;
340 // "result -= 0x80 << 28" is irrevelant.
341
342 // If the input is larger than 32 bits, we still need to read it all
343 // and discard the high-order bits.
344 for (int i = 0; i < kMaxVarintBytes - kMaxVarint32Bytes; i++) {
345 b = *(ptr++); if (!(b & 0x80)) goto done;
346 }
347
348 // We have overrun the maximum size of a varint (10 bytes). Assume
349 // the data is corrupt.
350 return std::make_pair(false, ptr);
351
352 done:
353 *value = result;
354 return std::make_pair(true, ptr);
355}
356
Austin Schuh40c16522018-10-28 20:27:54 -0700357GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE::std::pair<bool, const uint8*>
358ReadVarint64FromArray(const uint8* buffer, uint64* value);
359inline ::std::pair<bool, const uint8*> ReadVarint64FromArray(
360 const uint8* buffer, uint64* value) {
361 const uint8* ptr = buffer;
362 uint32 b;
363
364 // Splitting into 32-bit pieces gives better performance on 32-bit
365 // processors.
366 uint32 part0 = 0, part1 = 0, part2 = 0;
367
368 b = *(ptr++); part0 = b ; if (!(b & 0x80)) goto done;
369 part0 -= 0x80;
370 b = *(ptr++); part0 += b << 7; if (!(b & 0x80)) goto done;
371 part0 -= 0x80 << 7;
372 b = *(ptr++); part0 += b << 14; if (!(b & 0x80)) goto done;
373 part0 -= 0x80 << 14;
374 b = *(ptr++); part0 += b << 21; if (!(b & 0x80)) goto done;
375 part0 -= 0x80 << 21;
376 b = *(ptr++); part1 = b ; if (!(b & 0x80)) goto done;
377 part1 -= 0x80;
378 b = *(ptr++); part1 += b << 7; if (!(b & 0x80)) goto done;
379 part1 -= 0x80 << 7;
380 b = *(ptr++); part1 += b << 14; if (!(b & 0x80)) goto done;
381 part1 -= 0x80 << 14;
382 b = *(ptr++); part1 += b << 21; if (!(b & 0x80)) goto done;
383 part1 -= 0x80 << 21;
384 b = *(ptr++); part2 = b ; if (!(b & 0x80)) goto done;
385 part2 -= 0x80;
386 b = *(ptr++); part2 += b << 7; if (!(b & 0x80)) goto done;
387 // "part2 -= 0x80 << 7" is irrelevant because (0x80 << 7) << 56 is 0.
388
389 // We have overrun the maximum size of a varint (10 bytes). Assume
390 // the data is corrupt.
391 return std::make_pair(false, ptr);
392
393 done:
394 *value = (static_cast<uint64>(part0)) |
395 (static_cast<uint64>(part1) << 28) |
396 (static_cast<uint64>(part2) << 56);
397 return std::make_pair(true, ptr);
398}
399
Brian Silverman9c614bc2016-02-15 20:20:02 -0500400} // namespace
401
402bool CodedInputStream::ReadVarint32Slow(uint32* value) {
403 // Directly invoke ReadVarint64Fallback, since we already tried to optimize
404 // for one-byte varints.
405 std::pair<uint64, bool> p = ReadVarint64Fallback();
406 *value = static_cast<uint32>(p.first);
407 return p.second;
408}
409
410int64 CodedInputStream::ReadVarint32Fallback(uint32 first_byte_or_zero) {
411 if (BufferSize() >= kMaxVarintBytes ||
412 // Optimization: We're also safe if the buffer is non-empty and it ends
413 // with a byte that would terminate a varint.
414 (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
415 GOOGLE_DCHECK_NE(first_byte_or_zero, 0)
416 << "Caller should provide us with *buffer_ when buffer is non-empty";
417 uint32 temp;
418 ::std::pair<bool, const uint8*> p =
419 ReadVarint32FromArray(first_byte_or_zero, buffer_, &temp);
420 if (!p.first) return -1;
421 buffer_ = p.second;
422 return temp;
423 } else {
424 // Really slow case: we will incur the cost of an extra function call here,
425 // but moving this out of line reduces the size of this function, which
426 // improves the common case. In micro benchmarks, this is worth about 10-15%
427 uint32 temp;
428 return ReadVarint32Slow(&temp) ? static_cast<int64>(temp) : -1;
429 }
430}
431
Austin Schuh40c16522018-10-28 20:27:54 -0700432int CodedInputStream::ReadVarintSizeAsIntSlow() {
433 // Directly invoke ReadVarint64Fallback, since we already tried to optimize
434 // for one-byte varints.
435 std::pair<uint64, bool> p = ReadVarint64Fallback();
436 if (!p.second || p.first > static_cast<uint64>(INT_MAX)) return -1;
437 return p.first;
438}
439
440int CodedInputStream::ReadVarintSizeAsIntFallback() {
441 if (BufferSize() >= kMaxVarintBytes ||
442 // Optimization: We're also safe if the buffer is non-empty and it ends
443 // with a byte that would terminate a varint.
444 (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
445 uint64 temp;
446 ::std::pair<bool, const uint8*> p = ReadVarint64FromArray(buffer_, &temp);
447 if (!p.first || temp > static_cast<uint64>(INT_MAX)) return -1;
448 buffer_ = p.second;
449 return temp;
450 } else {
451 // Really slow case: we will incur the cost of an extra function call here,
452 // but moving this out of line reduces the size of this function, which
453 // improves the common case. In micro benchmarks, this is worth about 10-15%
454 return ReadVarintSizeAsIntSlow();
455 }
456}
457
Brian Silverman9c614bc2016-02-15 20:20:02 -0500458uint32 CodedInputStream::ReadTagSlow() {
459 if (buffer_ == buffer_end_) {
460 // Call refresh.
461 if (!Refresh()) {
462 // Refresh failed. Make sure that it failed due to EOF, not because
463 // we hit total_bytes_limit_, which, unlike normal limits, is not a
464 // valid place to end a message.
465 int current_position = total_bytes_read_ - buffer_size_after_limit_;
466 if (current_position >= total_bytes_limit_) {
467 // Hit total_bytes_limit_. But if we also hit the normal limit,
468 // we're still OK.
469 legitimate_message_end_ = current_limit_ == total_bytes_limit_;
470 } else {
471 legitimate_message_end_ = true;
472 }
473 return 0;
474 }
475 }
476
477 // For the slow path, just do a 64-bit read. Try to optimize for one-byte tags
478 // again, since we have now refreshed the buffer.
479 uint64 result = 0;
480 if (!ReadVarint64(&result)) return 0;
481 return static_cast<uint32>(result);
482}
483
484uint32 CodedInputStream::ReadTagFallback(uint32 first_byte_or_zero) {
485 const int buf_size = BufferSize();
486 if (buf_size >= kMaxVarintBytes ||
487 // Optimization: We're also safe if the buffer is non-empty and it ends
488 // with a byte that would terminate a varint.
489 (buf_size > 0 && !(buffer_end_[-1] & 0x80))) {
490 GOOGLE_DCHECK_EQ(first_byte_or_zero, buffer_[0]);
491 if (first_byte_or_zero == 0) {
492 ++buffer_;
493 return 0;
494 }
495 uint32 tag;
496 ::std::pair<bool, const uint8*> p =
497 ReadVarint32FromArray(first_byte_or_zero, buffer_, &tag);
498 if (!p.first) {
499 return 0;
500 }
501 buffer_ = p.second;
502 return tag;
503 } else {
504 // We are commonly at a limit when attempting to read tags. Try to quickly
505 // detect this case without making another function call.
506 if ((buf_size == 0) &&
507 ((buffer_size_after_limit_ > 0) ||
508 (total_bytes_read_ == current_limit_)) &&
509 // Make sure that the limit we hit is not total_bytes_limit_, since
510 // in that case we still need to call Refresh() so that it prints an
511 // error.
512 total_bytes_read_ - buffer_size_after_limit_ < total_bytes_limit_) {
513 // We hit a byte limit.
514 legitimate_message_end_ = true;
515 return 0;
516 }
517 return ReadTagSlow();
518 }
519}
520
521bool CodedInputStream::ReadVarint64Slow(uint64* value) {
522 // Slow path: This read might cross the end of the buffer, so we
523 // need to check and refresh the buffer if and when it does.
524
525 uint64 result = 0;
526 int count = 0;
527 uint32 b;
528
529 do {
Austin Schuh40c16522018-10-28 20:27:54 -0700530 if (count == kMaxVarintBytes) {
531 *value = 0;
532 return false;
533 }
Brian Silverman9c614bc2016-02-15 20:20:02 -0500534 while (buffer_ == buffer_end_) {
Austin Schuh40c16522018-10-28 20:27:54 -0700535 if (!Refresh()) {
536 *value = 0;
537 return false;
538 }
Brian Silverman9c614bc2016-02-15 20:20:02 -0500539 }
540 b = *buffer_;
541 result |= static_cast<uint64>(b & 0x7F) << (7 * count);
542 Advance(1);
543 ++count;
544 } while (b & 0x80);
545
546 *value = result;
547 return true;
548}
549
550std::pair<uint64, bool> CodedInputStream::ReadVarint64Fallback() {
551 if (BufferSize() >= kMaxVarintBytes ||
552 // Optimization: We're also safe if the buffer is non-empty and it ends
553 // with a byte that would terminate a varint.
554 (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
Austin Schuh40c16522018-10-28 20:27:54 -0700555 uint64 temp;
556 ::std::pair<bool, const uint8*> p = ReadVarint64FromArray(buffer_, &temp);
557 if (!p.first) {
558 return std::make_pair(0, false);
559 }
560 buffer_ = p.second;
561 return std::make_pair(temp, true);
Brian Silverman9c614bc2016-02-15 20:20:02 -0500562 } else {
563 uint64 temp;
564 bool success = ReadVarint64Slow(&temp);
565 return std::make_pair(temp, success);
566 }
567}
568
569bool CodedInputStream::Refresh() {
570 GOOGLE_DCHECK_EQ(0, BufferSize());
571
572 if (buffer_size_after_limit_ > 0 || overflow_bytes_ > 0 ||
573 total_bytes_read_ == current_limit_) {
574 // We've hit a limit. Stop.
575 int current_position = total_bytes_read_ - buffer_size_after_limit_;
576
577 if (current_position >= total_bytes_limit_ &&
578 total_bytes_limit_ != current_limit_) {
579 // Hit total_bytes_limit_.
580 PrintTotalBytesLimitError();
581 }
582
583 return false;
584 }
585
Brian Silverman9c614bc2016-02-15 20:20:02 -0500586 const void* void_buffer;
587 int buffer_size;
588 if (NextNonEmpty(input_, &void_buffer, &buffer_size)) {
589 buffer_ = reinterpret_cast<const uint8*>(void_buffer);
590 buffer_end_ = buffer_ + buffer_size;
591 GOOGLE_CHECK_GE(buffer_size, 0);
592
593 if (total_bytes_read_ <= INT_MAX - buffer_size) {
594 total_bytes_read_ += buffer_size;
595 } else {
596 // Overflow. Reset buffer_end_ to not include the bytes beyond INT_MAX.
597 // We can't get that far anyway, because total_bytes_limit_ is guaranteed
598 // to be less than it. We need to keep track of the number of bytes
599 // we discarded, though, so that we can call input_->BackUp() to back
600 // up over them on destruction.
601
602 // The following line is equivalent to:
603 // overflow_bytes_ = total_bytes_read_ + buffer_size - INT_MAX;
604 // except that it avoids overflows. Signed integer overflow has
605 // undefined results according to the C standard.
606 overflow_bytes_ = total_bytes_read_ - (INT_MAX - buffer_size);
607 buffer_end_ -= overflow_bytes_;
608 total_bytes_read_ = INT_MAX;
609 }
610
611 RecomputeBufferLimits();
612 return true;
613 } else {
614 buffer_ = NULL;
615 buffer_end_ = NULL;
616 return false;
617 }
618}
619
620// CodedOutputStream =================================================
621
Austin Schuh40c16522018-10-28 20:27:54 -0700622std::atomic<bool> CodedOutputStream::default_serialization_deterministic_{
623 false};
624
Brian Silverman9c614bc2016-02-15 20:20:02 -0500625CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* output)
Austin Schuh40c16522018-10-28 20:27:54 -0700626 : CodedOutputStream(output, true) {}
Brian Silverman9c614bc2016-02-15 20:20:02 -0500627
628CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* output,
629 bool do_eager_refresh)
630 : output_(output),
631 buffer_(NULL),
632 buffer_size_(0),
633 total_bytes_(0),
634 had_error_(false),
Austin Schuh40c16522018-10-28 20:27:54 -0700635 aliasing_enabled_(false),
636 is_serialization_deterministic_(IsDefaultSerializationDeterministic()) {
Brian Silverman9c614bc2016-02-15 20:20:02 -0500637 if (do_eager_refresh) {
638 // Eagerly Refresh() so buffer space is immediately available.
639 Refresh();
640 // The Refresh() may have failed. If the client doesn't write any data,
641 // though, don't consider this an error. If the client does write data, then
642 // another Refresh() will be attempted and it will set the error once again.
643 had_error_ = false;
644 }
645}
646
647CodedOutputStream::~CodedOutputStream() {
648 Trim();
649}
650
651void CodedOutputStream::Trim() {
652 if (buffer_size_ > 0) {
653 output_->BackUp(buffer_size_);
654 total_bytes_ -= buffer_size_;
655 buffer_size_ = 0;
656 buffer_ = NULL;
657 }
658}
659
660bool CodedOutputStream::Skip(int count) {
661 if (count < 0) return false;
662
663 while (count > buffer_size_) {
664 count -= buffer_size_;
665 if (!Refresh()) return false;
666 }
667
668 Advance(count);
669 return true;
670}
671
672bool CodedOutputStream::GetDirectBufferPointer(void** data, int* size) {
673 if (buffer_size_ == 0 && !Refresh()) return false;
674
675 *data = buffer_;
676 *size = buffer_size_;
677 return true;
678}
679
680void CodedOutputStream::WriteRaw(const void* data, int size) {
681 while (buffer_size_ < size) {
682 memcpy(buffer_, data, buffer_size_);
683 size -= buffer_size_;
684 data = reinterpret_cast<const uint8*>(data) + buffer_size_;
685 if (!Refresh()) return;
686 }
687
688 memcpy(buffer_, data, size);
689 Advance(size);
690}
691
692uint8* CodedOutputStream::WriteRawToArray(
693 const void* data, int size, uint8* target) {
694 memcpy(target, data, size);
695 return target + size;
696}
697
698
699void CodedOutputStream::WriteAliasedRaw(const void* data, int size) {
700 if (size < buffer_size_
701 ) {
702 WriteRaw(data, size);
703 } else {
704 Trim();
705
706 total_bytes_ += size;
707 had_error_ |= !output_->WriteAliasedRaw(data, size);
708 }
709}
710
711void CodedOutputStream::WriteLittleEndian32(uint32 value) {
712 uint8 bytes[sizeof(value)];
713
714 bool use_fast = buffer_size_ >= sizeof(value);
715 uint8* ptr = use_fast ? buffer_ : bytes;
716
717 WriteLittleEndian32ToArray(value, ptr);
718
719 if (use_fast) {
720 Advance(sizeof(value));
721 } else {
722 WriteRaw(bytes, sizeof(value));
723 }
724}
725
726void CodedOutputStream::WriteLittleEndian64(uint64 value) {
727 uint8 bytes[sizeof(value)];
728
729 bool use_fast = buffer_size_ >= sizeof(value);
730 uint8* ptr = use_fast ? buffer_ : bytes;
731
732 WriteLittleEndian64ToArray(value, ptr);
733
734 if (use_fast) {
735 Advance(sizeof(value));
736 } else {
737 WriteRaw(bytes, sizeof(value));
738 }
739}
740
741void CodedOutputStream::WriteVarint32SlowPath(uint32 value) {
742 uint8 bytes[kMaxVarint32Bytes];
743 uint8* target = &bytes[0];
744 uint8* end = WriteVarint32ToArray(value, target);
745 int size = end - target;
746 WriteRaw(bytes, size);
747}
748
Austin Schuh40c16522018-10-28 20:27:54 -0700749void CodedOutputStream::WriteVarint64SlowPath(uint64 value) {
750 uint8 bytes[kMaxVarintBytes];
751 uint8* target = &bytes[0];
752 uint8* end = WriteVarint64ToArray(value, target);
753 int size = end - target;
754 WriteRaw(bytes, size);
Brian Silverman9c614bc2016-02-15 20:20:02 -0500755}
756
757bool CodedOutputStream::Refresh() {
758 void* void_buffer;
759 if (output_->Next(&void_buffer, &buffer_size_)) {
760 buffer_ = reinterpret_cast<uint8*>(void_buffer);
761 total_bytes_ += buffer_size_;
762 return true;
763 } else {
764 buffer_ = NULL;
765 buffer_size_ = 0;
766 had_error_ = true;
767 return false;
768 }
769}
770
Brian Silverman9c614bc2016-02-15 20:20:02 -0500771uint8* CodedOutputStream::WriteStringWithSizeToArray(const string& str,
772 uint8* target) {
773 GOOGLE_DCHECK_LE(str.size(), kuint32max);
774 target = WriteVarint32ToArray(str.size(), target);
775 return WriteStringToArray(str, target);
776}
777
778} // namespace io
779} // namespace protobuf
780} // namespace google