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