1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 // http://code.google.com/p/protobuf/
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 <limits.h>
44 #include <google/protobuf/io/zero_copy_stream.h>
45 #include <google/protobuf/stubs/common.h>
46 #include <google/protobuf/stubs/stl_util.h>
47
48
49 namespace google {
50 namespace protobuf {
51 namespace io {
52
53 namespace {
54
55 static const int kMaxVarintBytes = 10;
56 static const int kMaxVarint32Bytes = 5;
57
58
NextNonEmpty(ZeroCopyInputStream * input,const void ** data,int * size)59 inline bool NextNonEmpty(ZeroCopyInputStream* input,
60 const void** data, int* size) {
61 bool success;
62 do {
63 success = input->Next(data, size);
64 } while (success && *size == 0);
65 return success;
66 }
67
68 } // namespace
69
70 // CodedInputStream ==================================================
71
~CodedInputStream()72 CodedInputStream::~CodedInputStream() {
73 if (input_ != NULL) {
74 BackUpInputToCurrentPosition();
75 }
76
77 if (total_bytes_warning_threshold_ == -2) {
78 GOOGLE_LOG(WARNING) << "The total number of bytes read was " << total_bytes_read_;
79 }
80 }
81
82 // Static.
83 int CodedInputStream::default_recursion_limit_ = 100;
84
85
BackUpInputToCurrentPosition()86 void CodedInputStream::BackUpInputToCurrentPosition() {
87 int backup_bytes = BufferSize() + buffer_size_after_limit_ + overflow_bytes_;
88 if (backup_bytes > 0) {
89 input_->BackUp(backup_bytes);
90
91 // total_bytes_read_ doesn't include overflow_bytes_.
92 total_bytes_read_ -= BufferSize() + buffer_size_after_limit_;
93 buffer_end_ = buffer_;
94 buffer_size_after_limit_ = 0;
95 overflow_bytes_ = 0;
96 }
97 }
98
RecomputeBufferLimits()99 inline void CodedInputStream::RecomputeBufferLimits() {
100 buffer_end_ += buffer_size_after_limit_;
101 int closest_limit = min(current_limit_, total_bytes_limit_);
102 if (closest_limit < total_bytes_read_) {
103 // The limit position is in the current buffer. We must adjust
104 // the buffer size accordingly.
105 buffer_size_after_limit_ = total_bytes_read_ - closest_limit;
106 buffer_end_ -= buffer_size_after_limit_;
107 } else {
108 buffer_size_after_limit_ = 0;
109 }
110 }
111
PushLimit(int byte_limit)112 CodedInputStream::Limit CodedInputStream::PushLimit(int byte_limit) {
113 // Current position relative to the beginning of the stream.
114 int current_position = CurrentPosition();
115
116 Limit old_limit = current_limit_;
117
118 // security: byte_limit is possibly evil, so check for negative values
119 // and overflow.
120 if (byte_limit >= 0 &&
121 byte_limit <= INT_MAX - current_position) {
122 current_limit_ = current_position + byte_limit;
123 } else {
124 // Negative or overflow.
125 current_limit_ = INT_MAX;
126 }
127
128 // We need to enforce all limits, not just the new one, so if the previous
129 // limit was before the new requested limit, we continue to enforce the
130 // previous limit.
131 current_limit_ = min(current_limit_, old_limit);
132
133 RecomputeBufferLimits();
134 return old_limit;
135 }
136
PopLimit(Limit limit)137 void CodedInputStream::PopLimit(Limit limit) {
138 // The limit passed in is actually the *old* limit, which we returned from
139 // PushLimit().
140 current_limit_ = limit;
141 RecomputeBufferLimits();
142
143 // We may no longer be at a legitimate message end. ReadTag() needs to be
144 // called again to find out.
145 legitimate_message_end_ = false;
146 }
147
BytesUntilLimit() const148 int CodedInputStream::BytesUntilLimit() const {
149 if (current_limit_ == INT_MAX) return -1;
150 int current_position = CurrentPosition();
151
152 return current_limit_ - current_position;
153 }
154
SetTotalBytesLimit(int total_bytes_limit,int warning_threshold)155 void CodedInputStream::SetTotalBytesLimit(
156 int total_bytes_limit, int warning_threshold) {
157 // Make sure the limit isn't already past, since this could confuse other
158 // code.
159 int current_position = CurrentPosition();
160 total_bytes_limit_ = max(current_position, total_bytes_limit);
161 if (warning_threshold >= 0) {
162 total_bytes_warning_threshold_ = warning_threshold;
163 } else {
164 // warning_threshold is negative
165 total_bytes_warning_threshold_ = -1;
166 }
167 RecomputeBufferLimits();
168 }
169
PrintTotalBytesLimitError()170 void CodedInputStream::PrintTotalBytesLimitError() {
171 GOOGLE_LOG(ERROR) << "A protocol message was rejected because it was too "
172 "big (more than " << total_bytes_limit_
173 << " bytes). To increase the limit (or to disable these "
174 "warnings), see CodedInputStream::SetTotalBytesLimit() "
175 "in google/protobuf/io/coded_stream.h.";
176 }
177
Skip(int count)178 bool CodedInputStream::Skip(int count) {
179 if (count < 0) return false; // security: count is often user-supplied
180
181 const int original_buffer_size = BufferSize();
182
183 if (count <= original_buffer_size) {
184 // Just skipping within the current buffer. Easy.
185 Advance(count);
186 return true;
187 }
188
189 if (buffer_size_after_limit_ > 0) {
190 // We hit a limit inside this buffer. Advance to the limit and fail.
191 Advance(original_buffer_size);
192 return false;
193 }
194
195 count -= original_buffer_size;
196 buffer_ = NULL;
197 buffer_end_ = buffer_;
198
199 // Make sure this skip doesn't try to skip past the current limit.
200 int closest_limit = min(current_limit_, total_bytes_limit_);
201 int bytes_until_limit = closest_limit - total_bytes_read_;
202 if (bytes_until_limit < count) {
203 // We hit the limit. Skip up to it then fail.
204 if (bytes_until_limit > 0) {
205 total_bytes_read_ = closest_limit;
206 input_->Skip(bytes_until_limit);
207 }
208 return false;
209 }
210
211 total_bytes_read_ += count;
212 return input_->Skip(count);
213 }
214
GetDirectBufferPointer(const void ** data,int * size)215 bool CodedInputStream::GetDirectBufferPointer(const void** data, int* size) {
216 if (BufferSize() == 0 && !Refresh()) return false;
217
218 *data = buffer_;
219 *size = BufferSize();
220 return true;
221 }
222
ReadRaw(void * buffer,int size)223 bool CodedInputStream::ReadRaw(void* buffer, int size) {
224 int current_buffer_size;
225 while ((current_buffer_size = BufferSize()) < size) {
226 // Reading past end of buffer. Copy what we have, then refresh.
227 memcpy(buffer, buffer_, current_buffer_size);
228 buffer = reinterpret_cast<uint8*>(buffer) + current_buffer_size;
229 size -= current_buffer_size;
230 Advance(current_buffer_size);
231 if (!Refresh()) return false;
232 }
233
234 memcpy(buffer, buffer_, size);
235 Advance(size);
236
237 return true;
238 }
239
ReadString(string * buffer,int size)240 bool 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
ReadStringFallback(string * buffer,int size)245 bool CodedInputStream::ReadStringFallback(string* buffer, int size) {
246 if (!buffer->empty()) {
247 buffer->clear();
248 }
249
250 int current_buffer_size;
251 while ((current_buffer_size = BufferSize()) < size) {
252 // Some STL implementations "helpfully" crash on buffer->append(NULL, 0).
253 if (current_buffer_size != 0) {
254 // Note: string1.append(string2) is O(string2.size()) (as opposed to
255 // O(string1.size() + string2.size()), which would be bad).
256 buffer->append(reinterpret_cast<const char*>(buffer_),
257 current_buffer_size);
258 }
259 size -= current_buffer_size;
260 Advance(current_buffer_size);
261 if (!Refresh()) return false;
262 }
263
264 buffer->append(reinterpret_cast<const char*>(buffer_), size);
265 Advance(size);
266
267 return true;
268 }
269
270
ReadLittleEndian32Fallback(uint32 * value)271 bool CodedInputStream::ReadLittleEndian32Fallback(uint32* value) {
272 uint8 bytes[sizeof(*value)];
273
274 const uint8* ptr;
275 if (BufferSize() >= sizeof(*value)) {
276 // Fast path: Enough bytes in the buffer to read directly.
277 ptr = buffer_;
278 Advance(sizeof(*value));
279 } else {
280 // Slow path: Had to read past the end of the buffer.
281 if (!ReadRaw(bytes, sizeof(*value))) return false;
282 ptr = bytes;
283 }
284 ReadLittleEndian32FromArray(ptr, value);
285 return true;
286 }
287
ReadLittleEndian64Fallback(uint64 * value)288 bool CodedInputStream::ReadLittleEndian64Fallback(uint64* value) {
289 uint8 bytes[sizeof(*value)];
290
291 const uint8* ptr;
292 if (BufferSize() >= sizeof(*value)) {
293 // Fast path: Enough bytes in the buffer to read directly.
294 ptr = buffer_;
295 Advance(sizeof(*value));
296 } else {
297 // Slow path: Had to read past the end of the buffer.
298 if (!ReadRaw(bytes, sizeof(*value))) return false;
299 ptr = bytes;
300 }
301 ReadLittleEndian64FromArray(ptr, value);
302 return true;
303 }
304
305 namespace {
306
307 inline const uint8* ReadVarint32FromArray(
308 const uint8* buffer, uint32* value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
ReadVarint32FromArray(const uint8 * buffer,uint32 * value)309 inline const uint8* ReadVarint32FromArray(const uint8* buffer, uint32* value) {
310 // Fast path: We have enough bytes left in the buffer to guarantee that
311 // this read won't cross the end, so we can skip the checks.
312 const uint8* ptr = buffer;
313 uint32 b;
314 uint32 result;
315
316 b = *(ptr++); result = (b & 0x7F) ; if (!(b & 0x80)) goto done;
317 b = *(ptr++); result |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done;
318 b = *(ptr++); result |= (b & 0x7F) << 14; if (!(b & 0x80)) goto done;
319 b = *(ptr++); result |= (b & 0x7F) << 21; if (!(b & 0x80)) goto done;
320 b = *(ptr++); result |= b << 28; if (!(b & 0x80)) goto done;
321
322 // If the input is larger than 32 bits, we still need to read it all
323 // and discard the high-order bits.
324 for (int i = 0; i < kMaxVarintBytes - kMaxVarint32Bytes; i++) {
325 b = *(ptr++); if (!(b & 0x80)) goto done;
326 }
327
328 // We have overrun the maximum size of a varint (10 bytes). Assume
329 // the data is corrupt.
330 return NULL;
331
332 done:
333 *value = result;
334 return ptr;
335 }
336
337 } // namespace
338
ReadVarint32Slow(uint32 * value)339 bool CodedInputStream::ReadVarint32Slow(uint32* value) {
340 uint64 result;
341 // Directly invoke ReadVarint64Fallback, since we already tried to optimize
342 // for one-byte varints.
343 if (!ReadVarint64Fallback(&result)) return false;
344 *value = (uint32)result;
345 return true;
346 }
347
ReadVarint32Fallback(uint32 * value)348 bool CodedInputStream::ReadVarint32Fallback(uint32* value) {
349 if (BufferSize() >= kMaxVarintBytes ||
350 // Optimization: If the varint ends at exactly the end of the buffer,
351 // we can detect that and still use the fast path.
352 (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
353 const uint8* end = ReadVarint32FromArray(buffer_, value);
354 if (end == NULL) return false;
355 buffer_ = end;
356 return true;
357 } else {
358 // Really slow case: we will incur the cost of an extra function call here,
359 // but moving this out of line reduces the size of this function, which
360 // improves the common case. In micro benchmarks, this is worth about 10-15%
361 return ReadVarint32Slow(value);
362 }
363 }
364
ReadTagSlow()365 uint32 CodedInputStream::ReadTagSlow() {
366 if (buffer_ == buffer_end_) {
367 // Call refresh.
368 if (!Refresh()) {
369 // Refresh failed. Make sure that it failed due to EOF, not because
370 // we hit total_bytes_limit_, which, unlike normal limits, is not a
371 // valid place to end a message.
372 int current_position = total_bytes_read_ - buffer_size_after_limit_;
373 if (current_position >= total_bytes_limit_) {
374 // Hit total_bytes_limit_. But if we also hit the normal limit,
375 // we're still OK.
376 legitimate_message_end_ = current_limit_ == total_bytes_limit_;
377 } else {
378 legitimate_message_end_ = true;
379 }
380 return 0;
381 }
382 }
383
384 // For the slow path, just do a 64-bit read. Try to optimize for one-byte tags
385 // again, since we have now refreshed the buffer.
386 uint64 result = 0;
387 if (!ReadVarint64(&result)) return 0;
388 return static_cast<uint32>(result);
389 }
390
ReadTagFallback()391 uint32 CodedInputStream::ReadTagFallback() {
392 const int buf_size = BufferSize();
393 if (buf_size >= kMaxVarintBytes ||
394 // Optimization: If the varint ends at exactly the end of the buffer,
395 // we can detect that and still use the fast path.
396 (buf_size > 0 && !(buffer_end_[-1] & 0x80))) {
397 uint32 tag;
398 const uint8* end = ReadVarint32FromArray(buffer_, &tag);
399 if (end == NULL) {
400 return 0;
401 }
402 buffer_ = end;
403 return tag;
404 } else {
405 // We are commonly at a limit when attempting to read tags. Try to quickly
406 // detect this case without making another function call.
407 if ((buf_size == 0) &&
408 ((buffer_size_after_limit_ > 0) ||
409 (total_bytes_read_ == current_limit_)) &&
410 // Make sure that the limit we hit is not total_bytes_limit_, since
411 // in that case we still need to call Refresh() so that it prints an
412 // error.
413 total_bytes_read_ - buffer_size_after_limit_ < total_bytes_limit_) {
414 // We hit a byte limit.
415 legitimate_message_end_ = true;
416 return 0;
417 }
418 return ReadTagSlow();
419 }
420 }
421
ReadVarint64Slow(uint64 * value)422 bool CodedInputStream::ReadVarint64Slow(uint64* value) {
423 // Slow path: This read might cross the end of the buffer, so we
424 // need to check and refresh the buffer if and when it does.
425
426 uint64 result = 0;
427 int count = 0;
428 uint32 b;
429
430 do {
431 if (count == kMaxVarintBytes) return false;
432 while (buffer_ == buffer_end_) {
433 if (!Refresh()) return false;
434 }
435 b = *buffer_;
436 result |= static_cast<uint64>(b & 0x7F) << (7 * count);
437 Advance(1);
438 ++count;
439 } while (b & 0x80);
440
441 *value = result;
442 return true;
443 }
444
ReadVarint64Fallback(uint64 * value)445 bool CodedInputStream::ReadVarint64Fallback(uint64* value) {
446 if (BufferSize() >= kMaxVarintBytes ||
447 // Optimization: If the varint ends at exactly the end of the buffer,
448 // we can detect that and still use the fast path.
449 (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
450 // Fast path: We have enough bytes left in the buffer to guarantee that
451 // this read won't cross the end, so we can skip the checks.
452
453 const uint8* ptr = buffer_;
454 uint32 b;
455
456 // Splitting into 32-bit pieces gives better performance on 32-bit
457 // processors.
458 uint32 part0 = 0, part1 = 0, part2 = 0;
459
460 b = *(ptr++); part0 = (b & 0x7F) ; if (!(b & 0x80)) goto done;
461 b = *(ptr++); part0 |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done;
462 b = *(ptr++); part0 |= (b & 0x7F) << 14; if (!(b & 0x80)) goto done;
463 b = *(ptr++); part0 |= (b & 0x7F) << 21; if (!(b & 0x80)) goto done;
464 b = *(ptr++); part1 = (b & 0x7F) ; if (!(b & 0x80)) goto done;
465 b = *(ptr++); part1 |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done;
466 b = *(ptr++); part1 |= (b & 0x7F) << 14; if (!(b & 0x80)) goto done;
467 b = *(ptr++); part1 |= (b & 0x7F) << 21; if (!(b & 0x80)) goto done;
468 b = *(ptr++); part2 = (b & 0x7F) ; if (!(b & 0x80)) goto done;
469 b = *(ptr++); part2 |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done;
470
471 // We have overrun the maximum size of a varint (10 bytes). The data
472 // must be corrupt.
473 return false;
474
475 done:
476 Advance(ptr - buffer_);
477 *value = (static_cast<uint64>(part0) ) |
478 (static_cast<uint64>(part1) << 28) |
479 (static_cast<uint64>(part2) << 56);
480 return true;
481 } else {
482 return ReadVarint64Slow(value);
483 }
484 }
485
Refresh()486 bool CodedInputStream::Refresh() {
487 GOOGLE_DCHECK_EQ(0, BufferSize());
488
489 if (buffer_size_after_limit_ > 0 || overflow_bytes_ > 0 ||
490 total_bytes_read_ == current_limit_) {
491 // We've hit a limit. Stop.
492 int current_position = total_bytes_read_ - buffer_size_after_limit_;
493
494 if (current_position >= total_bytes_limit_ &&
495 total_bytes_limit_ != current_limit_) {
496 // Hit total_bytes_limit_.
497 PrintTotalBytesLimitError();
498 }
499
500 return false;
501 }
502
503 if (total_bytes_warning_threshold_ >= 0 &&
504 total_bytes_read_ >= total_bytes_warning_threshold_) {
505 GOOGLE_LOG(WARNING) << "Reading dangerously large protocol message. If the "
506 "message turns out to be larger than "
507 << total_bytes_limit_ << " bytes, parsing will be halted "
508 "for security reasons. To increase the limit (or to "
509 "disable these warnings), see "
510 "CodedInputStream::SetTotalBytesLimit() in "
511 "google/protobuf/io/coded_stream.h.";
512
513 // Don't warn again for this stream, and print total size at the end.
514 total_bytes_warning_threshold_ = -2;
515 }
516
517 const void* void_buffer;
518 int buffer_size;
519 if (NextNonEmpty(input_, &void_buffer, &buffer_size)) {
520 buffer_ = reinterpret_cast<const uint8*>(void_buffer);
521 buffer_end_ = buffer_ + buffer_size;
522 GOOGLE_CHECK_GE(buffer_size, 0);
523
524 if (total_bytes_read_ <= INT_MAX - buffer_size) {
525 total_bytes_read_ += buffer_size;
526 } else {
527 // Overflow. Reset buffer_end_ to not include the bytes beyond INT_MAX.
528 // We can't get that far anyway, because total_bytes_limit_ is guaranteed
529 // to be less than it. We need to keep track of the number of bytes
530 // we discarded, though, so that we can call input_->BackUp() to back
531 // up over them on destruction.
532
533 // The following line is equivalent to:
534 // overflow_bytes_ = total_bytes_read_ + buffer_size - INT_MAX;
535 // except that it avoids overflows. Signed integer overflow has
536 // undefined results according to the C standard.
537 overflow_bytes_ = total_bytes_read_ - (INT_MAX - buffer_size);
538 buffer_end_ -= overflow_bytes_;
539 total_bytes_read_ = INT_MAX;
540 }
541
542 RecomputeBufferLimits();
543 return true;
544 } else {
545 buffer_ = NULL;
546 buffer_end_ = NULL;
547 return false;
548 }
549 }
550
551 // CodedOutputStream =================================================
552
CodedOutputStream(ZeroCopyOutputStream * output)553 CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* output)
554 : output_(output),
555 buffer_(NULL),
556 buffer_size_(0),
557 total_bytes_(0),
558 had_error_(false) {
559 // Eagerly Refresh() so buffer space is immediately available.
560 Refresh();
561 // The Refresh() may have failed. If the client doesn't write any data,
562 // though, don't consider this an error. If the client does write data, then
563 // another Refresh() will be attempted and it will set the error once again.
564 had_error_ = false;
565 }
566
~CodedOutputStream()567 CodedOutputStream::~CodedOutputStream() {
568 if (buffer_size_ > 0) {
569 output_->BackUp(buffer_size_);
570 }
571 }
572
Skip(int count)573 bool CodedOutputStream::Skip(int count) {
574 if (count < 0) return false;
575
576 while (count > buffer_size_) {
577 count -= buffer_size_;
578 if (!Refresh()) return false;
579 }
580
581 Advance(count);
582 return true;
583 }
584
GetDirectBufferPointer(void ** data,int * size)585 bool CodedOutputStream::GetDirectBufferPointer(void** data, int* size) {
586 if (buffer_size_ == 0 && !Refresh()) return false;
587
588 *data = buffer_;
589 *size = buffer_size_;
590 return true;
591 }
592
WriteRaw(const void * data,int size)593 void CodedOutputStream::WriteRaw(const void* data, int size) {
594 while (buffer_size_ < size) {
595 memcpy(buffer_, data, buffer_size_);
596 size -= buffer_size_;
597 data = reinterpret_cast<const uint8*>(data) + buffer_size_;
598 if (!Refresh()) return;
599 }
600
601 memcpy(buffer_, data, size);
602 Advance(size);
603 }
604
WriteRawToArray(const void * data,int size,uint8 * target)605 uint8* CodedOutputStream::WriteRawToArray(
606 const void* data, int size, uint8* target) {
607 memcpy(target, data, size);
608 return target + size;
609 }
610
611
WriteLittleEndian32(uint32 value)612 void CodedOutputStream::WriteLittleEndian32(uint32 value) {
613 uint8 bytes[sizeof(value)];
614
615 bool use_fast = buffer_size_ >= sizeof(value);
616 uint8* ptr = use_fast ? buffer_ : bytes;
617
618 WriteLittleEndian32ToArray(value, ptr);
619
620 if (use_fast) {
621 Advance(sizeof(value));
622 } else {
623 WriteRaw(bytes, sizeof(value));
624 }
625 }
626
WriteLittleEndian64(uint64 value)627 void CodedOutputStream::WriteLittleEndian64(uint64 value) {
628 uint8 bytes[sizeof(value)];
629
630 bool use_fast = buffer_size_ >= sizeof(value);
631 uint8* ptr = use_fast ? buffer_ : bytes;
632
633 WriteLittleEndian64ToArray(value, ptr);
634
635 if (use_fast) {
636 Advance(sizeof(value));
637 } else {
638 WriteRaw(bytes, sizeof(value));
639 }
640 }
641
WriteVarint32FallbackToArrayInline(uint32 value,uint8 * target)642 inline uint8* CodedOutputStream::WriteVarint32FallbackToArrayInline(
643 uint32 value, uint8* target) {
644 target[0] = static_cast<uint8>(value | 0x80);
645 if (value >= (1 << 7)) {
646 target[1] = static_cast<uint8>((value >> 7) | 0x80);
647 if (value >= (1 << 14)) {
648 target[2] = static_cast<uint8>((value >> 14) | 0x80);
649 if (value >= (1 << 21)) {
650 target[3] = static_cast<uint8>((value >> 21) | 0x80);
651 if (value >= (1 << 28)) {
652 target[4] = static_cast<uint8>(value >> 28);
653 return target + 5;
654 } else {
655 target[3] &= 0x7F;
656 return target + 4;
657 }
658 } else {
659 target[2] &= 0x7F;
660 return target + 3;
661 }
662 } else {
663 target[1] &= 0x7F;
664 return target + 2;
665 }
666 } else {
667 target[0] &= 0x7F;
668 return target + 1;
669 }
670 }
671
WriteVarint32(uint32 value)672 void CodedOutputStream::WriteVarint32(uint32 value) {
673 if (buffer_size_ >= kMaxVarint32Bytes) {
674 // Fast path: We have enough bytes left in the buffer to guarantee that
675 // this write won't cross the end, so we can skip the checks.
676 uint8* target = buffer_;
677 uint8* end = WriteVarint32FallbackToArrayInline(value, target);
678 int size = end - target;
679 Advance(size);
680 } else {
681 // Slow path: This write might cross the end of the buffer, so we
682 // compose the bytes first then use WriteRaw().
683 uint8 bytes[kMaxVarint32Bytes];
684 int size = 0;
685 while (value > 0x7F) {
686 bytes[size++] = (static_cast<uint8>(value) & 0x7F) | 0x80;
687 value >>= 7;
688 }
689 bytes[size++] = static_cast<uint8>(value) & 0x7F;
690 WriteRaw(bytes, size);
691 }
692 }
693
WriteVarint32FallbackToArray(uint32 value,uint8 * target)694 uint8* CodedOutputStream::WriteVarint32FallbackToArray(
695 uint32 value, uint8* target) {
696 return WriteVarint32FallbackToArrayInline(value, target);
697 }
698
WriteVarint64ToArrayInline(uint64 value,uint8 * target)699 inline uint8* CodedOutputStream::WriteVarint64ToArrayInline(
700 uint64 value, uint8* target) {
701 // Splitting into 32-bit pieces gives better performance on 32-bit
702 // processors.
703 uint32 part0 = static_cast<uint32>(value );
704 uint32 part1 = static_cast<uint32>(value >> 28);
705 uint32 part2 = static_cast<uint32>(value >> 56);
706
707 int size;
708
709 // Here we can't really optimize for small numbers, since the value is
710 // split into three parts. Cheking for numbers < 128, for instance,
711 // would require three comparisons, since you'd have to make sure part1
712 // and part2 are zero. However, if the caller is using 64-bit integers,
713 // it is likely that they expect the numbers to often be very large, so
714 // we probably don't want to optimize for small numbers anyway. Thus,
715 // we end up with a hardcoded binary search tree...
716 if (part2 == 0) {
717 if (part1 == 0) {
718 if (part0 < (1 << 14)) {
719 if (part0 < (1 << 7)) {
720 size = 1; goto size1;
721 } else {
722 size = 2; goto size2;
723 }
724 } else {
725 if (part0 < (1 << 21)) {
726 size = 3; goto size3;
727 } else {
728 size = 4; goto size4;
729 }
730 }
731 } else {
732 if (part1 < (1 << 14)) {
733 if (part1 < (1 << 7)) {
734 size = 5; goto size5;
735 } else {
736 size = 6; goto size6;
737 }
738 } else {
739 if (part1 < (1 << 21)) {
740 size = 7; goto size7;
741 } else {
742 size = 8; goto size8;
743 }
744 }
745 }
746 } else {
747 if (part2 < (1 << 7)) {
748 size = 9; goto size9;
749 } else {
750 size = 10; goto size10;
751 }
752 }
753
754 GOOGLE_LOG(FATAL) << "Can't get here.";
755
756 size10: target[9] = static_cast<uint8>((part2 >> 7) | 0x80);
757 size9 : target[8] = static_cast<uint8>((part2 ) | 0x80);
758 size8 : target[7] = static_cast<uint8>((part1 >> 21) | 0x80);
759 size7 : target[6] = static_cast<uint8>((part1 >> 14) | 0x80);
760 size6 : target[5] = static_cast<uint8>((part1 >> 7) | 0x80);
761 size5 : target[4] = static_cast<uint8>((part1 ) | 0x80);
762 size4 : target[3] = static_cast<uint8>((part0 >> 21) | 0x80);
763 size3 : target[2] = static_cast<uint8>((part0 >> 14) | 0x80);
764 size2 : target[1] = static_cast<uint8>((part0 >> 7) | 0x80);
765 size1 : target[0] = static_cast<uint8>((part0 ) | 0x80);
766
767 target[size-1] &= 0x7F;
768 return target + size;
769 }
770
WriteVarint64(uint64 value)771 void CodedOutputStream::WriteVarint64(uint64 value) {
772 if (buffer_size_ >= kMaxVarintBytes) {
773 // Fast path: We have enough bytes left in the buffer to guarantee that
774 // this write won't cross the end, so we can skip the checks.
775 uint8* target = buffer_;
776
777 uint8* end = WriteVarint64ToArrayInline(value, target);
778 int size = end - target;
779 Advance(size);
780 } else {
781 // Slow path: This write might cross the end of the buffer, so we
782 // compose the bytes first then use WriteRaw().
783 uint8 bytes[kMaxVarintBytes];
784 int size = 0;
785 while (value > 0x7F) {
786 bytes[size++] = (static_cast<uint8>(value) & 0x7F) | 0x80;
787 value >>= 7;
788 }
789 bytes[size++] = static_cast<uint8>(value) & 0x7F;
790 WriteRaw(bytes, size);
791 }
792 }
793
WriteVarint64ToArray(uint64 value,uint8 * target)794 uint8* CodedOutputStream::WriteVarint64ToArray(
795 uint64 value, uint8* target) {
796 return WriteVarint64ToArrayInline(value, target);
797 }
798
Refresh()799 bool CodedOutputStream::Refresh() {
800 void* void_buffer;
801 if (output_->Next(&void_buffer, &buffer_size_)) {
802 buffer_ = reinterpret_cast<uint8*>(void_buffer);
803 total_bytes_ += buffer_size_;
804 return true;
805 } else {
806 buffer_ = NULL;
807 buffer_size_ = 0;
808 had_error_ = true;
809 return false;
810 }
811 }
812
VarintSize32Fallback(uint32 value)813 int CodedOutputStream::VarintSize32Fallback(uint32 value) {
814 if (value < (1 << 7)) {
815 return 1;
816 } else if (value < (1 << 14)) {
817 return 2;
818 } else if (value < (1 << 21)) {
819 return 3;
820 } else if (value < (1 << 28)) {
821 return 4;
822 } else {
823 return 5;
824 }
825 }
826
VarintSize64(uint64 value)827 int CodedOutputStream::VarintSize64(uint64 value) {
828 if (value < (1ull << 35)) {
829 if (value < (1ull << 7)) {
830 return 1;
831 } else if (value < (1ull << 14)) {
832 return 2;
833 } else if (value < (1ull << 21)) {
834 return 3;
835 } else if (value < (1ull << 28)) {
836 return 4;
837 } else {
838 return 5;
839 }
840 } else {
841 if (value < (1ull << 42)) {
842 return 6;
843 } else if (value < (1ull << 49)) {
844 return 7;
845 } else if (value < (1ull << 56)) {
846 return 8;
847 } else if (value < (1ull << 63)) {
848 return 9;
849 } else {
850 return 10;
851 }
852 }
853 }
854
855 } // namespace io
856 } // namespace protobuf
857 } // namespace google
858