aboutsummaryrefslogtreecommitdiffstats
path: root/src/google/protobuf/wire_format_lite_inl.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/google/protobuf/wire_format_lite_inl.h')
-rw-r--r--src/google/protobuf/wire_format_lite_inl.h221
1 files changed, 167 insertions, 54 deletions
diff --git a/src/google/protobuf/wire_format_lite_inl.h b/src/google/protobuf/wire_format_lite_inl.h
index 3f0d7f8..ca367f5 100644
--- a/src/google/protobuf/wire_format_lite_inl.h
+++ b/src/google/protobuf/wire_format_lite_inl.h
@@ -36,12 +36,16 @@
#ifndef GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_INL_H__
#define GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_INL_H__
+#ifdef _MSC_VER
+// This is required for min/max on VS2013 only.
+#include <algorithm>
+#endif
+
#include <string>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/message_lite.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/wire_format_lite.h>
-#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/io/coded_stream.h>
@@ -151,8 +155,8 @@ template <>
inline bool WireFormatLite::ReadPrimitive<bool, WireFormatLite::TYPE_BOOL>(
io::CodedInputStream* input,
bool* value) {
- uint32 temp;
- if (!input->ReadVarint32(&temp)) return false;
+ uint64 temp;
+ if (!input->ReadVarint64(&temp)) return false;
*value = temp != 0;
return true;
}
@@ -222,10 +226,11 @@ inline const uint8* WireFormatLite::ReadPrimitiveFromArray<
}
template <typename CType, enum WireFormatLite::FieldType DeclaredType>
-inline bool WireFormatLite::ReadRepeatedPrimitive(int, // tag_size, unused
- uint32 tag,
- io::CodedInputStream* input,
- RepeatedField<CType>* values) {
+inline bool WireFormatLite::ReadRepeatedPrimitive(
+ int, // tag_size, unused.
+ uint32 tag,
+ io::CodedInputStream* input,
+ RepeatedField<CType>* values) {
CType value;
if (!ReadPrimitive<CType, DeclaredType>(input, &value)) return false;
values->Add(value);
@@ -285,7 +290,7 @@ inline bool WireFormatLite::ReadRepeatedFixedSizePrimitive(
return true;
}
-// Specializations of ReadRepeatedPrimitive for the fixed size types, which use
+// Specializations of ReadRepeatedPrimitive for the fixed size types, which use
// the optimized code path.
#define READ_REPEATED_FIXED_SIZE_PRIMITIVE(CPPTYPE, DECLARED_TYPE) \
template <> \
@@ -300,12 +305,12 @@ inline bool WireFormatLite::ReadRepeatedPrimitive< \
tag_size, tag, input, values); \
}
-READ_REPEATED_FIXED_SIZE_PRIMITIVE(uint32, TYPE_FIXED32);
-READ_REPEATED_FIXED_SIZE_PRIMITIVE(uint64, TYPE_FIXED64);
-READ_REPEATED_FIXED_SIZE_PRIMITIVE(int32, TYPE_SFIXED32);
-READ_REPEATED_FIXED_SIZE_PRIMITIVE(int64, TYPE_SFIXED64);
-READ_REPEATED_FIXED_SIZE_PRIMITIVE(float, TYPE_FLOAT);
-READ_REPEATED_FIXED_SIZE_PRIMITIVE(double, TYPE_DOUBLE);
+READ_REPEATED_FIXED_SIZE_PRIMITIVE(uint32, TYPE_FIXED32)
+READ_REPEATED_FIXED_SIZE_PRIMITIVE(uint64, TYPE_FIXED64)
+READ_REPEATED_FIXED_SIZE_PRIMITIVE(int32, TYPE_SFIXED32)
+READ_REPEATED_FIXED_SIZE_PRIMITIVE(int64, TYPE_SFIXED64)
+READ_REPEATED_FIXED_SIZE_PRIMITIVE(float, TYPE_FLOAT)
+READ_REPEATED_FIXED_SIZE_PRIMITIVE(double, TYPE_DOUBLE)
#undef READ_REPEATED_FIXED_SIZE_PRIMITIVE
@@ -335,6 +340,86 @@ inline bool WireFormatLite::ReadPackedPrimitive(io::CodedInputStream* input,
}
template <typename CType, enum WireFormatLite::FieldType DeclaredType>
+inline bool WireFormatLite::ReadPackedFixedSizePrimitive(
+ io::CodedInputStream* input, RepeatedField<CType>* values) {
+ uint32 length;
+ if (!input->ReadVarint32(&length)) return false;
+ const uint32 old_entries = values->size();
+ const uint32 new_entries = length / sizeof(CType);
+ const uint32 new_bytes = new_entries * sizeof(CType);
+ if (new_bytes != length) return false;
+ // We would *like* to pre-allocate the buffer to write into (for
+ // speed), but *must* avoid performing a very large allocation due
+ // to a malicious user-supplied "length" above. So we have a fast
+ // path that pre-allocates when the "length" is less than a bound.
+ // We determine the bound by calling BytesUntilTotalBytesLimit() and
+ // BytesUntilLimit(). These return -1 to mean "no limit set".
+ // There are four cases:
+ // TotalBytesLimit Limit
+ // -1 -1 Use slow path.
+ // -1 >= 0 Use fast path if length <= Limit.
+ // >= 0 -1 Use slow path.
+ // >= 0 >= 0 Use fast path if length <= min(both limits).
+ int64 bytes_limit = input->BytesUntilTotalBytesLimit();
+ if (bytes_limit == -1) {
+ bytes_limit = input->BytesUntilLimit();
+ } else {
+ bytes_limit =
+ min(bytes_limit, static_cast<int64>(input->BytesUntilLimit()));
+ }
+ if (bytes_limit >= new_bytes) {
+ // Fast-path that pre-allocates *values to the final size.
+#if defined(PROTOBUF_LITTLE_ENDIAN)
+ values->Resize(old_entries + new_entries, 0);
+ // values->mutable_data() may change after Resize(), so do this after:
+ void* dest = reinterpret_cast<void*>(values->mutable_data() + old_entries);
+ if (!input->ReadRaw(dest, new_bytes)) {
+ values->Truncate(old_entries);
+ return false;
+ }
+#else
+ values->Reserve(old_entries + new_entries);
+ CType value;
+ for (int i = 0; i < new_entries; ++i) {
+ if (!ReadPrimitive<CType, DeclaredType>(input, &value)) return false;
+ values->AddAlreadyReserved(value);
+ }
+#endif
+ } else {
+ // This is the slow-path case where "length" may be too large to
+ // safely allocate. We read as much as we can into *values
+ // without pre-allocating "length" bytes.
+ CType value;
+ for (int i = 0; i < new_entries; ++i) {
+ if (!ReadPrimitive<CType, DeclaredType>(input, &value)) return false;
+ values->Add(value);
+ }
+ }
+ return true;
+}
+
+// Specializations of ReadPackedPrimitive for the fixed size types, which use
+// an optimized code path.
+#define READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(CPPTYPE, DECLARED_TYPE) \
+template <> \
+inline bool WireFormatLite::ReadPackedPrimitive< \
+ CPPTYPE, WireFormatLite::DECLARED_TYPE>( \
+ io::CodedInputStream* input, \
+ RepeatedField<CPPTYPE>* values) { \
+ return ReadPackedFixedSizePrimitive< \
+ CPPTYPE, WireFormatLite::DECLARED_TYPE>(input, values); \
+}
+
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(uint32, TYPE_FIXED32);
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(uint64, TYPE_FIXED64);
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(int32, TYPE_SFIXED32);
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(int64, TYPE_SFIXED64);
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(float, TYPE_FLOAT);
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(double, TYPE_DOUBLE);
+
+#undef READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE
+
+template <typename CType, enum WireFormatLite::FieldType DeclaredType>
bool WireFormatLite::ReadPackedPrimitiveNoInline(io::CodedInputStream* input,
RepeatedField<CType>* values) {
return ReadPackedPrimitive<CType, DeclaredType>(input, values);
@@ -368,12 +453,24 @@ inline bool WireFormatLite::ReadMessage(io::CodedInputStream* input,
return true;
}
-template<typename MessageType>
-inline bool WireFormatLite::ReadGroupNoVirtual(int field_number,
- io::CodedInputStream* input,
- MessageType* value) {
+// We name the template parameter something long and extremely unlikely to occur
+// elsewhere because a *qualified* member access expression designed to avoid
+// virtual dispatch, C++03 [basic.lookup.classref] 3.4.5/4 requires that the
+// name of the qualifying class to be looked up both in the context of the full
+// expression (finding the template parameter) and in the context of the object
+// whose member we are accessing. This could potentially find a nested type
+// within that object. The standard goes on to require these names to refer to
+// the same entity, which this collision would violate. The lack of a safe way
+// to avoid this collision appears to be a defect in the standard, but until it
+// is corrected, we choose the name to avoid accidental collisions.
+template<typename MessageType_WorkAroundCppLookupDefect>
+inline bool WireFormatLite::ReadGroupNoVirtual(
+ int field_number, io::CodedInputStream* input,
+ MessageType_WorkAroundCppLookupDefect* value) {
if (!input->IncrementRecursionDepth()) return false;
- if (!value->MessageType::MergePartialFromCodedStream(input)) return false;
+ if (!value->
+ MessageType_WorkAroundCppLookupDefect::MergePartialFromCodedStream(input))
+ return false;
input->DecrementRecursionDepth();
// Make sure the last thing read was an end tag for this group.
if (!input->LastTagWas(MakeTag(field_number, WIRETYPE_END_GROUP))) {
@@ -381,14 +478,16 @@ inline bool WireFormatLite::ReadGroupNoVirtual(int field_number,
}
return true;
}
-template<typename MessageType>
-inline bool WireFormatLite::ReadMessageNoVirtual(io::CodedInputStream* input,
- MessageType* value) {
+template<typename MessageType_WorkAroundCppLookupDefect>
+inline bool WireFormatLite::ReadMessageNoVirtual(
+ io::CodedInputStream* input, MessageType_WorkAroundCppLookupDefect* value) {
uint32 length;
if (!input->ReadVarint32(&length)) return false;
if (!input->IncrementRecursionDepth()) return false;
io::CodedInputStream::Limit limit = input->PushLimit(length);
- if (!value->MessageType::MergePartialFromCodedStream(input)) return false;
+ if (!value->
+ MessageType_WorkAroundCppLookupDefect::MergePartialFromCodedStream(input))
+ return false;
// Make sure that parsing stopped when the limit was hit, not at an endgroup
// tag.
if (!input->ConsumedEntireMessage()) return false;
@@ -461,21 +560,24 @@ inline void WireFormatLite::WriteEnumNoTag(int value,
output->WriteVarint32SignExtended(value);
}
-template<typename MessageType>
-inline void WireFormatLite::WriteGroupNoVirtual(int field_number,
- const MessageType& value,
- io::CodedOutputStream* output) {
+// See comment on ReadGroupNoVirtual to understand the need for this template
+// parameter name.
+template<typename MessageType_WorkAroundCppLookupDefect>
+inline void WireFormatLite::WriteGroupNoVirtual(
+ int field_number, const MessageType_WorkAroundCppLookupDefect& value,
+ io::CodedOutputStream* output) {
WriteTag(field_number, WIRETYPE_START_GROUP, output);
- value.MessageType::SerializeWithCachedSizes(output);
+ value.MessageType_WorkAroundCppLookupDefect::SerializeWithCachedSizes(output);
WriteTag(field_number, WIRETYPE_END_GROUP, output);
}
-template<typename MessageType>
-inline void WireFormatLite::WriteMessageNoVirtual(int field_number,
- const MessageType& value,
- io::CodedOutputStream* output) {
+template<typename MessageType_WorkAroundCppLookupDefect>
+inline void WireFormatLite::WriteMessageNoVirtual(
+ int field_number, const MessageType_WorkAroundCppLookupDefect& value,
+ io::CodedOutputStream* output) {
WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output);
- output->WriteVarint32(value.MessageType::GetCachedSize());
- value.MessageType::SerializeWithCachedSizes(output);
+ output->WriteVarint32(
+ value.MessageType_WorkAroundCppLookupDefect::GetCachedSize());
+ value.MessageType_WorkAroundCppLookupDefect::SerializeWithCachedSizes(output);
}
// ===================================================================
@@ -644,15 +746,13 @@ inline uint8* WireFormatLite::WriteStringToArray(int field_number,
// WriteString() to avoid code duplication. If the implementations become
// different, you will need to update that usage.
target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target);
- target = io::CodedOutputStream::WriteVarint32ToArray(value.size(), target);
- return io::CodedOutputStream::WriteStringToArray(value, target);
+ return io::CodedOutputStream::WriteStringWithSizeToArray(value, target);
}
inline uint8* WireFormatLite::WriteBytesToArray(int field_number,
const string& value,
uint8* target) {
target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target);
- target = io::CodedOutputStream::WriteVarint32ToArray(value.size(), target);
- return io::CodedOutputStream::WriteStringToArray(value, target);
+ return io::CodedOutputStream::WriteStringWithSizeToArray(value, target);
}
@@ -672,20 +772,26 @@ inline uint8* WireFormatLite::WriteMessageToArray(int field_number,
return value.SerializeWithCachedSizesToArray(target);
}
-template<typename MessageType>
+// See comment on ReadGroupNoVirtual to understand the need for this template
+// parameter name.
+template<typename MessageType_WorkAroundCppLookupDefect>
inline uint8* WireFormatLite::WriteGroupNoVirtualToArray(
- int field_number, const MessageType& value, uint8* target) {
+ int field_number, const MessageType_WorkAroundCppLookupDefect& value,
+ uint8* target) {
target = WriteTagToArray(field_number, WIRETYPE_START_GROUP, target);
- target = value.MessageType::SerializeWithCachedSizesToArray(target);
+ target = value.MessageType_WorkAroundCppLookupDefect
+ ::SerializeWithCachedSizesToArray(target);
return WriteTagToArray(field_number, WIRETYPE_END_GROUP, target);
}
-template<typename MessageType>
+template<typename MessageType_WorkAroundCppLookupDefect>
inline uint8* WireFormatLite::WriteMessageNoVirtualToArray(
- int field_number, const MessageType& value, uint8* target) {
+ int field_number, const MessageType_WorkAroundCppLookupDefect& value,
+ uint8* target) {
target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target);
target = io::CodedOutputStream::WriteVarint32ToArray(
- value.MessageType::GetCachedSize(), target);
- return value.MessageType::SerializeWithCachedSizesToArray(target);
+ value.MessageType_WorkAroundCppLookupDefect::GetCachedSize(), target);
+ return value.MessageType_WorkAroundCppLookupDefect
+ ::SerializeWithCachedSizesToArray(target);
}
// ===================================================================
@@ -726,18 +832,25 @@ inline int WireFormatLite::GroupSize(const MessageLite& value) {
return value.ByteSize();
}
inline int WireFormatLite::MessageSize(const MessageLite& value) {
- int size = value.ByteSize();
- return io::CodedOutputStream::VarintSize32(size) + size;
+ return LengthDelimitedSize(value.ByteSize());
}
-template<typename MessageType>
-inline int WireFormatLite::GroupSizeNoVirtual(const MessageType& value) {
- return value.MessageType::ByteSize();
+// See comment on ReadGroupNoVirtual to understand the need for this template
+// parameter name.
+template<typename MessageType_WorkAroundCppLookupDefect>
+inline int WireFormatLite::GroupSizeNoVirtual(
+ const MessageType_WorkAroundCppLookupDefect& value) {
+ return value.MessageType_WorkAroundCppLookupDefect::ByteSize();
}
-template<typename MessageType>
-inline int WireFormatLite::MessageSizeNoVirtual(const MessageType& value) {
- int size = value.MessageType::ByteSize();
- return io::CodedOutputStream::VarintSize32(size) + size;
+template<typename MessageType_WorkAroundCppLookupDefect>
+inline int WireFormatLite::MessageSizeNoVirtual(
+ const MessageType_WorkAroundCppLookupDefect& value) {
+ return LengthDelimitedSize(
+ value.MessageType_WorkAroundCppLookupDefect::ByteSize());
+}
+
+inline int WireFormatLite::LengthDelimitedSize(int length) {
+ return io::CodedOutputStream::VarintSize32(length) + length;
}
} // namespace internal