diff options
Diffstat (limited to 'src/google/protobuf/unknown_field_set.cc')
-rw-r--r-- | src/google/protobuf/unknown_field_set.cc | 131 |
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 |