diff options
Diffstat (limited to 'src/google/protobuf/io/coded_stream.cc')
-rw-r--r-- | src/google/protobuf/io/coded_stream.cc | 164 |
1 files changed, 40 insertions, 124 deletions
diff --git a/src/google/protobuf/io/coded_stream.cc b/src/google/protobuf/io/coded_stream.cc index 5344975..6a91a13 100644 --- a/src/google/protobuf/io/coded_stream.cc +++ b/src/google/protobuf/io/coded_stream.cc @@ -1,6 +1,6 @@ // Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ +// http://code.google.com/p/protobuf/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -43,7 +43,7 @@ #include <limits.h> #include <google/protobuf/io/zero_copy_stream.h> #include <google/protobuf/stubs/common.h> -#include <google/protobuf/stubs/stl_util.h> +#include <google/protobuf/stubs/stl_util-inl.h> namespace google { @@ -56,36 +56,10 @@ static const int kMaxVarintBytes = 10; static const int kMaxVarint32Bytes = 5; -inline bool NextNonEmpty(ZeroCopyInputStream* input, - const void** data, int* size) { - bool success; - do { - success = input->Next(data, size); - } while (success && *size == 0); - return success; -} - } // namespace // CodedInputStream ================================================== -CodedInputStream::~CodedInputStream() { - if (input_ != NULL) { - BackUpInputToCurrentPosition(); - } - - if (total_bytes_warning_threshold_ == -2) { - GOOGLE_LOG(WARNING) << "The total number of bytes read was " << total_bytes_read_; - } -} - -// Static. -int CodedInputStream::default_recursion_limit_ = 100; - - -void CodedOutputStream::EnableAliasing(bool enabled) { - aliasing_enabled_ = enabled && output_->AllowsAliasing(); -} void CodedInputStream::BackUpInputToCurrentPosition() { int backup_bytes = BufferSize() + buffer_size_after_limit_ + overflow_bytes_; @@ -115,7 +89,8 @@ inline void CodedInputStream::RecomputeBufferLimits() { CodedInputStream::Limit CodedInputStream::PushLimit(int byte_limit) { // Current position relative to the beginning of the stream. - int current_position = CurrentPosition(); + int current_position = total_bytes_read_ - + (BufferSize() + buffer_size_after_limit_); Limit old_limit = current_limit_; @@ -149,9 +124,10 @@ void CodedInputStream::PopLimit(Limit limit) { legitimate_message_end_ = false; } -int CodedInputStream::BytesUntilLimit() const { +int CodedInputStream::BytesUntilLimit() { if (current_limit_ == INT_MAX) return -1; - int current_position = CurrentPosition(); + int current_position = total_bytes_read_ - + (BufferSize() + buffer_size_after_limit_); return current_limit_ - current_position; } @@ -160,22 +136,13 @@ void CodedInputStream::SetTotalBytesLimit( int total_bytes_limit, int warning_threshold) { // Make sure the limit isn't already past, since this could confuse other // code. - int current_position = CurrentPosition(); + int current_position = total_bytes_read_ - + (BufferSize() + buffer_size_after_limit_); total_bytes_limit_ = max(current_position, total_bytes_limit); - if (warning_threshold >= 0) { - total_bytes_warning_threshold_ = warning_threshold; - } else { - // warning_threshold is negative - total_bytes_warning_threshold_ = -1; - } + total_bytes_warning_threshold_ = warning_threshold; RecomputeBufferLimits(); } -int CodedInputStream::BytesUntilTotalBytesLimit() const { - if (total_bytes_limit_ == INT_MAX) return -1; - return total_bytes_limit_ - CurrentPosition(); -} - void CodedInputStream::PrintTotalBytesLimitError() { GOOGLE_LOG(ERROR) << "A protocol message was rejected because it was too " "big (more than " << total_bytes_limit_ @@ -256,14 +223,6 @@ bool CodedInputStream::ReadStringFallback(string* buffer, int size) { buffer->clear(); } - int closest_limit = min(current_limit_, total_bytes_limit_); - if (closest_limit != INT_MAX) { - int bytes_to_limit = closest_limit - CurrentPosition(); - if (bytes_to_limit > 0 && size > 0 && size <= bytes_to_limit) { - buffer->reserve(size); - } - } - int current_buffer_size; while ((current_buffer_size = BufferSize()) < size) { // Some STL implementations "helpfully" crash on buffer->append(NULL, 0). @@ -330,16 +289,11 @@ inline const uint8* ReadVarint32FromArray(const uint8* buffer, uint32* value) { uint32 b; uint32 result; - b = *(ptr++); result = b ; if (!(b & 0x80)) goto done; - result -= 0x80; - b = *(ptr++); result += b << 7; if (!(b & 0x80)) goto done; - result -= 0x80 << 7; - b = *(ptr++); result += b << 14; if (!(b & 0x80)) goto done; - result -= 0x80 << 14; - b = *(ptr++); result += b << 21; if (!(b & 0x80)) goto done; - result -= 0x80 << 21; - b = *(ptr++); result += b << 28; if (!(b & 0x80)) goto done; - // "result -= 0x80 << 28" is irrevelant. + b = *(ptr++); result = (b & 0x7F) ; if (!(b & 0x80)) goto done; + b = *(ptr++); result |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done; + b = *(ptr++); result |= (b & 0x7F) << 14; if (!(b & 0x80)) goto done; + b = *(ptr++); result |= (b & 0x7F) << 21; if (!(b & 0x80)) goto done; + b = *(ptr++); result |= b << 28; if (!(b & 0x80)) goto done; // If the input is larger than 32 bits, we still need to read it all // and discard the high-order bits. @@ -369,8 +323,8 @@ bool CodedInputStream::ReadVarint32Slow(uint32* value) { bool CodedInputStream::ReadVarint32Fallback(uint32* value) { if (BufferSize() >= kMaxVarintBytes || - // Optimization: We're also safe if the buffer is non-empty and it ends - // with a byte that would terminate a varint. + // Optimization: If the varint ends at exactly the end of the buffer, + // we can detect that and still use the fast path. (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) { const uint8* end = ReadVarint32FromArray(buffer_, value); if (end == NULL) return false; @@ -405,17 +359,16 @@ uint32 CodedInputStream::ReadTagSlow() { // For the slow path, just do a 64-bit read. Try to optimize for one-byte tags // again, since we have now refreshed the buffer. - uint64 result = 0; + uint64 result; if (!ReadVarint64(&result)) return 0; return static_cast<uint32>(result); } uint32 CodedInputStream::ReadTagFallback() { - const int buf_size = BufferSize(); - if (buf_size >= kMaxVarintBytes || - // Optimization: We're also safe if the buffer is non-empty and it ends - // with a byte that would terminate a varint. - (buf_size > 0 && !(buffer_end_[-1] & 0x80))) { + if (BufferSize() >= kMaxVarintBytes || + // Optimization: If the varint ends at exactly the end of the buffer, + // we can detect that and still use the fast path. + (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) { uint32 tag; const uint8* end = ReadVarint32FromArray(buffer_, &tag); if (end == NULL) { @@ -426,9 +379,7 @@ uint32 CodedInputStream::ReadTagFallback() { } else { // We are commonly at a limit when attempting to read tags. Try to quickly // detect this case without making another function call. - if ((buf_size == 0) && - ((buffer_size_after_limit_ > 0) || - (total_bytes_read_ == current_limit_)) && + if (buffer_ == buffer_end_ && buffer_size_after_limit_ > 0 && // Make sure that the limit we hit is not total_bytes_limit_, since // in that case we still need to call Refresh() so that it prints an // error. @@ -466,8 +417,8 @@ bool CodedInputStream::ReadVarint64Slow(uint64* value) { bool CodedInputStream::ReadVarint64Fallback(uint64* value) { if (BufferSize() >= kMaxVarintBytes || - // Optimization: We're also safe if the buffer is non-empty and it ends - // with a byte that would terminate a varint. + // Optimization: If the varint ends at exactly the end of the buffer, + // we can detect that and still use the fast path. (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) { // Fast path: We have enough bytes left in the buffer to guarantee that // this read won't cross the end, so we can skip the checks. @@ -479,30 +430,20 @@ bool CodedInputStream::ReadVarint64Fallback(uint64* value) { // processors. uint32 part0 = 0, part1 = 0, part2 = 0; - b = *(ptr++); part0 = b ; if (!(b & 0x80)) goto done; - part0 -= 0x80; - b = *(ptr++); part0 += b << 7; if (!(b & 0x80)) goto done; - part0 -= 0x80 << 7; - b = *(ptr++); part0 += b << 14; if (!(b & 0x80)) goto done; - part0 -= 0x80 << 14; - b = *(ptr++); part0 += b << 21; if (!(b & 0x80)) goto done; - part0 -= 0x80 << 21; - b = *(ptr++); part1 = b ; if (!(b & 0x80)) goto done; - part1 -= 0x80; - b = *(ptr++); part1 += b << 7; if (!(b & 0x80)) goto done; - part1 -= 0x80 << 7; - b = *(ptr++); part1 += b << 14; if (!(b & 0x80)) goto done; - part1 -= 0x80 << 14; - b = *(ptr++); part1 += b << 21; if (!(b & 0x80)) goto done; - part1 -= 0x80 << 21; - b = *(ptr++); part2 = b ; if (!(b & 0x80)) goto done; - part2 -= 0x80; - b = *(ptr++); part2 += b << 7; if (!(b & 0x80)) goto done; - // "part2 -= 0x80 << 7" is irrelevant because (0x80 << 7) << 56 is 0. + b = *(ptr++); part0 = (b & 0x7F) ; if (!(b & 0x80)) goto done; + b = *(ptr++); part0 |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done; + b = *(ptr++); part0 |= (b & 0x7F) << 14; if (!(b & 0x80)) goto done; + b = *(ptr++); part0 |= (b & 0x7F) << 21; if (!(b & 0x80)) goto done; + b = *(ptr++); part1 = (b & 0x7F) ; if (!(b & 0x80)) goto done; + b = *(ptr++); part1 |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done; + b = *(ptr++); part1 |= (b & 0x7F) << 14; if (!(b & 0x80)) goto done; + b = *(ptr++); part1 |= (b & 0x7F) << 21; if (!(b & 0x80)) goto done; + b = *(ptr++); part2 = (b & 0x7F) ; if (!(b & 0x80)) goto done; + b = *(ptr++); part2 |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done; // We have overrun the maximum size of a varint (10 bytes). The data // must be corrupt. - return false; + return NULL; done: Advance(ptr - buffer_); @@ -542,13 +483,13 @@ bool CodedInputStream::Refresh() { "CodedInputStream::SetTotalBytesLimit() in " "google/protobuf/io/coded_stream.h."; - // Don't warn again for this stream, and print total size at the end. - total_bytes_warning_threshold_ = -2; + // Don't warn again for this stream. + total_bytes_warning_threshold_ = -1; } const void* void_buffer; int buffer_size; - if (NextNonEmpty(input_, &void_buffer, &buffer_size)) { + if (input_->Next(&void_buffer, &buffer_size)) { buffer_ = reinterpret_cast<const uint8*>(void_buffer); buffer_end_ = buffer_ + buffer_size; GOOGLE_CHECK_GE(buffer_size, 0); @@ -587,8 +528,7 @@ CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* output) buffer_(NULL), buffer_size_(0), total_bytes_(0), - had_error_(false), - aliasing_enabled_(false) { + had_error_(false) { // Eagerly Refresh() so buffer space is immediately available. Refresh(); // The Refresh() may have failed. If the client doesn't write any data, @@ -642,23 +582,6 @@ uint8* CodedOutputStream::WriteRawToArray( } -void CodedOutputStream::WriteAliasedRaw(const void* data, int size) { - if (size < buffer_size_ - ) { - WriteRaw(data, size); - } else { - if (buffer_size_ > 0) { - output_->BackUp(buffer_size_); - total_bytes_ -= buffer_size_; - buffer_ = NULL; - buffer_size_ = 0; - } - - total_bytes_ += size; - had_error_ |= !output_->WriteAliasedRaw(data, size); - } -} - void CodedOutputStream::WriteLittleEndian32(uint32 value) { uint8 bytes[sizeof(value)]; @@ -902,13 +825,6 @@ int CodedOutputStream::VarintSize64(uint64 value) { } } -uint8* CodedOutputStream::WriteStringWithSizeToArray(const string& str, - uint8* target) { - GOOGLE_DCHECK_LE(str.size(), kuint32max); - target = WriteVarint32ToArray(str.size(), target); - return WriteStringToArray(str, target); -} - } // namespace io } // namespace protobuf } // namespace google |