Home | History | Annotate | Download | only in io
      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 (at) 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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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;
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    540 CodedOutputStream::~CodedOutputStream() {
    541   if (buffer_size_ > 0) {
    542     output_->BackUp(buffer_size_);
    543   }
    544 }
    545 
    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 
    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 
    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 
    578 uint8* CodedOutputStream::WriteRawToArray(
    579     const void* data, int size, uint8* target) {
    580   memcpy(target, data, size);
    581   return target + size;
    582 }
    583 
    584 
    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 
    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 
    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 
    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 
    667 uint8* CodedOutputStream::WriteVarint32FallbackToArray(
    668     uint32 value, uint8* target) {
    669   return WriteVarint32FallbackToArrayInline(value, target);
    670 }
    671 
    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 
    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 
    767 uint8* CodedOutputStream::WriteVarint64ToArray(
    768     uint64 value, uint8* target) {
    769   return WriteVarint64ToArrayInline(value, target);
    770 }
    771 
    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 
    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 
    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