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