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