aboutsummaryrefslogtreecommitdiffstats
path: root/src/google/protobuf/io/coded_stream.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/google/protobuf/io/coded_stream.h')
-rw-r--r--src/google/protobuf/io/coded_stream.h218
1 files changed, 44 insertions, 174 deletions
diff --git a/src/google/protobuf/io/coded_stream.h b/src/google/protobuf/io/coded_stream.h
index 81fabb1..e5f6161 100644
--- a/src/google/protobuf/io/coded_stream.h
+++ b/src/google/protobuf/io/coded_stream.h
@@ -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
@@ -110,27 +110,14 @@
#define GOOGLE_PROTOBUF_IO_CODED_STREAM_H__
#include <string>
-#ifdef _MSC_VER
- #if defined(_M_IX86) && \
- !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST)
- #define PROTOBUF_LITTLE_ENDIAN 1
- #endif
- #if _MSC_VER >= 1300
- // If MSVC has "/RTCc" set, it will complain about truncating casts at
- // runtime. This file contains some intentional truncating casts.
- #pragma runtime_checks("c", off)
- #endif
-#else
- #include <sys/param.h> // __BYTE_ORDER
- #if defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN && \
- !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST)
- #define PROTOBUF_LITTLE_ENDIAN 1
- #endif
-#endif
+#ifndef _MSC_VER
+#include <sys/param.h>
+#endif // !_MSC_VER
#include <google/protobuf/stubs/common.h>
-
+#include <google/protobuf/stubs/common.h> // for GOOGLE_PREDICT_TRUE macro
namespace google {
+
namespace protobuf {
class DescriptorPool;
@@ -170,9 +157,6 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
// successfully and the stream's byte limit.
~CodedInputStream();
- // Return true if this CodedInputStream reads from a flat array instead of
- // a ZeroCopyInputStream.
- inline bool IsFlat() const;
// Skips a number of bytes. Returns false if an underlying read error
// occurs.
@@ -233,22 +217,11 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
// Read a tag. This calls ReadVarint32() and returns the result, or returns
// zero (which is not a valid tag) if ReadVarint32() fails. Also, it updates
// the last tag value, which can be checked with LastTagWas().
- // Always inline because this is only called in one place per parse loop
+ // Always inline because this is only called in once place per parse loop
// but it is called for every iteration of said loop, so it should be fast.
// GCC doesn't want to inline this by default.
uint32 ReadTag() GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
- // This usually a faster alternative to ReadTag() when cutoff is a manifest
- // constant. It does particularly well for cutoff >= 127. The first part
- // of the return value is the tag that was read, though it can also be 0 in
- // the cases where ReadTag() would return 0. If the second part is true
- // then the tag is known to be in [0, cutoff]. If not, the tag either is
- // above cutoff or is 0. (There's intentional wiggle room when tag is 0,
- // because that can arise in several ways, and for best performance we want
- // to avoid an extra "is tag == 0?" check here.)
- inline std::pair<uint32, bool> ReadTagWithCutoff(uint32 cutoff)
- GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
-
// Usually returns true if calling ReadVarint32() now would produce the given
// value. Will always return false if ReadVarint32() would not return the
// given value. If ExpectTag() returns true, it also advances past
@@ -275,8 +248,8 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
// zero, and ConsumedEntireMessage() will return true.
bool ExpectAtEnd();
- // If the last call to ReadTag() or ReadTagWithCutoff() returned the
- // given value, returns true. Otherwise, returns false;
+ // If the last call to ReadTag() returned the given value, returns true.
+ // Otherwise, returns false;
//
// This is needed because parsers for some types of embedded messages
// (with field type TYPE_GROUP) don't actually know that they've reached the
@@ -325,10 +298,7 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
// Returns the number of bytes left until the nearest limit on the
// stack is hit, or -1 if no limits are in place.
- int BytesUntilLimit() const;
-
- // Returns current position relative to the beginning of the input stream.
- int CurrentPosition() const;
+ int BytesUntilLimit();
// Total Bytes Limit -----------------------------------------------
// To prevent malicious users from sending excessively large messages
@@ -344,9 +314,8 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
// cause integer overflows is 512MB. The default limit is 64MB. Apps
// should set shorter limits if possible. If warning_threshold is not -1,
// a warning will be printed to stderr after warning_threshold bytes are
- // read. For backwards compatibility all negative values get squashed to -1,
- // as other negative values might have special internal meanings.
- // An error will always be printed to stderr if the limit is reached.
+ // read. An error will always be printed to stderr if the limit is
+ // reached.
//
// This is unrelated to PushLimit()/PopLimit().
//
@@ -367,20 +336,15 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
// something unusual.
void SetTotalBytesLimit(int total_bytes_limit, int warning_threshold);
- // The Total Bytes Limit minus the Current Position, or -1 if there
- // is no Total Bytes Limit.
- int BytesUntilTotalBytesLimit() const;
-
// Recursion Limit -------------------------------------------------
// To prevent corrupt or malicious messages from causing stack overflows,
// we must keep track of the depth of recursion when parsing embedded
// messages and groups. CodedInputStream keeps track of this because it
// is the only object that is passed down the stack during parsing.
- // Sets the maximum recursion depth. The default is 100.
+ // Sets the maximum recursion depth. The default is 64.
void SetRecursionLimit(int limit);
-
// Increments the current recursion depth. Returns true if the depth is
// under the limit, false if it has gone over.
bool IncrementRecursionDepth();
@@ -456,8 +420,7 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
//
// Note that this feature is ignored when parsing "lite" messages as they do
// not have descriptors.
- void SetExtensionRegistry(const DescriptorPool* pool,
- MessageFactory* factory);
+ void SetExtensionRegistry(DescriptorPool* pool, MessageFactory* factory);
// Get the DescriptorPool set via SetExtensionRegistry(), or NULL if no pool
// has been provided.
@@ -481,7 +444,7 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
int overflow_bytes_;
// LastTagWas() stuff.
- uint32 last_tag_; // result of last ReadTag() or ReadTagWithCutoff().
+ uint32 last_tag_; // result of last ReadTag().
// This is set true by ReadTag{Fallback/Slow}() if it is called when exactly
// at EOF, or by ExpectAtEnd() when it returns true. This happens when we
@@ -506,11 +469,6 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
// Maximum number of bytes to read, period. This is unrelated to
// current_limit_. Set using SetTotalBytesLimit().
int total_bytes_limit_;
-
- // If positive/0: Limit for bytes read after which a warning due to size
- // should be logged.
- // If -1: Printing of warning disabled. Can be set by client.
- // If -2: Internal: Limit has been reached, print full size when destructing.
int total_bytes_warning_threshold_;
// Current recursion depth, controlled by IncrementRecursionDepth() and
@@ -563,13 +521,12 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
bool ReadStringFallback(string* buffer, int size);
// Return the size of the buffer.
- int BufferSize() const;
+ uint32 BufferSize() const;
static const int kDefaultTotalBytesLimit = 64 << 20; // 64MB
static const int kDefaultTotalBytesWarningThreshold = 32 << 20; // 32MB
-
- static int default_recursion_limit_; // 100 by default.
+ static const int kDefaultRecursionLimit = 64;
};
// Class which encodes and writes binary data which is composed of varint-
@@ -597,7 +554,7 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
// char text[] = "Hello world!";
//
// int coded_size = sizeof(magic_number) +
-// CodedOutputStream::VarintSize32(strlen(text)) +
+// CodedOutputStream::Varint32Size(strlen(text)) +
// strlen(text);
//
// uint8* buffer =
@@ -653,9 +610,6 @@ class LIBPROTOBUF_EXPORT CodedOutputStream {
// Write raw bytes, copying them from the given buffer.
void WriteRaw(const void* buffer, int size);
- // Like WriteRaw() but will try to write aliased data if aliasing is
- // turned on.
- void WriteRawMaybeAliased(const void* data, int size);
// Like WriteRaw() but writing directly to the target array.
// This is _not_ inlined, as the compiler often optimizes memcpy into inline
// copy loops. Since this gets called by every field with string or bytes
@@ -667,21 +621,8 @@ class LIBPROTOBUF_EXPORT CodedOutputStream {
void WriteString(const string& str);
// Like WriteString() but writing directly to the target array.
static uint8* WriteStringToArray(const string& str, uint8* target);
- // Write the varint-encoded size of str followed by str.
- static uint8* WriteStringWithSizeToArray(const string& str, uint8* target);
- // Instructs the CodedOutputStream to allow the underlying
- // ZeroCopyOutputStream to hold pointers to the original structure instead of
- // copying, if it supports it (i.e. output->AllowsAliasing() is true). If the
- // underlying stream does not support aliasing, then enabling it has no
- // affect. For now, this only affects the behavior of
- // WriteRawMaybeAliased().
- //
- // NOTE: It is caller's responsibility to ensure that the chunk of memory
- // remains live until all of the data has been consumed from the stream.
- void EnableAliasing(bool enabled);
-
// Write a 32-bit little-endian integer.
void WriteLittleEndian32(uint32 value);
// Like WriteLittleEndian32() but writing directly to the target array.
@@ -726,21 +667,6 @@ class LIBPROTOBUF_EXPORT CodedOutputStream {
// If negative, 10 bytes. Otheriwse, same as VarintSize32().
static int VarintSize32SignExtended(int32 value);
- // Compile-time equivalent of VarintSize32().
- template <uint32 Value>
- struct StaticVarintSize32 {
- static const int value =
- (Value < (1 << 7))
- ? 1
- : (Value < (1 << 14))
- ? 2
- : (Value < (1 << 21))
- ? 3
- : (Value < (1 << 28))
- ? 4
- : 5;
- };
-
// Returns the total number of bytes written since this object was created.
inline int ByteCount() const;
@@ -756,7 +682,6 @@ class LIBPROTOBUF_EXPORT CodedOutputStream {
int buffer_size_;
int total_bytes_; // Sum of sizes of all buffers seen so far.
bool had_error_; // Whether an error occurred during output.
- bool aliasing_enabled_; // See EnableAliasing().
// Advance the buffer by a given number of bytes.
void Advance(int amount);
@@ -765,10 +690,6 @@ class LIBPROTOBUF_EXPORT CodedOutputStream {
// Advance(buffer_size_).
bool Refresh();
- // Like WriteRaw() but may avoid copying if the underlying
- // ZeroCopyOutputStream supports it.
- void WriteAliasedRaw(const void* buffer, int size);
-
static uint8* WriteVarint32FallbackToArray(uint32 value, uint8* target);
// Always-inlined versions of WriteVarint* functions so that code can be
@@ -814,7 +735,8 @@ inline bool CodedInputStream::ReadVarint64(uint64* value) {
inline const uint8* CodedInputStream::ReadLittleEndian32FromArray(
const uint8* buffer,
uint32* value) {
-#if defined(PROTOBUF_LITTLE_ENDIAN)
+#if !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST) && \
+ defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN
memcpy(value, buffer, sizeof(*value));
return buffer + sizeof(*value);
#else
@@ -829,7 +751,8 @@ inline const uint8* CodedInputStream::ReadLittleEndian32FromArray(
inline const uint8* CodedInputStream::ReadLittleEndian64FromArray(
const uint8* buffer,
uint64* value) {
-#if defined(PROTOBUF_LITTLE_ENDIAN)
+#if !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST) && \
+ defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN
memcpy(value, buffer, sizeof(*value));
return buffer + sizeof(*value);
#else
@@ -848,8 +771,9 @@ inline const uint8* CodedInputStream::ReadLittleEndian64FromArray(
}
inline bool CodedInputStream::ReadLittleEndian32(uint32* value) {
-#if defined(PROTOBUF_LITTLE_ENDIAN)
- if (GOOGLE_PREDICT_TRUE(BufferSize() >= static_cast<int>(sizeof(*value)))) {
+#if !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST) && \
+ defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN
+ if (GOOGLE_PREDICT_TRUE(BufferSize() >= sizeof(*value))) {
memcpy(value, buffer_, sizeof(*value));
Advance(sizeof(*value));
return true;
@@ -862,8 +786,9 @@ inline bool CodedInputStream::ReadLittleEndian32(uint32* value) {
}
inline bool CodedInputStream::ReadLittleEndian64(uint64* value) {
-#if defined(PROTOBUF_LITTLE_ENDIAN)
- if (GOOGLE_PREDICT_TRUE(BufferSize() >= static_cast<int>(sizeof(*value)))) {
+#if !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST) && \
+ defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN
+ if (GOOGLE_PREDICT_TRUE(BufferSize() >= sizeof(*value))) {
memcpy(value, buffer_, sizeof(*value));
Advance(sizeof(*value));
return true;
@@ -886,45 +811,6 @@ inline uint32 CodedInputStream::ReadTag() {
}
}
-inline std::pair<uint32, bool> CodedInputStream::ReadTagWithCutoff(
- uint32 cutoff) {
- // In performance-sensitive code we can expect cutoff to be a compile-time
- // constant, and things like "cutoff >= kMax1ByteVarint" to be evaluated at
- // compile time.
- if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_)) {
- // Hot case: buffer_ non_empty, buffer_[0] in [1, 128).
- // TODO(gpike): Is it worth rearranging this? E.g., if the number of fields
- // is large enough then is it better to check for the two-byte case first?
- if (static_cast<int8>(buffer_[0]) > 0) {
- const uint32 kMax1ByteVarint = 0x7f;
- uint32 tag = last_tag_ = buffer_[0];
- Advance(1);
- return make_pair(tag, cutoff >= kMax1ByteVarint || tag <= cutoff);
- }
- // Other hot case: cutoff >= 0x80, buffer_ has at least two bytes available,
- // and tag is two bytes. The latter is tested by bitwise-and-not of the
- // first byte and the second byte.
- if (cutoff >= 0x80 &&
- GOOGLE_PREDICT_TRUE(buffer_ + 1 < buffer_end_) &&
- GOOGLE_PREDICT_TRUE((buffer_[0] & ~buffer_[1]) >= 0x80)) {
- const uint32 kMax2ByteVarint = (0x7f << 7) + 0x7f;
- uint32 tag = last_tag_ = (1u << 7) * buffer_[1] + (buffer_[0] - 0x80);
- Advance(2);
- // It might make sense to test for tag == 0 now, but it is so rare that
- // that we don't bother. A varint-encoded 0 should be one byte unless
- // the encoder lost its mind. The second part of the return value of
- // this function is allowed to be either true or false if the tag is 0,
- // so we don't have to check for tag == 0. We may need to check whether
- // it exceeds cutoff.
- bool at_or_below_cutoff = cutoff >= kMax2ByteVarint || tag <= cutoff;
- return make_pair(tag, at_or_below_cutoff);
- }
- }
- // Slow path
- last_tag_ = ReadTagFallback();
- return make_pair(last_tag_, static_cast<uint32>(last_tag_ - 1) < cutoff);
-}
-
inline bool CodedInputStream::LastTagWas(uint32 expected) {
return last_tag_ == expected;
}
@@ -981,9 +867,7 @@ inline bool CodedInputStream::ExpectAtEnd() {
// If we are at a limit we know no more bytes can be read. Otherwise, it's
// hard to say without calling Refresh(), and we'd rather not do that.
- if (buffer_ == buffer_end_ &&
- ((buffer_size_after_limit_ != 0) ||
- (total_bytes_read_ == current_limit_))) {
+ if (buffer_ == buffer_end_ && buffer_size_after_limit_ != 0) {
last_tag_ = 0; // Pretend we called ReadTag()...
legitimate_message_end_ = true; // ... and it hit EOF.
return true;
@@ -992,10 +876,6 @@ inline bool CodedInputStream::ExpectAtEnd() {
}
}
-inline int CodedInputStream::CurrentPosition() const {
- return total_bytes_read_ - (BufferSize() + buffer_size_after_limit_);
-}
-
inline uint8* CodedOutputStream::GetDirectBufferForNBytesAndAdvance(int size) {
if (buffer_size_ < size) {
return NULL;
@@ -1035,7 +915,8 @@ inline uint8* CodedOutputStream::WriteVarint32SignExtendedToArray(
inline uint8* CodedOutputStream::WriteLittleEndian32ToArray(uint32 value,
uint8* target) {
-#if defined(PROTOBUF_LITTLE_ENDIAN)
+#if !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST) && \
+ defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN
memcpy(target, &value, sizeof(value));
#else
target[0] = static_cast<uint8>(value);
@@ -1048,7 +929,8 @@ inline uint8* CodedOutputStream::WriteLittleEndian32ToArray(uint32 value,
inline uint8* CodedOutputStream::WriteLittleEndian64ToArray(uint64 value,
uint8* target) {
-#if defined(PROTOBUF_LITTLE_ENDIAN)
+#if !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST) && \
+ defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN
memcpy(target, &value, sizeof(value));
#else
uint32 part0 = static_cast<uint32>(value);
@@ -1101,21 +983,12 @@ inline int CodedOutputStream::VarintSize32SignExtended(int32 value) {
}
inline void CodedOutputStream::WriteString(const string& str) {
- WriteRaw(str.data(), static_cast<int>(str.size()));
-}
-
-inline void CodedOutputStream::WriteRawMaybeAliased(
- const void* data, int size) {
- if (aliasing_enabled_) {
- WriteAliasedRaw(data, size);
- } else {
- WriteRaw(data, size);
- }
+ WriteRaw(str.data(), str.size());
}
inline uint8* CodedOutputStream::WriteStringToArray(
const string& str, uint8* target) {
- return WriteRawToArray(str.data(), static_cast<int>(str.size()), target);
+ return WriteRawToArray(str.data(), str.size(), target);
}
inline int CodedOutputStream::ByteCount() const {
@@ -1144,7 +1017,7 @@ inline void CodedInputStream::DecrementRecursionDepth() {
if (recursion_depth_ > 0) --recursion_depth_;
}
-inline void CodedInputStream::SetExtensionRegistry(const DescriptorPool* pool,
+inline void CodedInputStream::SetExtensionRegistry(DescriptorPool* pool,
MessageFactory* factory) {
extension_pool_ = pool;
extension_factory_ = factory;
@@ -1158,7 +1031,7 @@ inline MessageFactory* CodedInputStream::GetExtensionFactory() {
return extension_factory_;
}
-inline int CodedInputStream::BufferSize() const {
+inline uint32 CodedInputStream::BufferSize() const {
return buffer_end_ - buffer_;
}
@@ -1171,12 +1044,12 @@ inline CodedInputStream::CodedInputStream(ZeroCopyInputStream* input)
last_tag_(0),
legitimate_message_end_(false),
aliasing_enabled_(false),
- current_limit_(kint32max),
+ current_limit_(INT_MAX),
buffer_size_after_limit_(0),
total_bytes_limit_(kDefaultTotalBytesLimit),
total_bytes_warning_threshold_(kDefaultTotalBytesWarningThreshold),
recursion_depth_(0),
- recursion_limit_(default_recursion_limit_),
+ recursion_limit_(kDefaultRecursionLimit),
extension_pool_(NULL),
extension_factory_(NULL) {
// Eagerly Refresh() so buffer space is immediately available.
@@ -1197,24 +1070,21 @@ inline CodedInputStream::CodedInputStream(const uint8* buffer, int size)
total_bytes_limit_(kDefaultTotalBytesLimit),
total_bytes_warning_threshold_(kDefaultTotalBytesWarningThreshold),
recursion_depth_(0),
- recursion_limit_(default_recursion_limit_),
+ recursion_limit_(kDefaultRecursionLimit),
extension_pool_(NULL),
extension_factory_(NULL) {
// Note that setting current_limit_ == size is important to prevent some
// code paths from trying to access input_ and segfaulting.
}
-inline bool CodedInputStream::IsFlat() const {
- return input_ == NULL;
+inline CodedInputStream::~CodedInputStream() {
+ if (input_ != NULL) {
+ BackUpInputToCurrentPosition();
+ }
}
} // namespace io
} // namespace protobuf
-
-#if defined(_MSC_VER) && _MSC_VER >= 1300
- #pragma runtime_checks("c", restore)
-#endif // _MSC_VER
-
} // namespace google
#endif // GOOGLE_PROTOBUF_IO_CODED_STREAM_H__