blob: 93e1a22e69090760436c2b79e401c51a9628af86 [file] [log] [blame]
temporal40ee5512008-07-10 02:12:20 +00001// Protocol Buffers - Google's data interchange format
kenton@google.com24bf56f2008-09-24 20:31:01 +00002// Copyright 2008 Google Inc. All rights reserved.
Feng Xiaoe4288622014-10-01 16:26:23 -07003// https://developers.google.com/protocol-buffers/
temporal40ee5512008-07-10 02:12:20 +00004//
kenton@google.com24bf56f2008-09-24 20:31:01 +00005// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
temporal40ee5512008-07-10 02:12:20 +00008//
kenton@google.com24bf56f2008-09-24 20:31:01 +00009// * 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.
temporal40ee5512008-07-10 02:12:20 +000018//
kenton@google.com24bf56f2008-09-24 20:31:01 +000019// 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.
temporal40ee5512008-07-10 02:12:20 +000030
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
kenton@google.comfccb1462009-12-18 02:11:36 +000041#include <google/protobuf/io/coded_stream_inl.h>
42#include <algorithm>
Feng Xiao6ef984a2014-11-10 17:34:54 -080043#include <utility>
temporal40ee5512008-07-10 02:12:20 +000044#include <limits.h>
temporal40ee5512008-07-10 02:12:20 +000045#include <google/protobuf/io/zero_copy_stream.h>
Feng Xiao6ef984a2014-11-10 17:34:54 -080046#include <google/protobuf/arena.h>
temporal40ee5512008-07-10 02:12:20 +000047#include <google/protobuf/stubs/common.h>
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +000048#include <google/protobuf/stubs/stl_util.h>
temporal40ee5512008-07-10 02:12:20 +000049
50
51namespace google {
52namespace protobuf {
53namespace io {
54
55namespace {
56
temporal40ee5512008-07-10 02:12:20 +000057static const int kMaxVarintBytes = 10;
58static const int kMaxVarint32Bytes = 5;
59
60
liujisi@google.com33165fe2010-11-02 13:14:58 +000061inline bool NextNonEmpty(ZeroCopyInputStream* input,
62 const void** data, int* size) {
63 bool success;
64 do {
65 success = input->Next(data, size);
66 } while (success && *size == 0);
67 return success;
68}
69
temporal40ee5512008-07-10 02:12:20 +000070} // namespace
71
72// CodedInputStream ==================================================
73
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +000074CodedInputStream::~CodedInputStream() {
75 if (input_ != NULL) {
76 BackUpInputToCurrentPosition();
77 }
78
79 if (total_bytes_warning_threshold_ == -2) {
80 GOOGLE_LOG(WARNING) << "The total number of bytes read was " << total_bytes_read_;
81 }
82}
83
84// Static.
85int CodedInputStream::default_recursion_limit_ = 100;
86
temporal40ee5512008-07-10 02:12:20 +000087
jieluo@google.com4de8f552014-07-18 00:47:59 +000088void CodedOutputStream::EnableAliasing(bool enabled) {
89 aliasing_enabled_ = enabled && output_->AllowsAliasing();
90}
91
kenton@google.com80b1d622009-07-29 01:13:20 +000092void CodedInputStream::BackUpInputToCurrentPosition() {
kenton@google.comfccb1462009-12-18 02:11:36 +000093 int backup_bytes = BufferSize() + buffer_size_after_limit_ + overflow_bytes_;
kenton@google.com80b1d622009-07-29 01:13:20 +000094 if (backup_bytes > 0) {
95 input_->BackUp(backup_bytes);
96
97 // total_bytes_read_ doesn't include overflow_bytes_.
kenton@google.comfccb1462009-12-18 02:11:36 +000098 total_bytes_read_ -= BufferSize() + buffer_size_after_limit_;
99 buffer_end_ = buffer_;
kenton@google.com80b1d622009-07-29 01:13:20 +0000100 buffer_size_after_limit_ = 0;
101 overflow_bytes_ = 0;
102 }
103}
104
temporal40ee5512008-07-10 02:12:20 +0000105inline void CodedInputStream::RecomputeBufferLimits() {
kenton@google.comfccb1462009-12-18 02:11:36 +0000106 buffer_end_ += buffer_size_after_limit_;
temporal40ee5512008-07-10 02:12:20 +0000107 int closest_limit = min(current_limit_, total_bytes_limit_);
108 if (closest_limit < total_bytes_read_) {
109 // The limit position is in the current buffer. We must adjust
110 // the buffer size accordingly.
111 buffer_size_after_limit_ = total_bytes_read_ - closest_limit;
kenton@google.comfccb1462009-12-18 02:11:36 +0000112 buffer_end_ -= buffer_size_after_limit_;
temporal40ee5512008-07-10 02:12:20 +0000113 } else {
114 buffer_size_after_limit_ = 0;
115 }
116}
117
118CodedInputStream::Limit CodedInputStream::PushLimit(int byte_limit) {
119 // Current position relative to the beginning of the stream.
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000120 int current_position = CurrentPosition();
temporal40ee5512008-07-10 02:12:20 +0000121
122 Limit old_limit = current_limit_;
123
124 // security: byte_limit is possibly evil, so check for negative values
125 // and overflow.
126 if (byte_limit >= 0 &&
127 byte_limit <= INT_MAX - current_position) {
128 current_limit_ = current_position + byte_limit;
129 } else {
130 // Negative or overflow.
131 current_limit_ = INT_MAX;
132 }
133
134 // We need to enforce all limits, not just the new one, so if the previous
135 // limit was before the new requested limit, we continue to enforce the
136 // previous limit.
137 current_limit_ = min(current_limit_, old_limit);
138
139 RecomputeBufferLimits();
140 return old_limit;
141}
142
143void CodedInputStream::PopLimit(Limit limit) {
144 // The limit passed in is actually the *old* limit, which we returned from
145 // PushLimit().
146 current_limit_ = limit;
147 RecomputeBufferLimits();
148
149 // We may no longer be at a legitimate message end. ReadTag() needs to be
150 // called again to find out.
151 legitimate_message_end_ = false;
152}
153
Feng Xiao6ef984a2014-11-10 17:34:54 -0800154std::pair<CodedInputStream::Limit, int>
155CodedInputStream::IncrementRecursionDepthAndPushLimit(int byte_limit) {
Jisi Liu885b6122015-02-28 14:51:22 -0800156 return std::make_pair(PushLimit(byte_limit), --recursion_budget_);
Feng Xiao6ef984a2014-11-10 17:34:54 -0800157}
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
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000167int CodedInputStream::BytesUntilLimit() const {
temporal40ee5512008-07-10 02:12:20 +0000168 if (current_limit_ == INT_MAX) return -1;
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000169 int current_position = CurrentPosition();
temporal40ee5512008-07-10 02:12:20 +0000170
171 return current_limit_ - current_position;
172}
173
174void CodedInputStream::SetTotalBytesLimit(
175 int total_bytes_limit, int warning_threshold) {
176 // Make sure the limit isn't already past, since this could confuse other
177 // code.
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000178 int current_position = CurrentPosition();
temporal40ee5512008-07-10 02:12:20 +0000179 total_bytes_limit_ = max(current_position, total_bytes_limit);
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000180 if (warning_threshold >= 0) {
181 total_bytes_warning_threshold_ = warning_threshold;
182 } else {
183 // warning_threshold is negative
184 total_bytes_warning_threshold_ = -1;
185 }
temporal40ee5512008-07-10 02:12:20 +0000186 RecomputeBufferLimits();
187}
188
jieluo@google.com4de8f552014-07-18 00:47:59 +0000189int CodedInputStream::BytesUntilTotalBytesLimit() const {
190 if (total_bytes_limit_ == INT_MAX) return -1;
191 return total_bytes_limit_ - CurrentPosition();
192}
193
temporal40ee5512008-07-10 02:12:20 +0000194void CodedInputStream::PrintTotalBytesLimitError() {
195 GOOGLE_LOG(ERROR) << "A protocol message was rejected because it was too "
196 "big (more than " << total_bytes_limit_
197 << " bytes). To increase the limit (or to disable these "
198 "warnings), see CodedInputStream::SetTotalBytesLimit() "
199 "in google/protobuf/io/coded_stream.h.";
200}
201
202bool CodedInputStream::Skip(int count) {
203 if (count < 0) return false; // security: count is often user-supplied
204
kenton@google.comfccb1462009-12-18 02:11:36 +0000205 const int original_buffer_size = BufferSize();
206
207 if (count <= original_buffer_size) {
temporal40ee5512008-07-10 02:12:20 +0000208 // Just skipping within the current buffer. Easy.
209 Advance(count);
210 return true;
211 }
212
213 if (buffer_size_after_limit_ > 0) {
214 // We hit a limit inside this buffer. Advance to the limit and fail.
kenton@google.comfccb1462009-12-18 02:11:36 +0000215 Advance(original_buffer_size);
temporal40ee5512008-07-10 02:12:20 +0000216 return false;
217 }
218
kenton@google.comfccb1462009-12-18 02:11:36 +0000219 count -= original_buffer_size;
temporal40ee5512008-07-10 02:12:20 +0000220 buffer_ = NULL;
kenton@google.comfccb1462009-12-18 02:11:36 +0000221 buffer_end_ = buffer_;
temporal40ee5512008-07-10 02:12:20 +0000222
223 // Make sure this skip doesn't try to skip past the current limit.
224 int closest_limit = min(current_limit_, total_bytes_limit_);
225 int bytes_until_limit = closest_limit - total_bytes_read_;
226 if (bytes_until_limit < count) {
227 // We hit the limit. Skip up to it then fail.
kenton@google.com80b1d622009-07-29 01:13:20 +0000228 if (bytes_until_limit > 0) {
229 total_bytes_read_ = closest_limit;
230 input_->Skip(bytes_until_limit);
231 }
temporal40ee5512008-07-10 02:12:20 +0000232 return false;
233 }
234
235 total_bytes_read_ += count;
236 return input_->Skip(count);
237}
238
kenton@google.com2d6daa72009-01-22 01:27:00 +0000239bool CodedInputStream::GetDirectBufferPointer(const void** data, int* size) {
kenton@google.comfccb1462009-12-18 02:11:36 +0000240 if (BufferSize() == 0 && !Refresh()) return false;
kenton@google.com2d6daa72009-01-22 01:27:00 +0000241
242 *data = buffer_;
kenton@google.comfccb1462009-12-18 02:11:36 +0000243 *size = BufferSize();
kenton@google.com2d6daa72009-01-22 01:27:00 +0000244 return true;
245}
246
temporal40ee5512008-07-10 02:12:20 +0000247bool CodedInputStream::ReadRaw(void* buffer, int size) {
kenton@google.comfccb1462009-12-18 02:11:36 +0000248 int current_buffer_size;
249 while ((current_buffer_size = BufferSize()) < size) {
temporal40ee5512008-07-10 02:12:20 +0000250 // Reading past end of buffer. Copy what we have, then refresh.
kenton@google.comfccb1462009-12-18 02:11:36 +0000251 memcpy(buffer, buffer_, current_buffer_size);
252 buffer = reinterpret_cast<uint8*>(buffer) + current_buffer_size;
253 size -= current_buffer_size;
254 Advance(current_buffer_size);
temporal40ee5512008-07-10 02:12:20 +0000255 if (!Refresh()) return false;
256 }
257
258 memcpy(buffer, buffer_, size);
259 Advance(size);
260
261 return true;
262}
263
264bool CodedInputStream::ReadString(string* buffer, int size) {
265 if (size < 0) return false; // security: size is often user-supplied
kenton@google.comfccb1462009-12-18 02:11:36 +0000266 return InternalReadStringInline(buffer, size);
267}
temporal40ee5512008-07-10 02:12:20 +0000268
kenton@google.comfccb1462009-12-18 02:11:36 +0000269bool CodedInputStream::ReadStringFallback(string* buffer, int size) {
temporal40ee5512008-07-10 02:12:20 +0000270 if (!buffer->empty()) {
271 buffer->clear();
272 }
273
jieluo@google.com4de8f552014-07-18 00:47:59 +0000274 int closest_limit = min(current_limit_, total_bytes_limit_);
275 if (closest_limit != INT_MAX) {
276 int bytes_to_limit = closest_limit - CurrentPosition();
277 if (bytes_to_limit > 0 && size > 0 && size <= bytes_to_limit) {
278 buffer->reserve(size);
279 }
280 }
281
kenton@google.comfccb1462009-12-18 02:11:36 +0000282 int current_buffer_size;
283 while ((current_buffer_size = BufferSize()) < size) {
temporal40ee5512008-07-10 02:12:20 +0000284 // Some STL implementations "helpfully" crash on buffer->append(NULL, 0).
kenton@google.comfccb1462009-12-18 02:11:36 +0000285 if (current_buffer_size != 0) {
temporal40ee5512008-07-10 02:12:20 +0000286 // Note: string1.append(string2) is O(string2.size()) (as opposed to
287 // O(string1.size() + string2.size()), which would be bad).
kenton@google.comfccb1462009-12-18 02:11:36 +0000288 buffer->append(reinterpret_cast<const char*>(buffer_),
289 current_buffer_size);
temporal40ee5512008-07-10 02:12:20 +0000290 }
kenton@google.comfccb1462009-12-18 02:11:36 +0000291 size -= current_buffer_size;
292 Advance(current_buffer_size);
temporal40ee5512008-07-10 02:12:20 +0000293 if (!Refresh()) return false;
294 }
295
296 buffer->append(reinterpret_cast<const char*>(buffer_), size);
297 Advance(size);
298
299 return true;
300}
301
302
kenton@google.comfccb1462009-12-18 02:11:36 +0000303bool CodedInputStream::ReadLittleEndian32Fallback(uint32* value) {
temporal40ee5512008-07-10 02:12:20 +0000304 uint8 bytes[sizeof(*value)];
305
306 const uint8* ptr;
kenton@google.comfccb1462009-12-18 02:11:36 +0000307 if (BufferSize() >= sizeof(*value)) {
temporal40ee5512008-07-10 02:12:20 +0000308 // Fast path: Enough bytes in the buffer to read directly.
309 ptr = buffer_;
310 Advance(sizeof(*value));
311 } else {
312 // Slow path: Had to read past the end of the buffer.
313 if (!ReadRaw(bytes, sizeof(*value))) return false;
314 ptr = bytes;
315 }
kenton@google.comfccb1462009-12-18 02:11:36 +0000316 ReadLittleEndian32FromArray(ptr, value);
temporal40ee5512008-07-10 02:12:20 +0000317 return true;
318}
319
kenton@google.comfccb1462009-12-18 02:11:36 +0000320bool CodedInputStream::ReadLittleEndian64Fallback(uint64* value) {
temporal40ee5512008-07-10 02:12:20 +0000321 uint8 bytes[sizeof(*value)];
322
323 const uint8* ptr;
kenton@google.comfccb1462009-12-18 02:11:36 +0000324 if (BufferSize() >= sizeof(*value)) {
temporal40ee5512008-07-10 02:12:20 +0000325 // Fast path: Enough bytes in the buffer to read directly.
326 ptr = buffer_;
327 Advance(sizeof(*value));
328 } else {
329 // Slow path: Had to read past the end of the buffer.
330 if (!ReadRaw(bytes, sizeof(*value))) return false;
331 ptr = bytes;
332 }
kenton@google.comfccb1462009-12-18 02:11:36 +0000333 ReadLittleEndian64FromArray(ptr, value);
334 return true;
335}
temporal40ee5512008-07-10 02:12:20 +0000336
kenton@google.comfccb1462009-12-18 02:11:36 +0000337namespace {
338
339inline const uint8* ReadVarint32FromArray(
340 const uint8* buffer, uint32* value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
341inline const uint8* ReadVarint32FromArray(const uint8* buffer, uint32* value) {
342 // Fast path: We have enough bytes left in the buffer to guarantee that
343 // this read won't cross the end, so we can skip the checks.
344 const uint8* ptr = buffer;
345 uint32 b;
346 uint32 result;
347
jieluo@google.com4de8f552014-07-18 00:47:59 +0000348 b = *(ptr++); result = b ; if (!(b & 0x80)) goto done;
349 result -= 0x80;
350 b = *(ptr++); result += b << 7; if (!(b & 0x80)) goto done;
351 result -= 0x80 << 7;
352 b = *(ptr++); result += b << 14; if (!(b & 0x80)) goto done;
353 result -= 0x80 << 14;
354 b = *(ptr++); result += b << 21; if (!(b & 0x80)) goto done;
355 result -= 0x80 << 21;
356 b = *(ptr++); result += b << 28; if (!(b & 0x80)) goto done;
357 // "result -= 0x80 << 28" is irrevelant.
kenton@google.comfccb1462009-12-18 02:11:36 +0000358
359 // If the input is larger than 32 bits, we still need to read it all
360 // and discard the high-order bits.
361 for (int i = 0; i < kMaxVarintBytes - kMaxVarint32Bytes; i++) {
362 b = *(ptr++); if (!(b & 0x80)) goto done;
363 }
364
365 // We have overrun the maximum size of a varint (10 bytes). Assume
366 // the data is corrupt.
367 return NULL;
368
369 done:
370 *value = result;
371 return ptr;
372}
373
374} // namespace
375
376bool CodedInputStream::ReadVarint32Slow(uint32* value) {
377 uint64 result;
378 // Directly invoke ReadVarint64Fallback, since we already tried to optimize
379 // for one-byte varints.
380 if (!ReadVarint64Fallback(&result)) return false;
381 *value = (uint32)result;
temporal40ee5512008-07-10 02:12:20 +0000382 return true;
383}
384
385bool CodedInputStream::ReadVarint32Fallback(uint32* value) {
kenton@google.comfccb1462009-12-18 02:11:36 +0000386 if (BufferSize() >= kMaxVarintBytes ||
jieluo@google.com4de8f552014-07-18 00:47:59 +0000387 // Optimization: We're also safe if the buffer is non-empty and it ends
388 // with a byte that would terminate a varint.
kenton@google.comfccb1462009-12-18 02:11:36 +0000389 (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
390 const uint8* end = ReadVarint32FromArray(buffer_, value);
391 if (end == NULL) return false;
392 buffer_ = end;
temporal40ee5512008-07-10 02:12:20 +0000393 return true;
temporal40ee5512008-07-10 02:12:20 +0000394 } else {
kenton@google.comfccb1462009-12-18 02:11:36 +0000395 // Really slow case: we will incur the cost of an extra function call here,
396 // but moving this out of line reduces the size of this function, which
397 // improves the common case. In micro benchmarks, this is worth about 10-15%
398 return ReadVarint32Slow(value);
temporal40ee5512008-07-10 02:12:20 +0000399 }
400}
401
kenton@google.comfccb1462009-12-18 02:11:36 +0000402uint32 CodedInputStream::ReadTagSlow() {
403 if (buffer_ == buffer_end_) {
404 // Call refresh.
405 if (!Refresh()) {
406 // Refresh failed. Make sure that it failed due to EOF, not because
407 // we hit total_bytes_limit_, which, unlike normal limits, is not a
408 // valid place to end a message.
409 int current_position = total_bytes_read_ - buffer_size_after_limit_;
410 if (current_position >= total_bytes_limit_) {
411 // Hit total_bytes_limit_. But if we also hit the normal limit,
412 // we're still OK.
413 legitimate_message_end_ = current_limit_ == total_bytes_limit_;
414 } else {
415 legitimate_message_end_ = true;
416 }
417 return 0;
418 }
419 }
420
421 // For the slow path, just do a 64-bit read. Try to optimize for one-byte tags
422 // again, since we have now refreshed the buffer.
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000423 uint64 result = 0;
kenton@google.comfccb1462009-12-18 02:11:36 +0000424 if (!ReadVarint64(&result)) return 0;
425 return static_cast<uint32>(result);
426}
427
428uint32 CodedInputStream::ReadTagFallback() {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000429 const int buf_size = BufferSize();
430 if (buf_size >= kMaxVarintBytes ||
jieluo@google.com4de8f552014-07-18 00:47:59 +0000431 // Optimization: We're also safe if the buffer is non-empty and it ends
432 // with a byte that would terminate a varint.
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000433 (buf_size > 0 && !(buffer_end_[-1] & 0x80))) {
kenton@google.comfccb1462009-12-18 02:11:36 +0000434 uint32 tag;
435 const uint8* end = ReadVarint32FromArray(buffer_, &tag);
436 if (end == NULL) {
437 return 0;
438 }
439 buffer_ = end;
440 return tag;
441 } else {
442 // We are commonly at a limit when attempting to read tags. Try to quickly
443 // detect this case without making another function call.
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000444 if ((buf_size == 0) &&
445 ((buffer_size_after_limit_ > 0) ||
446 (total_bytes_read_ == current_limit_)) &&
kenton@google.comfccb1462009-12-18 02:11:36 +0000447 // Make sure that the limit we hit is not total_bytes_limit_, since
448 // in that case we still need to call Refresh() so that it prints an
449 // error.
450 total_bytes_read_ - buffer_size_after_limit_ < total_bytes_limit_) {
451 // We hit a byte limit.
452 legitimate_message_end_ = true;
453 return 0;
454 }
455 return ReadTagSlow();
456 }
457}
458
459bool CodedInputStream::ReadVarint64Slow(uint64* value) {
460 // Slow path: This read might cross the end of the buffer, so we
461 // need to check and refresh the buffer if and when it does.
462
463 uint64 result = 0;
464 int count = 0;
465 uint32 b;
466
467 do {
468 if (count == kMaxVarintBytes) return false;
469 while (buffer_ == buffer_end_) {
470 if (!Refresh()) return false;
471 }
472 b = *buffer_;
473 result |= static_cast<uint64>(b & 0x7F) << (7 * count);
474 Advance(1);
475 ++count;
476 } while (b & 0x80);
477
478 *value = result;
479 return true;
480}
481
482bool CodedInputStream::ReadVarint64Fallback(uint64* value) {
483 if (BufferSize() >= kMaxVarintBytes ||
jieluo@google.com4de8f552014-07-18 00:47:59 +0000484 // Optimization: We're also safe if the buffer is non-empty and it ends
485 // with a byte that would terminate a varint.
kenton@google.comfccb1462009-12-18 02:11:36 +0000486 (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
temporal40ee5512008-07-10 02:12:20 +0000487 // Fast path: We have enough bytes left in the buffer to guarantee that
488 // this read won't cross the end, so we can skip the checks.
489
490 const uint8* ptr = buffer_;
491 uint32 b;
492
493 // Splitting into 32-bit pieces gives better performance on 32-bit
494 // processors.
495 uint32 part0 = 0, part1 = 0, part2 = 0;
496
jieluo@google.com4de8f552014-07-18 00:47:59 +0000497 b = *(ptr++); part0 = b ; if (!(b & 0x80)) goto done;
498 part0 -= 0x80;
499 b = *(ptr++); part0 += b << 7; if (!(b & 0x80)) goto done;
500 part0 -= 0x80 << 7;
501 b = *(ptr++); part0 += b << 14; if (!(b & 0x80)) goto done;
502 part0 -= 0x80 << 14;
503 b = *(ptr++); part0 += b << 21; if (!(b & 0x80)) goto done;
504 part0 -= 0x80 << 21;
505 b = *(ptr++); part1 = b ; if (!(b & 0x80)) goto done;
506 part1 -= 0x80;
507 b = *(ptr++); part1 += b << 7; if (!(b & 0x80)) goto done;
508 part1 -= 0x80 << 7;
509 b = *(ptr++); part1 += b << 14; if (!(b & 0x80)) goto done;
510 part1 -= 0x80 << 14;
511 b = *(ptr++); part1 += b << 21; if (!(b & 0x80)) goto done;
512 part1 -= 0x80 << 21;
513 b = *(ptr++); part2 = b ; if (!(b & 0x80)) goto done;
514 part2 -= 0x80;
515 b = *(ptr++); part2 += b << 7; if (!(b & 0x80)) goto done;
516 // "part2 -= 0x80 << 7" is irrelevant because (0x80 << 7) << 56 is 0.
temporal40ee5512008-07-10 02:12:20 +0000517
518 // We have overrun the maximum size of a varint (10 bytes). The data
519 // must be corrupt.
liujisi@google.comaabd7cf2012-05-17 04:59:53 +0000520 return false;
temporal40ee5512008-07-10 02:12:20 +0000521
522 done:
523 Advance(ptr - buffer_);
524 *value = (static_cast<uint64>(part0) ) |
525 (static_cast<uint64>(part1) << 28) |
526 (static_cast<uint64>(part2) << 56);
527 return true;
temporal40ee5512008-07-10 02:12:20 +0000528 } else {
kenton@google.comfccb1462009-12-18 02:11:36 +0000529 return ReadVarint64Slow(value);
temporal40ee5512008-07-10 02:12:20 +0000530 }
531}
532
533bool CodedInputStream::Refresh() {
kenton@google.comfccb1462009-12-18 02:11:36 +0000534 GOOGLE_DCHECK_EQ(0, BufferSize());
temporal40ee5512008-07-10 02:12:20 +0000535
kenton@google.com80b1d622009-07-29 01:13:20 +0000536 if (buffer_size_after_limit_ > 0 || overflow_bytes_ > 0 ||
537 total_bytes_read_ == current_limit_) {
538 // We've hit a limit. Stop.
temporal40ee5512008-07-10 02:12:20 +0000539 int current_position = total_bytes_read_ - buffer_size_after_limit_;
540
541 if (current_position >= total_bytes_limit_ &&
542 total_bytes_limit_ != current_limit_) {
543 // Hit total_bytes_limit_.
544 PrintTotalBytesLimitError();
545 }
546
547 return false;
548 }
549
550 if (total_bytes_warning_threshold_ >= 0 &&
551 total_bytes_read_ >= total_bytes_warning_threshold_) {
552 GOOGLE_LOG(WARNING) << "Reading dangerously large protocol message. If the "
553 "message turns out to be larger than "
554 << total_bytes_limit_ << " bytes, parsing will be halted "
555 "for security reasons. To increase the limit (or to "
556 "disable these warnings), see "
557 "CodedInputStream::SetTotalBytesLimit() in "
558 "google/protobuf/io/coded_stream.h.";
559
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000560 // Don't warn again for this stream, and print total size at the end.
561 total_bytes_warning_threshold_ = -2;
temporal40ee5512008-07-10 02:12:20 +0000562 }
563
564 const void* void_buffer;
kenton@google.comfccb1462009-12-18 02:11:36 +0000565 int buffer_size;
liujisi@google.com33165fe2010-11-02 13:14:58 +0000566 if (NextNonEmpty(input_, &void_buffer, &buffer_size)) {
temporal40ee5512008-07-10 02:12:20 +0000567 buffer_ = reinterpret_cast<const uint8*>(void_buffer);
kenton@google.comfccb1462009-12-18 02:11:36 +0000568 buffer_end_ = buffer_ + buffer_size;
569 GOOGLE_CHECK_GE(buffer_size, 0);
temporal40ee5512008-07-10 02:12:20 +0000570
kenton@google.comfccb1462009-12-18 02:11:36 +0000571 if (total_bytes_read_ <= INT_MAX - buffer_size) {
572 total_bytes_read_ += buffer_size;
temporal40ee5512008-07-10 02:12:20 +0000573 } else {
kenton@google.comfccb1462009-12-18 02:11:36 +0000574 // Overflow. Reset buffer_end_ to not include the bytes beyond INT_MAX.
temporal40ee5512008-07-10 02:12:20 +0000575 // We can't get that far anyway, because total_bytes_limit_ is guaranteed
576 // to be less than it. We need to keep track of the number of bytes
577 // we discarded, though, so that we can call input_->BackUp() to back
578 // up over them on destruction.
579
580 // The following line is equivalent to:
kenton@google.comfccb1462009-12-18 02:11:36 +0000581 // overflow_bytes_ = total_bytes_read_ + buffer_size - INT_MAX;
temporal40ee5512008-07-10 02:12:20 +0000582 // except that it avoids overflows. Signed integer overflow has
583 // undefined results according to the C standard.
kenton@google.comfccb1462009-12-18 02:11:36 +0000584 overflow_bytes_ = total_bytes_read_ - (INT_MAX - buffer_size);
585 buffer_end_ -= overflow_bytes_;
temporal40ee5512008-07-10 02:12:20 +0000586 total_bytes_read_ = INT_MAX;
587 }
588
589 RecomputeBufferLimits();
590 return true;
591 } else {
592 buffer_ = NULL;
kenton@google.comfccb1462009-12-18 02:11:36 +0000593 buffer_end_ = NULL;
temporal40ee5512008-07-10 02:12:20 +0000594 return false;
595 }
596}
597
598// CodedOutputStream =================================================
599
600CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* output)
601 : output_(output),
602 buffer_(NULL),
603 buffer_size_(0),
kenton@google.comd37d46d2009-04-25 02:53:47 +0000604 total_bytes_(0),
jieluo@google.com4de8f552014-07-18 00:47:59 +0000605 had_error_(false),
606 aliasing_enabled_(false) {
kenton@google.comd37d46d2009-04-25 02:53:47 +0000607 // Eagerly Refresh() so buffer space is immediately available.
608 Refresh();
609 // The Refresh() may have failed. If the client doesn't write any data,
610 // though, don't consider this an error. If the client does write data, then
611 // another Refresh() will be attempted and it will set the error once again.
612 had_error_ = false;
temporal40ee5512008-07-10 02:12:20 +0000613}
614
615CodedOutputStream::~CodedOutputStream() {
Jisi Liu885b6122015-02-28 14:51:22 -0800616 Trim();
617}
618
619void CodedOutputStream::Trim() {
temporal40ee5512008-07-10 02:12:20 +0000620 if (buffer_size_ > 0) {
621 output_->BackUp(buffer_size_);
Jisi Liu885b6122015-02-28 14:51:22 -0800622 total_bytes_ -= buffer_size_;
623 buffer_size_ = 0;
624 buffer_ = NULL;
temporal40ee5512008-07-10 02:12:20 +0000625 }
626}
627
kenton@google.com2d6daa72009-01-22 01:27:00 +0000628bool CodedOutputStream::Skip(int count) {
629 if (count < 0) return false;
630
631 while (count > buffer_size_) {
632 count -= buffer_size_;
633 if (!Refresh()) return false;
634 }
635
636 Advance(count);
637 return true;
638}
639
640bool CodedOutputStream::GetDirectBufferPointer(void** data, int* size) {
641 if (buffer_size_ == 0 && !Refresh()) return false;
642
643 *data = buffer_;
644 *size = buffer_size_;
645 return true;
646}
647
kenton@google.comd37d46d2009-04-25 02:53:47 +0000648void CodedOutputStream::WriteRaw(const void* data, int size) {
temporal40ee5512008-07-10 02:12:20 +0000649 while (buffer_size_ < size) {
650 memcpy(buffer_, data, buffer_size_);
651 size -= buffer_size_;
652 data = reinterpret_cast<const uint8*>(data) + buffer_size_;
kenton@google.comd37d46d2009-04-25 02:53:47 +0000653 if (!Refresh()) return;
temporal40ee5512008-07-10 02:12:20 +0000654 }
655
656 memcpy(buffer_, data, size);
657 Advance(size);
kenton@google.comd37d46d2009-04-25 02:53:47 +0000658}
659
660uint8* CodedOutputStream::WriteRawToArray(
661 const void* data, int size, uint8* target) {
662 memcpy(target, data, size);
663 return target + size;
temporal40ee5512008-07-10 02:12:20 +0000664}
665
666
jieluo@google.com4de8f552014-07-18 00:47:59 +0000667void CodedOutputStream::WriteAliasedRaw(const void* data, int size) {
668 if (size < buffer_size_
669 ) {
670 WriteRaw(data, size);
671 } else {
Jisi Liu885b6122015-02-28 14:51:22 -0800672 Trim();
jieluo@google.com4de8f552014-07-18 00:47:59 +0000673
674 total_bytes_ += size;
675 had_error_ |= !output_->WriteAliasedRaw(data, size);
676 }
677}
678
kenton@google.comd37d46d2009-04-25 02:53:47 +0000679void CodedOutputStream::WriteLittleEndian32(uint32 value) {
temporal40ee5512008-07-10 02:12:20 +0000680 uint8 bytes[sizeof(value)];
681
682 bool use_fast = buffer_size_ >= sizeof(value);
683 uint8* ptr = use_fast ? buffer_ : bytes;
684
kenton@google.com80b1d622009-07-29 01:13:20 +0000685 WriteLittleEndian32ToArray(value, ptr);
temporal40ee5512008-07-10 02:12:20 +0000686
687 if (use_fast) {
688 Advance(sizeof(value));
temporal40ee5512008-07-10 02:12:20 +0000689 } else {
kenton@google.comd37d46d2009-04-25 02:53:47 +0000690 WriteRaw(bytes, sizeof(value));
temporal40ee5512008-07-10 02:12:20 +0000691 }
692}
693
kenton@google.comd37d46d2009-04-25 02:53:47 +0000694void CodedOutputStream::WriteLittleEndian64(uint64 value) {
temporal40ee5512008-07-10 02:12:20 +0000695 uint8 bytes[sizeof(value)];
696
temporal40ee5512008-07-10 02:12:20 +0000697 bool use_fast = buffer_size_ >= sizeof(value);
698 uint8* ptr = use_fast ? buffer_ : bytes;
699
kenton@google.com80b1d622009-07-29 01:13:20 +0000700 WriteLittleEndian64ToArray(value, ptr);
temporal40ee5512008-07-10 02:12:20 +0000701
702 if (use_fast) {
703 Advance(sizeof(value));
temporal40ee5512008-07-10 02:12:20 +0000704 } else {
kenton@google.comd37d46d2009-04-25 02:53:47 +0000705 WriteRaw(bytes, sizeof(value));
temporal40ee5512008-07-10 02:12:20 +0000706 }
707}
708
Jisi Liu885b6122015-02-28 14:51:22 -0800709void CodedOutputStream::WriteVarint32SlowPath(uint32 value) {
710 uint8 bytes[kMaxVarint32Bytes];
711 uint8* target = &bytes[0];
712 uint8* end = WriteVarint32ToArray(value, target);
713 int size = end - target;
714 WriteRaw(bytes, size);
kenton@google.comd37d46d2009-04-25 02:53:47 +0000715}
716
717inline uint8* CodedOutputStream::WriteVarint64ToArrayInline(
718 uint64 value, uint8* target) {
719 // Splitting into 32-bit pieces gives better performance on 32-bit
720 // processors.
721 uint32 part0 = static_cast<uint32>(value );
722 uint32 part1 = static_cast<uint32>(value >> 28);
723 uint32 part2 = static_cast<uint32>(value >> 56);
724
725 int size;
726
727 // Here we can't really optimize for small numbers, since the value is
728 // split into three parts. Cheking for numbers < 128, for instance,
729 // would require three comparisons, since you'd have to make sure part1
730 // and part2 are zero. However, if the caller is using 64-bit integers,
731 // it is likely that they expect the numbers to often be very large, so
732 // we probably don't want to optimize for small numbers anyway. Thus,
733 // we end up with a hardcoded binary search tree...
734 if (part2 == 0) {
735 if (part1 == 0) {
736 if (part0 < (1 << 14)) {
737 if (part0 < (1 << 7)) {
738 size = 1; goto size1;
739 } else {
740 size = 2; goto size2;
741 }
742 } else {
743 if (part0 < (1 << 21)) {
744 size = 3; goto size3;
745 } else {
746 size = 4; goto size4;
747 }
748 }
749 } else {
750 if (part1 < (1 << 14)) {
751 if (part1 < (1 << 7)) {
752 size = 5; goto size5;
753 } else {
754 size = 6; goto size6;
755 }
756 } else {
757 if (part1 < (1 << 21)) {
758 size = 7; goto size7;
759 } else {
760 size = 8; goto size8;
761 }
762 }
763 }
764 } else {
765 if (part2 < (1 << 7)) {
766 size = 9; goto size9;
767 } else {
768 size = 10; goto size10;
769 }
770 }
771
772 GOOGLE_LOG(FATAL) << "Can't get here.";
773
774 size10: target[9] = static_cast<uint8>((part2 >> 7) | 0x80);
775 size9 : target[8] = static_cast<uint8>((part2 ) | 0x80);
776 size8 : target[7] = static_cast<uint8>((part1 >> 21) | 0x80);
777 size7 : target[6] = static_cast<uint8>((part1 >> 14) | 0x80);
778 size6 : target[5] = static_cast<uint8>((part1 >> 7) | 0x80);
779 size5 : target[4] = static_cast<uint8>((part1 ) | 0x80);
780 size4 : target[3] = static_cast<uint8>((part0 >> 21) | 0x80);
781 size3 : target[2] = static_cast<uint8>((part0 >> 14) | 0x80);
782 size2 : target[1] = static_cast<uint8>((part0 >> 7) | 0x80);
783 size1 : target[0] = static_cast<uint8>((part0 ) | 0x80);
784
785 target[size-1] &= 0x7F;
786 return target + size;
787}
788
789void CodedOutputStream::WriteVarint64(uint64 value) {
temporal40ee5512008-07-10 02:12:20 +0000790 if (buffer_size_ >= kMaxVarintBytes) {
791 // Fast path: We have enough bytes left in the buffer to guarantee that
792 // this write won't cross the end, so we can skip the checks.
793 uint8* target = buffer_;
794
kenton@google.comd37d46d2009-04-25 02:53:47 +0000795 uint8* end = WriteVarint64ToArrayInline(value, target);
796 int size = end - target;
temporal40ee5512008-07-10 02:12:20 +0000797 Advance(size);
temporal40ee5512008-07-10 02:12:20 +0000798 } else {
799 // Slow path: This write might cross the end of the buffer, so we
800 // compose the bytes first then use WriteRaw().
801 uint8 bytes[kMaxVarintBytes];
802 int size = 0;
803 while (value > 0x7F) {
804 bytes[size++] = (static_cast<uint8>(value) & 0x7F) | 0x80;
805 value >>= 7;
806 }
807 bytes[size++] = static_cast<uint8>(value) & 0x7F;
kenton@google.comd37d46d2009-04-25 02:53:47 +0000808 WriteRaw(bytes, size);
temporal40ee5512008-07-10 02:12:20 +0000809 }
810}
811
kenton@google.comd37d46d2009-04-25 02:53:47 +0000812uint8* CodedOutputStream::WriteVarint64ToArray(
813 uint64 value, uint8* target) {
814 return WriteVarint64ToArrayInline(value, target);
815}
816
temporal40ee5512008-07-10 02:12:20 +0000817bool CodedOutputStream::Refresh() {
818 void* void_buffer;
819 if (output_->Next(&void_buffer, &buffer_size_)) {
820 buffer_ = reinterpret_cast<uint8*>(void_buffer);
821 total_bytes_ += buffer_size_;
822 return true;
823 } else {
824 buffer_ = NULL;
825 buffer_size_ = 0;
kenton@google.comd37d46d2009-04-25 02:53:47 +0000826 had_error_ = true;
temporal40ee5512008-07-10 02:12:20 +0000827 return false;
828 }
829}
830
831int CodedOutputStream::VarintSize32Fallback(uint32 value) {
832 if (value < (1 << 7)) {
833 return 1;
834 } else if (value < (1 << 14)) {
835 return 2;
836 } else if (value < (1 << 21)) {
837 return 3;
838 } else if (value < (1 << 28)) {
839 return 4;
840 } else {
841 return 5;
842 }
843}
844
845int CodedOutputStream::VarintSize64(uint64 value) {
846 if (value < (1ull << 35)) {
847 if (value < (1ull << 7)) {
848 return 1;
849 } else if (value < (1ull << 14)) {
850 return 2;
851 } else if (value < (1ull << 21)) {
852 return 3;
853 } else if (value < (1ull << 28)) {
854 return 4;
855 } else {
856 return 5;
857 }
858 } else {
859 if (value < (1ull << 42)) {
860 return 6;
861 } else if (value < (1ull << 49)) {
862 return 7;
863 } else if (value < (1ull << 56)) {
864 return 8;
865 } else if (value < (1ull << 63)) {
866 return 9;
867 } else {
868 return 10;
869 }
870 }
871}
872
jieluo@google.com4de8f552014-07-18 00:47:59 +0000873uint8* CodedOutputStream::WriteStringWithSizeToArray(const string& str,
874 uint8* target) {
875 GOOGLE_DCHECK_LE(str.size(), kuint32max);
876 target = WriteVarint32ToArray(str.size(), target);
877 return WriteStringToArray(str, target);
878}
879
temporal40ee5512008-07-10 02:12:20 +0000880} // namespace io
881} // namespace protobuf
882} // namespace google