PageRenderTime 89ms CodeModel.GetById 26ms app.highlight 56ms RepoModel.GetById 1ms app.codeStats 1ms

/thirdparty/breakpad/third_party/protobuf/protobuf/src/google/protobuf/io/coded_stream.cc

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