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