• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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