aboutsummaryrefslogtreecommitdiff
path: root/src/google/protobuf/unknown_field_set.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/google/protobuf/unknown_field_set.cc')
-rw-r--r--src/google/protobuf/unknown_field_set.cc131
1 files changed, 131 insertions, 0 deletions
diff --git a/src/google/protobuf/unknown_field_set.cc b/src/google/protobuf/unknown_field_set.cc
index 35f24e7a..0226c76b 100644
--- a/src/google/protobuf/unknown_field_set.cc
+++ b/src/google/protobuf/unknown_field_set.cc
@@ -43,6 +43,8 @@
#include <google/protobuf/wire_format.h>
#include <google/protobuf/stubs/stl_util.h>
+#include <google/protobuf/port_def.inc>
+
namespace google {
namespace protobuf {
@@ -317,5 +319,134 @@ uint8* UnknownField::SerializeLengthDelimitedNoTagToArray(uint8* target) const {
return target;
}
+#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
+namespace internal {
+
+const char* PackedValidEnumParser(const char* begin, const char* end,
+ void* object, ParseContext* ctx) {
+ auto repeated_field = static_cast<RepeatedField<int>*>(object);
+ auto ptr = begin;
+ while (ptr < end) {
+ uint64 varint;
+ ptr = Varint::Parse64(ptr, &varint);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+ int val = varint;
+ if (ctx->extra_parse_data().ValidateEnum<UnknownFieldSet>(val))
+ repeated_field->Add(val);
+ }
+ return ptr;
+}
+
+const char* PackedValidEnumParserArg(const char* begin, const char* end,
+ void* object, ParseContext* ctx) {
+ auto repeated_field = static_cast<RepeatedField<int>*>(object);
+ auto ptr = begin;
+ while (ptr < end) {
+ uint64 varint;
+ ptr = Varint::Parse64(ptr, &varint);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+ int val = varint;
+ if (ctx->extra_parse_data().ValidateEnumArg<UnknownFieldSet>(val))
+ repeated_field->Add(val);
+ }
+ return ptr;
+}
+
+const char* UnknownGroupParse(const char* begin, const char* end, void* object,
+ ParseContext* ctx) {
+ auto unknown = static_cast<UnknownFieldSet*>(object);
+
+ auto ptr = begin;
+ while (ptr < end) {
+ uint32 tag;
+ ptr = Varint::Parse32Inline(ptr, &tag);
+ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+ GOOGLE_PROTOBUF_PARSER_ASSERT((tag >> 3) != 0);
+
+ auto res = UnknownFieldParse(tag, {UnknownGroupParse, unknown}, ptr, end,
+ unknown, ctx);
+ ptr = res.first;
+ if (res.second) break;
+ }
+ return ptr;
+}
+
+std::pair<const char*, bool> UnknownFieldParse(uint64 tag, ParseClosure parent,
+ const char* begin,
+ const char* end,
+ UnknownFieldSet* unknown,
+ ParseContext* ctx) {
+ uint32 size;
+ int depth;
+ void* object;
+ auto ptr = begin;
+
+ uint32 field_num = tag >> 3;
+ GOOGLE_PROTOBUF_ASSERT_RETURN(field_num != 0, std::make_pair(nullptr, true));
+ switch (tag & 7) {
+ case 0: {
+ uint64 val;
+ ptr = Varint::Parse64(ptr, &val);
+ GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));
+ unknown->AddVarint(field_num, val);
+ break;
+ }
+ case 1: {
+ uint64 val = UNALIGNED_LOAD64(ptr);
+ ptr = ptr + 8;
+ unknown->AddFixed64(field_num, val);
+ break;
+ }
+ case 2: {
+ ptr = Varint::Parse32Inline(ptr, &size);
+ GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));
+ object = unknown->AddLengthDelimited(field_num);
+ if (size > end - ptr) goto len_delim_till_end;
+ auto newend = ptr + size;
+ bool ok = ctx->ParseExactRange({StringParser, object}, ptr, newend);
+ GOOGLE_PROTOBUF_ASSERT_RETURN(ok, std::make_pair(nullptr, true));
+ ptr = newend;
+ break;
+ }
+ case 3: {
+ object = unknown->AddGroup(field_num);
+ bool ok = ctx->PrepareGroup(tag, &depth);
+ GOOGLE_PROTOBUF_ASSERT_RETURN(ok, std::make_pair(nullptr, true));
+ ptr = UnknownGroupParse(ptr, end, object, ctx);
+ GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));
+ if (ctx->GroupContinues(depth)) goto group_continues;
+ break;
+ }
+ case 4: {
+ bool ok = ctx->ValidEndGroup(tag);
+ GOOGLE_PROTOBUF_ASSERT_RETURN(ok, std::make_pair(nullptr, true));
+ return std::make_pair(ptr, true);
+ }
+ case 5: {
+ uint32 val = UNALIGNED_LOAD32(ptr);
+ ptr = ptr + 4;
+ unknown->AddFixed32(field_num, val);
+ break;
+ }
+ default:
+ GOOGLE_PROTOBUF_ASSERT_RETURN(false, std::make_pair(nullptr, true));
+ }
+ return std::make_pair(ptr, false);
+len_delim_till_end:
+ // Length delimited field crosses end
+ return std::make_pair(
+ ctx->StoreAndTailCall(ptr, end, parent, {StringParser, object}, size),
+ true);
+group_continues:
+ GOOGLE_DCHECK(ptr >= end);
+ // Group crossed end and must be continued. Either this a parse failure
+ // or we need to resume on the next chunk and thus save the state.
+ ctx->StoreGroup(parent, {UnknownGroupParse, object}, depth);
+ return std::make_pair(ptr, true);
+}
+
+} // namespace internal
+#endif // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
+
} // namespace protobuf
} // namespace google