blob: e3a34d0ac0f6ae99e42bf78dc877efb30d7f2a81 [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>
Feng Xiaoeee38b02015-08-22 18:25:48 -070047#include <google/protobuf/stubs/logging.h>
temporal40ee5512008-07-10 02:12:20 +000048#include <google/protobuf/stubs/common.h>
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +000049#include <google/protobuf/stubs/stl_util.h>
temporal40ee5512008-07-10 02:12:20 +000050
51
52namespace google {
53namespace protobuf {
54namespace io {
55
56namespace {
57
temporal40ee5512008-07-10 02:12:20 +000058static const int kMaxVarintBytes = 10;
59static const int kMaxVarint32Bytes = 5;
60
61
liujisi@google.com33165fe2010-11-02 13:14:58 +000062inline 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
temporal40ee5512008-07-10 02:12:20 +000071} // namespace
72
73// CodedInputStream ==================================================
74
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +000075CodedInputStream::~CodedInputStream() {
76 if (input_ != NULL) {
77 BackUpInputToCurrentPosition();
78 }
79
80 if (total_bytes_warning_threshold_ == -2) {
81 GOOGLE_LOG(WARNING) << "The total number of bytes read was " << total_bytes_read_;
82 }
83}
84
85// Static.
86int CodedInputStream::default_recursion_limit_ = 100;
87
temporal40ee5512008-07-10 02:12:20 +000088
jieluo@google.com4de8f552014-07-18 00:47:59 +000089void CodedOutputStream::EnableAliasing(bool enabled) {
90 aliasing_enabled_ = enabled && output_->AllowsAliasing();
91}
92
kenton@google.com80b1d622009-07-29 01:13:20 +000093void CodedInputStream::BackUpInputToCurrentPosition() {
kenton@google.comfccb1462009-12-18 02:11:36 +000094 int backup_bytes = BufferSize() + buffer_size_after_limit_ + overflow_bytes_;
kenton@google.com80b1d622009-07-29 01:13:20 +000095 if (backup_bytes > 0) {
96 input_->BackUp(backup_bytes);
97
98 // total_bytes_read_ doesn't include overflow_bytes_.
kenton@google.comfccb1462009-12-18 02:11:36 +000099 total_bytes_read_ -= BufferSize() + buffer_size_after_limit_;
100 buffer_end_ = buffer_;
kenton@google.com80b1d622009-07-29 01:13:20 +0000101 buffer_size_after_limit_ = 0;
102 overflow_bytes_ = 0;
103 }
104}
105
temporal40ee5512008-07-10 02:12:20 +0000106inline void CodedInputStream::RecomputeBufferLimits() {
kenton@google.comfccb1462009-12-18 02:11:36 +0000107 buffer_end_ += buffer_size_after_limit_;
temporal40ee5512008-07-10 02:12:20 +0000108 int closest_limit = 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;
kenton@google.comfccb1462009-12-18 02:11:36 +0000113 buffer_end_ -= buffer_size_after_limit_;
temporal40ee5512008-07-10 02:12:20 +0000114 } 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.
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000121 int current_position = CurrentPosition();
temporal40ee5512008-07-10 02:12:20 +0000122
123 Limit old_limit = current_limit_;
124
125 // security: byte_limit is possibly evil, so check for negative values
126 // and overflow.
127 if (byte_limit >= 0 &&
128 byte_limit <= INT_MAX - current_position) {
129 current_limit_ = current_position + byte_limit;
130 } else {
131 // Negative or overflow.
132 current_limit_ = INT_MAX;
133 }
134
135 // We need to enforce all limits, not just the new one, so if the previous
136 // limit was before the new requested limit, we continue to enforce the
137 // previous limit.
138 current_limit_ = min(current_limit_, old_limit);
139
140 RecomputeBufferLimits();
141 return old_limit;
142}
143
144void CodedInputStream::PopLimit(Limit limit) {
145 // The limit passed in is actually the *old* limit, which we returned from
146 // PushLimit().
147 current_limit_ = limit;
148 RecomputeBufferLimits();
149
150 // We may no longer be at a legitimate message end. ReadTag() needs to be
151 // called again to find out.
152 legitimate_message_end_ = false;
153}
154
Feng Xiao6ef984a2014-11-10 17:34:54 -0800155std::pair<CodedInputStream::Limit, int>
156CodedInputStream::IncrementRecursionDepthAndPushLimit(int byte_limit) {
Jisi Liu885b6122015-02-28 14:51:22 -0800157 return std::make_pair(PushLimit(byte_limit), --recursion_budget_);
Feng Xiao6ef984a2014-11-10 17:34:54 -0800158}
159
Bo Yang5db21732015-05-21 14:28:59 -0700160CodedInputStream::Limit CodedInputStream::ReadLengthAndPushLimit() {
161 uint32 length;
162 return PushLimit(ReadVarint32(&length) ? length : 0);
163}
164
Feng Xiao6ef984a2014-11-10 17:34:54 -0800165bool CodedInputStream::DecrementRecursionDepthAndPopLimit(Limit limit) {
166 bool result = ConsumedEntireMessage();
167 PopLimit(limit);
168 GOOGLE_DCHECK_LT(recursion_budget_, recursion_limit_);
169 ++recursion_budget_;
170 return result;
171}
172
Bo Yang5db21732015-05-21 14:28:59 -0700173bool CodedInputStream::CheckEntireMessageConsumedAndPopLimit(Limit limit) {
174 bool result = ConsumedEntireMessage();
175 PopLimit(limit);
176 return result;
177}
178
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000179int CodedInputStream::BytesUntilLimit() const {
temporal40ee5512008-07-10 02:12:20 +0000180 if (current_limit_ == INT_MAX) return -1;
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000181 int current_position = CurrentPosition();
temporal40ee5512008-07-10 02:12:20 +0000182
183 return current_limit_ - current_position;
184}
185
186void CodedInputStream::SetTotalBytesLimit(
187 int total_bytes_limit, int warning_threshold) {
188 // Make sure the limit isn't already past, since this could confuse other
189 // code.
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000190 int current_position = CurrentPosition();
temporal40ee5512008-07-10 02:12:20 +0000191 total_bytes_limit_ = max(current_position, total_bytes_limit);
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000192 if (warning_threshold >= 0) {
193 total_bytes_warning_threshold_ = warning_threshold;
194 } else {
195 // warning_threshold is negative
196 total_bytes_warning_threshold_ = -1;
197 }
temporal40ee5512008-07-10 02:12:20 +0000198 RecomputeBufferLimits();
199}
200
jieluo@google.com4de8f552014-07-18 00:47:59 +0000201int CodedInputStream::BytesUntilTotalBytesLimit() const {
202 if (total_bytes_limit_ == INT_MAX) return -1;
203 return total_bytes_limit_ - CurrentPosition();
204}
205
temporal40ee5512008-07-10 02:12:20 +0000206void CodedInputStream::PrintTotalBytesLimitError() {
207 GOOGLE_LOG(ERROR) << "A protocol message was rejected because it was too "
208 "big (more than " << total_bytes_limit_
209 << " bytes). To increase the limit (or to disable these "
210 "warnings), see CodedInputStream::SetTotalBytesLimit() "
211 "in google/protobuf/io/coded_stream.h.";
212}
213
214bool CodedInputStream::Skip(int count) {
215 if (count < 0) return false; // security: count is often user-supplied
216
kenton@google.comfccb1462009-12-18 02:11:36 +0000217 const int original_buffer_size = BufferSize();
218
219 if (count <= original_buffer_size) {
temporal40ee5512008-07-10 02:12:20 +0000220 // Just skipping within the current buffer. Easy.
221 Advance(count);
222 return true;
223 }
224
225 if (buffer_size_after_limit_ > 0) {
226 // We hit a limit inside this buffer. Advance to the limit and fail.
kenton@google.comfccb1462009-12-18 02:11:36 +0000227 Advance(original_buffer_size);
temporal40ee5512008-07-10 02:12:20 +0000228 return false;
229 }
230
kenton@google.comfccb1462009-12-18 02:11:36 +0000231 count -= original_buffer_size;
temporal40ee5512008-07-10 02:12:20 +0000232 buffer_ = NULL;
kenton@google.comfccb1462009-12-18 02:11:36 +0000233 buffer_end_ = buffer_;
temporal40ee5512008-07-10 02:12:20 +0000234
235 // Make sure this skip doesn't try to skip past the current limit.
236 int closest_limit = min(current_limit_, total_bytes_limit_);
237 int bytes_until_limit = closest_limit - total_bytes_read_;
238 if (bytes_until_limit < count) {
239 // We hit the limit. Skip up to it then fail.
kenton@google.com80b1d622009-07-29 01:13:20 +0000240 if (bytes_until_limit > 0) {
241 total_bytes_read_ = closest_limit;
242 input_->Skip(bytes_until_limit);
243 }
temporal40ee5512008-07-10 02:12:20 +0000244 return false;
245 }
246
247 total_bytes_read_ += count;
248 return input_->Skip(count);
249}
250
kenton@google.com2d6daa72009-01-22 01:27:00 +0000251bool CodedInputStream::GetDirectBufferPointer(const void** data, int* size) {
kenton@google.comfccb1462009-12-18 02:11:36 +0000252 if (BufferSize() == 0 && !Refresh()) return false;
kenton@google.com2d6daa72009-01-22 01:27:00 +0000253
254 *data = buffer_;
kenton@google.comfccb1462009-12-18 02:11:36 +0000255 *size = BufferSize();
kenton@google.com2d6daa72009-01-22 01:27:00 +0000256 return true;
257}
258
temporal40ee5512008-07-10 02:12:20 +0000259bool CodedInputStream::ReadRaw(void* buffer, int size) {
Bo Yang5db21732015-05-21 14:28:59 -0700260 return InternalReadRawInline(buffer, size);
temporal40ee5512008-07-10 02:12:20 +0000261}
262
263bool CodedInputStream::ReadString(string* buffer, int size) {
264 if (size < 0) return false; // security: size is often user-supplied
kenton@google.comfccb1462009-12-18 02:11:36 +0000265 return InternalReadStringInline(buffer, size);
266}
temporal40ee5512008-07-10 02:12:20 +0000267
kenton@google.comfccb1462009-12-18 02:11:36 +0000268bool CodedInputStream::ReadStringFallback(string* buffer, int size) {
temporal40ee5512008-07-10 02:12:20 +0000269 if (!buffer->empty()) {
270 buffer->clear();
271 }
272
jieluo@google.com4de8f552014-07-18 00:47:59 +0000273 int closest_limit = min(current_limit_, total_bytes_limit_);
274 if (closest_limit != INT_MAX) {
275 int bytes_to_limit = closest_limit - CurrentPosition();
276 if (bytes_to_limit > 0 && size > 0 && size <= bytes_to_limit) {
277 buffer->reserve(size);
278 }
279 }
280
kenton@google.comfccb1462009-12-18 02:11:36 +0000281 int current_buffer_size;
282 while ((current_buffer_size = BufferSize()) < size) {
temporal40ee5512008-07-10 02:12:20 +0000283 // Some STL implementations "helpfully" crash on buffer->append(NULL, 0).
kenton@google.comfccb1462009-12-18 02:11:36 +0000284 if (current_buffer_size != 0) {
temporal40ee5512008-07-10 02:12:20 +0000285 // Note: string1.append(string2) is O(string2.size()) (as opposed to
286 // O(string1.size() + string2.size()), which would be bad).
kenton@google.comfccb1462009-12-18 02:11:36 +0000287 buffer->append(reinterpret_cast<const char*>(buffer_),
288 current_buffer_size);
temporal40ee5512008-07-10 02:12:20 +0000289 }
kenton@google.comfccb1462009-12-18 02:11:36 +0000290 size -= current_buffer_size;
291 Advance(current_buffer_size);
temporal40ee5512008-07-10 02:12:20 +0000292 if (!Refresh()) return false;
293 }
294
295 buffer->append(reinterpret_cast<const char*>(buffer_), size);
296 Advance(size);
297
298 return true;
299}
300
301
kenton@google.comfccb1462009-12-18 02:11:36 +0000302bool CodedInputStream::ReadLittleEndian32Fallback(uint32* value) {
temporal40ee5512008-07-10 02:12:20 +0000303 uint8 bytes[sizeof(*value)];
304
305 const uint8* ptr;
kenton@google.comfccb1462009-12-18 02:11:36 +0000306 if (BufferSize() >= sizeof(*value)) {
temporal40ee5512008-07-10 02:12:20 +0000307 // Fast path: Enough bytes in the buffer to read directly.
308 ptr = buffer_;
309 Advance(sizeof(*value));
310 } else {
311 // Slow path: Had to read past the end of the buffer.
312 if (!ReadRaw(bytes, sizeof(*value))) return false;
313 ptr = bytes;
314 }
kenton@google.comfccb1462009-12-18 02:11:36 +0000315 ReadLittleEndian32FromArray(ptr, value);
temporal40ee5512008-07-10 02:12:20 +0000316 return true;
317}
318
kenton@google.comfccb1462009-12-18 02:11:36 +0000319bool CodedInputStream::ReadLittleEndian64Fallback(uint64* value) {
temporal40ee5512008-07-10 02:12:20 +0000320 uint8 bytes[sizeof(*value)];
321
322 const uint8* ptr;
kenton@google.comfccb1462009-12-18 02:11:36 +0000323 if (BufferSize() >= sizeof(*value)) {
temporal40ee5512008-07-10 02:12:20 +0000324 // Fast path: Enough bytes in the buffer to read directly.
325 ptr = buffer_;
326 Advance(sizeof(*value));
327 } else {
328 // Slow path: Had to read past the end of the buffer.
329 if (!ReadRaw(bytes, sizeof(*value))) return false;
330 ptr = bytes;
331 }
kenton@google.comfccb1462009-12-18 02:11:36 +0000332 ReadLittleEndian64FromArray(ptr, value);
333 return true;
334}
temporal40ee5512008-07-10 02:12:20 +0000335
kenton@google.comfccb1462009-12-18 02:11:36 +0000336namespace {
337
Bo Yang5db21732015-05-21 14:28:59 -0700338// Read a varint from the given buffer, write it to *value, and return a pair.
339// The first part of the pair is true iff the read was successful. The second
340// part is buffer + (number of bytes read). This function is always inlined,
341// so returning a pair is costless.
Feng Xiaoeee38b02015-08-22 18:25:48 -0700342GOOGLE_ATTRIBUTE_ALWAYS_INLINE ::std::pair<bool, const uint8*> ReadVarint32FromArray(
Bo Yang5db21732015-05-21 14:28:59 -0700343 uint32 first_byte, const uint8* buffer,
Feng Xiaoeee38b02015-08-22 18:25:48 -0700344 uint32* value);
Bo Yang5db21732015-05-21 14:28:59 -0700345inline ::std::pair<bool, const uint8*> ReadVarint32FromArray(
346 uint32 first_byte, const uint8* buffer, uint32* value) {
kenton@google.comfccb1462009-12-18 02:11:36 +0000347 // Fast path: We have enough bytes left in the buffer to guarantee that
348 // this read won't cross the end, so we can skip the checks.
Bo Yang5db21732015-05-21 14:28:59 -0700349 GOOGLE_DCHECK_EQ(*buffer, first_byte);
350 GOOGLE_DCHECK_EQ(first_byte & 0x80, 0x80) << first_byte;
kenton@google.comfccb1462009-12-18 02:11:36 +0000351 const uint8* ptr = buffer;
352 uint32 b;
Bo Yang5db21732015-05-21 14:28:59 -0700353 uint32 result = first_byte - 0x80;
354 ++ptr; // We just processed the first byte. Move on to the second.
jieluo@google.com4de8f552014-07-18 00:47:59 +0000355 b = *(ptr++); result += b << 7; if (!(b & 0x80)) goto done;
356 result -= 0x80 << 7;
357 b = *(ptr++); result += b << 14; if (!(b & 0x80)) goto done;
358 result -= 0x80 << 14;
359 b = *(ptr++); result += b << 21; if (!(b & 0x80)) goto done;
360 result -= 0x80 << 21;
361 b = *(ptr++); result += b << 28; if (!(b & 0x80)) goto done;
362 // "result -= 0x80 << 28" is irrevelant.
kenton@google.comfccb1462009-12-18 02:11:36 +0000363
364 // If the input is larger than 32 bits, we still need to read it all
365 // and discard the high-order bits.
366 for (int i = 0; i < kMaxVarintBytes - kMaxVarint32Bytes; i++) {
367 b = *(ptr++); if (!(b & 0x80)) goto done;
368 }
369
370 // We have overrun the maximum size of a varint (10 bytes). Assume
371 // the data is corrupt.
Bo Yang5db21732015-05-21 14:28:59 -0700372 return std::make_pair(false, ptr);
kenton@google.comfccb1462009-12-18 02:11:36 +0000373
374 done:
375 *value = result;
Bo Yang5db21732015-05-21 14:28:59 -0700376 return std::make_pair(true, ptr);
kenton@google.comfccb1462009-12-18 02:11:36 +0000377}
378
379} // namespace
380
381bool CodedInputStream::ReadVarint32Slow(uint32* value) {
kenton@google.comfccb1462009-12-18 02:11:36 +0000382 // Directly invoke ReadVarint64Fallback, since we already tried to optimize
383 // for one-byte varints.
Bo Yang5db21732015-05-21 14:28:59 -0700384 std::pair<uint64, bool> p = ReadVarint64Fallback();
385 *value = static_cast<uint32>(p.first);
386 return p.second;
temporal40ee5512008-07-10 02:12:20 +0000387}
388
Bo Yang5db21732015-05-21 14:28:59 -0700389int64 CodedInputStream::ReadVarint32Fallback(uint32 first_byte_or_zero) {
kenton@google.comfccb1462009-12-18 02:11:36 +0000390 if (BufferSize() >= kMaxVarintBytes ||
jieluo@google.com4de8f552014-07-18 00:47:59 +0000391 // Optimization: We're also safe if the buffer is non-empty and it ends
392 // with a byte that would terminate a varint.
kenton@google.comfccb1462009-12-18 02:11:36 +0000393 (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
Bo Yang5db21732015-05-21 14:28:59 -0700394 GOOGLE_DCHECK_NE(first_byte_or_zero, 0)
395 << "Caller should provide us with *buffer_ when buffer is non-empty";
396 uint32 temp;
397 ::std::pair<bool, const uint8*> p =
398 ReadVarint32FromArray(first_byte_or_zero, buffer_, &temp);
399 if (!p.first) return -1;
400 buffer_ = p.second;
401 return temp;
temporal40ee5512008-07-10 02:12:20 +0000402 } else {
kenton@google.comfccb1462009-12-18 02:11:36 +0000403 // Really slow case: we will incur the cost of an extra function call here,
404 // but moving this out of line reduces the size of this function, which
405 // improves the common case. In micro benchmarks, this is worth about 10-15%
Bo Yang5db21732015-05-21 14:28:59 -0700406 uint32 temp;
407 return ReadVarint32Slow(&temp) ? static_cast<int64>(temp) : -1;
temporal40ee5512008-07-10 02:12:20 +0000408 }
409}
410
kenton@google.comfccb1462009-12-18 02:11:36 +0000411uint32 CodedInputStream::ReadTagSlow() {
412 if (buffer_ == buffer_end_) {
413 // Call refresh.
414 if (!Refresh()) {
415 // Refresh failed. Make sure that it failed due to EOF, not because
416 // we hit total_bytes_limit_, which, unlike normal limits, is not a
417 // valid place to end a message.
418 int current_position = total_bytes_read_ - buffer_size_after_limit_;
419 if (current_position >= total_bytes_limit_) {
420 // Hit total_bytes_limit_. But if we also hit the normal limit,
421 // we're still OK.
422 legitimate_message_end_ = current_limit_ == total_bytes_limit_;
423 } else {
424 legitimate_message_end_ = true;
425 }
426 return 0;
427 }
428 }
429
430 // For the slow path, just do a 64-bit read. Try to optimize for one-byte tags
431 // again, since we have now refreshed the buffer.
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000432 uint64 result = 0;
kenton@google.comfccb1462009-12-18 02:11:36 +0000433 if (!ReadVarint64(&result)) return 0;
434 return static_cast<uint32>(result);
435}
436
Bo Yang5db21732015-05-21 14:28:59 -0700437uint32 CodedInputStream::ReadTagFallback(uint32 first_byte_or_zero) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000438 const int buf_size = BufferSize();
439 if (buf_size >= kMaxVarintBytes ||
jieluo@google.com4de8f552014-07-18 00:47:59 +0000440 // Optimization: We're also safe if the buffer is non-empty and it ends
441 // with a byte that would terminate a varint.
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000442 (buf_size > 0 && !(buffer_end_[-1] & 0x80))) {
Bo Yang5db21732015-05-21 14:28:59 -0700443 GOOGLE_DCHECK_EQ(first_byte_or_zero, buffer_[0]);
444 if (first_byte_or_zero == 0) {
445 ++buffer_;
kenton@google.comfccb1462009-12-18 02:11:36 +0000446 return 0;
447 }
Bo Yang5db21732015-05-21 14:28:59 -0700448 uint32 tag;
449 ::std::pair<bool, const uint8*> p =
450 ReadVarint32FromArray(first_byte_or_zero, buffer_, &tag);
451 if (!p.first) {
452 return 0;
453 }
454 buffer_ = p.second;
kenton@google.comfccb1462009-12-18 02:11:36 +0000455 return tag;
456 } else {
457 // We are commonly at a limit when attempting to read tags. Try to quickly
458 // detect this case without making another function call.
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000459 if ((buf_size == 0) &&
460 ((buffer_size_after_limit_ > 0) ||
461 (total_bytes_read_ == current_limit_)) &&
kenton@google.comfccb1462009-12-18 02:11:36 +0000462 // Make sure that the limit we hit is not total_bytes_limit_, since
463 // in that case we still need to call Refresh() so that it prints an
464 // error.
465 total_bytes_read_ - buffer_size_after_limit_ < total_bytes_limit_) {
466 // We hit a byte limit.
467 legitimate_message_end_ = true;
468 return 0;
469 }
470 return ReadTagSlow();
471 }
472}
473
474bool CodedInputStream::ReadVarint64Slow(uint64* value) {
475 // Slow path: This read might cross the end of the buffer, so we
476 // need to check and refresh the buffer if and when it does.
477
478 uint64 result = 0;
479 int count = 0;
480 uint32 b;
481
482 do {
483 if (count == kMaxVarintBytes) return false;
484 while (buffer_ == buffer_end_) {
485 if (!Refresh()) return false;
486 }
487 b = *buffer_;
488 result |= static_cast<uint64>(b & 0x7F) << (7 * count);
489 Advance(1);
490 ++count;
491 } while (b & 0x80);
492
493 *value = result;
494 return true;
495}
496
Bo Yang5db21732015-05-21 14:28:59 -0700497std::pair<uint64, bool> CodedInputStream::ReadVarint64Fallback() {
kenton@google.comfccb1462009-12-18 02:11:36 +0000498 if (BufferSize() >= kMaxVarintBytes ||
jieluo@google.com4de8f552014-07-18 00:47:59 +0000499 // Optimization: We're also safe if the buffer is non-empty and it ends
500 // with a byte that would terminate a varint.
kenton@google.comfccb1462009-12-18 02:11:36 +0000501 (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
temporal40ee5512008-07-10 02:12:20 +0000502 // Fast path: We have enough bytes left in the buffer to guarantee that
503 // this read won't cross the end, so we can skip the checks.
504
505 const uint8* ptr = buffer_;
506 uint32 b;
507
508 // Splitting into 32-bit pieces gives better performance on 32-bit
509 // processors.
510 uint32 part0 = 0, part1 = 0, part2 = 0;
511
jieluo@google.com4de8f552014-07-18 00:47:59 +0000512 b = *(ptr++); part0 = b ; if (!(b & 0x80)) goto done;
513 part0 -= 0x80;
514 b = *(ptr++); part0 += b << 7; if (!(b & 0x80)) goto done;
515 part0 -= 0x80 << 7;
516 b = *(ptr++); part0 += b << 14; if (!(b & 0x80)) goto done;
517 part0 -= 0x80 << 14;
518 b = *(ptr++); part0 += b << 21; if (!(b & 0x80)) goto done;
519 part0 -= 0x80 << 21;
520 b = *(ptr++); part1 = b ; if (!(b & 0x80)) goto done;
521 part1 -= 0x80;
522 b = *(ptr++); part1 += b << 7; if (!(b & 0x80)) goto done;
523 part1 -= 0x80 << 7;
524 b = *(ptr++); part1 += b << 14; if (!(b & 0x80)) goto done;
525 part1 -= 0x80 << 14;
526 b = *(ptr++); part1 += b << 21; if (!(b & 0x80)) goto done;
527 part1 -= 0x80 << 21;
528 b = *(ptr++); part2 = b ; if (!(b & 0x80)) goto done;
529 part2 -= 0x80;
530 b = *(ptr++); part2 += b << 7; if (!(b & 0x80)) goto done;
531 // "part2 -= 0x80 << 7" is irrelevant because (0x80 << 7) << 56 is 0.
temporal40ee5512008-07-10 02:12:20 +0000532
533 // We have overrun the maximum size of a varint (10 bytes). The data
534 // must be corrupt.
Bo Yang5db21732015-05-21 14:28:59 -0700535 return std::make_pair(0, false);
temporal40ee5512008-07-10 02:12:20 +0000536
537 done:
538 Advance(ptr - buffer_);
Bo Yang5db21732015-05-21 14:28:59 -0700539 return std::make_pair((static_cast<uint64>(part0)) |
540 (static_cast<uint64>(part1) << 28) |
541 (static_cast<uint64>(part2) << 56),
542 true);
temporal40ee5512008-07-10 02:12:20 +0000543 } else {
Bo Yang5db21732015-05-21 14:28:59 -0700544 uint64 temp;
545 bool success = ReadVarint64Slow(&temp);
546 return std::make_pair(temp, success);
temporal40ee5512008-07-10 02:12:20 +0000547 }
548}
549
550bool CodedInputStream::Refresh() {
kenton@google.comfccb1462009-12-18 02:11:36 +0000551 GOOGLE_DCHECK_EQ(0, BufferSize());
temporal40ee5512008-07-10 02:12:20 +0000552
kenton@google.com80b1d622009-07-29 01:13:20 +0000553 if (buffer_size_after_limit_ > 0 || overflow_bytes_ > 0 ||
554 total_bytes_read_ == current_limit_) {
555 // We've hit a limit. Stop.
temporal40ee5512008-07-10 02:12:20 +0000556 int current_position = total_bytes_read_ - buffer_size_after_limit_;
557
558 if (current_position >= total_bytes_limit_ &&
559 total_bytes_limit_ != current_limit_) {
560 // Hit total_bytes_limit_.
561 PrintTotalBytesLimitError();
562 }
563
564 return false;
565 }
566
567 if (total_bytes_warning_threshold_ >= 0 &&
568 total_bytes_read_ >= total_bytes_warning_threshold_) {
569 GOOGLE_LOG(WARNING) << "Reading dangerously large protocol message. If the "
570 "message turns out to be larger than "
571 << total_bytes_limit_ << " bytes, parsing will be halted "
572 "for security reasons. To increase the limit (or to "
573 "disable these warnings), see "
574 "CodedInputStream::SetTotalBytesLimit() in "
575 "google/protobuf/io/coded_stream.h.";
576
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000577 // Don't warn again for this stream, and print total size at the end.
578 total_bytes_warning_threshold_ = -2;
temporal40ee5512008-07-10 02:12:20 +0000579 }
580
581 const void* void_buffer;
kenton@google.comfccb1462009-12-18 02:11:36 +0000582 int buffer_size;
liujisi@google.com33165fe2010-11-02 13:14:58 +0000583 if (NextNonEmpty(input_, &void_buffer, &buffer_size)) {
temporal40ee5512008-07-10 02:12:20 +0000584 buffer_ = reinterpret_cast<const uint8*>(void_buffer);
kenton@google.comfccb1462009-12-18 02:11:36 +0000585 buffer_end_ = buffer_ + buffer_size;
586 GOOGLE_CHECK_GE(buffer_size, 0);
temporal40ee5512008-07-10 02:12:20 +0000587
kenton@google.comfccb1462009-12-18 02:11:36 +0000588 if (total_bytes_read_ <= INT_MAX - buffer_size) {
589 total_bytes_read_ += buffer_size;
temporal40ee5512008-07-10 02:12:20 +0000590 } else {
kenton@google.comfccb1462009-12-18 02:11:36 +0000591 // Overflow. Reset buffer_end_ to not include the bytes beyond INT_MAX.
temporal40ee5512008-07-10 02:12:20 +0000592 // We can't get that far anyway, because total_bytes_limit_ is guaranteed
593 // to be less than it. We need to keep track of the number of bytes
594 // we discarded, though, so that we can call input_->BackUp() to back
595 // up over them on destruction.
596
597 // The following line is equivalent to:
kenton@google.comfccb1462009-12-18 02:11:36 +0000598 // overflow_bytes_ = total_bytes_read_ + buffer_size - INT_MAX;
temporal40ee5512008-07-10 02:12:20 +0000599 // except that it avoids overflows. Signed integer overflow has
600 // undefined results according to the C standard.
kenton@google.comfccb1462009-12-18 02:11:36 +0000601 overflow_bytes_ = total_bytes_read_ - (INT_MAX - buffer_size);
602 buffer_end_ -= overflow_bytes_;
temporal40ee5512008-07-10 02:12:20 +0000603 total_bytes_read_ = INT_MAX;
604 }
605
606 RecomputeBufferLimits();
607 return true;
608 } else {
609 buffer_ = NULL;
kenton@google.comfccb1462009-12-18 02:11:36 +0000610 buffer_end_ = NULL;
temporal40ee5512008-07-10 02:12:20 +0000611 return false;
612 }
613}
614
615// CodedOutputStream =================================================
616
617CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* output)
618 : output_(output),
619 buffer_(NULL),
620 buffer_size_(0),
kenton@google.comd37d46d2009-04-25 02:53:47 +0000621 total_bytes_(0),
jieluo@google.com4de8f552014-07-18 00:47:59 +0000622 had_error_(false),
623 aliasing_enabled_(false) {
kenton@google.comd37d46d2009-04-25 02:53:47 +0000624 // Eagerly Refresh() so buffer space is immediately available.
625 Refresh();
626 // The Refresh() may have failed. If the client doesn't write any data,
627 // though, don't consider this an error. If the client does write data, then
628 // another Refresh() will be attempted and it will set the error once again.
629 had_error_ = false;
temporal40ee5512008-07-10 02:12:20 +0000630}
631
Feng Xiao76195052016-01-06 18:06:43 -0800632CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* output,
633 bool do_eager_refresh)
634 : output_(output),
635 buffer_(NULL),
636 buffer_size_(0),
637 total_bytes_(0),
638 had_error_(false),
639 aliasing_enabled_(false) {
640 if (do_eager_refresh) {
641 // Eagerly Refresh() so buffer space is immediately available.
642 Refresh();
643 // The Refresh() may have failed. If the client doesn't write any data,
644 // though, don't consider this an error. If the client does write data, then
645 // another Refresh() will be attempted and it will set the error once again.
646 had_error_ = false;
647 }
648}
649
temporal40ee5512008-07-10 02:12:20 +0000650CodedOutputStream::~CodedOutputStream() {
Jisi Liu885b6122015-02-28 14:51:22 -0800651 Trim();
652}
653
654void CodedOutputStream::Trim() {
temporal40ee5512008-07-10 02:12:20 +0000655 if (buffer_size_ > 0) {
656 output_->BackUp(buffer_size_);
Jisi Liu885b6122015-02-28 14:51:22 -0800657 total_bytes_ -= buffer_size_;
658 buffer_size_ = 0;
659 buffer_ = NULL;
temporal40ee5512008-07-10 02:12:20 +0000660 }
661}
662
kenton@google.com2d6daa72009-01-22 01:27:00 +0000663bool CodedOutputStream::Skip(int count) {
664 if (count < 0) return false;
665
666 while (count > buffer_size_) {
667 count -= buffer_size_;
668 if (!Refresh()) return false;
669 }
670
671 Advance(count);
672 return true;
673}
674
675bool CodedOutputStream::GetDirectBufferPointer(void** data, int* size) {
676 if (buffer_size_ == 0 && !Refresh()) return false;
677
678 *data = buffer_;
679 *size = buffer_size_;
680 return true;
681}
682
kenton@google.comd37d46d2009-04-25 02:53:47 +0000683void CodedOutputStream::WriteRaw(const void* data, int size) {
temporal40ee5512008-07-10 02:12:20 +0000684 while (buffer_size_ < size) {
685 memcpy(buffer_, data, buffer_size_);
686 size -= buffer_size_;
687 data = reinterpret_cast<const uint8*>(data) + buffer_size_;
kenton@google.comd37d46d2009-04-25 02:53:47 +0000688 if (!Refresh()) return;
temporal40ee5512008-07-10 02:12:20 +0000689 }
690
691 memcpy(buffer_, data, size);
692 Advance(size);
kenton@google.comd37d46d2009-04-25 02:53:47 +0000693}
694
695uint8* CodedOutputStream::WriteRawToArray(
696 const void* data, int size, uint8* target) {
697 memcpy(target, data, size);
698 return target + size;
temporal40ee5512008-07-10 02:12:20 +0000699}
700
701
jieluo@google.com4de8f552014-07-18 00:47:59 +0000702void CodedOutputStream::WriteAliasedRaw(const void* data, int size) {
703 if (size < buffer_size_
704 ) {
705 WriteRaw(data, size);
706 } else {
Jisi Liu885b6122015-02-28 14:51:22 -0800707 Trim();
jieluo@google.com4de8f552014-07-18 00:47:59 +0000708
709 total_bytes_ += size;
710 had_error_ |= !output_->WriteAliasedRaw(data, size);
711 }
712}
713
kenton@google.comd37d46d2009-04-25 02:53:47 +0000714void CodedOutputStream::WriteLittleEndian32(uint32 value) {
temporal40ee5512008-07-10 02:12:20 +0000715 uint8 bytes[sizeof(value)];
716
717 bool use_fast = buffer_size_ >= sizeof(value);
718 uint8* ptr = use_fast ? buffer_ : bytes;
719
kenton@google.com80b1d622009-07-29 01:13:20 +0000720 WriteLittleEndian32ToArray(value, ptr);
temporal40ee5512008-07-10 02:12:20 +0000721
722 if (use_fast) {
723 Advance(sizeof(value));
temporal40ee5512008-07-10 02:12:20 +0000724 } else {
kenton@google.comd37d46d2009-04-25 02:53:47 +0000725 WriteRaw(bytes, sizeof(value));
temporal40ee5512008-07-10 02:12:20 +0000726 }
727}
728
kenton@google.comd37d46d2009-04-25 02:53:47 +0000729void CodedOutputStream::WriteLittleEndian64(uint64 value) {
temporal40ee5512008-07-10 02:12:20 +0000730 uint8 bytes[sizeof(value)];
731
temporal40ee5512008-07-10 02:12:20 +0000732 bool use_fast = buffer_size_ >= sizeof(value);
733 uint8* ptr = use_fast ? buffer_ : bytes;
734
kenton@google.com80b1d622009-07-29 01:13:20 +0000735 WriteLittleEndian64ToArray(value, ptr);
temporal40ee5512008-07-10 02:12:20 +0000736
737 if (use_fast) {
738 Advance(sizeof(value));
temporal40ee5512008-07-10 02:12:20 +0000739 } else {
kenton@google.comd37d46d2009-04-25 02:53:47 +0000740 WriteRaw(bytes, sizeof(value));
temporal40ee5512008-07-10 02:12:20 +0000741 }
742}
743
Jisi Liu885b6122015-02-28 14:51:22 -0800744void CodedOutputStream::WriteVarint32SlowPath(uint32 value) {
745 uint8 bytes[kMaxVarint32Bytes];
746 uint8* target = &bytes[0];
747 uint8* end = WriteVarint32ToArray(value, target);
748 int size = end - target;
749 WriteRaw(bytes, size);
kenton@google.comd37d46d2009-04-25 02:53:47 +0000750}
751
752inline uint8* CodedOutputStream::WriteVarint64ToArrayInline(
753 uint64 value, uint8* target) {
754 // Splitting into 32-bit pieces gives better performance on 32-bit
755 // processors.
756 uint32 part0 = static_cast<uint32>(value );
757 uint32 part1 = static_cast<uint32>(value >> 28);
758 uint32 part2 = static_cast<uint32>(value >> 56);
759
760 int size;
761
762 // Here we can't really optimize for small numbers, since the value is
763 // split into three parts. Cheking for numbers < 128, for instance,
764 // would require three comparisons, since you'd have to make sure part1
765 // and part2 are zero. However, if the caller is using 64-bit integers,
766 // it is likely that they expect the numbers to often be very large, so
767 // we probably don't want to optimize for small numbers anyway. Thus,
768 // we end up with a hardcoded binary search tree...
769 if (part2 == 0) {
770 if (part1 == 0) {
771 if (part0 < (1 << 14)) {
772 if (part0 < (1 << 7)) {
773 size = 1; goto size1;
774 } else {
775 size = 2; goto size2;
776 }
777 } else {
778 if (part0 < (1 << 21)) {
779 size = 3; goto size3;
780 } else {
781 size = 4; goto size4;
782 }
783 }
784 } else {
785 if (part1 < (1 << 14)) {
786 if (part1 < (1 << 7)) {
787 size = 5; goto size5;
788 } else {
789 size = 6; goto size6;
790 }
791 } else {
792 if (part1 < (1 << 21)) {
793 size = 7; goto size7;
794 } else {
795 size = 8; goto size8;
796 }
797 }
798 }
799 } else {
800 if (part2 < (1 << 7)) {
801 size = 9; goto size9;
802 } else {
803 size = 10; goto size10;
804 }
805 }
806
807 GOOGLE_LOG(FATAL) << "Can't get here.";
808
809 size10: target[9] = static_cast<uint8>((part2 >> 7) | 0x80);
810 size9 : target[8] = static_cast<uint8>((part2 ) | 0x80);
811 size8 : target[7] = static_cast<uint8>((part1 >> 21) | 0x80);
812 size7 : target[6] = static_cast<uint8>((part1 >> 14) | 0x80);
813 size6 : target[5] = static_cast<uint8>((part1 >> 7) | 0x80);
814 size5 : target[4] = static_cast<uint8>((part1 ) | 0x80);
815 size4 : target[3] = static_cast<uint8>((part0 >> 21) | 0x80);
816 size3 : target[2] = static_cast<uint8>((part0 >> 14) | 0x80);
817 size2 : target[1] = static_cast<uint8>((part0 >> 7) | 0x80);
818 size1 : target[0] = static_cast<uint8>((part0 ) | 0x80);
819
820 target[size-1] &= 0x7F;
821 return target + size;
822}
823
824void CodedOutputStream::WriteVarint64(uint64 value) {
temporal40ee5512008-07-10 02:12:20 +0000825 if (buffer_size_ >= kMaxVarintBytes) {
826 // Fast path: We have enough bytes left in the buffer to guarantee that
827 // this write won't cross the end, so we can skip the checks.
828 uint8* target = buffer_;
829
kenton@google.comd37d46d2009-04-25 02:53:47 +0000830 uint8* end = WriteVarint64ToArrayInline(value, target);
831 int size = end - target;
temporal40ee5512008-07-10 02:12:20 +0000832 Advance(size);
temporal40ee5512008-07-10 02:12:20 +0000833 } else {
834 // Slow path: This write might cross the end of the buffer, so we
835 // compose the bytes first then use WriteRaw().
836 uint8 bytes[kMaxVarintBytes];
837 int size = 0;
838 while (value > 0x7F) {
839 bytes[size++] = (static_cast<uint8>(value) & 0x7F) | 0x80;
840 value >>= 7;
841 }
842 bytes[size++] = static_cast<uint8>(value) & 0x7F;
kenton@google.comd37d46d2009-04-25 02:53:47 +0000843 WriteRaw(bytes, size);
temporal40ee5512008-07-10 02:12:20 +0000844 }
845}
846
kenton@google.comd37d46d2009-04-25 02:53:47 +0000847uint8* CodedOutputStream::WriteVarint64ToArray(
848 uint64 value, uint8* target) {
849 return WriteVarint64ToArrayInline(value, target);
850}
851
temporal40ee5512008-07-10 02:12:20 +0000852bool CodedOutputStream::Refresh() {
853 void* void_buffer;
854 if (output_->Next(&void_buffer, &buffer_size_)) {
855 buffer_ = reinterpret_cast<uint8*>(void_buffer);
856 total_bytes_ += buffer_size_;
857 return true;
858 } else {
859 buffer_ = NULL;
860 buffer_size_ = 0;
kenton@google.comd37d46d2009-04-25 02:53:47 +0000861 had_error_ = true;
temporal40ee5512008-07-10 02:12:20 +0000862 return false;
863 }
864}
865
866int CodedOutputStream::VarintSize32Fallback(uint32 value) {
867 if (value < (1 << 7)) {
868 return 1;
869 } else if (value < (1 << 14)) {
870 return 2;
871 } else if (value < (1 << 21)) {
872 return 3;
873 } else if (value < (1 << 28)) {
874 return 4;
875 } else {
876 return 5;
877 }
878}
879
880int CodedOutputStream::VarintSize64(uint64 value) {
881 if (value < (1ull << 35)) {
882 if (value < (1ull << 7)) {
883 return 1;
884 } else if (value < (1ull << 14)) {
885 return 2;
886 } else if (value < (1ull << 21)) {
887 return 3;
888 } else if (value < (1ull << 28)) {
889 return 4;
890 } else {
891 return 5;
892 }
893 } else {
894 if (value < (1ull << 42)) {
895 return 6;
896 } else if (value < (1ull << 49)) {
897 return 7;
898 } else if (value < (1ull << 56)) {
899 return 8;
900 } else if (value < (1ull << 63)) {
901 return 9;
902 } else {
903 return 10;
904 }
905 }
906}
907
jieluo@google.com4de8f552014-07-18 00:47:59 +0000908uint8* CodedOutputStream::WriteStringWithSizeToArray(const string& str,
909 uint8* target) {
910 GOOGLE_DCHECK_LE(str.size(), kuint32max);
911 target = WriteVarint32ToArray(str.size(), target);
912 return WriteStringToArray(str, target);
913}
914
temporal40ee5512008-07-10 02:12:20 +0000915} // namespace io
916} // namespace protobuf
917} // namespace google